【07】OpenCV C++实战篇——鼠标在图片上绘制矩形,计算矩形区域内灰度值的累加值显示在图片上,支持连续多次框选,快速计算结果,快速刷新画面不卡顿

发布于:2025-08-10 ⋅ 阅读:(18) ⋅ 点赞:(0)

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;  // 设置加载标志为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. 调用示例

#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;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


网站公告

今日签到

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