【07】OpenCV C++实战篇——鼠标在图片上绘制矩形,计算矩形区域内灰度值的累加值显示在图片上,支持连续多次框选,快速计算结果,快速刷新画面不卡顿
文章目录
- 1 "imgPro.h"
- 2 imgPro.cpp
- 3. 调用示例
OpenCV C++ ,鼠标在图片上绘制矩形,计算矩形区域内灰度值的累加值显示在图片上。
如果图片是多通道,则先转换为灰度图。
图像上显示每次框选的矩形区域,并显示每次矩形区域内的灰度值累加和、
支持连续多次框选,快速计算结果,快速刷新画面不卡顿。每次框选后页面都会快速刷新新的结果。
支持快速切换图像,当你打开新的图像画面无缝切换。本代码是有实际项目剥离的
1 “imgPro.h”
#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
#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; // 设置加载标志为falsereturn;}isLoaded = true; // 设置加载标志为truedisplayImageWithSum = 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. 调用示例
#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;
}