C++ OpenCV Advanced Image Processing
Advanced image processing refers to performing more complex tasks on the basis of basic image processing (such as filtering, edge detection, etc.), such as image segmentation, contour detection, morphological operations, histogram processing, and more. These techniques are widely used in fields such as object detection, image analysis, and medical image processing.
Application Scenarios of Advanced Image Processing
Medical Image Analysis:
Use image segmentation techniques to extract lesion regions.
Use morphological operations to remove noise.
Object Detection and Tracking:
Use contour detection and template matching to locate objects.
Use histogram processing to enhance object features.
Image Enhancement:
Use histogram equalization to improve image contrast.
Use the watershed algorithm to separate overlapping objects.
Image Segmentation
Image segmentation is an important step in image processing. It divides an image into multiple regions or objects for further analysis and processing. Common image segmentation methods include threshold-based segmentation, edge-based segmentation, and region-based segmentation.
Threshold-based Segmentation
Threshold-based segmentation is one of the simplest image segmentation methods. It classifies pixel values into different categories by setting one or more thresholds. Common threshold segmentation methods include global thresholding and adaptive thresholding.
Global Thresholding
Global thresholding uses a fixed threshold to divide an image into foreground and background. OpenCV provides thecv::thresholdfunction to implement this.
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat dst;
cv::threshold(src, dst, 128, 255, cv::THRESH_BINARY);
In the above code,128is the threshold,255is the maximum pixel value,cv::THRESH_BINARYindicates the use of the binary threshold method.
Adaptive Thresholding
Adaptive thresholding dynamically adjusts the threshold based on local regions of the image. OpenCV provides thecv::adaptiveThresholdfunction to implement this.
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat dst;
cv::adaptiveThreshold(src, dst, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 11, 2);
In the above code,255is the maximum pixel value,cv::ADAPTIVE_THRESH_MEAN_Cindicates using the local mean as the threshold,11is the neighborhood size,2is the constant.
Edge-based Segmentation
Edge-based segmentation segments an image by detecting edges in the image. Common edge detection algorithms include Canny edge detection and the Sobel operator.
Canny Edge Detection
Canny edge detection is a multi-stage edge detection algorithm. OpenCV provides thecv::Cannyfunction to implement this.
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat edges;
cv::Canny(src, edges, 100, 200);
In the above code,100and200are the two thresholds of the Canny algorithm.
Region-based Segmentation (Watershed Algorithm)
Region-based segmentation achieves segmentation by dividing the image into multiple regions. The watershed algorithm is a commonly used region-based segmentation method.
Watershed Algorithm
The watershed algorithm treats the image as a topographic map and segments it by simulating the diffusion of water flow. OpenCV provides thecv::watershedfunction to implement this.
cv::Mat src = cv::imread("image.jpg");
cv::Mat markers = cv::Mat::zeros(src.size(), CV_32S);
cv::watershed(src, markers);
In the above code,markersis the marker matrix, used to store the segmentation result.
Contour Detection
Contour detection is an important step in image processing. It is used to detect object boundaries in an image. OpenCV provides various functions for contour detection and processing.
Finding Contours
Finding contours is the first step of contour detection. OpenCV provides thecv::findContoursfunction to implement this.
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(src, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
In the above code,contoursis the vector storing the contours,hierarchyis the vector storing the contour hierarchy.
Contour Features
Contour features include area, perimeter, bounding box, and more. OpenCV provides various functions to compute these features.
Area
Area is an important feature of a contour. OpenCV provides thecv::contourAreafunction to calculate the area of a contour.
double area = cv::contourArea(contours[0]);
Perimeter
Perimeter is another important feature of a contour. OpenCV provides thecv::arcLengthfunction to calculate the perimeter of a contour.
double perimeter = cv::arcLength(contours[0], true);
Bounding Box
A bounding box is the minimum enclosing rectangle of a contour. OpenCV provides thecv::boundingRectfunction to compute the bounding box.
cv::Rect rect = cv::boundingRect(contours[0]);
Drawing Contours
Drawing contours means drawing the detected contours onto an image. OpenCV provides thecv::drawContoursfunction to implement this.
cv::Mat dst = cv::Mat::zeros(src.size(), CV_8UC3); cv::drawContours(dst, contours, -1, cv::Scalar(0, 255, 0), 2);
In the above code,dstis the image after drawing the contours,cv::Scalar(0, 255, 0)is the color of the contours,2is the line width of the contours.
Template Matching
Template matching is a method for finding a specific template in an image. OpenCV provides thecv::matchTemplatefunction to implement this.
Single Template Matching
Single template matching is finding one template in an image. OpenCV provides thecv::matchTemplatefunction to implement this.
cv::Mat src = cv::imread("image.jpg");
cv::Mat templ = cv::imread("template.jpg");
cv::Mat result;
cv::matchTemplate(src, templ, result, cv::TM_CCOEFF_NORMED);
In the above code,resultis the matching result matrix,cv::TM_CCOEFF_NORMEDis the matching method.
Multiple Template Matching
Multiple template matching is finding multiple templates in an image. It can be implemented by iterating over the matching result matrix.
double minVal, maxVal; cv::Point minLoc, maxLoc; cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
In the above code,maxLocis the position of the maximum value in the matching result.
Example
Watershed Algorithm
Example
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// Read the image
Mat image = imread("objects.jpg");
if (image.empty()) {
cout << "Error: Unable to load image. Please check whether the path is correct." << endl;
return -1;
}
// Convert to grayscale
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
// Binarize
Mat binary;
threshold(gray, binary, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
// Remove noise
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(binary, binary, MORPH_OPEN, kernel, Point(-1, -1), 2);
// Compute distance transform
Mat dist;
distanceTransform(binary, dist, DIST_L2, 5);
// Normalize the distance transform image
normalize(dist, dist, 0, 1.0, NORM_MINMAX);
// Binarize the distance transform image
threshold(dist, dist, 0.5, 1.0, THRESH_BINARY);
// Find contours
Mat dist_8u;
dist.convertTo(dist_8u, CV_8U);
vector<vector<Point>> contours;
findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// Create marker image
Mat markers = Mat::zeros(dist.size(), CV_32S);
for (size_t i = 0; i < contours.size(); i++) {
drawContours(markers, contours, static_cast<int>(i), Scalar(static_cast<int>(i) + 1), -1);
}
// Apply watershed algorithm
watershed(image, markers);
// Display the result
Mat result = image.clone();
for (int i = 0; i < markers.rows; i++) {
for (int j = 0; j < markers.cols; j++) {
if (markers.at<int>(i, j) == -1) {
result.at<Vec3b>(i, j) = Vec3b(0, 255, 0); // Mark boundaries in green
}
}
}
imshow("Watershed Result", result);
waitKey(0);
return 0;
}
Contour Detection
Contour detection is used to extract object boundaries in an image.
OpenCV provides the findContours function to detect contours.
Example
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// Read the image
Mat image = imread("objects.jpg");
if (image.empty()) {
cout << "Error: Unable to load image. Please check whether the path is correct." << endl;
return -1;
}
// Convert to grayscale
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
// Binarize
Mat binary;
threshold(gray, binary, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
// Find contours
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
// Draw contours
Mat result = Mat::zeros(image.size(), CV_8UC3);
for (size_t i = 0; i < contours.size(); i++) {
drawContours(result, contours, i, Scalar(0, 255, 0), 2);
}
// Display the result
imshow("Contours", result);
waitKey(0);
return 0;
}
Morphological Operations
Morphological operations are shape-based image processing techniques, commonly used for removing noise, separating objects, and more.
Example
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// Read the image
Mat image = imread("noisy_image.jpg");
if (image.empty()) {
cout << "Error: Unable to load image. Please check whether the path is correct." << endl;
return -1;
}
// Convert to grayscale
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
// Binarize
Mat binary;
threshold(gray, binary, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
// Define the kernel
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
// Opening operation (remove noise)
Mat opened;
morphologyEx(binary, opened, MORPH_OPEN, kernel);
// Closing operation (fill holes)
Mat closed;
morphologyEx(opened, closed, MORPH_CLOSE, kernel);
// Display the result
imshow("Original Binary", binary);
imshow("Opened Image", opened);
imshow("Closed Image", closed);
waitKey(0);
return 0;
}
Histogram Processing
Histogram processing is used to analyze the pixel distribution of an image. Common operations include histogram equalization, histogram matching, and more.
Example
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// Read the image
Mat image = imread("low_contrast.jpg");
if (image.empty()) {
cout << "Error: Unable to load image. Please check whether the path is correct." << endl;
return -1;
}
// Convert to grayscale
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
// Histogram equalization
Mat equalized;
equalizeHist(gray, equalized);
// Display the result
imshow("Original Image", gray);
imshow("Equalized Image", equalized);
waitKey(0);
return 0;
}
Template Matching
Template matching is used to find regions in an image that are similar to a template.
Example
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// Read the image and the template
Mat image = imread("scene.jpg");
Mat templ = imread("template.jpg");
if (image.empty() || templ.empty()) {
cout << "Error: Unable to load image. Please check whether the path is correct." << endl;
return -1;
}
// Template matching
Mat result;
matchTemplate(image, templ, result, TM_CCOEFF_NORMED);
// Find the best match position
double minVal, maxVal;
Point minLoc, maxLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
// Draw a rectangle
rectangle(image, maxLoc, Point(maxLoc.x + templ.cols, maxLoc.y + templ.rows), Scalar(0, 255, 0), 2);
// Display the result
imshow("Template Matching", image);
waitKey(0);
return 0;
}