【视觉项目】【day4】8.24号实验记录(消除瓶子内部“边缘”)

思路分析以及代码

思路1:使用findContours函数,设置轮廓为最外部RETR_EXTERNAL,结果发现结果仍然是所有轮廓。
思路2:先二值化,然后进行闭操作,然后canny,得到的轮廓确实比之前少很多,但是有个缺点:瓶子的边缘由于二值化的影响失真了。

原图
直接canny得到的图
二值化后canny图

思路3:先二值化,然后进行闭操作,然后填充较小的黑色区域,然后再进行腐蚀操作,得到了比原本瓶子要小一圈的mask,然后对canny后的图进行去轮廓操作(mask区域为黑),这样或许就可以了。

结果:确实好很多,但是有两张图片的没有结果,观察:有一个是因为孔洞填充选取的点有问题,还有一个 debug发现也是孔洞填充出现了问题。暂时现将大棕瓶区别对待。因为他的大津二值化结果有点特殊。
验证结果,发现效果确实比直接模板匹配canny后的好,但是仍然会有误判,发现误判主要出现在将大一点的瓶子的某部分识别成小瓶子,所以需要从瓶子像素多少来进行限制,规则是:不能识别成像素比模板瓶子像素少的类别。
所要做的:总结出模板图中瓶子像素值,得到每张测试图的瓶子像素(这里使用mask2的像素个数需要用连通域来进行甄别是否为,比实际瓶子要小)
空洞填充函数
输入:待处理图像的二值图
参数:背景颜色(黑还是白) 漫水填充的起始点(填充的是背景,一般选择(0,0))
输出:填充后的二值图

void My_hole_filling(Mat& srcImage, Mat& dstImage,int color,Point &startPoint)
{// Floodfill from point (0, 0) 以点(0,0)为种子点,进行漫水填充/*int x = startPoint.x;int y = startPoint.y;*///srcImage.at<char>(x, y)if ( color== 255)		//背景为白{srcImage = ~srcImage;}Mat im_floodfill = srcImage.clone();floodFill(im_floodfill, startPoint, Scalar(255));//255// Invert floodfilled image 反转图像Mat im_floodfill_inv;bitwise_not(im_floodfill, im_floodfill_inv);// Combine the two images to get the foreground. 获得前景dstImage = (srcImage | im_floodfill_inv);dstImage = ~dstImage;
}

获取瓶子外轮廓的函数
输入:原图灰度图 canny阈值 输出:轮廓图 mask2图

void get_external_Contours_function(Mat& srcImage, Mat& dstImage,Mat& dstmask, int canny_thred)
{//模糊化降噪blur(srcImage, srcImage, Size(5, 5));Mat mask;//大津二值化threshold(srcImage, mask, 100, 255, THRESH_OTSU);//闭操作int Abs_offset = 2;Mat element = getStructuringElement(MORPH_ELLIPSE, Size(Abs_offset * 2 + 1, Abs_offset * 2 + 1), Point(Abs_offset, Abs_offset));	//返回的是内核矩阵morphologyEx(mask, mask, MORPH_CLOSE, element);//孔洞填充Point startpoint = Point(40,40);My_hole_filling(mask, mask, 0, startpoint);//将mask缩小一圈Mat mask2;Mat element_erode = getStructuringElement(MORPH_ELLIPSE, Size(Abs_offset * 2 + 1, Abs_offset * 2 + 1), Point(Abs_offset, Abs_offset));	//返回的是内核矩阵morphologyEx(mask, mask2, MORPH_DILATE, element_erode);dstmask = mask2;//mask2就是我们的掩膜//对模糊后的灰度图进行canny检测Canny(srcImage, dstImage, canny_thred, canny_thred * 2, 3);//将在mask2内的所有为白的像素置为黑int height = dstImage.rows;int width = dstImage.cols;for (int j = 0; j < height; j++){for (int i = 0; i < width; i++){if (mask2.at<uchar>(j, i) == 0 && dstImage.at<uchar>(j, i) == 255){dstImage.at<uchar>(j, i) = 0;}}}
}

连通域测试代码,找出mask2中面积最大的连通域的像素个数

