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_<double>(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<double>(p,q)) {max = tmp.at<double>(p,q);x = q;y = p;}}}if (x == anchor) {contour.at<uchar>(i,j) = grad.at<uchar>(i,j);}}}// 5.膨胀Mat dilateKernel = (Mat_<uchar>(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