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

如何基于图像宽度分析颜色分布及定位目标像素区域(OpenCV 4.0.0 C++)

嘿,这个需求我刚好有过类似的实现经验,用OpenCV 4.0.0 + C++完全能搞定,我给你拆解成一步步的实操方案,跟着来肯定没问题~

整体思路

核心就是先锁定红色边框限定的分析区域,再统计该区域内每一列的白色像素占比,最后通过占比阈值找到右侧的密集区域,完全契合你说的“提取水平切片分析”的思路,只不过我们不用真的切图,直接按列统计更高效。

1. 定位红色边框的ROI区域

首先得把红色框出来的范围提取出来,不然整个图像分析太宽泛。红色在HSV空间里容易区分,我们可以通过颜色阈值+轮廓检测来获取ROI:

// 读取目标图像
cv::Mat img = cv::imread("your_image_path.jpg");
if (img.empty()) {
    std::cerr << "Failed to load image!" << std::endl;
    return -1;
}

// 转HSV色彩空间,方便检测红色
cv::Mat hsv_img;
cv::cvtColor(img, hsv_img, cv::COLOR_BGR2HSV);

// 红色的HSV阈值(分两段,因为HSV里红色是首尾衔接的)
cv::Mat red_mask1, red_mask2;
cv::inRange(hsv_img, cv::Scalar(0, 120, 70), cv::Scalar(10, 255, 255), red_mask1);
cv::inRange(hsv_img, cv::Scalar(170, 120, 70), cv::Scalar(180, 255, 255), red_mask2);
cv::Mat red_mask = red_mask1 | red_mask2;

// 找红色边框的轮廓,取面积最大的那个(就是我们要的限定框)
std::vector<std::vector<cv::Point>> contours;
cv::findContours(red_mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
if (contours.empty()) {
    std::cerr << "No red border detected!" << std::endl;
    return -1;
}

int max_contour_idx = 0;
double max_area = cv::contourArea(contours[0]);
for (int i = 1; i < contours.size(); ++i) {
    double area = cv::contourArea(contours[i]);
    if (area > max_area) {
        max_area = area;
        max_contour_idx = i;
    }
}

// 获取ROI的矩形坐标,提取ROI区域
cv::Rect roi_rect = cv::boundingRect(contours[max_contour_idx]);
cv::Mat roi = img(roi_rect);

2. 统计每一列的白色像素占比

接下来我们对ROI的每一列统计白色像素数量,模拟你说的“720x1切片”的分析逻辑:

// ROI转灰度图,方便二值化提取白色
cv::Mat gray_roi;
cv::cvtColor(roi, gray_roi, cv::COLOR_BGR2GRAY);

// 二值化提取白色区域(阈值可根据实际图像调整,黑白图的白色一般接近255)
cv::Mat white_mask;
cv::threshold(gray_roi, white_mask, 240, 255, cv::THRESH_BINARY);

// 统计每一列的白色像素数
int roi_width = roi.cols;
int roi_height = roi.rows;
std::vector<int> white_count_per_col(roi_width, 0);

for (int col = 0; col < roi_width; ++col) {
    // 提取当前列,统计非零像素(白色)的数量
    white_count_per_col[col] = cv::countNonZero(white_mask.col(col));
}

// 计算每一列的白色像素占比(占该列总像素的比例)
std::vector<float> white_ratio_per_col(roi_width, 0.0f);
for (int col = 0; col < roi_width; ++col) {
    white_ratio_per_col[col] = static_cast<float>(white_count_per_col[col]) / roi_height;
}

3. 定位右侧的白色密集区域

现在有了每一列的占比数据,我们可以设定一个阈值(比如占比超过80%就算密集),从右往左找连续符合条件的区域,最后转换回原图坐标:

// 自定义参数,可根据需求调整
const float DENSITY_THRESHOLD = 0.8f; // 白色占比超过这个值就算密集
const int MIN_CONTINUOUS_COLS = 15;   // 至少连续N列符合条件才算有效区域

int start_col = -1;
int end_col = roi_width - 1;
int continuous_match = 0;

// 从右往左遍历,找连续的密集列
for (int col = roi_width - 1; col >= 0; --col) {
    if (white_ratio_per_col[col] >= DENSITY_THRESHOLD) {
        continuous_match++;
        // 找到足够多的连续密集列,记录起始位置
        if (continuous_match == MIN_CONTINUOUS_COLS) {
            start_col = col;
            break;
        }
    } else {
        continuous_match = 0;
        end_col = col;
    }
}

// 如果找到有效区域,转换为原图坐标并可视化
if (start_col != -1) {
    int orig_start_x = roi_rect.x + start_col;
    int orig_end_x = roi_rect.x + end_col;
    int orig_y = roi_rect.y;
    int orig_h = roi_rect.height;

    std::cout << "白色密集区域(原图坐标):\n"
              << "X范围:" << orig_start_x << " ~ " << orig_end_x << "\n"
              << "Y范围:" << orig_y << " ~ " << orig_y + orig_h << std::endl;

    // 用浅粉色标注目标区域,和你说的需求对应
    cv::rectangle(img, cv::Rect(orig_start_x, orig_y, orig_end_x - orig_start_x, orig_h),
                  cv::Scalar(255, 105, 180), 2);
    cv::imwrite("result_with_mark.jpg", img);
} else {
    std::cerr << "未找到符合条件的白色密集区域!" << std::endl;
}

一些实用优化建议

  • 如果图像有噪声,可以在二值化前加高斯模糊:cv::GaussianBlur(gray_roi, gray_roi, cv::Size(3,3), 0);,减少误判。
  • 红色的HSV阈值可以根据实际图像微调,比如用OpenCV的滑动条工具实时调试,能更精准地定位红色边框。
  • 要是不需要严格的连续列,也可以用滑动窗口计算平均占比(比如每20列算一个窗口的平均占比),这样结果会更平滑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:50:22