c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

文章目录

前言

数字图像处理c++ opencv(VS2019 opencv4.53)持续更新

一、直方图(histogram)

非归一化直方图:
h ( r k ) = n k h(r_k)=n_k h (r k ​)=n k ​
其中r k r_k r k ​为图像像素灰度值,比如常见的0-255,n k n_k n k ​为图像中某一灰度级的像素个数。
归一化直方图:
p ( r k ) = h ( r k ) M N = n k M N p(r_k)=\frac{h(r_k)}{MN}=\frac{n_k}{MN}p (r k ​)=M N h (r k ​)​=M N n k ​​
其中MN为图像行数和列数,常说的图像直方图就是归一化直方图。

直方图的现状表现了图像的外观:

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

获取图像直方图示例:
代码如下(示例):

#include
#include
using namespace cv;
using namespace std;

int main()
{
    Mat image, image_gray, hist;
    image = imread("lena.png");
    if (image.empty())
    {
        cout << "读取错误" << endl;
        return -1;
    }

    cvtColor(image, image_gray, COLOR_BGR2GRAY);
    imshow(" image_gray", image_gray);

    int histsize = 256;
    float ranges[] = { 0,256 };
    const float* histRanges = { ranges };
    calcHist(&image_gray, 1, 0, Mat(), hist, 1, &histsize, &histRanges, true, false);

    int hist_h = 300;
    int hist_w = 512;
    int bin_w = hist_w / histsize;
    Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));

    normalize(hist, hist, 0, hist_h, NORM_MINMAX, -1, Mat());
    for (int i = 1; i < histsize; i++)
    {
        line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(hist.at<float>(i - 1))),
            Point((i)*bin_w, hist_h - cvRound(hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
    }
    imshow("histImage", histImage);

    waitKey(0);
    return 0;
}
}

结果:

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

二、直方图处理

1.直方图均衡化

(1)均衡化原理
目的:通过均衡化处理使得输入图像的直方图变得范围较广以及分布较均匀。
原理公式:
s k = ( L − 1 ) ∑ j = 0 k P r ( r j ) , k = 0 , 1 , . . . , L − 1 s_k=(L-1)\sum_{j=0}^k P_r(r_j), k=0,1,…,L-1 s k ​=(L −1 )j =0 ∑k ​P r ​(r j ​),k =0 ,1 ,…,L −1

如:
s 1 = ( L − 1 ) P r ( 1 ) s_1=(L-1)P_r(1)s 1 ​=(L −1 )P r ​(1 )
s 2 = ( L − 1 ) ( P r ( 1 ) + P r ( 2 ) ) s_2=(L-1)(P_r(1)+P_r(2) )s 2 ​=(L −1 )(P r ​(1 )+P r ​(2 ))
s L − 1 = ( L − 1 ) ( P r ( 1 ) + P r ( 2 ) + . . . + P r ( L − 1 ) ) = L − 1 s_{L-1}=(L-1)(P_r(1)+P_r(2) +…+P_r(L-1))=L-1 s L −1 ​=(L −1 )(P r ​(1 )+P r ​(2 )+…+P r ​(L −1 ))=L −1

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))
直方图均衡化就是将图像的直方图以上图中右图为目标进行转变。不管原图的直方图现状,直方图均衡化处理后都能达到右边的效果。

(2)代码如下:

using namespace cv;
using namespace std;

int main()
{
    Mat image, image_gray, image_enhanced;
    image = imread("lena.png");
    if (image.empty())
    {
        cout << "读取错误" << endl;
        return -1;
    }

    cvtColor(image, image_gray, COLOR_BGR2GRAY);
    imshow(" image_gray", image_gray);

    equalizeHist(image_gray, image_enhanced);
    imshow(" image_enhanced", image_enhanced);

    waitKey(0);
    return 0;
}

(3)结果:

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

2.直方图匹配(规定化)

(1)直方图匹配(规定化)原理
从字面意思理解,就是为需要处理的图像匹配另一幅图的直方图形状或规定一个目标直方图形状。比如前面的直方图均衡化处理也可以理解为特殊的直方图匹配,匹配目标直方图为:

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))
类似直方图均衡化,以其他直方图形状为目标的处理为直方图匹配(规定)。

直方图匹配原理(个人理解):

前面的直方图均衡化提到:不管原图像的直方图是什么形状,直方图均衡化后的直方图都是一样的,如下图:

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))
这里的映射函数规定为单调递增的,即变换后的直方图可以经过逆变换回到原直方图。那么直方图匹配就可以根据这个性质进行处理,示意图如下:
c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))
内容相同的图像,直方图均衡化后的直方图相似。想要a图所示的直方图转变到c图,那么可以有:
c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

因此,直方图匹配的步骤为:
1,计算输入图像的直方图P ( r ) P(r)P (r ),并进行直方图均衡化,得到均衡化后的灰度s k , k = 1 , 2… L − 1 s_k,k=1,2…L-1 s k ​,k =1 ,2 …L −1.(直方图a到直方图b)
2,根据 G ( z q ) = ( L − 1 ) ∑ i = 0 q P z ( z j ) G(z_q)=(L-1)\sum _{i=0} ^q P_z(z_j)G (z q ​)=(L −1 )i =0 ∑q ​P z ​(z j ​)计算G ( z q ) G(z_q)G (z q ​)所有值,并存储到一个查找表中。(记录z与G的映射,z与G一一对应,逆变换就可以直接查对应的值)
3,对s k , k = 1 , 2… L − 1 s_k,k=1,2…L-1 s k ​,k =1 ,2 …L −1的每个值,用步骤2得到的表找到z q z_q z q ​对应的值,使得G ( z q ) G(z_q)G (z q ​)最接近s k s_k s k ​,并存储s到z的映射。(逆变换)
4,使用步骤3找到的映射,将s k s_k s k ​值映射到直方图指定图像中值为z q z_q z q ​的对应像素,形成直方图指定图像。

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

