通过投影分析做图像分割
适用于较为干净的,噪点较少的图片
图片初步处理过程:
换色彩域 -> 阈值变化 -> 投影分析
备注:在实际使用过程中要加错误控制。
原图(百度上随意找的一张噪点不多的图片):
处理过后的结果图:
原理图:
横线的地方没有像素所以为0,遇到有像素的地方,值会上升,一个图像块结束会下降,可以通过这种波形图来分割图像。
我理解的投影分析是这种,如果有不对的各位大佬随意指出来,互相讨论继续学习:
1.简单处理原图,进行图像二值化,并反色,方便后面使用。
预处理后的反色图,可以看到下方还是有一些噪点:
2.通过列数把原图分割成单列roi区域。
//做竖直的投影
Mat data = Frame.col(i);
3.通过countNonZero这个函数可以统计出单列(roi区域)的非零的向量个数,加入大容器中。
int itmp = countNonZero(data);//统计非0个数向量
vectorV.push_back(itmp);
4.把大容器内的数据按上方原理图的方法分别分成上波形与下波形存入对应的容器中。(可以遍历大容器内的数据进行分析,如果改数据不为0,但他的前一个数据为0,则判断为上波形,相反则为下波形。)
if (vectorV[i - 1] == 0 && vectorV[i]>0)
{
VUpper.push_back(i);
}
if (vectorV[i - 1]>0 && vectorV[i] == 0)
{
VDown.push_back(i);
}
5.区分好波形,相当于将图像分为几大块如例图,因为噪点的存在,所以共分成11块,可以寻找每块中最大轮廓,从而确定最小外接矩形,这样就能够得到矩形的宽与高。
Mat roitmp = Frame(Rect(VUpper[i], 0, VDown[i] - VUpper[i], Frame.rows));
dilate(roitmp, roitmp, Mat());//对 Frame 的结果适当膨胀
Rect boundRect2;//最小外接矩形
boundRect2 = boundingRect(Mat(FindBigestContour(roitmp)));
6.通过肉眼可以判断出例图中4个数字的大小应相差不大,判断矩形的宽/高,排除过小的块,这样可以得到比较清晰的块。
if (boundRect2.height >20)
{
Mat result = src(Rect(VUpper[i], 0, VDown[i] - VUpper[i], ostu.rows));
line(test, Point(VUpper[i],0),Point(VUpper[i],src.rows),Scalar(255),2);
line(test, Point(VDown[i], 0), Point(VDown[i],src.rows),Scalar(255),1);
}
7.最后把块拼接在一起得到结果图。
以上均为学习笔记,因大部分源码是别人的,我也在学习中,源码就不往上放了。
我个人感觉投影分析能运用的场合还是非常多的,继续学习,继续分享,如果有大佬愿意指点一二,就更好啦!