在灰度图像中计算质心时,我们需要考虑像素的灰度值作为权重,这与二值图像不同。以下是使用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;
}
关键解释:
灰度权重计算:
与二值图像不同,灰度图像的质心计算考虑了每个像素的亮度值
计算时权重:
权重 = 像素值 / 255.0
质心计算公式:
xc=∑x,yI(x,y)∑x,y(x⋅I(x,y))
yc=∑x,yI(x,y)∑x,y(y⋅I(x,y))
其中 I(x,y)是像素点(x,y)的灰度值
图像矩的属性:
m00
:加权面积总和(所有像素值的总和)m10
:加权x坐标总和m01
:加权y坐标总和
应用场景:
光线不均匀的物体跟踪
医学图像中器官的位置分析
天文图像中星体或星系的定位
多物体质心计算:
如果灰度图像中有多个离散物体,可以配合连通区域分析计算各自的质心:
// 二值化图像(可选)
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)
);
// 处理每个物体的质心...
}
注意事项:
确保图像已正确加载为灰度格式
处理大图像时,建议使用
double
类型避免精度丢失对于全黑图像(m00=0),需要处理除零错误
质心坐标可能为浮点数,使用
cv::Point2f
存储结果
这个实现可以直接应用于灰度图像处理任务,如特征定位、目标跟踪和图像分析等应用场景。