7.0 Edge Detection and Feature Extraction
This module introduces some of the most powerful and widely used algorithms in computer vision. While the concepts may seem complex, the provided examples will make their application clear and accessible. Edge detection is a foundational problem, serving as a critical first step for many higher-level applications like object recognition. Edges represent boundaries in an image, which correspond to significant changes in pixel intensity. This module will cover key algorithms for finding these boundaries, from derivative-based operators to the Canny edge detector and the Hough transform.
7.1 Derivative-Based Edge Detection
The core idea behind derivative-based edge detection is that edges correspond to points of sharp intensity change. In mathematical terms, these changes can be found by calculating the first or second derivative of the image’s intensity function. Large derivative values indicate the presence of an edge.
Sobel Operator
The Sobel operator is a first-order derivative operator that calculates an approximation of the image gradient. It can be configured to detect horizontal edges, vertical edges, or both.
- Function: Imgproc.Sobel(src, dst, ddepth, dx, dy)
- Key Parameters:
- dx: Order of the derivative x (1 for vertical edges, 0 otherwise).
- dy: Order of the derivative y (1 for horizontal edges, 0 otherwise).
The following table shows the output for different combinations of dx and dy.
| dx | dy | Output |
| 1 | 0 | Detects primarily vertical edges. |
| 0 | 1 | Detects primarily horizontal edges. |
| 1 | 1 | Detects both horizontal and vertical edges. |
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class SobelTest {
public static void main(String args[]) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat src = Imgcodecs.imread(“path/to/your/image.jpg”);
Mat dst = new Mat();
Imgproc.Sobel(src, dst, -1, 1, 1);
Imgcodecs.imwrite(“path/to/your/sobel_output.jpg”, dst);
System.out.println(“Image processed with Sobel operator.”);
}
}
Scharr Operator
The Scharr operator is another first-order derivative filter, similar to Sobel, but designed to be more accurate for small kernels.
- Function: Imgproc.Scharr(src, dst, ddepth, dx, dy)
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class ScharrTest {
public static void main( String[] args ) {
System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
Mat src = Imgcodecs.imread(“path/to/your/image.jpg”);
Mat dst = new Mat();
Imgproc.Scharr(src, dst, Imgproc.CV_SCHARR, 0, 1);
Imgcodecs.imwrite(“path/to/your/scharr_output.jpg”, dst);
System.out.println(“Image processed with Scharr operator.”);
}
}
Laplacian Operator
The Laplacian operator is a second-order derivative operator. Unlike first-order operators that detect edge direction, the Laplacian is direction-agnostic and is used to find all edges in an image.
- Function: Imgproc.Laplacian(src, dst, ddepth)
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class LaplacianTest {
public static void main(String args[]) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat src = Imgcodecs.imread(“path/to/your/image.jpg”);
Mat dst = new Mat();
Imgproc.Laplacian(src, dst, 10);
Imgcodecs.imwrite(“path/to/your/laplacian_output.jpg”, dst);
System.out.println(“Image Processed with Laplacian operator.”);
}
}
7.2 Canny Edge Detection Algorithm
The Canny edge detector is widely considered to be the optimal edge detection algorithm. It is a multi-stage process that includes noise reduction, gradient calculation, non-maximum suppression, and a double-thresholding “hysteresis” procedure to connect weak and strong edges. This results in clean, thin, and continuous edge lines.
Before applying the Canny algorithm, the source image must be converted to grayscale.
- Function: Imgproc.Canny(image, edges, threshold1, threshold2)
- Key Parameters: threshold1 and threshold2 are the lower and upper thresholds for the hysteresis procedure. Any edge with a gradient higher than threshold2 is a “sure” edge. Any edge with a gradient below threshold1 is discarded. Edges between the two thresholds are kept only if they are connected to a “sure” edge. This two-threshold approach prevents edges from being broken up by noise.
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class CannyEdgeDetection {
public static void main(String args[]) throws Exception {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat src = Imgcodecs.imread(“path/to/your/image.jpg”);
Mat gray = new Mat();
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
Mat edges = new Mat();
Imgproc.Canny(gray, edges, 60, 180);
Imgcodecs.imwrite(“path/to/your/canny_output.jpg”, edges);
System.out.println(“Image Processed with Canny Edge Detection.”);
}
}
The output is a binary image with single-pixel-thick lines representing the detected edges, which are typically much cleaner than those produced by Sobel or Laplacian operators.
7.3 Hough Transform for Line Detection
The Hough Transform is a feature extraction technique used to find instances of objects with a certain shape. The Hough Line Transform is specifically designed to detect straight lines. A crucial point to understand is that the Hough Transform operates on edge pixels, not the raw image. Therefore, running an edge detector like Canny is a necessary prerequisite; its output is the ideal input for HoughLines.
- Function: Imgproc.HoughLines(image, lines, rho, theta, threshold)
- Key Parameters:
- rho: The resolution of the distance parameter r in pixels. A value of 1 is common.
- theta: The resolution of the angle parameter θ in radians. Math.PI/180 corresponds to one-degree accuracy.
- threshold: The minimum number of votes (intersections in the parameter space) needed to detect a line. A higher threshold will detect fewer, more prominent lines.
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class HoughlinesTest {
public static void main(String args[]) throws Exception {
System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
Mat src = Imgcodecs.imread(“path/to/your/image_with_lines.jpg”, Imgcodecs.IMREAD_GRAYSCALE);
// 1. Find edges using Canny
Mat canny = new Mat();
Imgproc.Canny(src, canny, 50, 200, 3, false);
// 2. Apply Hough Line Transform
Mat lines = new Mat();
Imgproc.HoughLines(canny, lines, 1, Math.PI/180, 100);
// 3. Draw the detected lines on a new color image
Mat cannyColor = new Mat();
Imgproc.cvtColor(canny, cannyColor, Imgproc.COLOR_GRAY2BGR);
for (int i = 0; i < lines.cols(); i++) {
double[] data = lines.get(0, i);
double rho = data[0];
double theta = data[1];
double a = Math.cos(theta);
double b = Math.sin(theta);
double x0 = a * rho;
double y0 = b * rho;
Point pt1 = new Point(Math.round(x0 + 1000 * (-b)), Math.round(y0 + 1000 * (a)));
Point pt2 = new Point(Math.round(x0 – 1000 * (-b)), Math.round(y0 – 1000 * (a)));
Imgproc.line(cannyColor, pt1, pt2, new Scalar(0, 0, 255), 2);
}
Imgcodecs.imwrite(“path/to/your/hough_output.jpg”, cannyColor);
System.out.println(“Image Processed with Hough Line Transform.”);
}
}
After the code runs, you can observe the key logic. We first generate an edge map with Canny. Then, HoughLines processes this map to find line parameters (rho and theta). Finally, we loop through these parameters, convert them back to Cartesian coordinates (pt1, pt2), and draw the resulting lines on the image.
This module’s focus on structural features like edges now shifts to techniques for analyzing and enhancing global image properties, such as contrast and scale.