int main()
{cv::Mat srcMat = imread("D:\\opencv_picture_test\\视觉项目resize后的图片夹\\测试图片夹\\测试图\\10+麻点.jpg",1);//cv::Mat srcMat = imread("D:\\opencv_picture_test\\视觉项目resize后的图片夹\\测试图片夹\\测试图\\大棕瓶.jpg", 1);//cv::Mat srcMat = imread("D:\\opencv_picture_test\\视觉项目resize后的图片夹\\测试图片夹\\均衡化前的测试图\\方肩+肩薄.jpg", 1);Mat dstMat;Mat mask2;int thred = 40;//转换成灰度cvtColor(srcMat, dstMat, COLOR_BGR2GRAY);get_external_Contours_function(dstMat, dstMat, mask2, thred);//观察连通域个数,同时选出最大的那个连通域,之前对mask2进行反色mask2 = 255 - mask2;Mat lableMat;Mat statsMat;Mat centerMat;int nComp = cv::connectedComponentsWithStats(mask2,lableMat,statsMat,centerMat,8,CV_32S);//找出连通域像素个数最多的那个,然后记录下像素个数int max_pixels = 0;int max_pixels_label = 0;if (nComp == 1) max_pixels = statsMat.at<int>(1, 4);else{//找到像素点最多的连通域标记vector<int > pixels_nums;for (int i = 1; i < nComp; i++){pixels_nums.push_back(statsMat.at<int>(i, 4));	//将连通域面积入vector}//找到最大的值并且返回它在vector的位置auto maxPosition = max_element(pixels_nums.begin(), pixels_nums.end());max_pixels = *maxPosition;max_pixels_label = maxPosition - pixels_nums.begin();}cout <<"连通域个数(算上背景)="<< nComp << endl;cout << "max_pixels = " << max_pixels << endl;cout << endl;imshow("die_on_chip", dstMat);waitKey(0);return 0;
}

结果:

获取地址成功
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\10+波纹.jpg
0 max_pixels = 14347
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\10+麻点.jpg
1 max_pixels = 13617
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\10+气泡+瓶口破裂.jpg
2 max_pixels = 13368
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\10.jpg
3 max_pixels = 14335
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\10_2.jpg
4 max_pixels = 12677
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\11.jpg
5 max_pixels = 11718
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\12.jpg
6 max_pixels = 12413
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\13+炸口.jpg
7 max_pixels = 8002
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\14.jpg
8 max_pixels = 8870
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\2+料纹.jpg
9 max_pixels = 18144
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\3.jpg
10 max_pixels = 16658
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\3_2.jpg
11 max_pixels = 15836
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\4+厚底.jpg
12 max_pixels = 17636
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\4+厚底2.jpg
13 max_pixels = 16468
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\4+炸肩.jpg
14 max_pixels = 15504
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\5+脖夹料.jpg
15 max_pixels = 19443
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\5+肩薄.jpg
16 max_pixels = 18623
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\5+气泡.jpg
17 max_pixels = 19209
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\5+炸口.jpg
18 max_pixels = 20063
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\5+皱纹气泡.jpg
19 max_pixels = 19552
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\6.jpg
20 max_pixels = 14913
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\6_2.jpg
21 max_pixels = 15616
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\6_3.jpg
22 max_pixels = 15653
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\7+厚底.jpg
23 max_pixels = 15158
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\7+厚底2.jpg
24 max_pixels = 13383
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\8.jpg
25 max_pixels = 14950
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\8_2.jpg
26 max_pixels = 15271
D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图\9.jpg
27 max_pixels = 13192

统计每个瓶子的像素个数(取最小的再减去2000作为标准)

判断序列像素个数
1暂不统计
218144
315836
415504
518623
614913
713383
814950
913192
10(A)12677
11(B)11718
12©12413
13(D)8002
14(E)8870

实现思路:获取测试图后,得到其mask2像素个数。与pixels_num_criterion[ ]中的元素相比较。
记录下满足(test_mask_pxiels>=pixels_num_criterion[i]-pixels_num_sub)的序号i,放入新的vector:prepare_template_num然后用序号属于其中的模板去匹配。
代码好像有点问题,存个档,明天检查一下:

