直方图均衡
直方图均衡是一种用于增强和调整图像对比度的图像处理技术。它通过重新分配图像的像素值,使得图像的灰度级在整个范围内均匀分布,从而增强图像的视觉效果。
图像的直方图是像素强度分布的图形表示。它提供了像素值集中位置以及是否存在异常偏差的估计值。
例如 - 考虑下图。假设,所有像素值的深度均为 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();
}