文章目录
- 1 "imgPro.h"
- [2 imgPro.cpp](#2 imgPro.cpp)
- [3. 调用示例](#3. 调用示例)
OpenCV C++ ,鼠标在图片上绘制矩形,计算矩形区域内灰度值的累加值显示在图片上。
如果图片是多通道,则先转换为灰度图。
图像上显示每次框选的矩形区域,并显示每次矩形区域内的灰度值累加和、
支持连续多次框选,快速计算结果,快速刷新画面不卡顿。每次框选后页面都会快速刷新新的结果。
支持快速切换图像,当你打开新的图像画面无缝切换。本代码是有实际项目剥离的
1 "imgPro.h"
cpp
#ifndef IMGPRO_H
#define IMGPRO_H
#include <opencv2/opencv.hpp>
#include <string>
class imgPro
{
public:
// 加载图像并显示图像
void loadImage(const std::string& imagePath);
void displayImage();
// 计算指定矩形区域内的灰度值累加和
void calculateGraySum(const cv::Rect& rect);
// 静态鼠标回调函数
static void onMouse(int event, int x, int y, int flags, void* userdata);
private:
cv::Mat image; // 原始图像
cv::Mat displayImageWithSum; // 用于显示的带有累加和覆盖的图像
std::string imagePath; // 图像文件路径
bool isLoaded; // 图像是否已加载的标志
bool drawing; // 是否正在绘制的标志
cv::Point startPoint; // 矩形的起始点
cv::Rect selectedRect; // 选定的矩形区域
};
#endif // IMGPRO_H
2 imgPro.cpp
cpp
#include "imgPro.h"
#include <opencv2/imgproc.hpp>
#include <iostream>
// 加载图像
void imgPro::loadImage(const std::string& imagePath)
{
this->imagePath = imagePath; // 设置图像路径
image = cv::imread(imagePath); // 读取图像
if (image.empty())
{
std::cerr << "加载图像失败: " << imagePath << std::endl; // 如果图像加载失败,输出错误信息
isLoaded = false; // 设置加载标志为false
return;
}
isLoaded = true; // 设置加载标志为true
displayImageWithSum = image.clone(); // 克隆图像用于显示
cv::namedWindow("Image", cv::WINDOW_NORMAL); // 创建一个可调整大小的窗口
cv::setMouseCallback("Image", onMouse, this); // 设置鼠标回调函数
}
// 显示图像
void imgPro::displayImage()
{
if (isLoaded)
{
cv::imshow("Image", displayImageWithSum); // 使用OpenCV显示图像
cv::waitKey(0); // 等待按键
}
else
{
std::cerr << "图像未加载." << std::endl; // 如果图像未加载,输出错误信息
}
}
// 计算指定矩形区域内的灰度值累加和
void imgPro::calculateGraySum(const cv::Rect& rect)
{
if (!isLoaded)
{
std::cerr << "图像未加载." << std::endl; // 如果图像未加载,输出错误信息
return;
}
// 确保矩形在图像边界内
cv::Rect boundedRect = rect & cv::Rect(0, 0, image.cols, image.rows);
// 克隆矩形区域的图像
cv::Mat roi = image(boundedRect).clone();
cv::Mat grayRoi;
// 如果是彩色图像,转换为灰度图像
if (roi.channels() == 3)
{
cv::cvtColor(roi, grayRoi, cv::COLOR_BGR2GRAY);
}
else
{
grayRoi = roi;
}
// 计算灰度值累加和
long long sum = 0;
for (int y = 0; y < grayRoi.rows; y++)
{
for (int x = 0; x < grayRoi.cols; x++)
{
sum += grayRoi.at<uchar>(y, x); // 累加灰度值
}
}
// 在图像上显示累加和
displayImageWithSum = image.clone();
cv::rectangle(displayImageWithSum, boundedRect, cv::Scalar(0, 0, 255), 2); // 绘制矩形框
std::string text = "Sum: " + std::to_string(sum); // 准备显示的文本内容
int baseLine; // 基线,用于计算文本尺寸
// 获取文本尺寸,以便在绘制时调整位置
cv::Size textSize = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 1, 2, &baseLine);
cv::Point textOrg(boundedRect.x, boundedRect.y - 10); // 文本的起始位置
// 调整文本位置,避免超出图像边界
if (textOrg.y - textSize.height < 0) {
textOrg.y = boundedRect.y + textSize.height + 10; // 如果文本高度超出图像顶部,则向下移动
}
if (textOrg.x + textSize.width > displayImageWithSum.cols) {
textOrg.x = boundedRect.x - textSize.width - 10; // 如果文本宽度超出图像右边,则向左移动
}
cv::putText(displayImageWithSum, text, textOrg, cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2); // 在图像上显示累加和
cv::imshow("Image", displayImageWithSum); // 使用OpenCV显示带有累加和的图像
}
// 鼠标回调函数
void imgPro::onMouse(int event, int x, int y, int flags, void* userdata)
{
imgPro* self = static_cast<imgPro*>(userdata);
if (!self->isLoaded)
return;
switch (event)
{
case cv::EVENT_LBUTTONDOWN: // 左键按下事件
self->drawing = true;
self->startPoint = cv::Point(x, y);
break;
case cv::EVENT_MOUSEMOVE: // 鼠标移动事件
if (self->drawing)
{
self->displayImageWithSum = self->image.clone();
cv::rectangle(self->displayImageWithSum, self->startPoint, cv::Point(x, y), cv::Scalar(0, 0, 255), 2);
cv::imshow("Image", self->displayImageWithSum);
}
break;
case cv::EVENT_LBUTTONUP: // 左键释放事件
self->drawing = false;
self->selectedRect = cv::Rect(self->startPoint, cv::Point(x, y));
self->calculateGraySum(self->selectedRect);
break;
}
}
3. 调用示例
cpp
#include "imgPro.h"
#include <opencv2/opencv.hpp>
#include <iostream>
int main(int argc, char** argv)
{
imgPro imgpro;
std::string imagePath = "E:\\projects\\grayVal\\3.png"; // 设置图像路径
imgpro.loadImage(imagePath); // 加载图像
imgpro.displayImage(); // 显示图像
return 0;
}