OpenCV+python:直方图的应用(一)

1,直方图均衡化 (Histogram Equalization)
假如图像的灰度分布不均匀,其灰度分布集中在较窄的范围内,使图像的细节不够清晰,对比度较低。直方图均衡化,对图像进行非线性拉伸,重新分配图像的灰度值,使一定范围内图像的灰度值大致相等。这样,原来直方图中间的峰值部分对比度得到增强,而两侧的谷底部分对比度降低,输出图像的直方图是一个较为平坦的直方图。使图像的灰度范围拉开或使灰度均匀分布,从而增大反差,使图像细节清晰,以达到增强的目的。
在这里插入图片描述

均衡化的基本思想是:尽量使得每个灰度级的像素数量相等。直方图均衡化的另一个优势是:不需要额外参数,整个过程是自动的;直方图均衡化的缺点是:拉伸后有些灰度级可能不被映射到,造成图像观感上的颗粒感

均衡化算法

直方图的均衡化实际也是一种灰度的变换过程,将当前的灰度分布通过一个变换函数,变换为范围更宽、灰度分布更均匀的图像。也就是将原图像的直方图修改为在整个灰度区间内大致均匀分布,因此扩大了图像的动态范围,增强图像的对比度。通常均衡化选择的变换函数是灰度的累积概率,直方图均衡化算法的步骤:
(1)计算原图像的灰度直方图 P(Sk)=nk/n,其中n为像素总数,nk为灰度级Sk的像素个数
(2)计算原始图像的累积直方图 CDF(Sk)=∑ni/n=∑Ps(Si)
(3)Dj=L⋅CDF(Si),其中 Dj是目的图像的像素,CDF(Si)是源图像灰度为i的累积分布,L是图像中最大灰度级(灰度图为255)
具体代码如下:

void equalization_self(const Mat &src, Mat &dst)
{
    Histogram1D hist1D;
    MatND hist = hist1D.getHistogram(src);

    hist /= (src.rows * src.cols); // 对得到的灰度直方图进行归一化
    float cdf[256] = { 0 }; // 灰度的累积概率
    Mat lut(1, 256, CV_8U); // 灰度变换的查找表
    for (int i = 0; i < 256; i++)
    {
        // 计算灰度级的累积概率
        if (i == 0)
            cdf[i] = hist.at<float>(i);
        else
            cdf[i] = cdf[i - 1] + hist.at<float>(i);

        lut.at<uchar>(i) = static_cast<uchar>(255 * cdf[i]); // 创建灰度的查找表
    }

    LUT(src, lut, dst); // 应用查找表,进行灰度变化,得到均衡化后的图像

}

上面代码只是加深下对均衡化算法流程的理解,实际在OpenCV中也提供了灰度均衡化的函数。
全局直方图均衡化 源代码示例:

import cv2 as cv
import numpy as np


def equalHist_demo(image): #直方图均衡化,自动调整图像对比度,是图像增强的一种手段
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)#首先转化为灰度图
    dst = cv.equalizeHist(gray)
    cv.imshow("equalHist_demo", dst)
src = cv.imread("F:/images/rice.png")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
equalHist_demo(src)
cv.waitKey(0)

cv.destroyAllWindows()

运行结果:
在这里插入图片描述在这里插入图片描述全局直方图均衡后背景对比度有所改善。但导致亮度过高,我们可能会丢失了大部分信息。这是因为它的直方图并不局限于特定区域。
2,自适应直方图均衡化(Adaptive histgram equalization/AHE)

