在工业检测领域,经常会遇到用计算机去检测感兴趣图像(ROI区域)的一些图像特性,例如目标物体的面积,目标物体的长度和宽度,以此判断产品合不合格。例如在自动化流水线上,经常需要看工人们或者机器手有没有把焊锡焊好,卡口有没有卡紧等。这些用人工固然可以,现代大多数车间都是用机器视觉系统代替人眼去检测的。这有很多优点,机器能在环境恶劣的条件下,长时间,精准的,快速的工作,这是人所做不到的。
例如下面如要计算机检测工件有没有焊好,就需要用到模式识别、机器视觉方面的知识,这里我使用OpenCV 2.1版本。图像测量是机器视觉最为基础和简单的方法。
要检测途中的引线有没有焊上,我的算法的核心是先提取出目标区域,再测量引线在引脚上的宽度,是不是宽窄不一。若有宽度不一,且宽度差距较大,则说明已经焊上。
如果哪位朋友有更好的方法,不妨告知我一下。
那么言归正传,如何测量图像的宽度呢,我们先将图像进行预处理,不外乎将彩色图转化为灰度图,图像平滑处理,图像形态学运算,二值化等等。又跑偏话题了。
举例我们得到一幅如下的二值图像。
如何测量白色区域的宽度呢?
方法如下:可以将图像看成一个二维数组,从第一行开始,找到第一行从黑色转化成白色的点的横坐标,再去找第一行从白色转化成黑色的点的横坐标。两者之差就是图像的宽度。第一行处理完毕,继续处理第二第三行等等。思想很简单,代码不长,也不做过多的解释。如有问题,可以留言。
#include "stdio.h" #include "cv.h" #include "highgui.h" #include <cxcore.hpp> #include <afxcom_.h> using namespace cv; using namespace std; int main() { IplImage* src; src=cvLoadImage("bin.jpg",CV_LOAD_IMAGE_GRAYSCALE); cvThreshold( src, src,80, 255, CV_THRESH_BINARY );//二值化 int width=src->width; int height=src->height; BOOL bFirst=FALSE; int x1,x2; for (int j=1;j<height;++j) { for (int i=1;i<width;++i) { int tempElem; tempElem=CV_IMAGE_ELEM(src,byte,j,i); ASSERT(tempElem==0||tempElem==255); if (CV_IMAGE_ELEM(src,byte,j,i)>0&&CV_IMAGE_ELEM(src,byte,j,i-1)==0) { x1=i; } if (CV_IMAGE_ELEM(src,byte,j,i)==0&&CV_IMAGE_ELEM(src,byte,j,i-1)>0) { x2=i; printf("x1=%d, x2=%d ,y=%d ,Image width=%d \n",x1,x2,j,x2-x1); } } } cvNamedWindow( "Source", 1 ); cvShowImage( "Source", src ); cvWaitKey(0); cvDestroyWindow( "Source" ); cvReleaseImage(&src); return 0; }
测试结果图片如下。
完!