【视觉项目】基于梯度的NCC模板匹配代码以及效果

462 阅读16分钟

文章目录

流程分析

#预处理部分
1、将测试图转为150:100,缩小图片尺寸
2、截取备用模板图
3、加载模板到结构体vector中
4、计算每个temp每个像素点的dx,dy,mag,包括着坐标信息x,y,存入vector vModel中(注意双for循环顺序)
#主要部分
5、加载测试图
6、使用test_covertTo_Outer_contour函数得到测试图的外轮廓
7、用不同的模板与测试图searchNcc,每次结果的最佳匹配值,将值存入vector中,最小外接矩形存入vector中
8、找到匹配值vector中最大的值,确定模板标签,打印结果,在原图上绘制对应模板的最小外接矩形

工程代码

【1】NCC代码

【Ⅰ】sttPxGrdnt结构体

//定义数据结构体,存放某一像素点的位置,及其梯度信息
typedef struct 
{
	int x;
	int y;
	float gx;
	float gy;
	float mag;
}sttPxGrdnt;

【Ⅱ】sttTemplateModel模板结构体

由于简化,我们这边不考虑旋转因素,不考虑图像金字塔加速

//定义模板结构体
struct sttTemplateModel
{
	//int no;
	//int pyrLevel;			//金字塔层数
	std::vector <sttPxGrdnt> vModel;
	//长宽指的是在原模版的基础上
	//包含了尺度和旋转变换后的的bounding box的尺寸
	int height;
	int width;
	float score;		//存放最大值
	//float scale;
	//float angle;
	//指在原图的基础上
	//进行尺度变化后的图像的rect,进一步进行旋转后的旋转Rect
	//cv::RotatedRect rotRect;
	cv::Rect resRect;	//存放最大值得坐标,外接矩形
};

【Ⅲ】calcAccNCC计算ncc系数函数

//计算ncc系数
//由于分母 (sqrtf(gx1*gx1 + gy1*gy1) * sqrtf(gx2*gx2 + gy2*gy2))
//即mag1 和 mag2,存在重复计算部分,故在建立模型时预先计算,并且把除法转换为乘法
//创建此版本作为加速
float calcAccNCC(float gx1, float gy1, float gx2, float gy2, float magMinus1, float magMinus2)
{
	return ((gx1 * gx2 + gy1 * gy2) * (magMinus1 * magMinus2));
}

【Ⅳ】searchNcc NCC模板匹配函数