自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术。和普通的直方图均衡算法不同,AHE算法通过计算图像的局部直方图,然后重新分布亮度来改变图像对比度。因此,该算法更适合于改进图像的局部对比度以及获得更多的图像细节。
图像被分成称为“图块”的小块(在OpenCV中,tileSize默认为8x8)。然后像往常一样对这些块中的每一个进行直方图均衡。所以在一个小区域内,直方图会限制在一个小区域(除非有噪音)。如果有噪音,它会被放大。为避免这种情况,应用对比度限制。如果任何直方图区间高于指定的对比度限制(在OpenCV中默认为40),则在应用直方图均衡之前,将这些像素剪切并均匀分布到其他区间。均衡后,为了去除图块边框中的瑕疵,应用双线性插值。
算法思想:
移动模板W在图像A上逐行移动,并且模板W的中心c(x0,y0)对应图像上的点f(x0,y0);计算模板W区域的直方图均衡化变化关系:g(x,y)= T(f(x,y),计算模板中心点c(x0,y0)的均衡化对应像素值:g(x0,y0) = T(f(x0,y0))。用g(x0,y0)替代f(x0,y0);逐行计算得到整幅图像的自适应直方图均衡化图像。

就是在一个给定框内做直方图均衡化,而框内所有处理(包括均衡化)只为了这个将原始中心点像素a变化到新的像素点b。
代码实现:

function [ output_img ] = my_AHE( input_img, w)
%UNTITLED Summary of this function goes here
%   Detailed explanation goes here
%   自适应直方图均衡化
%   输入:input_img:待处理图像
%        w: 局部处理的窗口大小
 
[height,width,channels]=size(input_img);
 
if channels==1
    src = inpit_img;
else
    src = rgb2gray(input_img);
end
 
%1.图像边界扩展
padsize=[(w-1)/2,(w-1)/2];
padSrc = padarray(src,padsize,'symmetric','both');
 
%2.循环求解每个区域对应的值
output_img = zeros(height,width);
iter = 0;
for i=1:height
    for j=1:width
        slideWindow = zeros(w,w);
        slideWindow = padSrc(i:i+w-1,j:j+w-1);
        AHE_piexl = my_AHE_piexl(slideWindow,src(i,j));
        output_img(i,j) = AHE_piexl;
        iter = iter+1;
        disp(iter);
    end
end
 
output_img = uint8(output_img);
 
 
end
 
function [ outPiexl ] = my_AHE_piexl( window,inPiexl )
%UNTITLED2 Summary of this function goes here
%   Detailed explanation goes here
%   计算局部图像的直方图均衡化的像素对应值
%   输入:window: 局部图像
%        inPiexl:输入像素
%        outPiexl:输出像素
 
[height,width]=size(window);
 
%1.像素灰度统计
NumPixel = zeros(1,256);
for i=1:height
    for j=1:width
        grayValue = window(i,j);
        NumPixel(1,grayValue+1) = NumPixel(1,grayValue+1)+1;
    end
end
 
%2.计算灰度分布密度
ProbPixel = zeros(1,256);  
for k=1:256
    ProbPixel(1,k)=NumPixel(1,k)/(height*width*1.0);
end
 
%3.计算累积分布密度
CumuPixel = zeros(1,256);  
CumuPixel(1,1) = ProbPixel(1,1);
for l=2:256
    CumuPixel(1,l) = CumuPixel(1,l-1)+ProbPixel(1,l);    
end
CumuPixel = uint8(255 .* CumuPixel + 0.5); %取整数
 
%4.计算灰度值映射
outPiexl = CumuPixel(inPiexl);
 
end

同样,上面代码只是加深下对均衡化算法流程的理解,实际在OpenCV中也提供了灰度均衡化的函数。
源代码示例:

import cv2 as cv
import numpy as np

def clahe_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    clahe = cv.createCLAHE(clipLimit=5.0, tileGridSize=(8, 8))
    dst = clahe.apply(gray)
    cv.imshow("clahe_demo", dst)


src = cv.imread("F:/images/rice.png")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
clahe_demo(src)

cv.waitKey(0)
cv.destroyAllWindows()

运行结果:
在这里插入图片描述在这里插入图片描述3,直方图比较
对输入的两张图像进行直方图均衡化及直方图计算步骤后,可以对两个图像的直方图进行对比,并通过对比的结果得到一些我们想要的结论。

直方图比较应用

(1)图像相似度比较
如果我们有两张图像,并且这两张图像的直方图一样,或者有极高的相似度,那么在一定程度上,我们可以认为这两幅图是一样的,这就是直方图比较的应用之一。

(2)分析图像之间关系
两张图像的直方图反映了该图像像素的分布情况,可以利用图像的直方图,来分析两张图像的关系。

直方图比较方法

要比较两个直方图(H1 和 H2),首先必须要选择一个衡量直方图相似度的对比标准,我们设为d(H1,H2)
在这里插入图片描述6.API介绍——compareHist

(1)步骤
a.先用cvtColor()把图像从RGB色彩空间转换到HSV色彩空间;
b.计算图像的直方图,然后归一化到[0~1]之间,用到函数 calcHist() 和 normalize() ;
c.使用上述的四种方法之一进行比较,用到函数compareHist()。

(2)API介绍

函数一共有三个参数,一个输入图像,一个输出图像,一个比较方法。比较方法的取值的情况为上面的四种方法,在OpenCV中,每个都有自己的名字:Correlation ( CV_COMP_CORREL );Chi-Square ( CV_COMP_CHISQR );Intersection ( CV_COMP_INTERSECT );Bhattacharyya 距离( CV_COMP_BHATTACHARYYA )。
源代码示例:

import cv2 as cv
import numpy as np



def create_rgb_hist(image):
    h, w, c = image.shape
    rgbHist = np.zeros([16*16*16, 1], np.float32)   #需要是 np.float32类型
    bsize = 256 / 1
    for row in range(h):
        for col in range(w):
            b = image[row, col, 0]
            g = image[row, col, 1]
            r = image[row, col, 2]
            index = np.int(b/bsize)*16*16 + np.int(g/bsize)*16 + np.int(r/bsize)
            rgbHist[np.int(index), 0] = rgbHist[np.int(index), 0] + 1
    return rgbHist


def hist_compare(image1, image2):
    hist1 = create_rgb_hist(image1)
    hist2 = create_rgb_hist(image2)
    match1 = cv.compareHist(hist1, hist2, cv.HISTCMP_BHATTACHARYYA)#巴氏距离,越小越相似
    match2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL)#相关性,越大越相似
    match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)#卡方,越小越相似
    print("巴氏距离: %s, 相关性: %s, 卡方: %s"%(match1, match2, match3))



image1 = cv.imread("F:/images/lena.png")
image2 = cv.imread("F:/images/lenanoise.png")
cv.imshow("image1", image1)
cv.imshow("image2", image2)
hist_compare(image1, image2)

cv.waitKey(0)

cv.destroyAllWindows()

运行结果:
在这里插入图片描述在这里插入图片描述
巴氏距离: 0.09072200336618969, 相关性: 0.9788106004024394, 卡方: 164.3082768373199
以上数据说明两张图很相似。如果图像大小不一致需要对直方图进行归一化。

猜你喜欢

转载自blog.csdn.net/qq_43660987/article/details/90947177