[计算机视觉项目]【Day1】

[计算机视觉项目]【Day1】


前言

进入大学后,这是我接手的第一个项目
项目具体内容就是青岛的一个玻璃厂,想要区分其生产的瓶子,有具体十几个种类,我们的大致思路就是用摄像头在特定光照条件下,将瓶子的轮廓拍出来,然后利用模板匹配进行识别。但在思考的过程中,我们发现了很多问题,例如瓶子是玻璃材质的,对于拍照的光照条件十分严苛,还有感谢@拾牙慧者,发现如果使用灰度图模板匹配的话,准确度会十分低。所以最终,我们尝试使用梯度来进行模板匹配。


基本思路

利用梯度ncc模板匹配,来进行相似度检测,利用模板匹配样图,取出ncc值最大的就是相似度最高的模型。

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));
}

具体实现函数代码如下:

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;
	}

	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;//ncc矩阵里面的最小值和最大值
		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;
}
/**********************

总结

刚刚回到熟悉的学校,还有一点没走出智能车失利的心态,但是既然已经明确了目标,就不要不断的向这个方向努力,我就不相信努力没有结果,我命由我不由天,加油。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值