直方圖均衡化是對於一幅圖像,其具備多個灰度等級的像素,咱們儘量讓這些灰度等級出現頻率的機率密度函數趨近於常數。這麼作的意義在哪裏?當一幅圖像比較暗的時候,灰度等級絕大部分處於低等級的狀態,那麼因爲咱們使灰度等級頻率的機率密度函數儘量趨向於常數,即儘量保證在各個灰度等級出現頻率同樣,咱們認爲此時應該有更高的對比度,展現的細節更加細膩。在圖像處於過亮的狀況下也能夠得出相近結論。python
舉個例子,來自於《數字圖像處理》第三章
有大小爲64 * 64 像素的3比特數字圖像的灰度分佈和直方圖值以下:
app
下面咱們計算本來的灰度等級各自映射到哪一個等級。
\(s_0 = 7\Sigma_{j=0}^0p_r(r_0) = 7 * p_r(r_0) = 1.33\)
\(s_1 = 7\Sigma_{j=0}^1p_r(r_0) = 7 * p_r(r_0) + 7 * p_r(r_1) = 3.08\)
則\(s_0\)四捨五入得1(實際計算機中灰度等級只能是離散的)
\(s_1\)四捨五入得3。
其餘每一個灰度等級的映射都相似,能夠分別計算出均衡化後每一個原灰度等級應該映射到的新的灰度等級。
Lena的灰度圖函數
Lena灰度圖作直方圖均衡化後spa
Lena的彩色圖code
Lena彩色圖作直方圖均衡化後blog
對於彩色圖像的直方圖均衡化,能夠考慮使用R,G,B三個通道分別均衡化,而後將三個通道合在一塊兒。但這樣有可能會改變色調。
下面是直方圖均衡化的python實現,依賴PIL包圖片
def his_equ(img, outfile,level=256,mode='RGB'): ''' :param img: Image.open打開的文件句柄 :param outfile: 輸出文件的文件名 :param level:灰度等級,彩色圖是每一個通道對應的等級數 :param mode:'rgb'爲彩色模式,'gray'爲灰度圖 :return: 按照輸出文件路徑保存均衡化以後的圖片 ''' if mode == 'RGB' or mode == 'rgb': r, g, b = [], [], [] width, height = img.size[0], img.size[1] sum_pix = width * height pix = img.load() for x in range(width): for y in range(height): r.append(pix[x, y][0]) g.append(pix[x, y][1]) b.append(pix[x, y][2]) r_c = dict(Counter(r)) g_c = dict(Counter(g)) b_c = dict(Counter(b)) r_p,g_p,b_p = [],[],[] for i in range(level): if r_c.has_key(i): r_p.append(float(r_c[i]) / sum_pix) else: r_p.append(0) if g_c.has_key(i): g_p.append(float(g_c[i])/sum_pix) else: g_p.append(0) if b_c.has_key(i): b_p.append(float(b_c[i])/sum_pix) else: b_p.append(0) temp_r,temp_g,temp_b = 0,0,0 for i in range(level): temp_r += r_p[i] r_p[i] = int(temp_r * (level-1)) temp_b += b_p[i] b_p[i] = int(temp_b *(level-1)) temp_g += g_p[i] g_p[i] = int(temp_g*(level -1)) new_photo = Image.new('RGB',(width,height)) for x in range(width): for y in range(height): new_photo.putpixel((x,y),(r_p[pix[x,y][0]],g_p[pix[x,y][1]],b_p[pix[x,y][2]])) new_photo.save(outfile) elif mode == 'gray' or mode == 'GRAY': width, height = img.size[0], img.size[1] sum_pix = width * height pix = img.load() pb = [] for x in range(width): for y in range(height): pb.append(pix[x,y]) pc = dict(Counter(pb)) pb = [] for i in range(level): if pc.has_key(i): pb.append(float(pc[i]) / sum_pix) else: pb.append(0) temp = 0 for i in range(level): temp += pb[i] pb[i] = int(temp * (level-1)) new_photo = Image.new('L',(width,height)) for x in range(width): for y in range(height): new_photo.putpixel((x,y),pb[pix[x,y]]) new_photo.save(outfile) if __name__ == '__main__': ppp = Image.open('Lena.jpg','r') his_equ(ppp,'lena_his.jpg')