int searchNcc(cv::Mat srcGx,cv::Mat srcGy,cv::Mat srcMag,cv::Mat srcCannyMat,int searchStep,sttTemplateModel& srcModel)
{
	//检查参数
	int t_width = srcModel.width;
	int t_height = srcModel.height;
	int s_width = srcGx.cols;
	int s_height = srcGy.rows;

	int d_width = s_width - t_width;
	int d_height = s_height - t_height;

	//如果测试图小于模板图的大小,则退出
	if (d_width < 0 || d_height < 0) {
		return 1;
	}

	//建立NCC系数矩阵
	cv::Mat nccMat(d_height, d_width, CV_64FC1);
	nccMat = 0;

	int nEdge = srcModel.vModel.size();

	//以步进为searchStep搜索整个图像
	for (int i = 0; i < d_height; i = i + searchStep)
	{
		for (int j = 0; j < d_width; j = j + searchStep)
		{
			//遍历向量
			int cnt = 0;
			int nccSum = 0;	
			for (int m = 0; m < nEdge; m++) {

				int dx = srcModel.vModel[m].x;
				int dy = srcModel.vModel[m].y;
				int srcx = j + dx;
				int srcy = i + dy;

				//只对轮廓点进行计算
				if (srcCannyMat.at<uchar>(srcy, srcx) == 255) {

					//如果匹配图像上的边缘信息不为0,则计算
					float gxs = srcGx.at<float>(srcy, srcx);
					float gys = srcGy.at<float>(srcy, srcx);
					float gxr = srcModel.vModel[m].gx;
					float gyr = srcModel.vModel[m].gy;
					float magr = srcModel.vModel[m].mag;
					float mags = srcMag.at<float>(srcy, srcx);

					//如果分母不为0
					if (!((gxr == 0 && gyr == 0) || (gxs == 0 && gys == 0))) {

						//计算ncc
						float ncc = calcAccNCC(gxr, gyr, gxs, gys, magr, mags);
						nccSum = ncc + nccSum;
					}
				}

			}

			nccMat.at<double>(i, j) = (float)nccSum;
		}
	}
	//若步进大于1 就二次搜索
	if (searchStep > 1)
	{
		//先找到nccMat中像素值前三大的坐标
		double minVal1, maxVal1;
		int minIdx1[2] = {}, maxIdx1[2] = {};	// minnimum Index, maximum Index
		minMaxIdx(nccMat, &minVal1, &maxVal1, minIdx1, maxIdx1);
		int maxX1 = maxIdx1[1];
		int maxY1 = maxIdx1[0];

		Mat nccMatForMaxIdx;
		nccMat.copyTo(nccMatForMaxIdx);
		nccMatForMaxIdx.at<double>(maxY1, maxX1) = minVal1;
		minMaxIdx(nccMatForMaxIdx, &minVal1, &maxVal1, minIdx1, maxIdx1);
		int maxX2 = maxIdx1[1];
		int maxY2 = maxIdx1[0];

		nccMatForMaxIdx.at<double>(maxY2, maxX2) = minVal1;
		minMaxIdx(nccMatForMaxIdx, &minVal1, &maxVal1, minIdx1, maxIdx1);
		int maxX3 = maxIdx1[1];
		int maxY3 = maxIdx1[0];

		//在像素点附近进行 步进为1的搜索
		searchSecondNcc(maxX1, maxY2, searchStep, d_width, d_height, srcGx, srcGy, srcMag, srcCannyMat, srcModel, nccMat);
		searchSecondNcc(maxX2, maxY2, searchStep, d_width, d_height, srcGx, srcGy, srcMag, srcCannyMat, srcModel, nccMat);
		searchSecondNcc(maxX3, maxY3, searchStep, d_width, d_height, srcGx, srcGy, srcMag, srcCannyMat, srcModel, nccMat);
	}
	// 这里要注意 arr[0] 代表坐标y ,arr[1]代表坐标x。
	double minVal, maxVal;
	int minIdx[2] = {}, maxIdx[2] = {};	// minnimum Index, maximum Index
	minMaxIdx(nccMat, &minVal, &maxVal, minIdx, maxIdx);

	srcModel.resRect.x = maxIdx[1];
	srcModel.resRect.y = maxIdx[0];
	srcModel.resRect.height = srcModel.height;
	srcModel.resRect.width = srcModel.width;
	srcModel.score = maxVal;

	return 0;
}

【Ⅴ】searchSecondNcc 二级搜索:在某一特定点周围再以步进为1搜索

/******************************************************
searchSecondNcc:
二级搜索:在某一特定点周围再以步进为1搜索

输入:
x:点的x坐标
y:点的y坐标
srcGx:图像在x方向的梯度大小图
srcGy:图像在y方向的梯度大小图
srcMag:用于计算ncc系数的图
srcCannyMat:图像的边缘信息图
nccMat:计算后的ncc图。
*******************************************************/
void searchSecondNcc(int x, int y, int searchStep, int d_width, int d_height, cv::Mat srcGx, cv::Mat srcGy, cv::Mat srcMag, cv::Mat srcCannyMat, sttTemplateModel& srcModel, cv::Mat& nccMat)
{
	int sx = (x - searchStep + 1) < 0 ? 0 : (x - searchStep + 1);
	int ex = (x + searchStep) > d_width ? d_width : (x + searchStep);
	int sy = (y - searchStep + 1) < 0 ? 0 : (y - searchStep + 1);
	int ey = (y + searchStep) > d_height ? d_height : (y + searchStep);

	int nEdge = srcModel.vModel.size();
	//开始遍历
	for (int i = sy; i < ey; i++)
	{
		for (int j = sx; j < ex; j++)
		{
			//遍历向量
			int cnt = 0;
			int nccSum = 0;
			for (int m = 0; m < nEdge; m++) {

				int dx = srcModel.vModel[m].x;
				int dy = srcModel.vModel[m].y;
				int srcx = j + dx;
				int srcy = i + dy;

				if (srcCannyMat.at<uchar>(srcy, srcx) == 255) {

					//如果匹配图像上的边缘信息不为0,则计算
					float gxs = srcGx.at<float>(srcy, srcx);
					float gys = srcGy.at<float>(srcy, srcx);
					float gxr = srcModel.vModel[m].gx;
					float gyr = srcModel.vModel[m].gy;
					float magr = srcModel.vModel[m].mag;
					float mags = srcMag.at<float>(srcy, srcx);

					//如果分母不为0
					if (!((gxr == 0 && gyr == 0) || (gxs == 0 && gys == 0))) {

						//计算ncc
						float ncc = calcAccNCC(gxr, gyr, gxs, gys, magr, mags);
						nccSum = ncc + nccSum;
					}
				}

			}

			nccMat.at<double>(i, j) = (float)nccSum;
		}
	}
}

