用於計算圖像中每一個非零點距離離自己最近的零點的距離
1.png
cv::Mat src = cv::imread("D:/bb/tu1/1.png",0); cv::Mat imageThin(src.size(), CV_32FC1); //定義保存距離變換結果的Mat矩陣 distanceTransform(src, imageThin, CV_DIST_L2, 3); //距離計算 /* 參數1:8-bit, 單通道輸入圖片 參數2:輸出結果中包含計算的距離,這是一個32-bit float 單通道的Mat類型,大小與輸入圖片相同 參數3:distanceType計算距離的類型 distanceType maskSize a \ b \ c CV_DIST_C 3(3X3) a = 1, b = 1 CV_DIST_L1 3(3X3) a = 1, b = 2 CV_DIST_L2 3(3X3) a=0.955, b=1.3693 CV_DIST_L2 5(5X5) a=1, b=1.4, c=2.1969 參數4:maskSize – 距離變換掩碼矩陣的大小 3(CV_DIST_L1、 CV_DIST_L2 、CV_DIST_C) 5(CV_DIST_L2 ) CV_DIST_MASK_PRECISE (這個只能在4參數的API中使用) 參數5:目標矩陣的數據類型
CV_8U
說明:其中 a b c 含義:在這個函數中計算每個非0像素到黑色像素(0值像素)的最短距離,因此需要通過最短的移動方式找到這個點計算他們之間的值。通常來說移動有水平方向、豎直方向、對角方向、跳躍式幾個移動方法。雖然計算距離的方法都是一些很基礎的公式,但是這個這個掩碼矩陣必須是對陣的,因此掩碼矩陣上所有水平和豎直方向的變化量,這里用 a 代表;對角方向的變化量用 b 代表;跳躍移動的變化量用 c 代表。CV_DIST_C、CV_DIST_L1、CV_DIST_L2(maskSize=5)的計算結果是精確的,CV_DIST_L2(maskSize=3)是一個快速計算方法 */
應用一:細化輪廓
2.png
float maxValue = 0; //保存距離變換矩陣中的最大值 cv::Mat src = cv::imread("D:/bb/tu1/2.png",0); cv::Mat imageGray=~src; //取反 cv::GaussianBlur(imageGray, imageGray, cv::Size(5, 5), 2); //濾波-去除雜點 cv::threshold(imageGray, imageGray, 10, 200, 0); cv::namedWindow("imageGray"); cv::imshow("imageGray",imageGray); cv::Mat imageThin(imageGray.size(), CV_32FC1); cv::distanceTransform(imageGray, imageThin, CV_DIST_L2, 3); //距離計算 cv::Mat distShow; distShow = cv::Mat::zeros(imageGray.size(), CV_8UC1); for (int i = 0; i < imageThin.rows; i++) { for (int j = 0; j < imageThin.cols; j++) { if (imageThin.at<float>(i, j) > maxValue) { maxValue = imageThin.at<float>(i, j); //獲取距離變換的最大值 } } } for (int i = 0; i < imageThin.rows; i++) { for (int j = 0; j < imageThin.cols; j++) { if (imageThin.at<float>(i, j) > maxValue / 1.9) { distShow.at<uchar>(i, j) = 255; //符合距離大於最大值一定比例條件的點設為255 } } } cv::namedWindow("distShow"); cv::imshow("distShow", distShow);
應用二:查找物體質心
3.png
cv::Mat src = cv::imread("D:/bb/tu1/3.png"); cv::Mat imageGray; cv::cvtColor(src, imageGray, CV_RGB2GRAY); imageGray = ~imageGray; cv::threshold(imageGray, imageGray, 20, 255, 0); cv::Mat imageThin(imageGray.size(), CV_32FC1); cv::distanceTransform(imageGray, imageThin, CV_DIST_L2, 3); //距離變換 cv::Mat distShow; distShow = cv::Mat::zeros(imageGray.size(), CV_8UC1); float maxValue = 0; cv::Point Pt(0, 0); for (int i = 0; i < imageThin.rows; i++) { for (int j = 0; j < imageThin.cols; j++) { distShow.at<uchar>(i, j) = imageThin.at<float>(i, j); //把float轉換成uchar之后,距離越遠的地方越亮 if (imageThin.at<float>(i, j) > maxValue) { maxValue = imageThin.at<float>(i, j); //獲取距離變換的最大值 Pt = cv::Point(j, i); //最大值的坐標 } } } cv::normalize(distShow, distShow, 0, 255, CV_MINMAX); //為了顯示清晰,做了0~255歸一化 cv::circle(src, Pt, maxValue, cv::Scalar(0, 0, 255), 3); cv::circle(src, Pt, 3, cv::Scalar(0, 255, 0), 3); cv::namedWindow("src1"); cv::imshow("src1", src); cv::waitKey();