//将测试图转换成与模板图相匹配的函数
//输入:测试图 canny算子阈值 输出:外轮廓图 
//返回值:该测试图mask2中的瓶子像素个数
int test_covertTo_Outer_contour(Mat& srcImg, Mat& dstImg, int thred)
{//这里我们批量处理Mat mask2;//int thred = 40;//转换成灰度cvtColor(srcImg, dstImg, COLOR_BGR2GRAY);get_external_Contours_function(dstImg, dstImg, mask2, thred);//观察连通域个数,同时选出最大的那个连通域,之前对mask2进行反色mask2 = 255 - mask2;Mat lableMat;Mat statsMat;Mat centerMat;int nComp = cv::connectedComponentsWithStats(mask2,lableMat,statsMat,centerMat,8,CV_32S);//找出连通域像素个数最多的那个,然后记录下像素个数int max_pixels = 0;int max_pixels_label = 0;if (nComp == 1) max_pixels = statsMat.at<int>(1, 4);else{//找到像素点最多的连通域标记vector<int > pixels_nums;//0是背景for (int i = 1; i < nComp; i++){pixels_nums.push_back(statsMat.at<int>(i, 4));	//将连通域面积入vector}//找到最大的值并且返回它在vector的位置,然后还需要+1才是在连通域label中的位置auto maxPosition = max_element(pixels_nums.begin(), pixels_nums.end());max_pixels = *(maxPosition);max_pixels_label = (maxPosition - pixels_nums.begin() + 1);}return max_pixels;
}
int main()
{//改变控制台字体颜色system("color 02");//******************************************【0】获取测试文件夹路径和模板文件夹路径********************************************************////获取测试文件夹路径和模板文件夹路径cv::String path_test = "D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/测试图/";        cv::String path_template = "D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/template外轮廓/";    cout << "获取地址成功" << endl;//******************************************【1】加载模板图像********************************************************////创建模板vectorvector<Mat>tempMat;//插入模板元素Mat srcImage;std::vector<cv::String> temp_filenames;cv::glob(path_template, temp_filenames);                 //opencv里面用来读取指定路径下文件名的一个很好用的函数for (int i = 0; i < temp_filenames.size(); i++){srcImage = cv::imread(temp_filenames[i],0);tempMat.push_back(srcImage);cout << temp_filenames[i] << endl;}//获取模板数目int tempMat_Nums = tempMat.size();//******************************************【2】加载测试图像********************************************************////创建测试vectorvector<Mat>testMat;//插入测试元素std::vector<cv::String> test_filenames;cv::glob(path_test, test_filenames);                 //opencv里面用来读取指定路径下文件名的一个很好用的函数for (int i = 0; i < test_filenames.size(); i++){srcImage = cv::imread(test_filenames[i]);testMat.push_back(srcImage);//cout << test_filenames[i] << endl;}//获取测试图数目int testMat_Nums = testMat.size();//******************************************【3】对每张测试图进行模板匹配********************************************************//for (int j = 0;j < testMat_Nums;j++){cout <<"第"<< j <<"张测试图片的测试"<< endl;Mat resultMat;Mat CompareMat;Mat dispMat;//将测试图转换成与模板图相匹配的类型int test_mask_pxiels = 0;test_mask_pxiels=test_covertTo_Outer_contour(testMat[j], CompareMat, 40);cout << "test_mask_pxiels" << test_mask_pxiels << endl;int match_method = TM_CCORR_NORMED;		//经过试错发现此参数较好。//用每个模板去匹配测试图,并且找出每次结果的最佳匹配值,将值存入vector中vector<double>goodval;vector<Point>goodlock;int matchnum = 0;Point matchLoc;vector<int>prepare_template_num;cout << "可能的模板序号" << endl;for (int i = 0;i < 14;i++){if (test_mask_pxiels >= (pixels_num_criterion[i] - pixels_num_sub)){//将符合规则的模板序号导入vector中prepare_template_num.push_back(i);cout << i <<" ";}}cout << endl;for (int x = 0;x < prepare_template_num.size();x++){cout << prepare_template_num[x] << " ";}cout << endl;for (int i = 0;i < tempMat_Nums;i++){//采用模板与目标图像像素与各自图像的平均值计算dot product,正值越大匹配度越高,负值越大图像的区别越大,但如果图像没有明显的特征(即图像中的像素值与平均值接近)则返回值越接近0;matchTemplate(CompareMat, tempMat[i], resultMat, match_method);//不归一化,因为不同模板归一化后的最佳值皆为1,无法比较//normalize(resultMat, resultMat, 0, 1, NORM_MINMAX, -1, Mat());	//归一化double minVal; double maxVal; Point minLoc; Point maxLoc;	//定义最大值最小值以及它们的位置变量minMaxLoc(resultMat, &minVal, &maxVal, &minLoc, &maxLoc, Mat());	//从结果矩阵中找到匹配度最大以及最小的值并且确定其位置//对于方法SQDIFF和SQDIFF_NORMED两种方法来讲,越小的值就有着更高的匹配结果//而其余的方法则是数值越大匹配效果越好if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED){//将不符合像素数目规则的模板的可能性置1vector<int>::iterator result = find(prepare_template_num.begin(), prepare_template_num.end(), i); //查找该模板是否食欲符合规则的模板if (result == prepare_template_num.end()) //没找到{minVal = 1;}goodlock.push_back(minLoc);goodval.push_back(minVal);}else{//将不符合像素数目规则的模板的可能性置0vector<int>::iterator result = find(prepare_template_num.begin(), prepare_template_num.end(), i); //查找该模板是否食欲符合规则的模板if (result == prepare_template_num.end()) //没找到{maxVal = 0;}goodlock.push_back(maxLoc);goodval.push_back(maxVal);}show_probability(i, maxVal);//cout << i << "  " << maxVal << endl;}//找到goodval中最佳的一组if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED){auto goodPosition = min_element(goodval.begin(), goodval.end());matchnum = distance(begin(goodval), goodPosition);}else{auto goodPosition = max_element(goodval.begin(), goodval.end());matchnum = distance(begin(goodval), goodPosition);}show_text(matchnum, test_filenames[j]);matchLoc = goodlock[matchnum];testMat[j].copyTo(dispMat);//以最佳匹配点为中心绘制与模板相同大小的框rectangle(dispMat, matchLoc, Point(matchLoc.x + tempMat[matchnum].cols, matchLoc.y + tempMat[matchnum].rows), Scalar::all(255), 2, 8, 0);namedWindow("testMat", WINDOW_NORMAL);//WINDOW_NORMAL允许用户自由伸缩imshow("testMat", dispMat);waitKey(30);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/378381.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

operator.ne_Python operator.ne()函数与示例

operator.neoperator.ne()函数 (operator.ne() Function) operator.ne() function is a library function of operator module, it is used to perform "not equal to operation" on two values and returns True if the first value is not equal to the second val…

国产操作系统和linux 之间的关系,为何国产系统大多基于开源Linux?操作系统从0做起到底有多难?...

今年貌似是国产操作系统的“爆发”之年&#xff0c;除了老牌的银河麒麟、中标麒麟、深度之外&#xff0c;中兴近日发布了自己的“新支点”&#xff0c;华为也公开了自研的操作系统“鸿蒙”。纵观这些国产操作系统&#xff0c;大多基于开源的Linux。那么为什么我们不可以从0开始…

away3d创建基础view世界(基础 一)

对于away3d可能很多人有畏惧心里&#xff0c;其实away3d没有想象中的那么难&#xff0c;现在我就教大家创建一个简单的view世界。 package{import away3d.containers.View3D;import flash.display.Sprite;public class Main extends Sprite{private var view:View3D;//兴建一个…

operator.eq_Python operator.eq()函数与示例

operator.eqoperator.eq()函数 (operator.eq() Function) operator.eq() function is a library function of operator module, it is used to perform "equal to operation" on two values and returns True if the first value is equal to the second value, Fals…

智能车复工日记【7】:关于会车的图像问题

目录 系列文章更换扫线方式获取车的轮廓车屁股所在行数确定白色球台导致的问题5.21思考1、 关于会车地点确定如何判断会车状态博主联系方式: QQ:1540984562 QQ交流群:892023501 群里会有往届的smarters和电赛选手,群里也会不时分享一些有用的资料,有问题可以在群里多问问。…

详解Spring 3.0 基于Annotation 的依赖注入实现

简介&#xff1a; Spring 的依赖配置方式与 Spring 框架的内核自身是松耦合设计的。然而&#xff0c;直到 Spring 3.0 以前&#xff0c;使用 XML 进行依赖配置几乎是唯一的选择。Spring 3.0 的出现改变了这一状况&#xff0c;它提供了一系列的针对依赖注入的注解&#xff0c;这…

linux如何停用xdmcp服务,如何禁用XDMCP服务

看你用到是什么linux版本&#xff0c;例如下面&#xff1a;For kdm (which comes with the KDE desktop), it is a replacement of xdm and configures the same way, except its files are in /etc/X11/kdm in Caldera/SCO, /etc/kde/kdm in Red Hat (and Fedora Core) and /u…

第一章 基础知识

这篇博文是本人在学习《Python基础教程 &#xff08;第3版&#xff09;》的时候所记录下来的关键要点&#xff0c;书中的核心知识点也都在本篇博客中所涉及&#xff0c;需要耐心每天坚持点点滴滴学习进步 第一章 基础知识 数和表达式 1&#xff0c;执行整除运算// 4//3 —&…

Python operator.le()函数与示例

operator.le()函数 (operator.le() Function) operator.le() function is a library function of operator module, it is used to perform "less than or equal to operation" on two values and returns True if the first value is less than or equal to the sec…

jQuery.validator

$(document).ready(function(){ /* 设置默认属性 */$.validator.setDefaults({ submitHandler: function(form) { form.submit(); } }); // 中文字两个字节 jQuery.validator.addMethod("byteRangeLength", function(value, element, param) { var length value.le…

js 第四课

正则表达式&#xff1a;RegExp对象 正则表达式描述一个字符模式的对象&#xff0c;或者说用某种模式去匹配一类字符串的一个公式。 1.创建 可以用RegExp构造函数和直接量两种方式。正则表达式直接量被包含在一对"/"中. 1 var partern1 RegExp(\\d*); 2 …

第二章 列表和元组

第二章 列表和元组 在Python中&#xff0c;最基本的数据结构为序列&#xff08;包括列表、元组、字符串等&#xff09;&#xff08;sequence&#xff09; 列表是可以修改的&#xff0c;而元组不可以 Python支持一种数据结构的基本概念&#xff0c;名为容器&#xff08;contain…

linux下mac风格菜单栏,ubuntu 8.04 安装mac风格菜单

ubuntu 8.04 安装mac风格菜单发布时间:2008-07-13 00:22:22来源:红联作者:bindex这只是一份草案文档&#xff0c;它可能会导致一些计算机故障。引言这份指南假定你没有在电脑上编译过其他程序&#xff0c;并且&#xff0c;假定你使用的是Ubuntu Gusty。1.使用deb包安装 32位系统…

解析法实现一元线性回归、多元线性回归以及数据模型可视化操作

目录【1】解析法实现一元线性回归python列表实现利用Numpy实现利用TensorFlow实现数据和模型可视化【2】解析法实现多元线性回归利用Numpy实现需要用到的NumPy数组运算函数数据和模型可视化绘制空间点集&#xff1a;绘制空间平面图&#xff1a;绘制线框图并且与散点图对比&…

带有示例的Python File readlines()方法

文件readlines()方法 (File readlines() Method) readlines() method is an inbuilt method in Python, it is used to get all lines from the file, the method is called with this object (current file stream/IO object) and returns all available lines in the file, w…

32位系统win2008+mssql2008 6G内存折腾纪实

十年没搞硬件了&#xff0c;现在计算机发展到大硬盘大内存的时代了。一直都少搞服务器配置、运营&#xff0c;以前弄服务器都是普通的PC来当服务器。公司原来的一个业务系统用的是mssql2000好几年了&#xff0c;由于业务数据越积压越多最大的一张表已经有7000多万条记录了&…

case使用 上下篇

上篇 Case具有两种格式。简单Case函数和Case搜索函数。 --简单Case函数 CASE sexWHEN 1 THEN 男WHEN 2 THEN 女 ELSE 其他 END --Case搜索函数 CASE WHEN sex 1 THEN 男WHEN sex 2 THEN 女 ELSE 其他 END这两种方式&#xff0c;可以实现相同的功能。简单Case函数的写法相对比…

第三章 字符串

第三章 字符串% 字符串是不可变的&#xff0c;所有的元素赋值和切片赋值都是非法的 Python提供了多种字符串格式设置方法 yanyu "hello, %s I like %s age is %s" beyond ("beyond","band",23) yanyu % beyond#结果为&#xff1a;hello, bey…

【视觉项目】【day5】8.25号实验记录(修完BUG,28张测试图,13个样本,四张测试图误判,这比之前效果好很多了)

目录修改完BUG后的程序以及效果优化思路&#xff0c;增强正确识别率&#xff08;待验证&#xff09;修改完BUG后的程序以及效果 修改代码后的测试结果&#xff1a;(利用连通域面积将明显比本张测试图的瓶子要小的模板提前去除&#xff0c;减少误判) 这样下来&#xff0c;28张测…

linux kernel and user space通信机制,Linux内核空间与用户空间通信机制地研究.doc

实用文案标准文档Linux内核空间与用户空间通信机制的研究Linux kernel space and user space communication mechanism摘 要Linux 是一个源码开放的操作系统&#xff0c;无论是普通用户还是企业用户都可以编写自己的内核代码&#xff0c;再加上对标准内核的裁剪从而制作出适合自…