【2】测试图转外轮廓

【Ⅰ】孔洞填充(默认背景为黑)

//输入:待处理图像的二值图
//参数:背景颜色(黑还是白) 漫水填充的起始点(填充的是背景,一般选择(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;
			}
		}
	}
}

【Ⅲ】测试图转外轮廓

//将测试图转换成与模板图相匹配的函数
//输入:测试图 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;
}

【3】总代码

int main()
{
	//改变控制台字体颜色
	system("color 02");
	//******************************************【0】获取测试文件夹路径和模板文件夹路径********************************************************//
	//获取测试文件夹路径和模板文件夹路径
	cv::String path_test = "D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图/";
	cv::String path_template = "D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图/";
	cout << "获取地址成功" << endl;
	//******************************************【1】加载模板图像********************************************************//
	//创建模板vector
	vector<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】模板处理********************************************************//
	//计算每个temp每个像素点的dx,dy, mag,包括着坐标信息x, y,存入vector vModel中
	vector<sttTemplateModel> Template;
	for (int hh = 0;hh < tempMat_Nums;hh++)
	{
		//计算dx,dy,mag
		Mat gradxMat, gradyMat,magMat;
		Mat abs_gradx, abs_grady;
		//求x方向的梯度
		Sobel(tempMat[hh], gradxMat, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);//	x方向1阶差分 y方向0 核大小3
		convertScaleAbs(gradxMat, abs_gradx);		//绝对值
		//求y方向的梯度
		Sobel(tempMat[hh], gradyMat, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);//	x方向1阶差分 y方向0 核大小3
		convertScaleAbs(gradyMat, abs_grady);		//绝对值
		//计算幅值
		//magnitude(gradxMat, gradyMat, magMat);
		//这里使用绝对值之和近似
		addWeighted(abs_gradx, 0.5, abs_grady, 0.5, 0, magMat);
		//convertScaleAbs(magMat, abs_magMat);
		//对Template进行赋值操作
		sttTemplateModel temp;
		temp.height = tempMat[hh].rows;
		temp.width = tempMat[hh].cols;
		vector <sttPxGrdnt> temmodel;
		//二维Mat转化为一维vector的temmodel(数据类型是sttPxGrdnt)
		for (int i = 0; i < tempMat[hh].rows; i++)
		{
			for (int j = 0; j < tempMat[hh].cols; j++)
			{
				sttPxGrdnt model;
				model.x = j;
				model.y = i;
				model.gx = abs_gradx.at<uchar>(i, j);
				model.gy= abs_grady.at<uchar>(i, j);
				model.mag= magMat.at<uchar>(i, j);
				//至此一个像素的model参数填充完成
				temmodel.push_back(model);
			}
		}
		//至此一张模板图的vModel参数填充完成
		//temmodel类型:vector <sttPxGrdnt>     temp.vModel类型:vector <sttPxGrdnt>  类型相同
		temp.vModel = temmodel;
		temp.score = 0;
		//至此一张模板图的sttTemplateModel参数填充完成rect不初始化,之后会填充的。
		Template.push_back(temp);
	}
	cout << "TemplateNum: " << Template.size() << endl;
	cout << "tempMat_Nums: " << tempMat_Nums << endl;
	//******************************************【3】加载测试图********************************************************//
	//创建测试vector
	vector<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 dispMat;
		//==============计算测试图的srcGx、srcGy、srcMag、srcCannyMat==================================
		Mat gradxMat, gradyMat, srcMag;
		Mat srcGx, srcGy;
		Mat srcCannyMat;
		//求x方向的梯度
		Sobel(testMat[j], gradxMat, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);//	x方向1阶差分 y方向0 核大小3
		convertScaleAbs(gradxMat, srcGx);		//绝对值
		//求y方向的梯度
		Sobel(testMat[j], gradyMat, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);//	x方向1阶差分 y方向0 核大小3
		convertScaleAbs(gradyMat, srcGy);		//绝对值
		//计算幅值
		//magnitude(gradxMat, gradyMat, magMat);
		//这里使用绝对值之和近似
		addWeighted(srcGx, 0.5, srcGy, 0.5, 0, srcMag);
		int test_mask_pxiels = 0;
		test_mask_pxiels = test_covertTo_Outer_contour(testMat[j], srcCannyMat, 40);
		cout << "test_mask_pxiels" << test_mask_pxiels << endl;
		//用每个模板去匹配测试图,并且找出每次结果的最佳匹配值,将值存入vector中
		vector<double>goodval;
		vector<Point>goodlock;
		int matchnum = 0;
		Point matchLoc;
		for (int i = 0;i < tempMat_Nums;i++)
		{
			//sttTemplateModel tempinrepeat = Template[i];
			searchNcc(srcGx, srcGy, srcMag, srcCannyMat, 2, Template[i]);
			goodlock.push_back(Template[i].maxLoc);
			goodval.push_back(Template[i].score);
			show_probability(i,Template[i].score);
			//cout << i << "  " << maxVal << endl;
		}
		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;
}

