使用OpenCV计算灰度图像的质心

发布于:2025-08-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

在灰度图像中计算质心时,我们需要考虑像素的灰度值作为权重,这与二值图像不同。以下是使用OpenCV在C++中计算灰度图像质心的完整实现:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cmath>

int main() {
    // 1. 读取图像为灰度图
    cv::Mat grayImage = cv::imread("grayscale_image.jpg", cv::IMREAD_GRAYSCALE);
    
    if (grayImage.empty()) {
        std::cerr << "Error: 无法加载图像文件" << std::endl;
        return -1;
    }

    // 2. 计算图像矩 - 灰度值作为权重
    cv::Moments m = cv::moments(grayImage, true);  // true表示使用灰度值作为权重

    // 3. 检查有效像素权重
    if (std::fabs(m.m00) < 1e-5) {
        std::cerr << "Error: 图像不包含有效像素信息" << std::endl;
        return -1;
    }

    // 4. 计算质心坐标
    cv::Point2f centroid(
        static_cast<float>(m.m10 / m.m00),
        static_cast<float>(m.m01 / m.m00)
    );

    // 5. 输出结果
    std::cout << "图像大小: " << grayImage.cols << "x" << grayImage.rows << std::endl;
    std::cout << "灰度质心坐标: (" << centroid.x << ", " << centroid.y << ")\n";

    // 6. 可视化结果 (可选)
    // 创建彩色图像用于可视化
    cv::Mat colorImage;
    cv::cvtColor(grayImage, colorImage, cv::COLOR_GRAY2BGR);
    
    // 绘制质心标记
    cv::circle(colorImage, centroid, 7, cv::Scalar(0, 0, 255), 2);  // 红色圆圈
    cv::drawMarker(colorImage, centroid, cv::Scalar(255, 0, 0), 
                   cv::MARKER_CROSS, 15, 2);  // 蓝色十字标记
    
    // 添加坐标文本
    std::string coordText = "(" + std::to_string(centroid.x) + ", " + 
                            std::to_string(centroid.y) + ")";
    cv::putText(colorImage, coordText, 
                cv::Point(centroid.x + 20, centroid.y - 15), 
                cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 2);

    // 7. 显示和保存结果
    cv::imshow("Gray Image with Centroid", colorImage);
    cv::imwrite("centroid_result.jpg", colorImage);
    cv::waitKey(0);

    return 0;
}

关键解释:

  1. ​灰度权重计算​​:

    • 与二值图像不同,灰度图像的质心计算考虑了每个像素的亮度值

    • 计算时权重:权重 = 像素值 / 255.0

  2. ​质心计算公式​​:

    • xc​=∑x,y​I(x,y)∑x,y​(x⋅I(x,y))​

    • yc​=∑x,y​I(x,y)∑x,y​(y⋅I(x,y))​

    • 其中 I(x,y)是像素点(x,y)的灰度值

  3. ​图像矩的属性​​:

    • m00:加权面积总和(所有像素值的总和)

    • m10:加权x坐标总和

    • m01:加权y坐标总和

  4. ​应用场景​​:

    • 光线不均匀的物体跟踪

    • 医学图像中器官的位置分析

    • 天文图像中星体或星系的定位

多物体质心计算:

如果灰度图像中有多个离散物体,可以配合连通区域分析计算各自的质心:

// 二值化图像(可选)
cv::Mat binary;
cv::threshold(grayImage, binary, 128, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

// 查找连通区域
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

// 计算每个物体的质心
for (const auto& contour : contours) {
    // 计算区域像素值总和
    cv::Scalar area = cv::sum(grayImage & (cv::Mat(contour) != 0));
    
    // 计算加权质心
    cv::Moments m = cv::moments(contour);
    cv::Point2f centroid(
        static_cast<float>(m.m10 / m.m00),
        static_cast<float>(m.m01 / m.m00)
    );
    
    // 处理每个物体的质心...
}

注意事项:

  1. 确保图像已正确加载为灰度格式

  2. 处理大图像时,建议使用double类型避免精度丢失

  3. 对于全黑图像(m00=0),需要处理除零错误

  4. 质心坐标可能为浮点数,使用cv::Point2f存储结果

这个实现可以直接应用于灰度图像处理任务,如特征定位、目标跟踪和图像分析等应用场景。


网站公告

今日签到

点亮在社区的每一天
去签到