5:OpenCV—直方图均衡化

直方图均衡

直方图均衡是一种用于增强和调整图像对比度的图像处理技术。它通过重新分配图像的像素值,使得图像的灰度级在整个范围内均匀分布,从而增强图像的视觉效果。

图像的直方图是像素强度分布的图形表示。它提供了像素值集中位置以及是否存在异常偏差的估计值。

例如 - 考虑下图。假设,所有像素值的深度均为 2 位,并且是无符号的。因此,像素的允许值范围为 0 - 3。

示例图像

如上图所示,有 5 个值为 0 的像素、值为 7 的 1 个像素、值为 9 的 2 个像素和值为 4 的 3 个像素。这些信息按下表列出。

![上图的强度分布](images/Histogram(Table).png)
上图的强度分布

图像的直方图通常以图形形式表示。下图表示上图的直方图。

![图像直方图](images/Histogram+(Graph).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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值