一、开发环境:

 Qt版本:Qt5.12.3VS版本:VS2017opencv版本:opencv-4.5.1-vc14_vc15

二、要求:实现基于图像分块+OTSU的图像分割

1.OTSU大津法实现

算法原理:OTSU的算法是假设存在阈值TH将所有图像分成两类C1,也叫前景(小于TH)和C2,也叫后景(大于TH),这两类的均值分别为m1和m2,整个图像的均值为mG。同时图像被分为C1类和C2类的概率分别为p1和p2。因此有:
m 1 ∗ p 1 + m 2 ∗ p 2 = m G ; ① m1*p1+m2*p2 = mG;① m1∗p1+m2∗p2=mG;①
p 1 + p 2 = 1 ; ② p1+p2 = 1;② p1+p2=1;②
根据方差的知识,类间方差的表达式为:
σ ² = p 1 ∗ ( m 1 − m G ) ² + p 2 ∗ ( m 2 − m G ) ² ; ③ σ² = p1*(m1-mG)² + p2*(m2-mG)²;③ σ²=p1∗(m1−mG)²+p2∗(m2−mG)²;③
化简后,有
σ ² = p 1 ∗ p 2 ∗ ( m 2 − m 1 ) ² ; ④ σ² = p1* p2*(m2-m1)²;④ σ²=p1∗p2∗(m2−m1)²;④
求能使σ²最大的灰度级最大的k为该图像的最佳阈值,这就是大津法(OTSU)。
实现:
输入:原图像(src)

// 大津法
double QtWidgetsApplication1::myOSTU(cv::Mat &src) {// 判断输入图像是否为空if (src.empty()) {//qDebug() << "empty";return -1;}// 图像转灰度图Mat dst;src.copyTo(dst);if (dst.channels() > 1) {cvtColor(dst, dst, COLOR_BGR2GRAY);}// 最佳阈值int mythreshold = 0;double maxVariance = 0;  // 最大类间方差 double p1 = 0, p2 = 0;  // 前景与背景像素点所占比例double m1 = 0, m2 = 0;  // 前景与背景像素值平均灰度double histogram[256] = { 0 };double sum = 0;  // 像素总和const double EPS = 1e-6;//统计256个bin,每个bin像素的个数int tmp = 0;int index = 0;for (int i = 0; i < dst.rows; i++) {for (int j = 0; j < dst.cols; j++) {index = i * dst.cols + j;tmp = (int)dst.data[index];histogram[tmp]++;}}// 计算所有像素点的频次总数for (int i = 0; i < 256; i++) {sum += histogram[i];}// 前景像素统计for (int i = 0; i <= 254; i++) {for (int j = 0; j <= i; j++) {p1 += histogram[j];//以i为阈值,统计前景像素个数m1 += j * histogram[j];//以i为阈值,统计前景像素灰度总和}p1 = p1 / sum; m1 = m1 / p1;//背景像素统计for (int j = i + 1; j <= 255; j++) {m2 += j * histogram[j];//以i为阈值,统计背景像素灰度总和p2 += histogram[j];//以i为阈值,统计前景像素个数}p2 = 1 - p1;m2 = m2 / p2;double variance = p1 * p2*(m1 - m2)*(m1 - m2); //当前类间方差计算// 保留当前最佳阈值if (variance > maxVariance+EPS){maxVariance = variance;mythreshold = i;}// 清零p1 = 0;p2 = 0;m1 = 0;m2 = 0;}// 返回最佳阈值return mythreshold;
}

2.图像分块+阈值分割

图像分块算法原理:在原图上需要的部分,然后分割
实现的方式有很多,本文的逻辑是
① 获取图像,对图像按比例进行切块,切块时应当注意不能整除的边界部分
② 用一个容器来保存存放这些小的图像
③ 获取需要处理的块数,为其最佳阈值申请堆空间
④ 调用上面写的大津法,得到每一小块的最佳阈值
⑤ 阈值分割,对小于最佳阈值的置为255(白),其他部分置为0(黑),这里看具体需要选择自己需要的灰度值
⑥ 图像合并
⑦ 显示图像
整个过程的源代码如下:
其中输入的参数分别是:
参数1:输入图像(src)
参数2:输出图像(dst)
参数3:阈值处理的算法(type – 大津法,这里是预留的接口,为后面添加其他的处理算法)
参数4:行需要切“几刀”(Rnum)
参数5:列需要切“几刀”(Cnum)

