1.函数了解-->
读取图片:IplImage* cvLoadImage( const char* filename, int flags=CV_LOAD_IMAGE_COLOR );
shape是自定义核的形状,具体为
1.CV_SHAPE_RECT 核是矩形
2.CV_SHAPE_CROSS 核是勺子交叉形
3.CV_SHAPE_ELLIPSE 核是椭圆形
4.CV_SHAPE_CUSTOM 核是用户自定义类型
二值化(相当于阈值处理):void cvThreshold( const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type );
腐蚀:void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );
膨胀:void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 ); (最后一个参数表示腐蚀/膨胀的次数)
顶帽变换:原始图像减去其开运算的图像 而开运算可用于补偿不均匀的背景亮度,所以用一个大的结构元素做开运算后 然后用原图像减去这个开运算,就得到了背景均衡的图像。
开操作:先腐蚀,后膨胀。
二值图像中检索轮廓,并返回检测到的轮廓的个数(百度):int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,int header_size=sizeof(CvContour),int mode=CV_RETR_LIST,int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );
轮廓面积计算:double cvContourArea( const CvArr* contour, CvSliceslice=CV_WHOLE_SEQ );
轮廓周长计算:double cvArcLength( const void* curve, CvSlice slice=CV_WHOLE_SEQ, int is_closed=-1 );
2.实验步骤:
1.得到原始图片;
2.去除背景干扰(顶帽变换);
3.二值化(阈值处理);
4.开操作(去除噪声,删除较小的噪声点);
5.寻找连通域,计算米粒个数(可以认为合适的处理之后,一个连通域就代表着一个米粒);
6.查找最大面积的米粒(认为是最大的米粒),对所有轮廓进行标记,对最大轮廓描红标记;
7.输出米粒个数、最大米粒面积和周长。
3.结果:
原图 背景图 去背景图
结果图
4.代码(VC6.0,OpenCV):
1 #include "stdio.h" 2 #include "cv.h" 3 #include "highgui.h" 4 5 6 int main(int arge,char * argv[]) 7 { 8 char root_path[150]; // 米粒图片路径 9 IplImage *src, *backImg, *backRImg, *cutImg, *finallyImg, *dst_contours; 10 // 获取原图像 11 sprintf(root_path, "E:\4_大三下\机器视觉\实验图片\rice.jpg"); 12 src = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE); // 原始图片--灰度方式读取 13 backImg = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE); // 背景图片 14 backRImg = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE); // 存放去背景图片 15 cutImg = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE); 16 finallyImg = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE); 17 dst_contours = cvLoadImage(root_path); 18 19 20 // 图像处理 21 IplConvKernel * element = cvCreateStructuringElementEx(4,4,1,1,CV_SHAPE_ELLIPSE,0); // 形态学构建指针[创建结构元素,4*4,椭圆形] 22 cvErode(src,backImg,element,5); // 腐蚀 23 cvDilate(backImg,backImg,element,5); // 膨胀 24 cvSub(src,backImg,backRImg,0); // 去背景--综合为顶帽变换 25 cvThreshold(backRImg,cutImg,50,255,CV_THRESH_BINARY); // 二值化函数 26 cvErode(cutImg,finallyImg,element,1); // 腐蚀 27 cvDilate(finallyImg,finallyImg,element,1); // 膨胀--综合为一次开操作,去除噪声(较小突出部分) 28 // 寻找连通域,计算米粒个数 29 CvMemStorage * stor = cvCreateMemStorage(0); // 容器 30 CvSeq * cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor); 31 CvSeq * cont1 = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor); 32 // 二值图像中提取轮廓,返回值为轮廓的数目 33 int numberOfObject = cvFindContours(finallyImg,stor,&cont,sizeof(CvContour),CV_RETR_TREE); 34 printf("米粒数目为 :%d ",numberOfObject); 35 // 遍历轮廓,并画出外轮廓 36 int max_area = 0; 37 int max_length = 0; 38 for(;cont != NULL;cont = cont->h_next) { 39 CvRect rect = cvBoundingRect(cont,0); 40 double tmpArea = fabs(cvContourArea(cont,CV_WHOLE_SEQ)); 41 double tmpLength = cvArcLength(cont); 42 if(max_area < tmpArea) { 43 max_area = tmpArea; 44 max_length = tmpLength; 45 cont1 = cont; 46 } 47 // if(tmpArea > 0) { 48 cvDrawContours(dst_contours,cont,CV_RGB(0,255,0),CV_RGB(255,0,0),0,1,8,cvPoint(0,0)); 49 // } 50 } 51 cvDrawContours(dst_contours,cont1,CV_RGB(255,0,0),CV_RGB(255,0,0),0,1,8,cvPoint(0,0)); 52 printf("最大米粒的面积 area = %d , 周长 perimeter = %d ",max_area,max_length); 53 54 55 // 图像显示 56 cvNamedWindow("src"); 57 cvShowImage("src",src); 58 // cvNamedWindow("back"); 59 // cvShowImage("back",backImg); 60 // cvNamedWindow("backR"); 61 // cvShowImage("backR",backRImg); 62 cvNamedWindow("cut"); 63 cvShowImage("cut",cutImg); 64 // cvNamedWindow("finallyImg"); 65 // cvShowImage("finallyImg",finallyImg); 66 cvNamedWindow("dst_contours"); 67 cvShowImage("dst_contours",dst_contours); 68 69 cvWaitKey(0); 70 return 0; 71 }
2021-05-01