直方图均衡
直方图均衡是一种用于增强和调整图像对比度的图像处理技术。它通过重新分配图像的像素值,使得图像的灰度级在整个范围内均匀分布,从而增强图像的视觉效果。
图像的直方图是像素强度分布的图形表示。它提供了像素值集中位置以及是否存在异常偏差的估计值。
例如 - 考虑下图。假设,所有像素值的深度均为 2 位,并且是无符号的。因此,像素的允许值范围为 0 - 3。
![]() |
---|
示例图像 |
如上图所示,有 5 个值为 0 的像素、值为 7 的 1 个像素、值为 9 的 2 个像素和值为 4 的 3 个像素。这些信息按下表列出。
.png) |
---|
上图的强度分布 |
图像的直方图通常以图形形式表示。下图表示上图的直方图。
.png) |
---|
图像直方图 |
直方图均衡是图像处理中常用的技术,通过均衡强度分布来增强图像的对比度。它会使黑暗的图像(曝光不足)不那么暗,明亮的图像(曝光过度)不那么明亮。
理想情况下,上图的均衡直方图应如下图所示。
![]() |
---|
均衡后图像的理想直方图 |
但实际上,很难实现这种完美的直方图均衡。但是,有多种技术可以实现接近完美的直方图均衡。在OpenCV中,有一个内置函数来均衡直方图。
使用OpenCV对灰度图像进行直方图均衡
//Uncomment the following line if you are compiling this code in Visual Studio //#include "stdafx.h" #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { // Read the image file Mat image = imread("C:/Users/Gerry/Desktop/fly-agaric.jpg"); // Check for failure if (image.empty()) { cout << "Could not open or find the image" << endl; cin.get(); //wait for any key press return -1; } //change the color image to grayscale image cvtColor(image, image, COLOR_BGR2GRAY); //equalize the histogram Mat hist_equalized_image; equalizeHist(image, hist_equalized_image); //Define names of windows String windowNameOfOriginalImage = "Original Image"; String windowNameOfHistogramEqualized = "Histogram Equalized Image"; // Create windows with the above names namedWindow(windowNameOfOriginalImage, WINDOW_NORMAL); namedWindow(windowNameOfHistogramEqualized, WINDOW_NORMAL); // Show images inside created windows. imshow(windowNameOfOriginalImage, image); imshow(windowNameOfHistogramEqualized, hist_equalized_image); waitKey(0); // Wait for any keystroke in one of the windows destroyAllWindows(); //Destroy all open windows return 0; }
![]() |
---|
灰度图像的直方图均衡 |
代码解释
// Read the image file Mat image = imread("D:/My OpenCV Website/fly-agaric.jpg"); // Check for failure if (image.empty()) { cout << "Could not open or find the image" << endl; cin.get(); //wait for any key press return -1; }
上面的代码段将从指定的文件加载图像。如果图像加载失败,程序将退出。
//change the color image to grayscale image cvtColor(image, image, COLOR_BGR2GRAY); //equalize the histogram Mat hist_equalized_image; equalizeHist(image, hist_equalized_image); //Define names of windows String windowNameOfOriginalImage = "Original Image"; String windowNameOfHistogramEqualized = "Histogram Equalized Image"; // Create windows with the above names namedWindow(windowNameOfOriginalImage, WINDOW_NORMAL); namedWindow(windowNameOfHistogramEqualized, WINDOW_NORMAL); // Show images inside the created windows. imshow(windowNameOfOriginalImage, image); imshow(windowNameOfHistogramEqualized, hist_equalized_image); waitKey(0); // Wait for any keystroke in the window destroyAllWindows(); //destroy all open windows return 0;
上述函数将BGR色彩空间中的图像转换为灰度色彩空间。
请注意,加载图像的色彩空间是 BGR,而不是 RGB。(即 - 通道按蓝色、绿色和红色排序。
上述函数均衡灰度*图像*的直方图,并将输出存储在*hist_equalized_image中。*
上面的代码段将创建窗口并在其中显示图像。当窗口是通过标志WINDOW_NORMAL创建的,因此可以自由调整它们的大小。
程序将等待,直到按下任何键。按下一个键后,所有创建的窗口将被销毁,程序将退出。
使用OpenCV对彩色图像进行直方图均衡
//Uncomment the following line if you are compiling this code in Visual Studio //#include "stdafx.h" #include <QCoreApplication> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main() { // Read the image file Mat image = imread("D:/Gerry/project/opencvproj/singleandslot/OpenCV-2/ImageAndVideoHandle/resources/fly-agaric1.jpg"); // Check for failure if (image.empty()) { cout << "Could not open or find the image" << endl; cin.get(); //wait for any key press return -1; } //把图像从BGR色彩空间转换为YCrCb色彩空间 // 直方图均衡只能处理强度信息,不能处理带颜色的通道 Mat hist_equalized_image; cvtColor(image, hist_equalized_image, COLOR_BGR2YCrCb); //把转换好的色彩空间对象分割处对应通道分别是Y,Cr,Cb并把结果存储到vector集合中 vector<Mat> vec_channels; split(hist_equalized_image, vec_channels); //把拆分出来的Y通道进行直方图均衡 equalizeHist(vec_channels[0], vec_channels[0]); //合并处理好的3通道数据合并到YCrCb的色彩空间中 merge(vec_channels, hist_equalized_image); //把YCrCb的色彩空间图像转换到BGR颜色空间 cvtColor(hist_equalized_image, hist_equalized_image, COLOR_YCrCb2BGR); //Define the names of windows String windowNameOfOriginalImage = "Original Image"; String windowNameOfHistogramEqualized = "Histogram Equalized Color Image"; // Create windows with the above names namedWindow(windowNameOfOriginalImage, WINDOW_NORMAL); namedWindow(windowNameOfHistogramEqualized, WINDOW_NORMAL); // Show images inside the created windows. imshow(windowNameOfOriginalImage, image); imshow(windowNameOfHistogramEqualized, hist_equalized_image); waitKey(0); // Wait for any keystroke in one of the windows destroyAllWindows(); //Destroy all open windows return 0; }
![]() |
---|
彩色图像的直方图均衡 |
OpenCV 在 BGR 色彩空间中加载彩色图像。使用此颜色空间,不可能在不影响颜色信息的情况下均衡直方图,因为所有 3 个通道都包含颜色信息。因此,您必须将BGR图像转换为YCrCb之类的色彩空间。在 YCrCb 色彩空间中,图像的 Y 通道仅包含强度信息,而 Cr 和 Cb 通道包含图像的所有颜色信息。因此,只应处理Y通道以获得直方图均衡图像,而不改变任何颜色信息。处理完成后,在调用 imshow() 函数之前,应将 YCrCb 图像转换回 BGR 色彩空间。
代码解释
// Read the image file Mat image = imread("D:/My OpenCV Website/fly-agaric.jpg"); // Check for failure if (image.empty()) { cout << "Could not open or find the image" << endl; cin.get(); //Wait for any key press return -1; }
上面的代码段从指定的文件加载图像。如果加载图像失败,程序将退出。
//Convert the image from BGR to YCrCb color space Mat hist_equalized_image; cvtColor(image, hist_equalized_image, COLOR_BGR2YCrCb);
加载的图像位于 BGR 色彩空间中。此颜色空间的 3 个通道(蓝色、绿色和红色)中的任何一个都无法处理以均衡直方图,因为所有通道都包含颜色信息。因此,加载的图像应转换为 YCrCb 色彩空间。在此颜色空间中,Y 通道仅包含强度信息,而 Cr 和 Cb 通道包含颜色信息。因此,只需要处理Y通道即可均衡直方图。
//Split the image into 3 channels; Y, Cr and Cb channels respectively and store it in a std::vector vector<Mat> vec_channels; split(hist_equalized_image, vec_channels);
上述 OpenCV 函数将 3 通道图像拆分为 3 个单独的矩阵。每个矩阵都被推送到 std::vector。vec_channels[0] 包含 Y 通道,vec_channels[1] 包含 Cr 通道,vec_channels[2] 包含 Cb 通道。
//Equalize the histogram of the Y channel equalizeHist(vec_channels[0], vec_channels[0])
上述函数均衡了 Y 通道的直方图。
//Merge 3 channels in the vector to form the color image in YCrCB color space. merge(vec_channels, hist_equalized_image);
上述函数执行*拆分*函数的反向操作。它采用一个 std::vector,它由代表 Y、Cr 和 Cb 通道的 3 个矩阵组成,并在 YCrCb 色彩空间中创建 3 通道图像。
//Convert the histogram equalized image from YCrCb to BGR color space again cvtColor(hist_equalized_image, hist_equalized_image, COLOR_YCrCb2BGR);
上行将 YCrCb 色彩空间中的图像转换为 BGR 色彩空间。此步骤是必需的,因为像 cv::imshow() 这样的 OpenCV 函数总是期望 BGR 色彩空间中的图像。
//Define the names of windows String windowNameOfOriginalImage = "Original Image"; String windowNameOfHistogramEqualized = "Histogram Equalized Color Image"; // Create windows with the above names namedWindow(windowNameOfOriginalImage, WINDOW_NORMAL); namedWindow(windowNameOfHistogramEqualized, WINDOW_NORMAL); // Show images inside the created windows imshow(windowNameOfOriginalImage, image); imshow(windowNameOfHistogramEqualized, hist_equalized_image);
上面的代码段将创建窗口并在其中显示图像。由于两个窗口都是通过标志WINDOW_NORMAL创建的,因此可以自由调整它们的大小。
waitKey(0); // Wait for any keystroke in any one of the windows destroyAllWindows(); //Destroy all opened windows return 0;
程序将等待,直到按下任何键。按下一个键后,所有创建的窗口将被销毁,程序将退出。
对视频进行直方图均衡
QT+OpenCV编程环境不可用原因:
1、OpenCV编译成功了,没有进行安装。 (编译过程:mingw32-make -j 8,安装:mingw32-make install)
2、编译和安装都是操作了的也是没有出现问题,安装完成后需要配置环境变量,这个地方配置的环境变量需要重启电脑才能生效。
3、可以能在在QT项目中没有添加项目INCLUDEPATH,LIBS
#include <QCoreApplication> #include "opencv2/opencv.hpp" #include "opencv/highgui.h" using namespace std; using namespace cv; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 1、 读取一个视频文件 VideoCapture cap("D:/Gerry/project/opencvproj/singleandslot/OpenCV-2/ImageAndVideoHandle/resources/点云应用.mp4"); // 判断是否能正常打开视频 if (!cap.isOpened()) { cout << "打开视频失败"; cin.get(); return -1; } // 创建2个窗口对象 // 1. 定义两个窗口名称 string originVideo = "原始视频"; string equlizedVideo = "直方均衡的视频"; // 2. 使用窗口名称实例2个窗口对象 namedWindow(originVideo, WINDOW_NORMAL); namedWindow(equlizedVideo, WINDOW_NORMAL); // 开始循环读取视频的每一帧数据 while(true) { Mat currentFrame; // 获取视频当前帧 bool isOK = cap.read(currentFrame); // 判断视频是否已经读取完成 if (!isOK) { cout << "视频已经读取完成"; break; } // 就像前面讲解的图像处理套路一样 // 把当前帧从BGR色彩空间转换为YCrCb的色彩空间 Mat YCrCbImage; cvtColor(currentFrame, YCrCbImage, COLOR_BGR2YCrCb); // 把当前处理的好的图像进行拆分为Y,Cr,Cb三个通道并存储到Vector对象中 vector<Mat> channels; split(YCrCbImage, channels); // 把拆分的Y通道取出来进行直方图均衡处理 equalizeHist(channels[0], channels[0]); // 把集合中3个通道进行合并,形成YCrCb色彩空间的彩色图像 merge(channels, YCrCbImage); // 把YCrCb色彩空间的彩色图像转换为BGR彩色图像 Mat BGRImage; cvtColor(YCrCbImage, BGRImage, COLOR_YCrCb2BGR); // 把出去前的图像和处理后的图像进行显示 imshow(originVideo, currentFrame); imshow(equlizedVideo, BGRImage); if (waitKey(10) == 27) { cout << "按下ESC键,停止处理视频"; } } // 释放所有打开的窗口 destroyAllWindows(); return a.exec(); }