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

使用OpenCV计算Blob质心结果偏差问题求助

质心计算向左向上偏差的问题排查与修复

核心问题分析

1. 循环内变量重定义导致累加完全失效

在质心计算的双重循环中,你错误地在循环体内重新定义了sum_x和sum_y局部变量,直接覆盖了外部用于累加的变量:

for (e=0; e<thresholded_window.rows; e++)
{
    for (r=0; r<thresholded_window.cols; r++)
    {
        double intensity = thresholded_window.at<double>(e, r);
        double sum_x = sum_x + intensity * r; // 重定义sum_x,外部累加变量始终为0
        double sum_y = sum_y + intensity * e; // 同理sum_y也被重定义
    }
}

这导致sum_x和sum_y始终保持初始值0,最终计算出的窗口内质心为(0,0),加上ROI的左上角坐标x_min/y_min,结果自然偏向图像左上角,与你描述的偏差完全吻合。

2. 像素类型访问错误

thresholded_window由8位灰度图(CV_8U)处理得到,你使用at<double>访问会导致内存越界,读取到错误的像素值,进一步干扰质心计算。必须使用at<uint8_t>获取原始像素值后再转换为double类型。

3. 质心计算公式分母错误

质心的正确计算公式应为:
$$x_c = \frac{\sum (I(x,y) \cdot x)}{\sum I(x,y)}, \quad y_c = \frac{\sum (I(x,y) \cdot y)}{\sum I(x,y)}$$
你错误地使用了降采样后Blob的像素数量max_group_size作为分母,而非ROI内阈值后所有像素的强度总和,这会导致质心计算结果严重偏离真实值。

4. 坐标顺序混淆风险

OpenCV中cv::Mat的坐标顺序是(行, 列)即(y, x),你最终输出的real_centroid[0]对应y坐标,real_centroid[1]对应x坐标,若测试时的实际质心是(x, y)顺序,会造成坐标含义的混淆,建议输出时明确标注。

修复后的关键代码片段

修正质心计算部分

/* Compute the centroid of this window. */
double sum_x = 0;
double sum_y = 0;
double sum_intensity = 0; // 新增:累加所有有效像素的强度总和
double *windowed_centroid = new double[2];
for (e=0; e<thresholded_window.rows; e++)
{
    for (r=0; r<thresholded_window.cols; r++)
    {
        // 正确访问8位灰度图的像素值
        uint8_t pixel_val = thresholded_window.at<uint8_t>(e, r);
        double intensity = static_cast<double>(pixel_val);
        // 直接累加,不再重定义变量
        sum_x += intensity * r;
        sum_y += intensity * e;
        sum_intensity += intensity;
    }
}

// 使用强度总和作为分母,同时避免除以0的异常情况
if (sum_intensity > 0) {
    windowed_centroid[1] = sum_x / sum_intensity; // 对应原图像x坐标
    windowed_centroid[0] = sum_y / sum_intensity; // 对应原图像y坐标
} else {
    // 处理ROI内无有效像素的异常情况
    windowed_centroid[0] = windowed_centroid[1] = 0;
}

其他潜在优化点

  • 连通分量分析阶段,加入extreme_size_thresh和min_size_thresh的判断,剔除不符合尺寸的区域,避免误选背景或噪声:
    if (members > extreme_size_thresh || members < min_size_thresh) {
        continue;
    }
    
  • 构建ROI时,确保坐标不超出原图像边界,防止越界访问:
    x_min = std::max(0, x_min_decimated * decimation - border_size);
    y_min = std::max(0, y_min_decimated * decimation - border_size);
    x_max = std::min(static_cast<int>(SizeX), x_max_decimated * decimation + border_size);
    y_max = std::min(static_cast<int>(SizeY), y_max_decimated * decimation + border_size);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:04:53