轮廓提取demo

note

步骤:

1.滤波(使用高斯核对原图卷积)

2.取梯度(使用sobel核对步骤1之后的图卷积得到x,y两个方向的梯度分量)

3.合成梯度图(x,y两个方向的梯度分量相加)

4.取梯度平方和矩阵(x*x + y*y)

5.取八邻域掩膜(3x3矩阵)

6.根据掩膜,合成梯度图,梯度平方和矩阵确定轮廓图中锚点位置的灰度值(保留梯度平方和最大的锚点灰度值为合成梯度图的对应点灰度值)

7.二值化(otsu)

8.膨胀(十字架膨胀)

code

// 轮廓提取
void MyContour(Mat& src, Mat& res) {
	Mat sobelX, sobelY;	// sobel梯度卷积核
	GetSobelMat(sobelX, sobelY);
	
	// 1.高斯滤波
	GaussianBlur(src, res, Size(3,3), 1);

	// 2.soble算子求梯度
	Mat gradX, gradY;
	filter2D(res, gradX, src.type(), sobelX);
	filter2D(res, gradY, src.type(), sobelY);
	Mat grad;	// 梯度合成图
	add(gradX, gradY, grad);

	// 3.求梯度幅值矩阵
	gradX.convertTo(gradX, CV_64FC1);
	gradY.convertTo(gradY, CV_64FC1);
	Mat gradAmplitude(gradX.rows, gradX.cols, gradX.type());
	multiply(gradX, gradX, gradX);
	multiply(gradY, gradY, gradY);
	add(gradX, gradY, gradAmplitude);

	// 4.从梯度合成图筛选出轮廓(若锚点位置梯度幅值最大则保留)
	Mat contour(src.rows, src.cols, src.type(), Scalar(0));	// 轮廓
	// Mat neiberHood = (Mat_(3,3) << 1,1,1,1,0,1,1,1,1); // 8邻域矩阵,掩膜
	Rect roi;
	roi.width = 3;
	roi.height = 3;
	int anchor = roi.width / 2;
	for (int i = 0; i + roi.height <= gradAmplitude.rows; ++i) {
		for (int j = 0; j + roi.width <= gradAmplitude.cols; ++j) {
			roi.x = j;
			roi.y = i;
			double max = 0;
			Mat tmp = gradAmplitude(roi);
			int x = 0;
			int y = 0;
			for (int p = 0; p < tmp.rows; p++) {
				for (int q = 0; q < tmp.cols; q++) {
					if (max < tmp.at(p,q)) {
						max = tmp.at(p,q);
						x = q;
						y = p;
					}
				}
			}
			if (x == anchor) {
				contour.at(i,j) =  grad.at(i,j);
			}
		}
	}

	// 5.膨胀
	Mat dilateKernel = (Mat_(3,3) << 0,255,0,255,255,255,0,255,0);	// 十字架膨胀
	dilate(contour, contour, dilateKernel);
	
	contour.copyTo(res);
	res.convertTo(res, CV_8UC1);

	threshold(res, res, 128, 255, THRESH_BINARY|THRESH_OTSU);

}

test

轮廓提取demo_第1张图片

 

你可能感兴趣的:(图像处理,计算机视觉,c++)