图像均衡化及直方图匹配的详细实现,python

最近在学习图像处理方面的基础知识,在这里简单总结和分享。

一.直方图均衡化

图像的灰度直方图是一种概率直方图,表示不同灰度值在图像中出现的概率
图像的灰度直方图可以用来判断图像曝光是否合适,一种对曝光度异常的图像进行图像增强的操作就是直方图均衡化。
那么怎样进行图像直方图均衡化呢?

主流的图像处理库都封装了直方图均衡化的函数,比如matlab中的histeq()函数,对于这一函数的讲解可参考这篇文章histeq从用法到原理。
这里介绍一下如何自己写代码实现这一功能,使用了python语言。

将读取文件的灰度矩阵,转化为直方图,这里的直方图定义为python的dict类型,索引为灰度级,值为对应的概率。

#将灰度数组映射为直方图字典,nums表示灰度的数量级
def arrayToHist(grayArray,nums):
    if(len(grayArray.shape) != 2):
        print("length error")
        return None
    w,h = grayArray.shape
    hist = {}
    for k in range(nums):
        hist[k] = 0
    for i in range(w):
        for j in range(h):
            if(hist.get(grayArray[i][j]) is None):
                hist[grayArray[i][j]] = 0
            hist[grayArray[i][j]] += 1
    #normalize
    n = w*h
    for key in hist.keys():
        hist[key] = float(hist[key])/n
    return hist

直方图均衡化函数,传入原始图片的灰度矩阵和其直方图,计算累计的概率直方图,再进行均衡化。

#计算累计直方图计算出新的均衡化的图片,nums为灰度数,256
def equalization(grayArray,h_s,nums):
    #计算累计直方图
    tmp = 0.0
    h_acc = h_s.copy()
    for i in range(256):
        tmp += h_s[i]
        h_acc[i] = tmp

    if(len(grayArray.shape) != 2):
        print("length error")
        return None
    w,h = grayArray.shape
    des = np.zeros((w,h),dtype = np.uint8)
    for i in range(w):
        for j in range(h):
            des[i][j] = int((nums - 1)* h_acc[grayArray[i][j] ] +0.5)
    return des

绘制直方图的函数,借助pyplot

#传入的直方图要求是个字典,每个灰度对应着概率
def drawHist(hist,name):
    keys = hist.keys()
    values = hist.values()
    x_size = len(hist)-1#x轴长度,也就是灰度级别
    axis_params = []
    axis_params.append(0)
    axis_params.append(x_size)

    #plt.figure()
    if name != None:
        plt.title(name)
    plt.bar(tuple(keys),tuple(values))#绘制直方图
    #plt.show()

整个调用流程如下:

import numpy as np 
from matplotlib import pyplot as plt
from PIL import Image
import matplotlib

matplotlib.rcParams['font.sans-serif']=['SimHei']   # 用黑体显示中文

imdir = "./hw1_s.jpg"#原始图片的路径

#打开文件并灰度化
im_s = Image.open(imdir).convert("L")
im_s = np.array(im_s)
print(np.shape(im_s))

#开始绘图,分成四个部分
plt.figure()
plt.subplot(2,2,1)
plt.imshow(im_s,cmap = 'gray')
plt.title("原始灰度图")
#plt.show()

#创建原始直方图
plt.subplot(2,2,3)
hist_s = arrayToHist(im_s,256)
drawHist(hist_s,"原始直方图")

#计算均衡化的新的图片,根据累计直方图
im_d = equalization(im_s,hist_s,256)
plt.subplot(2,2,2)
plt.imshow(im_d,cmap="gray")
plt.title("均衡的灰度图")

#根据新的图片的数组,计算新的直方图
plt.subplot(2,2,4)
hist_d = arrayToHist(im_d,256)
drawHist(hist_d,"均衡直方图")

plt.show()

最终结果

equal.PNG

二.直方图匹配

直方图匹配类似于直方图均衡,不同之处在于直方图均衡的输出结果是固定的,较均衡的图像,而直方图匹配的结果则是我们指定的直方图,具体的数学原理不再赘述,不过注意,由于原始图像的累计直方图和我们指定的输出图片的直方图的累计直方图不可能完全相同,所以匹配结果并非百分之百的匹配
下面看实现
定义的匹配函数:注意第二个参数是我们指定的直方图,而非原始图片的直方图。

#直方图匹配函数,接受原始图像和目标灰度直方图
def histMatch(grayArray,h_d):
    #计算累计直方图
    tmp = 0.0
    h_acc = h_d.copy()
    for i in range(256):
        tmp += h_d[i]
        h_acc[i] = tmp

    h1 = arrayToHist(grayArray,256)
    tmp = 0.0
    h1_acc = h1.copy()
    for i in range(256):
        tmp += h1[i]
        h1_acc[i] = tmp
    #计算映射
    M = np.zeros(256)
    for i in range(256):
        idx = 0
        minv = 1
        for j in h_acc:
            if (np.fabs(h_acc[j] - h1_acc[i]) < minv):
                minv = np.fabs(h_acc[j] - h1_acc[i])
                idx = int(j)
        M[i] = idx
    des = M[grayArray]
    return des

具体调用,读取第二张图片,其直方图为我们指定的直方图

imdir = "./hw1_s2.jpg"
imdir_match = "./hw1_s22.jpg"

#直方图匹配
#打开文件并灰度化
im_s = Image.open(imdir).convert("L")
im_s = np.array(im_s)
print(np.shape(im_s))
#打开文件并灰度化
im_match = Image.open(imdir_match).convert("L")
im_match = np.array(im_match)
print(np.shape(im_match))
#开始绘图
plt.figure()

#原始图和直方图
plt.subplot(2,3,1)
plt.title("原始图片")
plt.imshow(im_s,cmap='gray')

plt.subplot(2,3,4)
hist_s = arrayToHist(im_s,256)
drawHist(hist_s,"原始直方图")

#match图和其直方图
plt.subplot(2,3,2)
plt.title("match图片")
plt.imshow(im_match,cmap='gray')

plt.subplot(2,3,5)
hist_m = arrayToHist(im_match,256)
drawHist(hist_m,"match直方图")

#match后的图片及其直方图
im_d = histMatch(im_s,hist_m)#将目标图的直方图用于给原图做均衡,也就实现了match
plt.subplot(2,3,3)
plt.title("match后的图片")
plt.imshow(im_d,cmap='gray')

plt.subplot(2,3,6)
hist_d = arrayToHist(im_d,256)
drawHist(hist_d,"match后的直方图")

plt.show()

最后结果

match.PNG

可以看到匹配出的图像与指定的图像灰度接近,灰度直方图相似。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容