该代码能够实现以下功能:
(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);