Opencv C++ 七、绘制一副图像的灰度直方图

该代码能够实现以下功能:

(1)将导入的图片转变成灰度图像;

(2)获取该灰度图像的直方图;

(3)显示点击位置的数值(点击直方图);

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

Mat histImage;
int histHeight = 400;
int histWidth = 512;
int histSize = 256;
const float range[] = { 0, 256 };
const float* histRange = { range };
Mat hist;

void onMouse(int event, int x, int y, int flags, void* param) {
    if (event == EVENT_LBUTTONDOWN) {
        if (x >= 0 && x < histWidth && y >= 0 && y < histHeight) {
            int bin = x * histSize / histWidth;
            int value = hist.at<float>(bin);
            cout << "在直方图中点击的位置处的坐标为 (" << x << ", " << y << ") 对应的灰度级别:" << bin << ",频率:" << value << endl;
        }
    }
}

void onMouse1(int event, int x, int y, int flags, void* param) {
    if (event == EVENT_LBUTTONDOWN) {
        if (x >= 0 && x < histWidth && y >= 0 && y < histHeight) {
            int bin = x * histSize / histWidth;
            int value = hist.at<float>(bin);
            cout << "在原始图片中点击的位置处的坐标为 (" << x << ", " << y << ") 对应的灰度级别:" << bin << ",频率:" << value << endl;
        }
    }
}
//上述的onMouse和onMouse1是分别设置的两个鼠标左键点击事件,其目的是为了让我们点击原始图像或者是直方图时,能够显示出点击位置的相关灰度和坐标信息。
int main() {
    Mat image = imread("D://lena.png", IMREAD_GRAYSCALE);

    if (image.empty()) {
        cout << "无法加载图像" << endl;
        return -1;
    }

    calcHist(&image, 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);
    normalize(hist, hist, 0, histHeight, NORM_MINMAX, -1, Mat());

    histImage = Mat(histHeight, histWidth, CV_8UC3, Scalar(255, 255, 255));
    //CV_8UC1是单通道,Scalar(255)对应的意思是直方图的底色是白色,Scalar(0)对应的底色是黑色。CV_8UC3,则对应三通道,Scalar应该对应三个数值(x,x,x)
    for (int i = 1; i < histSize; i++) {
        line(histImage, Point(i - 1, histHeight - cvRound(hist.at<float>(i - 1))),
            Point(i, histHeight - cvRound(hist.at<float>(i))),
            Scalar(0, 0, 0), 2, 8, 0);
    }

    line(histImage, Point(0, histHeight), Point(histWidth, histHeight), Scalar(0, 0, 0), 1, 8, 0);
    line(histImage, Point(0, 0), Point(0, histHeight), Scalar(0, 0, 0), 1, 8, 0);

    for (int i = 0; i < histSize; i += 32) {
        line(histImage, Point(i, histHeight - 5), Point(i, histHeight + 5), Scalar(0, 0, 0), 1, 8, 0);
        putText(histImage, to_string(i), Point(i - 10, histHeight + 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0), 1, LINE_8, false);
    }

    for (int i = 0; i <= histHeight; i += histHeight / 4) {
        line(histImage, Point(-5, i), Point(5, i), Scalar(0, 0, 0), 1, 8, 0);
        putText(histImage, to_string(histHeight - i), Point(-30, i + 5), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0), 1, LINE_8, false);
    }

    namedWindow("直方图");
    setMouseCallback("直方图", onMouse);
    imshow("直方图", histImage);
    namedWindow("原始图片");
    setMouseCallback("原始图片", onMouse1);
    imshow("原始图片", image);
    waitKey(0);


    return 0;
}

结果如图所示:

当我们点击了直方图上某一个位置,在左侧的控制台里就会出现该点的相关信息。

函数介绍:

0.定义变量和参数:

