# Sobel edge detection Implementation

I am trying to implement sobel edge detection from scratch but my output can't seem to match with OpenCV's sobel function. I performed correlation on the image with the sobel operator in both x and y directions and then computed gradient magnitude as square root of sum of squares of magnitudes in both x & y direction. I believe the problem is how I assign the threshold for edge detection.

Images-

1.Original Image- 2.My implementation of Sobel Edge Detection - 3.Opencv Sobel edge function output - Code-

#include <iostream>
#include <bits/stdc++.h>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/objdetect/objdetect.hpp>
#include <math.h>

using namespace cv;
using namespace std;

int main()
{

// Blurring and Converting to grayscale
Mat img_gray,image_blur;
GaussianBlur( img, image_blur, Size(5,5), 3, 3);
cvtColor(image_blur,img_gray,CV_RGB2GRAY);

int cols = img_gray.cols;
int rows = img_gray.rows;

// Creating sobel operator in x direction
int sobel_x = {-1,0,1,-2,0,2,-1,0,1};
// Creating sobel operator in y direction
int sobel_y = {-1,-2,-1,0,0,0,1,2,1};

// Handle border issues
Mat _src;

// Create output matrix

int max=0;

// Correlation loop in x direction

// Iterate on image
{
{
int s = 0;

// Iterate on kernel
{
{
s += _src.at<uchar>(r + i, c + j) * sobel_x[i + radius][j + radius];
}
}

/*if(s>200)
else
*/
}
}

// Conrrelation loop in y direction

// Iterate on image
{
{
int s = 0;

// Iterate on kernel
{
{
s += _src.at<uchar>(r + i, c + j) * sobel_y[i + radius][j + radius];
}
}

/*if(s>200)
else
*/
}
}

{
{

else
}
}

waitKey(0);

cv::Mat Gx, Gy; int ksize=3;
cv::Sobel(img_gray, Gx, CV_8U, 1, 0, ksize);
cv ...
edit retag close merge delete

That' really a weird idea.

I don't understand this line

gradient_x.at<uchar>(r - radius, c - radius) = s/30;


It should be gradient_x.at<uchar>(r , c ) = s/30; and why s/30? What about negative value?

Gradient could be a negative or positive value. There is no threshold...

Remark :

Sobel is a separable fiter

Hey LBerger, actually that indexing is required to access all the pixels in the image. Initially, I pad the image with one pixel across the whole border so that I could implement correlaton properly.

I'm calculating gradient magnitude which is sum of square of gradients in x and y direction, so the negative values are getting squared. Or am I suppose to ignore the negative gradients?

Oh so sobel doens't require a threshold? Do you have any idea how the OpenCV implementation works as I'm almost following allthe steps in Sobel edge detection but still my output is different from Opencv?

In your image there in no gradient between black to white because you use cv::Sobel(img_gray, Gx, CV_8U, 1, 0, ksize); and it should be cv::Sobel(img_gray, Gx, CV_8S, 1, 0, ksize);

I think now I understand your threshold gradient negative become 0... If you want to implement "sobel edge detection from scratch " don't kill negative gradient

I do padding to take care of edge pixels.

If I use gradient_y.at<char>(r - radius, c - radius) = s; then my edges become much worse. I don't understand the reason why but when I'm dividing by 30, the edges becomes much more clearer.

In the link below, final1.png is s/30, final2.png is s.

Sort by » oldest newest most voted

That's not an answer. But I must say that's I don't understand results given by my program. One thing I still don't understand this line gradient_x.at<uchar>(r - radius, c - radius) I have changed to gradient_x.at<uchar>(r, c )

Now your program with my change :

Mat img_gray = (Mat_<uchar>(7, 7) <<
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0,0,1,2,1,0,0,
0,0,28,3,12,0,0,
0,0,1,32,11,0,0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0);

int sobel_x = { { -1,0,1 },{ -2,0,2 },{ -1,0,1 } };
int scharr_x = { { -3,0,3 },{ -10,0,10 },{ -3,0,3 } };

// Iterate on image
for (int r = 1; r < img_gray.rows - 1; ++r)
{
for (int c = 1; c < img_gray.cols - 1; ++c)
{
int s = 0;

// Iterate on kernel
for (int i = -1; i <= 1; ++i)
{
for (int j = -1; j <= 1; ++j)
{
s += img_gray.at<uchar>(r + i, c + j) * scharr_x[i+1][j+1];
}
}
gradient_x.at<short>(r , c ) = saturate_cast<short>(s) ;

}
}
Mat Gx;
cout << img_gray << endl;
Sobel(img_gray, Gx, CV_32F, 1, 0, CV_SCHARR, 1, 0, BORDER_ISOLATED);
cout << "Scharr OPENCV=\n" << Gx << endl;

// Iterate on image
for (int r = 1; r < img_gray.rows - 1; ++r)
{
for (int c = 1; c < img_gray.cols - 1; ++c)
{
int s = 0;

// Iterate on kernel
for (int i = -1; i <= 1; ++i)
{
for (int j = -1; j <= 1; ++j)
{
s += img_gray.at<uchar>(r + i, c + j) * sobel_x[i + 1][j + 1];
}
}

}
}

/// BUG Sobel(img_gray, Gx, CV_32F, 1, 0, 1,1,0,BORDER_CONSTANT);
Sobel(img_gray, Gx, CV_32F, 1, 0, 3,1,0,BORDER_CONSTANT); // GOOD with ksize 3 (I should read the doc!)
cout << "Sobel OPENCV =\n" << Gx << endl;


results are :

[  0,   0,   0,   0,   0,   0,   0;
0,   0,   0,   0,   0,   0,   0;
0,   0,   1,   2,   1,   0,   0;
0,   0,  28,   3,  12,   0,   0;
0,   0,   1,  32,  11,   0,   0;
0,   0,   0,   0,   0,   0,   0;
0,   0,   0,   0,   0,   0,   0]
Scharr =
[0, 0, 0, 0, 0, 0, 0;
0, 3, 6, 0, -6, -3, 0;
0, 94, 29, -48, -29, -46, 0;
0, 286, 132, -130, -132, -156, 0;
0, 94, 329, 52, -329, -146, 0;
0, 3, 96, 30, -96, -33, 0;
0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0;
0, 3, 6, 0, -6, -3, 0;
0, 94, 29, -48, -29, -46, 0;
0, 286, 132, -130, -132, -156, 0;
0, 94, 329, 52, -329, -146, 0;
0, 3, 96, 30, -96, -33, 0;
0, 0, 0, 0, 0, 0, 0]
Sobel =
[0, 0, 0, 0, 0, 0, 0;
0, 1, 2, 0, -2, -1, 0 ...
more

Official site

GitHub

Wiki

Documentation