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);

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用 OpenCV 中的 `calcHist` 函数来计算图像灰度直方图,然后使用 Matplotlib 绘制显示直方图。以下是一个示例代码: ```python import cv2 import matplotlib.pyplot as plt # 读取图像 img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE) # 计算直方图 hist = cv2.calcHist([img], [0], None, [256], [0, 256]) # 绘制直方图 plt.plot(hist) # 显示图像和直方图 plt.subplot(121), plt.imshow(img, cmap='gray') plt.subplot(122), plt.plot(hist) plt.xlim([0, 256]) plt.show() ``` 在上面的代码中,`cv2.imread` 函数读取灰度图像,并使用 `cv2.IMREAD_GRAYSCALE` 参数将其转换为灰度图像。然后,`cv2.calcHist` 函数计算图像灰度直方图。该函数的第一个参数是图像,第二个参数是通道索引,这里我们只计算单通道的直方图,因此为 `[0]`。第三个参数是掩膜图像,这里我们不使用掩膜,因此为 `None`。第四个参数是直方图的大小,这里我们使用 `256`,表示将灰度值分为 `256` 个区间。最后一个参数是灰度值的范围,这里我们使用 `[0, 256]`,表示灰度值的范围为 `0` 到 `255`。 绘制直方图时,我们使用 Matplotlib 的 `plot` 函数。然后使用 `plt.subplot` 函数将图像和直方图显示在同一个窗口中。`plt.xlim` 函数用于设置直方图的 x 轴范围,这里我们将其设置为 `[0, 256]`,表示灰度值的范围为 `0` 到 `255`。最后,使用 `plt.show` 函数来显示窗口。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值