Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Canny using separate functions

Hi! I've tried to write Canny edge detector using OpenCV's functions for better understanding. As I can see, my own pipeline has wrong results after non-maximum suppression.

  cv::GaussianBlur(input, blur, cv::Size(5, 5), 1.4, 1.4);
  cv::Sobel(blur, dx, CV_32F, 1, 0, 3);
  cv::Sobel(blur, dy, CV_32F, 0, 1, 3);
  cv::cartToPolar(dx, dy, magnitudes, angles);

  cv::Mat edges = cv::Mat::zeros(img.size(), CV_8UC1);
  for (int y = 1; y < angles.rows - 1; ++y) {
    for (int x = 1; x < angles.cols - 1; ++x) {
      float a = angles.at<float>(y, x);
      float m = magnitudes.at<float>(y, x);
      if (a > CV_PI) {
        a -= CV_PI;
      }

      if (a < CV_PI / 8 || a > CV_PI - CV_PI / 8) {
        if (m > magnitudes.at<float>(y, x + 1) &&
            m > magnitudes.at<float>(y, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI - CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x + 1) &&
            m > magnitudes.at<float>(y + 1, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI + CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x) &&
            m > magnitudes.at<float>(y + 1, x)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else {
        if (m > magnitudes.at<float>(y - 1, x - 1) &&
            m > magnitudes.at<float>(y + 1, x + 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      }
    }
  }

Float32 input.
image description

OpenCV's Canny output

cv::Canny(input, output, 100, 200, 3, true);

image description

My
image description

Next steps of method only reduces number of edge pixels. Thus my mistake already here.
Based on OpenCV 3.2.x doc and OpenCV 2.4.x doc.
Version of Opencv: 3.1.0-dev

Please tell me if I have obvious misunderstanding. Thanks!

Canny using separate functions

Hi! I've tried to write Canny edge detector using OpenCV's functions for better understanding. As I can see, my own pipeline has wrong results after non-maximum suppression.

  cv::GaussianBlur(input, blur, cv::Size(5, 5), 1.4, 1.4);
  cv::Sobel(blur, dx, CV_32F, 1, 0, 3);
  cv::Sobel(blur, dy, CV_32F, 0, 1, 3);
  cv::cartToPolar(dx, dy, magnitudes, angles);

  cv::Mat edges = cv::Mat::zeros(img.size(), CV_8UC1);
  for (int y = 1; y < angles.rows - 1; ++y) {
    for (int x = 1; x < angles.cols - 1; ++x) {
      float a = angles.at<float>(y, x);
      float m = magnitudes.at<float>(y, x);
      if (a > CV_PI) {
        a -= CV_PI;
      }

      if (a < CV_PI / 8 || a > CV_PI - CV_PI / 8) {
        if (m > magnitudes.at<float>(y, x + 1) &&
            m > magnitudes.at<float>(y, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI - CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x + 1) &&
            m > magnitudes.at<float>(y + 1, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI + CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x) &&
            m > magnitudes.at<float>(y + 1, x)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else {
        if (m > magnitudes.at<float>(y - 1, x - 1) &&
            m > magnitudes.at<float>(y + 1, x + 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      }
    }
  }

Float32 input.
image description

OpenCV's Canny output

cv::Canny(input, output, 100, 200, 3, true);

image description

My
image description

Next steps of method only reduces number of edge pixels. Thus my mistake already here.
Based on OpenCV 3.2.x doc and OpenCV 2.4.x doc.
Version of Opencv: 3.1.0-dev

Please tell me if I have obvious misunderstanding. Thanks!


Update: Problem solved, removed gaussian blur (not used in OpenCV's implementation) and edited conditions (two '>' replaced to '>=' and swapped diagonals).

  cv::Sobel(blur, dx, CV_32F, 1, 0, 3);
  cv::Sobel(blur, dy, CV_32F, 0, 1, 3);
  cv::cartToPolar(dx, dy, magnitudes, angles);

  cv::Mat edges = cv::Mat::zeros(img.size(), CV_8UC1);
  for (int y = 1; y < angles.rows - 1; ++y) {
    for (int x = 1; x < angles.cols - 1; ++x) {
      float a = angles.at<float>(y, x);
      float m = magnitudes.at<float>(y, x);
      if (a > CV_PI) {
        a -= CV_PI;
      }

      if (a < CV_PI / 8 || a > CV_PI - CV_PI / 8) {
        if (m >= magnitudes.at<float>(y, x + 1) &&
            m > magnitudes.at<float>(y, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI - CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x - 1) &&
            m > magnitudes.at<float>(y + 1, x + 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI + CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x) &&
            m >= magnitudes.at<float>(y + 1, x)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else {
        if (m > magnitudes.at<float>(y - 1, x + 1) &&
            m > magnitudes.at<float>(y + 1, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      }
    }
  }

Canny using separate functions

Hi! I've tried to write Canny edge detector using OpenCV's functions for better understanding. As I can see, my own pipeline has wrong results after non-maximum suppression.

  cv::GaussianBlur(input, blur, cv::Size(5, 5), 1.4, 1.4);
  cv::Sobel(blur, dx, CV_32F, 1, 0, 3);
  cv::Sobel(blur, dy, CV_32F, 0, 1, 3);
  cv::cartToPolar(dx, dy, magnitudes, angles);

  cv::Mat edges = cv::Mat::zeros(img.size(), CV_8UC1);
  for (int y = 1; y < angles.rows - 1; ++y) {
    for (int x = 1; x < angles.cols - 1; ++x) {
      float a = angles.at<float>(y, x);
      float m = magnitudes.at<float>(y, x);
      if (a > CV_PI) {
        a -= CV_PI;
      }

      if (a < CV_PI / 8 || a > CV_PI - CV_PI / 8) {
        if (m > magnitudes.at<float>(y, x + 1) &&
            m > magnitudes.at<float>(y, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI - CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x + 1) &&
            m > magnitudes.at<float>(y + 1, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI + CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x) &&
            m > magnitudes.at<float>(y + 1, x)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else {
        if (m > magnitudes.at<float>(y - 1, x - 1) &&
            m > magnitudes.at<float>(y + 1, x + 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      }
    }
  }

Float32 input.
image description

OpenCV's Canny output

cv::Canny(input, output, 100, 200, 3, true);

image description

My
image description

Next steps of method only reduces number of edge pixels. Thus my mistake already here.
Based on OpenCV 3.2.x doc and OpenCV 2.4.x doc.
Version of Opencv: 3.1.0-dev

Please tell me if I have obvious misunderstanding. Thanks!


Update: Update: Problem solved, removed gaussian blur (not used in OpenCV's implementation) and edited conditions (two '>' replaced to '>=' and swapped diagonals).

  cv::Sobel(blur, dx, CV_32F, 1, 0, 3);
  cv::Sobel(blur, dy, CV_32F, 0, 1, 3);
  cv::cartToPolar(dx, dy, magnitudes, angles);

  cv::Mat edges = cv::Mat::zeros(img.size(), CV_8UC1);
  for (int y = 1; y < angles.rows - 1; ++y) {
    for (int x = 1; x < angles.cols - 1; ++x) {
      float a = angles.at<float>(y, x);
      float m = magnitudes.at<float>(y, x);
      if (a > CV_PI) {
        a -= CV_PI;
      }

      if (a < CV_PI / 8 || a > CV_PI - CV_PI / 8) {
        if (m >= magnitudes.at<float>(y, x + 1) &&
            m > magnitudes.at<float>(y, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI - CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x - 1) &&
            m > magnitudes.at<float>(y + 1, x + 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else if (a < 0.5f * CV_PI + CV_PI / 8) {
        if (m > magnitudes.at<float>(y - 1, x) &&
            m >= magnitudes.at<float>(y + 1, x)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      } else {
        if (m > magnitudes.at<float>(y - 1, x + 1) &&
            m > magnitudes.at<float>(y + 1, x - 1)) {
          edges.at<uint8_t>(y, x) = 255;
        }
      }
    }
  }