# 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[3][3] = {-1,0,1,-2,0,2,-1,0,1};
// Creating sobel operator in y direction
int sobel_y[3][3] = {-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

( 2016-11-06 05:29:39 -0600 )edit

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?

( 2016-11-06 23:39:05 -0600 )edit

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

( 2016-11-07 01:26:08 -0600 )edit

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.

( 2016-11-07 23:33:36 -0600 )edit

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[3][3] = { { -1,0,1 },{ -2,0,2 },{ -1,0,1 } };
int scharr_x[3][3] = { { -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