C++ Opencv 实现Canny算法

时间:2024-10-05 15:54:37
  • {
  • // 1. Gaussian blurring
  • Mat gauImg;
  • GaussianBlur(*pSrcImg, gauImg, Size(5, 5), 0);
  • if (debug)
  • {
  • imshow("gaussian", gauImg);
  • cv::waitKey(0);
  • }
  • Mat grayImg;
  • if (gauImg.channels() == 3)
  • cvtColor(gauImg, grayImg, COLOR_BGR2GRAY);
  • else
  • grayImg = gauImg.clone();
  • if (debug)
  • {
  • imshow("gray", grayImg);
  • cv::waitKey(0);
  • }
  • // 2. calc gradient angle and magnitude
  • Mat sobxImg, sobyImg, angleImg_orig, angleImg, magImg;
  • Sobel(grayImg, sobxImg, CV_32FC1, 1, 0);
  • Sobel(grayImg, sobyImg, CV_32FC1, 0, 1);
  • if (debug)
  • {
  • imshow("sobel x", sobxImg);
  • imshow("sobel y", sobyImg);
  • cv::waitKey(0);
  • }
  • cartToPolar(sobxImg, sobyImg, magImg, angleImg_orig, true);
  • // normal angleImg_orig(angle value: 0~360) to angleImg( angle value: [0, 45, 90, 135])
  • angleImg = Mat(angleImg_orig.size(), CV_8UC1);
  • for (int row = 0; row < angleImg_orig.rows; row++)
  • {
  • for (int col = 0; col < angleImg_orig.cols; col++)
  • {
  • if ((angleImg_orig.at<float>(row, col) >= 0 && angleImg_orig.at<float>(row, col) < 22.5) ||
  • (angleImg_orig.at<float>(row, col) >= 337.5 && angleImg_orig.at<float>(row, col) < 360) ||
  • angleImg_orig.at<float>(row, col) >= 157.5 && angleImg_orig.at<float>(row, col) < 202.5)
  • {
  • angleImg.at<uchar>(row, col) = 0;
  • }
  • else if ((angleImg_orig.at<float>(row, col) >= 22.5 && angleImg_orig.at<float>(row, col) < 67.5) ||
  • (angleImg_orig.at<float>(row, col) >= 202.5 && angleImg_orig.at<float>(row, col) < 247.5))
  • {
  • angleImg.at<uchar>(row, col) = 45;
  • }
  • else if ((angleImg_orig.at<float>(row, col) >= 67.5 && angleImg_orig.at<float>(row, col) < 112.5) ||
  • (angleImg_orig.at<float>(row, col) >= 247.5 && angleImg_orig.at<float>(row, col) < 292.5))
  • {
  • angleImg.at<uchar>(row, col) = 90;
  • }
  • else
  • {
  • angleImg.at<uchar>(row, col) = 135;
  • }
  • }
  • }
  • // 3. non-maximum magnitude edge point suppression
  • Mat nmsImg = Mat::zeros(magImg.size(), CV_8UC1);
  • Mat nmsMagImg = Mat::zeros(magImg.size(), CV_32FC1);
  • for (int row = 1; row < - 1; row++)
  • {
  • for (int col = 1; col < - 1; col++)
  • {
  • if (angleImg.at<uchar>(row, col) == 0 &&
  • (magImg.at<float>(row, col) > magImg.at<float>(row, col - 1) &&
  • magImg.at<float>(row, col) > magImg.at<float>(row, col + 1)))
  • {
  • nmsMagImg.at<float>(row, col) = magImg.at<float>(row, col);
  • nmsImg.at<uchar>(row, col) = 255;
  • continue;
  • }
  • if (angleImg.at<uchar>(row, col) == 45 &&
  • (magImg.at<float>(row, col) > magImg.at<float>(row - 1, col + 1) &&
  • magImg.at<float>(row, col) > magImg.at<float>(row + 1, col - 1)))
  • {
  • nmsMagImg.at<float>(row, col) = magImg.at<float>(row, col);
  • nmsImg.at<uchar>(row, col) = 255;
  • continue;
  • }
  • if (angleImg.at<uchar>(row, col) == 90 &&
  • (magImg.at<float>(row, col) > magImg.at<float>(row - 1, col) &&
  • magImg.at<float>(row, col) > magImg.at<float>(row + 1, col)))
  • {
  • nmsMagImg.at<float>(row, col) = magImg.at<float>(row, col);
  • nmsImg.at<uchar>(row, col) = 255;
  • continue;
  • }
  • if (angleImg.at<uchar>(row, col) == 135 &&
  • (magImg.at<float>(row, col) > magImg.at<float>(row - 1, col - 1) &&
  • magImg.at<float>(row, col) > magImg.at<float>(row + 1, col + 1)))
  • {
  • nmsMagImg.at<float>(row, col) = magImg.at<float>(row, col);
  • nmsImg.at<uchar>(row, col) = 255;
  • continue;
  • }
  • }
  • }
  • if (debug)
  • {
  • imshow("nms", nmsImg);
  • imshow("nms mag", nmsMagImg);
  • cv::waitKey(0);
  • }
  • // 4. filter out edge points by low theshold and high threshold
  • // 4.1 judge strong edge point: nmxMagImg pixel value > hightThres
  • // judge weakge edge point: nmxMagImg pixel value < lowThres
  • // note: if use magImg to judge, result image will like threshold() output image - rough edge
  • Mat result = nmsImg.clone();
  • for (int row = 1; row < - 1; row++)
  • {
  • for (int col = 1; col < - 1; col++)
  • {
  • if (nmsMagImg.at<float>(row, col) >= highThres)// note: must be nmsMagImg, not be magImg
  • {
  • result.at<uchar>(row, col) = 255;
  • }
  • if (nmsMagImg.at<float>(row, col) < lowThres)
  • {
  • result.at<uchar>(row, col) = 0;
  • }
  • }
  • }
  • if (debug)
  • {
  • imshow("strong edge", result);
  • cv::waitKey(0);
  • }
  • // .4.2 judge medium edge points : lowThres< nmsMagImg pixel value <hightThres
  • for (int row = 1; row < - 1; row++)
  • {
  • for (int col = 1; col < - 1; col++)
  • {
  • if (nmsMagImg.at<float>(row, col) >= lowThres && nmsMagImg.at<float>(row, col) < highThres)
  • {
  • if (result.at<uchar>(row - 1, col - 1) == 255 || result.at<uchar>(row - 1, col) == 255 ||
  • result.at<uchar>(row - 1, col + 1) == 255 || result.at<uchar>(row, col + 1) == 255 ||
  • result.at<uchar>(row + 1, col + 1) == 255 || result.at<uchar>(row + 1, col) == 255 ||
  • result.at<uchar>(row + 1, col - 1) == 255 || result.at<uchar>(row, col - 1) == 255)
  • {
  • result.at<uchar>(row, col) = 255;
  • }
  • else
  • {
  • result.at<uchar>(row, col) = 0;
  • }
  • }
  • }
  • }
  • if (debug)
  • {
  • imshow("my canny", result);
  • cv::waitKey(0);
  • }
  • }