Mat histImage;                // 用于绘制直方图的图像
int histHeight = 400;         // 直方图图像的高度
int histWidth = 512;          // 直方图图像的宽度
int histSize = 256;           // 直方图的灰度级别数量
const float range[] = { 0, 256 };
const float* histRange = { range };
Mat hist;                      // 存储直方图数据

1.创建鼠标事件处理函数 onMouse

void onMouse(int event, int x, int y, int flags, void* param) {
    if (event == EVENT_LBUTTONDOWN) {
        if (x >= 0 && x < histWidth && y >= 0 && y < histHeight) {
            int bin = x * histSize / histWidth;
            int value = hist.at<float>(bin);
            cout << "在直方图中点击的位置处的坐标为 (" << x << ", " << y << ") 对应的灰度级别:" << bin << ",频率:" << value << endl;
        }
    }
}

void onMouse1(int event, int x, int y, int flags, void* param) {
    if (event == EVENT_LBUTTONDOWN) {
        if (x >= 0 && x < histWidth && y >= 0 && y < histHeight) {
            int bin = x * histSize / histWidth;
            int value = hist.at<float>(bin);
            cout << "在原始图片中点击的位置处的坐标为 (" << x << ", " << y << ") 对应的灰度级别:" << bin << ",频率:" << value << endl;
        }
    }
}

这个函数处理鼠标左键点击事件,获取点击坐标,并计算点击位置对应的直方图灰度级别和频率。

上述的onMouse和onMouse1是分别设置的两个鼠标左键点击事件,其目的是为了让我们点击原始图像或者是直方图时,能够显示出点击位置的相关灰度和坐标信息。
 

2.计算直方图并绘制

calcHist(&image, 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);
normalize(hist, hist, 0, histHeight, NORM_MINMAX, -1, Mat());
  • calcHist 函数用于计算图像的直方图。
  • normalize 函数将直方图数据归一化到指定的范围内,以适合绘制。

3.创建直方图图像 histImage 并绘制直方图:

istImage = Mat(histHeight, histWidth, CV_8UC3, Scalar(255, 255, 255));
    for (int i = 1; i < histSize; i++) {
        line(histImage, Point(i - 1, histHeight - cvRound(hist.at<float>(i - 1))),
            Point(i, histHeight - cvRound(hist.at<float>(i))),
            Scalar(0, 0, 0), 2, 8, 0);
    }

    line(histImage, Point(0, histHeight), Point(histWidth, histHeight), Scalar(0, 0, 0), 1, 8, 0);
    line(histImage, Point(0, 0), Point(0, histHeight), Scalar(0, 0, 0), 1, 8, 0);

line 函数用于绘制直方图的条形,坐标轴和刻度线。

    CV_8UC1是单通道,Scalar(255)对应的意思是直方图的底色是白色,Scalar(0)对应的底色是黑色。CV_8UC3,则对应三通道,Scalar应该对应三个数值(x,x,x)

4.绘制刻度和标签

for (int i = 0; i < histSize; i += 32) {
        line(histImage, Point(i, histHeight - 5), Point(i, histHeight + 5), Scalar(0, 0, 0), 1, 8, 0);
        putText(histImage, to_string(i), Point(i - 10, histHeight + 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0), 1, LINE_8, false);
    }

    for (int i = 0; i <= histHeight; i += histHeight / 4) {
        line(histImage, Point(-5, i), Point(5, i), Scalar(0, 0, 0), 1, 8, 0);
        putText(histImage, to_string(histHeight - i), Point(-30, i + 5), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0), 1, LINE_8, false);
    }

5.创建窗口并设置鼠标回调函数,显示图像和直方图窗口:

 namedWindow("直方图");
    setMouseCallback("直方图", onMouse);
    imshow("直方图", histImage);
    namedWindow("原始图片");
    setMouseCallback("原始图片", onMouse1);
    imshow("原始图片", image);
    waitKey(0);

猜你喜欢

转载自blog.csdn.net/w2492602718/article/details/134145129