// 基于图像分块的阈值分割
void QtWidgetsApplication1::Threshold(cv::Mat &src, cv::Mat &dst, int type, int Rnum, int Cnum) {// 判断输入图像是否为空if (src.empty()) {return;}//图像分块QVector<Mat> ceilImg;Mat imageCut, roiImg; Mat MergeImage(Size(src.cols, src.rows), src.type());  // 合并后图像int rowSize = 0;int colSize = 0;// 图像分块,每块大小为(src.cols / Cnum -- 列,src.rows / Rnum -- 行)for (int j = 0; j < Rnum; j++){for (int i = 0; i < Cnum; i++){Rect rect(i *(src.cols / Cnum), j * (src.rows / Rnum), src.cols / Cnum, src.rows / Rnum);imageCut = Mat(src, rect);roiImg = imageCut.clone();ceilImg.push_back(roiImg);}}// 行边界colSize = src.cols % Cnum;if (colSize > 0) {Rect rect(Cnum *(src.cols / Cnum), 0, colSize, src.rows);imageCut = Mat(src, rect);roiImg = imageCut.clone();ceilImg.push_back(roiImg);}// 列边界rowSize = src.rows%Rnum;if (rowSize > 0) {Rect rect(0, Rnum * (src.rows / Rnum), src.cols, rowSize);imageCut = Mat(src, rect);roiImg = imageCut.clone();ceilImg.push_back(roiImg);}// 大津法阈值分割// 获取需要处理的图像块数int count = ceilImg.size();// 为每一块图像的最佳阈值申请堆空间double *myThreshold = new double[count];for (int t = 0; t < count; t++) {// 获取最佳阈值myThreshold[t] = myOSTU(ceilImg[t]);// 根据最佳阈值分割for (int i = 0; i < ceilImg[t].rows; i++) {for (int j = 0; j < ceilImg[t].cols; j++) {if (ceilImg[t].ptr<uchar>(i)[j] < myThreshold[t]) {ceilImg[t].ptr<uchar>(i)[j] = 0;}else {ceilImg[t].ptr<uchar>(i)[j] = 255;}}}//threshold(ceilImg[t], ceilImg[t], myThreshold[t], 255, THRESH_BINARY);}// 释放堆空间delete myThreshold;//图像合并int t = 0;for (int j = 0; j < Rnum; j++){for (int i = 0; i < Cnum; i++){Rect ROI(i *(src.cols / Cnum), j * (src.rows / Rnum), src.cols / Cnum, src.rows / Rnum);ceilImg[t].copyTo(MergeImage(ROI));t++;}}//合并边界if (colSize > 0) {Rect ROI(Cnum *(src.cols / Cnum), 0, colSize, src.rows);ceilImg[t].copyTo(MergeImage(ROI));t++;}if (rowSize > 0) {Rect ROI(0, Rnum * (src.rows / Rnum), src.cols, rowSize);ceilImg[t].copyTo(MergeImage(ROI));t++;}imshow("mergeimage", MergeImage);}

3.效果图

3行1列的效果如下

3行2列的效果图如下

4行2列的效果如下

4行3列的效果图如下

由上面的结果图可以看出,这张图片分成4行2列,和3行2列的效果比较好
下面分享一下遇到的几个问题

  1. 白线
    取矩形时应当注意,系统自带的优化问题,做运算时应当注意优先级。如图1:
    下面代码中i *(src.cols / Cnum) 写成 i *src.cols / Cnum,导致范围截断
Rect ROI(i *(src.cols / Cnum), j * (src.rows / Rnum), src.cols / Cnum, src.rows / Rnum);

  1. 边缘问题 ---- 边界不做处理(一般边界重要信息不多)
    分为四种情况:行用R表示,列用C表示
    ① R、C均能整除,如下图

② R整除,C不能整除,如图

③ R不能整除,C整除,如图:

④ R、C均不能整除,如图:

初步解决,简单边界单独处理,如图:

  1. imread(“xxx”,flag);问题
    当flag = 0,生成的灰度图与cvtColor(xx,xx,BGR转灰度)生成的灰度图有局部灰度不同。
    imread(“xxx”,0)效果图如图:

CvtColor效果图

• When using IMREAD_GRAYSCALE, the codec’s internal grayscale conversion will be used, if available. Results may differ to the output of cvtColor()
• 使用IMREAD_GRAYSCALE时,将使用编解码器的内部灰度转换(如果有)。结果可能与cvtColor()的输出不同

基于OTSU(大津法)的图像分块的阈值分割相关推荐

  1. 图像二值化——OTSU大津法

    最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU.它是按图像的灰度特性,将图像分成背景和目标两部分,或者说,是寻找 ...

  2. java大津法确定阈值,大津法(最大类间阈值法)

    大津法又叫最大类间方差法.最大类间阈值法(OTSU).它的基本思想是,用一个阈值将图像中的数据分为两类,一类中图像的像素点的灰度均小于这个阈值,另一类中的图像的像素点的灰度均大于或者等于该阈值.如果这 ...

  3. 大津阈值分割matlab实验,OTSU(大津法)分割源程序(MATLAB版)

    接下来介绍OTSU方法的原理: ************************************************************************************ ...

  4. 图像处理入门系列--使用numpy实现OTSU大津法及其改进

  5. 算法001:大津法OTSU学习记录

    OTSU算法 一.大津法主要的工作是什么? 大多数时候,我们需要获取到一幅图像中的特定目标.如果可以根据像素值将图像进行合理的分割,例如全局阈值分割那样,找到一个阈值TTT,大于阈值TTT的赋予一个像 ...

  6. 自适应阈值分割—大津法(OTSU算法)C++实现

    转自:https://blog.csdn.net/dcrmg/article/details/52216622 大津法是一种图像灰度自适应的阈值分割算法,是1979年由日本学者大津提出,并由他的名字命 ...

  7. matlab大津法函数,matlab 大津阈值分割【相关词_ 大津法阈值分割matlab】

    阈值法 阈值分割程序 Otsu Thresholding 赞(0) 踩(0) 收藏(0) 说明:大津法实现图像阈值分割的matlab源程序代码 (Otsu Thresholding Image sou ...

  8. 【图像处理】——图像的二值化操作及阈值化操作(固定阈值法(全局阈值法——大津法OTSU和三角法TRIANGLE)和自适应阈值法(局部阈值法——均值和高斯法))

    目录 一.二值化的概念(实际上就是一个阈值化操作) 1.概念: 2.实现方法 3.常用方法 二.阈值类型 1.常见阈值类型(主要有五种类型) (1)公式描述 (2)图表描述 2.两种特殊的阈值算法(O ...

  9. 图像二值化之最大类间方差法(大津法,OTSU)

    参考文章1:图像二值化与otsu算法介绍 参考文章2:python opencv cv2.threshold() (将固定级别的阈值应用于每个数组元素)ThresholdTypes 最大类间方差法(大 ...

最新文章

  1. Verilog初级教程(7)Verilog模块例化以及悬空端口的处理
  2. 每日一皮:后来…后来…他得到了永生...
  3. Qt第五课 无构造函数可以接受源类型,或构造函数重载决策不明确
  4. bestcoder #66
  5. 送书!1991-2018,区块链的那点事,都在这里了!
  6. 15个实用的管理mysql的MySQLadmin命令
  7. python java go 区别 一句话概括
  8. 基坑监测日报模板_基坑水平监测日报表
  9. Composer Laravel 下载安装
  10. 投影仪融合+拼接处理系统制作原理
  11. 海康摄像头监控预览二开,萤石云对接说明
  12. 禅道管理员忘记密码找回密码
  13. 初探 Linux操作系统 (一):站在巨人的肩膀上
  14. 知识库管理系统——项目
  15. U盘提示格式化,8G的U盘变成了8M,并无法格式化打不开U盘解决方法
  16. java作品欣赏_[Java教程]推荐25个强大的 jQuery 网页布局设计作品欣赏
  17. 【转】图解领带的打法10种
  18. 基于JAVA准妈妈孕期交流平台计算机毕业设计源码+系统+lw文档+部署
  19. 压力测试-Jmeter测试移动APP
  20. yolo v5 NVIDIA Jetson Xavier NX 部署刷机+安环境(2)

热门文章

  1. 关于androidannotations(注解)的理解和使用(文档篇)
  2. 第22回 多线程是干什么滴!
  3. 演说演讲PPT模板推荐
  4. 打印机安装(驱动+安装)
  5. C语言做图书管理系统
  6. JS--文章置顶功能
  7. 聚类算法--近邻聚类算法(C++实现)
  8. 海南师范大学计算机网络,海南师范大学网络空间安全考研难吗
  9. 聚焦 Android 11: Google Play 应用分发与盈利
  10. 科沃斯机器人发布首个智生活报告 全民迈入智能化清扫时代