Edge detection with Laplacian Operator without using OpenCv laplacian inbuilt function.
Edge detection is an image processing technique for finding the boundaries of images. Here we are going to go through the Laplacian method which is quite popular among edge detection methods.
if you are new to OpenCV please refer to the following document for required installation. we are not using the OpenCV inbuilt function for the Laplacian method to better understand this method.
Why do we use the Laplacian method?
When it comes to Images there are ramp edges, step edges, as in the below pictures.
It's easy to recognize the step edges, we can use a simple filter like successive difference operator which proceed only the first derivate to get the rate of change in colour levels of pixels.
When it comes to Ramp edges it isn’t easy to identify with the use of the difference of colour values of neighbouring pixels. So we have to find the second derivative to recognize those edges. here we get “the rate of change of rate of change” of the colour levels.
Here As we circled in the above picture, it is negative, zero, positive or positive, zero, negative. So we can easily recognize these kinds of edges. When we use 2nd derivative.
When it comes to the Laplacian filter what we do is finding the 2nd derivative concerning x and y.
Ultimately we can derive metrics as below.
The laplacian function is highly sensitive to noises so that when we are applying this Laplacian filter. It's better if we can reduce the noise .and we can use Zero crossing property to avoid those issues.
When it comes to Laplacian of gaussian, It is an operator which combines the Laplacian operator and the gaussian operator, Here It will process gaussian smoothing first and then computing the Laplacian
By applying the 5 by 5 convolutional kernel below, we can get the results of the Laplacian of Gaussians.
Now let's see the practical examples of using these matrices for edge detection.
Please refer to the code
Code Explanation
Mat img = imread(argv[1], 1);if (!img.data) {cout << "Could not find the image!" << endl;
return -1;
}int height = img.rows;int width = img.cols;Mat gr(height, width, CV_8UC1, Scalar(0));cvtColor(img, gr, COLOR_BGR2GRAY);Mat gr2(height, width, CV_8UC1, Scalar(0));
cvtColor(img, gr2, COLOR_BGR2GRAY);
Here we read the image and get the relevant data like the height of the image and width of the image. in the if the condition is used to give a message if the image doesn’t exist.
Then we create grey images gr, gr2
Mat output = gr.clone();Mat output4 = gr.clone();Mat output3(height, width, CV_8UC1, Scalar(0));
Here creating images to display outputs.
for (int i = 1; i < height - 1; i++) {for (int j = 1; j < width - 1; j++) {#laplacian filter without considering diagonal pixels int sum2 = 1 * gr.at<uchar>(i + 1, j) +
1 * gr.at<uchar>(i - 1, j) +
1 * gr.at<uchar>(i, j + 1) +
1 * gr.at<uchar>(i, j - 1) +
(-4 * gr.at<uchar>(i, j));#laplacian filter with diagonal pixelsint sum = (-1 * gr.at<uchar>(i + 1, j)) +
(-1 * gr.at<uchar>(i - 1, j)) +
(-1 * gr.at<uchar>(i, j + 1)) +
(-1 * gr.at<uchar>(i, j - 1)) +
(-1 * gr.at<uchar>(i - 1, j - 1)) +
(-1 * gr.at<uchar>(i + 1, j + 1)) +
(-1 * gr.at<uchar>(i - 1, j + 1)) +
(-1 * gr.at<uchar>(i + 1, j - 1)) +
(8 * gr.at<uchar>(i, j));output3.at<uchar>(i, j) = cv::saturate_cast<uchar>
(sum);output.at<uchar>(i, j) = cv::saturate_cast<uchar>(sum2);}
}
Here, Looping the pixels to apply the Laplacian, and applying Laplacian for orthogonal pixels (sum2), then applying Laplacian for considering both orthogonal and diagonal pixels (sum)
In cv::saturate_cast<uchar>(sum);
What we do is normalizing the data . here when we directly assign the value like below
output.at<uchar>(y, x) = sum;
Then there will be values with
255 + 255 + 255 + 255–4 * 0 = 1020
0 + 0 + 0 + 0–4 * 255 = -1020
To normalize these values between 0 to 255, we use saturate_cast.
#gray picture without laplacian
namedWindow("Gray Image");
imshow("Gray Image", gr);#showing and writing the image with Laplacian for orthogonal and diagonal pixels
namedWindow("laplace diagonal");
imshow("laplace diagonal", output3);
imwrite("laplacian_diagonal.png", output3);#showing and writing the image with Laplacian for orthogonal pixels
namedWindow("laplace orthogonal");
imshow("laplace orthogonal", output);
imwrite("laplacian_orthogonal.png", output);
Here, using the above code we have displayed and saved the images generated.
Output Images
Laplacian of Gaussians
int sum3 = 0;for (int i = 2; i < height - 2; i++) { for (int j = 2; j < width - 2;j++) { // calculate laplacian with guassian smoothing sum3 = 2 * gr2.at<uchar>(i, j + 1) +
2 * gr2.at<uchar>(i, j - 1) +
2 * gr2.at<uchar>(i + 1, j) +
2 * gr2.at<uchar>(i - 1, j) +
gr2.at<uchar>(i, j + 2) +
gr2.at<uchar>(i, j - 2) +
gr2.at<uchar>(i + 2, j) +
gr2.at<uchar>(i - 2, j) +
gr2.at<uchar>(i - 1, j + 1) +
gr2.at<uchar>(i + 1, j + 1) +
gr2.at<uchar>(i + 1, j - 1) +
gr2.at<uchar>(i - 1, j - 1) -
16 * gr2.at<uchar>(i, j);output4.at<uchar>(i, j) = cv::saturate_cast<uchar>(sum3);
}}
Here we start with “i” and “j” from value 2 to avoid errors that occur when the values are out of bounds.
Output Image
Conclusion
Here it's visible that Laplacian of gaussian which is also known as Mexican hat kernel usage can detect edges well than the other two Laplacian kernels.