Real-Time Defect Detection System for Manufacturing Production Lines Using Computer Vision C++
👤 Sharing: AI
```cpp
#include <iostream>
#include <opencv2/opencv.hpp> // Include OpenCV library
using namespace cv;
using namespace std;
// Configuration parameters (adjustable)
const int BLUR_SIZE = 5; // Size of the Gaussian blur kernel
const int CANNY_THRESHOLD1 = 50; // Canny edge detector threshold 1
const int CANNY_THRESHOLD2 = 150; // Canny edge detector threshold 2
const int MIN_CONTOUR_AREA = 100; // Minimum area for a contour to be considered a defect
const double DEFECT_AREA_RATIO_THRESHOLD = 0.1; //Threshold for defect area ratio
// Function to preprocess the image (noise reduction and edge detection)
Mat preprocessImage(const Mat& image) {
Mat gray, blurred, edges;
// 1. Convert to grayscale
cvtColor(image, gray, COLOR_BGR2GRAY);
// 2. Apply Gaussian blur for noise reduction
GaussianBlur(gray, blurred, Size(BLUR_SIZE, BLUR_SIZE), 0);
// 3. Detect edges using the Canny edge detector
Canny(blurred, edges, CANNY_THRESHOLD1, CANNY_THRESHOLD2);
return edges;
}
// Function to detect defects based on contour analysis
vector<vector<Point>> detectDefects(const Mat& edges, const Mat& originalImage) {
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
// Find contours in the edge image
findContours(edges, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
vector<vector<Point>> defectContours;
// Iterate through the found contours
for (size_t i = 0; i < contours.size(); i++) {
// Calculate the area of the contour
double area = contourArea(contours[i]);
// Filter out small contours (noise)
if (area > MIN_CONTOUR_AREA) {
// Approximate the contour with a polygon
vector<Point> approx;
double epsilon = 0.01 * arcLength(contours[i], true);
approxPolyDP(contours[i], approx, epsilon, true);
// If it's a good size contour, consider it a potential defect
defectContours.push_back(contours[i]);
}
}
return defectContours;
}
// Function to visually highlight the detected defects on the original image
void highlightDefects(Mat& image, const vector<vector<Point>>& defectContours) {
for (size_t i = 0; i < defectContours.size(); i++) {
// Draw a red bounding rectangle around the defect
Rect bounding_rect = boundingRect(defectContours[i]);
rectangle(image, bounding_rect.tl(), bounding_rect.br(), Scalar(0, 0, 255), 2); // Red rectangle
putText(image, "Defect", bounding_rect.tl() - Point(0, 10), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 0, 255), 2);
}
}
int main() {
// 1. Capture video from a camera or load from a video file.
VideoCapture cap(0); // Use camera index 0 (default camera)
//VideoCapture cap("defect_video.mp4"); // Uncomment to load from video file. Make sure "defect_video.mp4" exists in the same directory.
if (!cap.isOpened()) {
cout << "Error opening video stream or file" << endl;
return -1;
}
// Create a window to display the output
namedWindow("Defect Detection", WINDOW_NORMAL);
Mat frame;
while (true) {
// 2. Read a frame from the video stream
cap >> frame;
// If the frame is empty, break the loop
if (frame.empty())
break;
// 3. Preprocess the image to enhance defects
Mat edges = preprocessImage(frame);
// 4. Detect defects based on contour analysis
vector<vector<Point>> defectContours = detectDefects(edges, frame);
// 5. Highlight the detected defects on the original image
highlightDefects(frame, defectContours);
// 6. Display the original image with highlighted defects
imshow("Defect Detection", frame);
// Exit the loop if the 'Esc' key is pressed
char c = (char)waitKey(30); // Wait for 30 milliseconds
if (c == 27)
break;
}
// Release the video capture and destroy all windows
cap.release();
destroyAllWindows();
return 0;
}
```
**Explanation and Breakdown:**
1. **Includes:**
* `<iostream>`: For input/output operations (like `cout`).
* `<opencv2/opencv.hpp>`: The main OpenCV header file. This includes most of the commonly used OpenCV modules.
2. **Namespaces:**
* `using namespace cv;`: Allows you to use OpenCV functions and classes without the `cv::` prefix (e.g., `Mat` instead of `cv::Mat`).
* `using namespace std;`: Allows you to use standard C++ library elements without the `std::` prefix (e.g., `cout` instead of `std::cout`).
3. **Configuration Parameters (Constants):**
* `BLUR_SIZE`: The size of the Gaussian blur kernel. A larger size will result in more blurring, which can help reduce noise but may also blur out small defects. It must be an odd number.
* `CANNY_THRESHOLD1`, `CANNY_THRESHOLD2`: The thresholds for the Canny edge detector. These values determine the sensitivity of the edge detection. Adjust these carefully. A lower `CANNY_THRESHOLD1` will detect more edges, but also more noise.
* `MIN_CONTOUR_AREA`: The minimum area (in pixels) for a contour to be considered a potential defect. This helps filter out small noise-related contours. Increase this if you're getting many false positives from small imperfections.
* `DEFECT_AREA_RATIO_THRESHOLD`: The required area percentage to be recognized as a defect
4. **`preprocessImage(const Mat& image)` Function:**
* Takes a `Mat` object (representing the input image) as a constant reference (to avoid copying the image data).
* **Converts to Grayscale:** `cvtColor(image, gray, COLOR_BGR2GRAY)` converts the input color image to grayscale. Grayscale images are easier to process for edge detection.
* **Gaussian Blur:** `GaussianBlur(gray, blurred, Size(BLUR_SIZE, BLUR_SIZE), 0)` applies a Gaussian blur to the grayscale image. This smooths the image and reduces noise, making edge detection more reliable. The `Size` parameter specifies the kernel size for the blur. The `0` for the last parameter indicates that the standard deviation is calculated automatically.
* **Canny Edge Detection:** `Canny(blurred, edges, CANNY_THRESHOLD1, CANNY_THRESHOLD2)` applies the Canny edge detection algorithm. The Canny detector finds edges in the image. The two thresholds control the hysteresis thresholding process in the Canny algorithm.
* Returns the `edges` `Mat` object (the image with detected edges).
5. **`detectDefects(const Mat& edges, const Mat& originalImage)` Function:**
* Takes the edge image (`edges`) and the original image (`originalImage`) as input. The original image is needed for some defect analysis or feature extraction that might be color-dependent.
* **Find Contours:** `findContours(edges, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE)` finds contours in the edge image.
* `edges`: The input edge image (output of the Canny detector).
* `contours`: A `vector<vector<Point>>` to store the detected contours. Each contour is a vector of points.
* `hierarchy`: A `vector<Vec4i>` that contains information about the hierarchy of the contours (which contours are nested inside others).
* `RETR_EXTERNAL`: Retrieves only the *outermost* contours (important to avoid detecting edges within a defect as separate contours).
* `CHAIN_APPROX_SIMPLE`: Approximates the contours by storing only the endpoints of line segments, which reduces memory usage and processing time.
* **Iterate Through Contours:** Loops through each detected contour.
* **Calculate Area:** `contourArea(contours[i])` calculates the area of the current contour.
* **Filter Small Contours:** `if (area > MIN_CONTOUR_AREA)` checks if the area of the contour is greater than the minimum area threshold. This filters out small contours that are likely noise or insignificant details.
* **Approximate Contour:** `approxPolyDP` approximates the polygon.
* **Store Defect Contours:** If the contour passes the area threshold, it's added to the `defectContours` vector.
* Returns the `defectContours` vector (containing the contours that are considered potential defects).
6. **`highlightDefects(Mat& image, const vector<vector<Point>>& defectContours)` Function:**
* Takes the original image (`image`) and the defect contours (`defectContours`) as input.
* **Iterates through defect contours.**
* **Bounding Rectangle:** `boundingRect(defectContours[i])` gets the bounding rectangle for each defect contour.
* **Draws Rectangle:** `rectangle(image, bounding_rect.tl(), bounding_rect.br(), Scalar(0, 0, 255), 2)` draws a red rectangle around the detected defect on the original image.
* `image`: The image on which to draw the rectangle (passed by reference, so it's modified).
* `bounding_rect.tl()`: The top-left corner of the rectangle.
* `bounding_rect.br()`: The bottom-right corner of the rectangle.
* `Scalar(0, 0, 255)`: The color of the rectangle (red in BGR format).
* `2`: The thickness of the rectangle's border in pixels.
* **Puts Text:** `putText` adds the text "Defect" to the image near the bounding box.
7. **`main()` Function:**
* **Video Capture:**
* `VideoCapture cap(0)`: Creates a `VideoCapture` object to capture video from the default camera (camera index 0). You can change the index to use a different camera.
* `VideoCapture cap("defect_video.mp4")`: Alternatively, you can load a video from a file. Uncomment this line and replace `"defect_video.mp4"` with the path to your video file.
* `cap.isOpened()`: Checks if the video capture was successfully initialized.
* **Window Creation:** `namedWindow("Defect Detection", WINDOW_NORMAL)` creates a window to display the output. `WINDOW_NORMAL` allows you to resize the window.
* **Main Loop:** `while (true)`: This loop continuously reads frames from the video stream and processes them.
* **Read Frame:** `cap >> frame`: Reads a frame from the video stream into the `frame` `Mat` object.
* **Check for Empty Frame:** `if (frame.empty()) break;`: If the frame is empty (e.g., the video has ended), the loop breaks.
* **Process Frame:**
* `Mat edges = preprocessImage(frame)`: Preprocesses the frame to get the edge image.
* `vector<vector<Point>> defectContours = detectDefects(edges, frame)`: Detects the defects in the preprocessed image.
* `highlightDefects(frame, defectContours)`: Draws red rectangles around the detected defects on the original frame.
* **Display Image:** `imshow("Defect Detection", frame)`: Displays the processed frame in the "Defect Detection" window.
* **Wait for Key Press:** `waitKey(30)`: Waits for 30 milliseconds for a key press. This controls the frame rate of the video. `27` is the ASCII code for the Escape key. If the Escape key is pressed, the loop breaks.
* **Release Resources:**
* `cap.release()`: Releases the video capture object. This is important to free up the camera or video file.
* `destroyAllWindows()`: Closes all OpenCV windows.
**How to Compile and Run:**
1. **Install OpenCV:** You need to have OpenCV installed on your system. The installation process varies depending on your operating system. Refer to the official OpenCV documentation for instructions: [https://docs.opencv.org/4.x/d0/d3d/tutorial_general_install.html](https://docs.opencv.org/4.x/d0/d3d/tutorial_general_install.html)
2. **Compiler:** You'll need a C++ compiler (like g++, clang++, or Visual Studio).
3. **Compilation Command (using g++ on Linux/macOS):**
```bash
g++ -o defect_detection defect_detection.cpp `pkg-config --cflags --libs opencv4`
```
* `g++ -o defect_detection defect_detection.cpp`: This compiles the `defect_detection.cpp` file and creates an executable named `defect_detection`.
* ``pkg-config --cflags --libs opencv4``: This part uses the `pkg-config` utility to get the necessary compiler flags (include paths) and linker flags (library paths) for OpenCV. This is the recommended way to link against OpenCV. If you are using an older version of OpenCV, you might need to use `opencv` instead of `opencv4`.
* If `pkg-config` doesn't work, you'll need to manually specify the include paths and library paths. This is more complicated and depends on how you installed OpenCV.
4. **Run the Executable:**
```bash
./defect_detection
```
This will run the program, which will attempt to capture video from your default camera and display the defect detection results. If you are using the video file, you don't need to worry about camera permissions.
**Important Considerations and Improvements:**
* **Calibration:** For more accurate measurements (e.g., defect size), you might need to calibrate your camera. Camera calibration involves determining the camera's intrinsic parameters (focal length, principal point, distortion coefficients).
* **Lighting:** Consistent lighting is crucial for reliable defect detection. Changes in lighting can significantly affect edge detection. Consider using controlled lighting in your manufacturing environment.
* **Defect Classification:** This code only *detects* potential defects. To *classify* the defects (e.g., scratch, dent, crack), you'll need to extract features from the defect regions (e.g., size, shape, texture) and train a machine learning classifier (e.g., SVM, neural network).
* **Segmentation:** For complex images, you might need to use image segmentation techniques to isolate the object being inspected before applying defect detection.
* **Performance Optimization:** For real-time performance on high-resolution video, you might need to optimize the code:
* Use multi-threading to parallelize image processing tasks.
* Use GPU acceleration (e.g., using CUDA or OpenCL) if your system has a GPU.
* Reduce the image resolution if possible (trade-off between speed and accuracy).
* **User Interface:** Consider adding a user interface (e.g., using Qt or another GUI framework) to allow users to adjust parameters, view results, and save data.
* **Error Handling:** Add more robust error handling (e.g., check if the video stream is valid, handle exceptions) to make the code more reliable.
* **Logging:** Implement logging to record events, errors, and debugging information.
* **Adaptive Thresholding:** Instead of fixed thresholds, explore adaptive thresholding techniques (e.g., Otsu's method) to automatically determine appropriate threshold values based on the image content.
* **Defect ratio check:** Implement logic that checks for the defect ratio threshold and only marks it as a defect when the required condition is met
This detailed explanation and the improved code should provide a solid foundation for building a real-time defect detection system using C++ and OpenCV. Remember to experiment with the parameters and techniques to optimize the system for your specific manufacturing application and product.
👁️ Viewed: 2
Comments