结果:

获取地址成功
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\2.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\3.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\4.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\5.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\6.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\7.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\8.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\9.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\A.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\B.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\C.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\D.jpg
D:/opencv_picture_test/视觉项目resize后的图片夹/模板图片夹/更小的模板图\E.jpg
TemplateNum: 13
tempMat_Nums: 13
第0张测试图片的测试
test_mask_pxiels1416
推测: 2 7.76891e+09
推测: 3 6.08647e+09
推测: 4 8.46855e+09
推测: 5 8.03057e+09
推测: 6 8.2642e+09
推测: 7 7.32424e+09
推测: 8 4.21286e+09
推测: 9 6.60641e+09
推测: 10 6.11642e+09
推测: 11 5.44163e+09
推测: 12 3.30044e+09
推测: 13 3.50808e+09
推测: 14 4.77945e+09
推测: 4 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\10+波纹.jpg
第1张测试图片的测试
test_mask_pxiels1333
推测: 2 3.35523e+09
推测: 3 1.35581e+10
推测: 4 8.65575e+09
推测: 5 1.27386e+10
推测: 6 4.49022e+09
推测: 7 1.41066e+10
推测: 8 2.06567e+10
推测: 9 2.12286e+10
推测: 10 8.22353e+09
推测: 11 9.90977e+09
推测: 12 1.5269e+10
推测: 13 1.00363e+10
推测: 14 1.65281e+10
推测: 9 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\10+麻点.jpg
第2张测试图片的测试
test_mask_pxiels1345
推测: 2 1.01031e+10
推测: 3 8.67801e+09
推测: 4 1.19367e+10
推测: 5 1.19407e+10
推测: 6 1.10023e+10
推测: 7 1.16832e+10
推测: 8 6.69674e+09
推测: 9 1.03455e+10
推测: 10 7.78547e+09
推测: 11 8.65128e+09
推测: 12 6.30006e+09
推测: 13 7.85052e+09
推测: 14 7.66856e+09
推测: 5 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\10+气泡+瓶口破裂.jpg
第3张测试图片的测试
test_mask_pxiels1442
推测: 2 1.53585e+10
推测: 3 1.31416e+10
推测: 4 1.70326e+10
推测: 5 1.65049e+10
推测: 6 1.61574e+10
推测: 7 1.576e+10
推测: 8 9.58215e+09
推测: 9 1.12565e+10
推测: 10 1.33957e+10
推测: 11 1.10719e+10
推测: 12 7.99814e+09
推测: 13 8.02709e+09
推测: 14 8.7746e+09
推测: 4 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\10.jpg
第4张测试图片的测试
test_mask_pxiels1307
推测: 2 7.86552e+09
推测: 3 7.99583e+09
推测: 4 1.21866e+10
推测: 5 9.24638e+09
推测: 6 9.61011e+09
推测: 7 9.1374e+09
推测: 8 5.79389e+09
推测: 9 7.02821e+09
推测: 10 7.43108e+09
推测: 11 6.42511e+09
推测: 12 4.32574e+09
推测: 13 5.07164e+09
推测: 14 5.45143e+09
推测: 4 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\10_2.jpg
第5张测试图片的测试
test_mask_pxiels1179
推测: 2 5.15639e+09
推测: 3 5.14794e+09
推测: 4 5.48102e+09
推测: 5 5.47599e+09
推测: 6 5.4206e+09
推测: 7 5.76432e+09
推测: 8 5.54363e+09
推测: 9 5.41065e+09
推测: 10 6.1458e+09
推测: 11 6.50305e+09
推测: 12 4.81589e+09
推测: 13 4.78103e+09
推测: 14 4.99855e+09
推测: 11 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\11.jpg
第6张测试图片的测试
test_mask_pxiels1207
推测: 2 7.31454e+09
推测: 3 6.91087e+09
推测: 4 6.44054e+09
推测: 5 7.07961e+09
推测: 6 7.13823e+09
推测: 7 6.7975e+09
推测: 8 7.35677e+09
推测: 9 7.82278e+09
推测: 10 5.83812e+09
推测: 11 6.02332e+09
推测: 12 5.21921e+09
推测: 13 4.11696e+09
推测: 14 6.95839e+09
推测: 9 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\12.jpg
第7张测试图片的测试
test_mask_pxiels779
推测: 2 1.10956e+10
推测: 3 8.73321e+09
推测: 4 1.12175e+10
推测: 5 9.66985e+09
推测: 6 1.12074e+10
推测: 7 1.00132e+10
推测: 8 8.25873e+09
推测: 9 1.32147e+10
推测: 10 9.62355e+09
推测: 11 9.91485e+09
推测: 12 7.01122e+09
推测: 13 8.50425e+09
推测: 14 1.00896e+10
推测: 9 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\13+炸口.jpg
第8张测试图片的测试
test_mask_pxiels881
推测: 2 3.32404e+09
推测: 3 2.55615e+09
推测: 4 3.19277e+09
推测: 5 2.89486e+09
推测: 6 3.22644e+09
推测: 7 3.25131e+09
推测: 8 2.33429e+09
推测: 9 3.92018e+09
推测: 10 3.12022e+09
推测: 11 3.11579e+09
推测: 12 2.04237e+09
推测: 13 2.04328e+09
推测: 14 3.28055e+09
推测: 9 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\14.jpg
第9张测试图片的测试
test_mask_pxiels1768
推测: 2 1.99602e+09
推测: 3 1.12828e+09
推测: 4 1.53632e+09
推测: 5 1.47012e+09
推测: 6 1.57056e+09
推测: 7 1.76038e+09
推测: 8 8.7309e+08
推测: 9 1.6778e+09
推测: 10 1.42781e+09
推测: 11 1.37872e+09
推测: 12 7.19919e+08
推测: 13 1.24003e+09
推测: 14 1.26879e+09
推测: 2 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\2+料纹.jpg
第10张测试图片的测试
test_mask_pxiels1666
推测: 2 1.5527e+10
推测: 3 1.47107e+10
推测: 4 1.60174e+10
推测: 5 1.75179e+10
推测: 6 1.61053e+10
推测: 7 1.50694e+10
推测: 8 8.51156e+09
推测: 9 1.63962e+10
推测: 10 1.41407e+10
推测: 11 1.40457e+10
推测: 12 7.8593e+09
推测: 13 1.24679e+10
推测: 14 1.28981e+10
推测: 5 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\3.jpg
第11张测试图片的测试
test_mask_pxiels1618
推测: 2 2.15178e+09
推测: 3 2.36388e+09
推测: 4 2.12818e+09
推测: 5 2.3344e+09
推测: 6 2.346e+09
推测: 7 2.04907e+09
推测: 8 1.91143e+09
推测: 9 2.23518e+09
推测: 10 2.01474e+09
推测: 11 1.74694e+09
推测: 12 1.42347e+09
推测: 13 1.1717e+09
推测: 14 1.39725e+09
推测: 3 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\3_2.jpg
第12张测试图片的测试
test_mask_pxiels1786
推测: 2 2.52058e+09
推测: 3 1.82568e+09
推测: 4 2.61639e+09
推测: 5 2.62928e+09
推测: 6 2.43084e+09
推测: 7 2.7574e+09
推测: 8 1.66082e+09
推测: 9 2.32472e+09
推测: 10 1.89285e+09
推测: 11 2.25175e+09
推测: 12 1.32364e+09
推测: 13 1.50924e+09
推测: 14 1.53588e+09
推测: 7 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\4+厚底.jpg
第13张测试图片的测试
test_mask_pxiels1645
推测: 2 5.41047e+09
推测: 3 3.76042e+09
推测: 4 6.23646e+09
推测: 5 5.1281e+09
推测: 6 5.02001e+09
推测: 7 4.65652e+09
推测: 8 2.77086e+09
推测: 9 4.8981e+09
推测: 10 3.64862e+09
推测: 11 3.62146e+09
推测: 12 2.12629e+09
推测: 13 2.43897e+09
推测: 14 2.96858e+09
推测: 4 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\4+厚底2.jpg
第14张测试图片的测试
test_mask_pxiels1568
推测: 2 1.02309e+10
推测: 3 1.07811e+10
推测: 4 1.02411e+10
推测: 5 1.1357e+10
推测: 6 1.23884e+10
推测: 7 8.60844e+09
推测: 8 7.21905e+09
推测: 9 8.52574e+09
推测: 10 9.17857e+09
推测: 11 7.784e+09
推测: 12 5.68596e+09
推测: 13 5.94044e+09
推测: 14 6.46818e+09
推测: 6 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\4+炸肩.jpg
第15张测试图片的测试
test_mask_pxiels1988
推测: 2 6.25886e+09
推测: 3 5.20353e+09
推测: 4 5.86726e+09
推测: 5 7.51986e+09
推测: 6 5.58032e+09
推测: 7 4.72602e+09
推测: 8 3.67791e+09
推测: 9 5.03681e+09
推测: 10 5.00086e+09
推测: 11 4.07587e+09
推测: 12 3.01887e+09
推测: 13 3.6537e+09
推测: 14 3.82125e+09
推测: 5 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\5+脖夹料.jpg
第16张测试图片的测试
test_mask_pxiels1882
推测: 2 3.20653e+10
推测: 3 2.76892e+10
推测: 4 2.76938e+10
推测: 5 3.50479e+10
推测: 6 2.36017e+10
推测: 7 3.38148e+10
推测: 8 2.91187e+10
推测: 9 4.04712e+10
推测: 10 2.89815e+10
推测: 11 3.27775e+10
推测: 12 2.32076e+10
推测: 13 2.00089e+10
推测: 14 3.54917e+10
推测: 9 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\5+肩薄.jpg
第17张测试图片的测试
test_mask_pxiels1858
推测: 2 5.82607e+09
推测: 3 5.5297e+09
推测: 4 5.42484e+09
推测: 5 7.30172e+09
推测: 6 5.48253e+09
推测: 7 5.47554e+09
推测: 8 4.01811e+09
推测: 9 5.99446e+09
推测: 10 5.02572e+09
推测: 11 5.20654e+09
推测: 12 4.07417e+09
推测: 13 4.18127e+09
推测: 14 4.8048e+09
推测: 5 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\5+气泡.jpg
第18张测试图片的测试
test_mask_pxiels2056
推测: 2 5.45695e+09
推测: 3 5.55576e+09
推测: 4 5.46873e+09
推测: 5 7.44879e+09
推测: 6 5.48393e+09
推测: 7 4.00633e+09
推测: 8 4.52542e+09
推测: 9 5.4767e+09
推测: 10 4.43553e+09
推测: 11 4.55286e+09
推测: 12 4.35857e+09
推测: 13 3.45853e+09
推测: 14 4.7197e+09
推测: 5 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\5+炸口.jpg
第19张测试图片的测试
test_mask_pxiels1948
推测: 2 6.65222e+09
推测: 3 6.07512e+09
推测: 4 6.65503e+09
推测: 5 7.16401e+09
推测: 6 7.486e+09
推测: 7 4.69526e+09
推测: 8 5.32825e+09
推测: 9 5.99114e+09
推测: 10 8.14169e+09
推测: 11 4.49538e+09
推测: 12 5.89747e+09
推测: 13 4.23926e+09
推测: 14 8.63315e+09
推测: 14 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\5+皱纹气泡.jpg
第20张测试图片的测试
test_mask_pxiels1499
推测: 2 1.10044e+10
推测: 3 9.56812e+09
推测: 4 1.08293e+10
推测: 5 1.21681e+10
推测: 6 1.14699e+10
推测: 7 1.15628e+10
推测: 8 6.91678e+09
推测: 9 1.30719e+10
推测: 10 9.61323e+09
推测: 11 1.0836e+10
推测: 12 6.1744e+09
推测: 13 9.67348e+09
推测: 14 8.75079e+09
推测: 9 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\6.jpg
第21张测试图片的测试
test_mask_pxiels1576
推测: 2 2.05596e+09
推测: 3 1.90442e+09
推测: 4 3.00622e+09
推测: 5 2.93261e+09
推测: 6 3.66942e+09
推测: 7 2.53279e+09
推测: 8 1.46139e+09
推测: 9 2.40446e+09
推测: 10 1.83032e+09
推测: 11 1.91043e+09
推测: 12 1.278e+09
推测: 13 1.30937e+09
推测: 14 1.85519e+09
推测: 6 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\6_2.jpg
第22张测试图片的测试
test_mask_pxiels1563
推测: 2 3.96171e+09
推测: 3 3.72847e+09
推测: 4 5.03716e+09
推测: 5 4.4465e+09
推测: 6 6.02446e+09
推测: 7 4.15961e+09
推测: 8 2.45023e+09
推测: 9 3.58917e+09
推测: 10 3.6738e+09
推测: 11 3.8432e+09
推测: 12 2.19844e+09
推测: 13 2.67596e+09
推测: 14 2.98359e+09
推测: 6 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\6_3.jpg
第23张测试图片的测试
test_mask_pxiels1567
推测: 2 6.35999e+09
推测: 3 4.53041e+09
推测: 4 6.83978e+09
推测: 5 7.42691e+09
推测: 6 6.37482e+09
推测: 7 7.4714e+09
推测: 8 3.77141e+09
推测: 9 6.40438e+09
推测: 10 4.32262e+09
推测: 11 4.06384e+09
推测: 12 2.8407e+09
推测: 13 3.31714e+09
推测: 14 4.10857e+09
推测: 7 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\7+厚底.jpg
第24张测试图片的测试
test_mask_pxiels1473
推测: 2 3.57902e+09
推测: 3 2.94167e+09
推测: 4 4.36023e+09
推测: 5 4.08142e+09
推测: 6 4.58802e+09
推测: 7 3.13068e+09
推测: 8 2.30722e+09
推测: 9 3.88275e+09
推测: 10 2.27335e+09
推测: 11 2.50362e+09
推测: 12 1.93677e+09
推测: 13 3.05888e+09
推测: 14 2.70974e+09
推测: 6 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\7+厚底2.jpg
第25张测试图片的测试
test_mask_pxiels1391
推测: 2 1.00562e+10
推测: 3 1.05996e+10
推测: 4 1.02783e+10
推测: 5 1.10004e+10
推测: 6 1.35885e+10
推测: 7 8.84774e+09
推测: 8 1.17561e+10
推测: 9 1.13903e+10
推测: 10 8.9951e+09
推测: 11 9.04684e+09
推测: 12 6.17875e+09
推测: 13 7.90862e+09
推测: 14 8.86442e+09
推测: 6 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\8.jpg
第26张测试图片的测试
test_mask_pxiels1520
推测: 2 8.57156e+09
推测: 3 7.44973e+09
推测: 4 8.3013e+09
推测: 5 7.10376e+09
推测: 6 8.81428e+09
推测: 7 8.1691e+09
推测: 8 7.15676e+09
推测: 9 8.1174e+09
推测: 10 6.4955e+09
推测: 11 6.68006e+09
推测: 12 4.7698e+09
推测: 13 5.97653e+09
推测: 14 5.61839e+09
推测: 6 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\8_2.jpg
第27张测试图片的测试
test_mask_pxiels1336
推测: 2 1.32233e+10
推测: 3 1.30193e+10
推测: 4 1.36028e+10
推测: 5 1.34414e+10
推测: 6 1.40028e+10
推测: 7 1.35393e+10
推测: 8 9.5189e+09
推测: 9 1.69174e+10
推测: 10 1.36004e+10
推测: 11 1.42358e+10
推测: 12 8.62458e+09
推测: 13 9.22531e+09
推测: 14 1.06515e+10
推测: 9 D:/opencv_picture_test/视觉项目resize后的图片夹/测试图片夹/更小的测试图\9.jpg

总结

感觉速度比之前的方法慢了好多,而且误判也很多,不知道是不是我写的有问题。明天再看