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

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

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

均衡化算法

直方图的均衡化实际也是一种灰度的变换过程,将当前的灰度分布通过一个变换函数,变换为范围更宽、灰度分布更均匀的图像。也就是将原图像的直方图修改为在整个灰度区间内大致均匀分布,因此扩大了图像的动态范围,增强图像的对比度。通常均衡化选择的变换函数是灰度的累积概率,直方图均衡化算法的步骤:
(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(i);
        else
            cdf[i] = cdf[i - 1] + hist.at(i);

        lut.at(i) = static_cast(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()

运行结果:
OpenCV+python:直方图的应用(一)_第2张图片OpenCV+python:直方图的应用(一)_第3张图片全局直方图均衡后背景对比度有所改善。但导致亮度过高,我们可能会丢失了大部分信息。这是因为它的直方图并不局限于特定区域。
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()

运行结果:
OpenCV+python:直方图的应用(一)_第4张图片OpenCV+python:直方图的应用(一)_第5张图片3,直方图比较
对输入的两张图像进行直方图均衡化及直方图计算步骤后,可以对两个图像的直方图进行对比,并通过对比的结果得到一些我们想要的结论。

直方图比较应用

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

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

直方图比较方法

要比较两个直方图(H1 和 H2),首先必须要选择一个衡量直方图相似度的对比标准,我们设为d(H1,H2)
OpenCV+python:直方图的应用(一)_第6张图片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()

运行结果:
OpenCV+python:直方图的应用(一)_第7张图片OpenCV+python:直方图的应用(一)_第8张图片
巴氏距离: 0.09072200336618969, 相关性: 0.9788106004024394, 卡方: 164.3082768373199
以上数据说明两张图很相似。如果图像大小不一致需要对直方图进行归一化。

你可能感兴趣的:(OpenCV/基本图像处理算法)