You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV 3.4.6:检测并反转图像负片矩形区域的方法求助

Solution for Detecting and Reversing Negative Rectangular Regions in OpenCV 3.4.6

Hey there, let's work through this problem together. Those visible negative rectangles should be detectable with OpenCV—let's fix your approach step by step.

First: Fix the findContours Parameter Mistake

Looking at your code, there's a critical error in the findContours call:

findContours( thresholded, contours, hierarchy, CV_RETR_EXTERNAL, CV_RETR_TREE );

The fifth parameter is supposed to be the contour approximation method, not another retrieval mode. You used CV_RETR_TREE twice—replace that with CV_CHAIN_APPROX_SIMPLE (or CV_CHAIN_APPROX_NONE if you need all contour points). This alone might fix a lot of your detection issues.

Adjust Preprocessing for Negative Regions

Negative rectangles have inverted pixel values compared to their surroundings, so your current thresholding and contrast approach might not be optimal. Let's tweak the pipeline:

1. Start with Grayscale Conversion

Thresholding works best on single-channel images. Skip direct BGR thresholding—convert your original image to grayscale first:

Mat gray;
cvtColor(matOriginal, gray, CV_BGR2GRAY);

2. Use Adaptive Thresholding (Instead of Global Threshold)

Global thresholds like 125 can fail if lighting is uneven. Adaptive thresholding adjusts to local pixel conditions, which is perfect for detecting distinct rectangular regions:

Mat thresholded;
adaptiveThreshold(gray, thresholded, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 11, 2);

We use THRESH_BINARY_INV here because negative regions are inverted—this will make the negative rectangles white (foreground) against a black background, which is easier for contour detection.

3. Optional: Simplify Contrast Enhancement

Your CLAHE implementation is solid, but sometimes over-enhancing can introduce noise. Try testing without CLAHE first, or adjust the clip limit to a lower value (like 2) if you still need it. If you keep CLAHE, apply it to the grayscale image instead of BGR for better control.

Filter Contours to Find Rectangles

Once you have the thresholded image and corrected findContours call, you need to filter out non-rectangular contours:

std::vector<std::vector<cv::Point>> contours;
std::vector<Vec4i> hierarchy;
// Fixed parameters: retrieval mode + approximation method
findContours(thresholded, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

// Iterate through contours to find rectangles
for (size_t i = 0; i < contours.size(); i++) {
    // Approximate the contour to a polygon
    std::vector<cv::Point> approx;
    double epsilon = 0.02 * arcLength(contours[i], true);
    approxPolyDP(contours[i], approx, epsilon, true);
    
    // Check if the approximated polygon is a rectangle (4 vertices) and has enough area
    if (approx.size() == 4 && contourArea(contours[i]) > 100) {
        // Convert the polygon to a rectangle
        Rect rect = boundingRect(approx);
        
        // Reverse the negative region: 255 - pixel value
        Mat roi = matOriginal(rect);
        roi = 255 - roi;
        roi.copyTo(matOriginal(rect));
    }
}
  • epsilon controls how closely the approximation matches the original contour—tweak this value if rectangles are not being detected correctly.
  • The area filter (>100) removes small noise contours that might be mistaken for rectangles.

Full Revised Pipeline Example

Here's how all the pieces fit together:

// Step 1: Convert to grayscale
Mat gray;
cvtColor(matOriginal, gray, CV_BGR2GRAY);

// Step 2: Adaptive thresholding for negative regions
Mat thresholded;
adaptiveThreshold(gray, thresholded, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 11, 2);

// Step 3: Find contours with corrected parameters
std::vector<std::vector<cv::Point>> contours;
std::vector<Vec4i> hierarchy;
findContours(thresholded, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

// Step 4: Filter rectangles and reverse negative regions
for (size_t i = 0; i < contours.size(); i++) {
    std::vector<cv::Point> approx;
    double epsilon = 0.02 * arcLength(contours[i], true);
    approxPolyDP(contours[i], approx, epsilon, true);
    
    if (approx.size() == 4 && contourArea(contours[i]) > 100) {
        Rect rect = boundingRect(approx);
        Mat roi = matOriginal(rect);
        roi = 255 - roi;
        roi.copyTo(matOriginal(rect));
    }
}

Additional Tips

  • If adaptive thresholding isn't working, try THRESH_OTSU with global thresholding: threshold(gray, thresholded, 0, 255, THRESH_BINARY_INV | THRESH_OTSU); Otsu's method automatically calculates the optimal threshold value.
  • For noisy images, add a blur step before thresholding: GaussianBlur(gray, gray, Size(3,3), 0); this will smooth out small noise points.

内容的提问来源于stack exchange,提问作者NucciDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 12:29:07