(2)示例1
如下图将一个64*64大小的图进行直方图规定化

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

第一步:得到原图均衡化后的值并四舍五入
根据公式:
s k = ( L − 1 ) ∑ j = 0 k P r ( r j ) , k = 0 , 1 , . . . , L − 1 s_k=(L-1)\sum_{j=0}^k P_r(r_j), k=0,1,…,L-1 s k ​=(L −1 )j =0 ∑k ​P r ​(r j ​),k =0 ,1 ,…,L −1
有:
s 0 = 7 ∗ ∑ j = 0 0 P r ( r j ) = 1.33 − − 1 s_0=7\sum_{j=0}^0 P_r(r_j)= 1.33–1 s 0 ​=7 ∗j =0 ∑0 ​P r ​(r j ​)=1 .3 3 −−1
s 1 = 7 ∗ ∑ j = 0 1 P r ( r j ) = 3.08 − − 3 s_1=7
\sum_{j=0}^1 P_r(r_j)= 3.08–3 s 1 ​=7 ∗j =0 ∑1 ​P r ​(r j ​)=3 .0 8 −−3
最后有:

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))
c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

第二步:使用p z p_z p z ​计算G(z)的值

根据公式:
G ( z q ) = ( L − 1 ) ∑ i = 0 q P z ( z j ) G(z_q)=(L-1)\sum {i=0} ^q P_z(z_j)G (z q ​)=(L −1 )i =0 ∑q ​P z ​(z j ​)
有:
G ( z 0 ) = 7 ∗ ∑ i = 0 0 P z ( z i ) = 0 − − 0 G(z_0)=7*\sum
{i=0}^0 P_z(z_i)= 0–0 G (z 0 ​)=7 ∗i =0 ∑0 ​P z ​(z i ​)=0 −−0
最终有:

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

第三步:找s k s_k s k ​和z q z_q z q ​的映射(G的逆变换)

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))
将原s k s_k s k ​的改为映射的值后的值有:
c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))
c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

(3)示例2
以下图为例,将上面的直方图向下面的直方图进行转变

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

代码如下

#include
#include

using namespace cv;
using namespace std;

int main()
{
    Mat image1, image1_gray, hist1, image2, image2_gray, hist2, image_enhanced;
    image1 = imread("lena.png");
    if (image1.empty())
    {
        cout << "读取错误" << endl;
        return -1;
    }

    cvtColor(image1, image1_gray, COLOR_BGR2GRAY);
    imshow(" image1_gray", image1_gray);

    image2 = imread("1043.jpg");
    if (image2.empty())
    {
        cout << "读取错误" << endl;
        return -1;
    }

    cvtColor(image2, image2_gray, COLOR_BGR2GRAY);
    imshow(" image2_gray", image2_gray);

    equalizeHist(image1_gray, image1_gray);
    equalizeHist(image2_gray, image2_gray);

    int histsize = 256;
    float ranges[] = { 0,256 };
    const float* histRanges = { ranges };
    calcHist(&image1_gray, 1, 0, Mat(), hist1, 1, &histsize, &histRanges, true, false);
    calcHist(&image2_gray, 1, 0, Mat(), hist2, 1, &histsize, &histRanges, true, false);

    float hist1_cdf[256] = { hist1.at<float>(0) };
    float hist2_cdf[256] = { hist2.at<float>(0) };
    for (int i = 1; i < 256; i++)
    {
        hist1_cdf[i] = (hist1_cdf[i - 1] + hist1.at<float>(i)) ;
        hist2_cdf[i] = (hist2_cdf[i - 1] + hist2.at<float>(i)) ;
    }

    for (int i = 0; i < 256; i++)
    {
        hist1_cdf[i] = hist1_cdf[i] / (image1_gray.rows * image1_gray.cols);
        hist2_cdf[i] = hist2_cdf[i] / (image2_gray.rows * image2_gray.cols);
    }

    float diff_cdf[256][256];
    for (int i = 0; i < 256; i++) {
        for (int j = 0; j < 256; j++)
        {
            diff_cdf[i][j] = fabs(hist1_cdf[i] - hist2_cdf[j]);
        }
    }

    Mat lut(1, 256, CV_8U);
    for (int i = 0; i < 256; i++)
    {

        float min = diff_cdf[i][0];
        int index = 0;
        for (int j = 0; j < 256; j++) {
            if (min > diff_cdf[i][j]) {
                min = diff_cdf[i][j];
                index = j;
            }
        }
        lut.at<uchar>(i) = index;
    }
    LUT(image1_gray, lut, image_enhanced);
    imshow("image_enhanced", image_enhanced);

    waitKey(0);
    return 0;
}

结果:

c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

三、opencv函数总结

1.equalizeHist图像均衡化

equalizeHist(image1_gray, image1_gray);

2.calcHist获取图像直方图

int histsize = 256;
float ranges[] = { 0,256 };
const float* histRanges = { ranges };
calcHist(&image1_gray, 1, 0, Mat(), hist1, 1, &histsize, &histRanges, true, false);

3.LUT数据映射

LUT(image1_gray, lut, image_enhanced);

Original: https://blog.csdn.net/qq_44785013/article/details/120343339
Author: ‭刘燚
Title: c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/632878/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球