1. 程式人生 > >直方圖均衡化處理影象(python)

直方圖均衡化處理影象(python)

對於曝光過度或者逆光拍攝的圖片可以通過直方圖均衡化來進行處理用來增強區域性或整體的對比度。具體思路是通過找出影象中最亮和最暗的畫素值將之對映到純黑和純白之後再將其他的像數值按某種演算法對映到純黑純白之間的值。而對於彩圖可以將各個顏色通道分開處理然後再合併到一起。

那麼首先是單通道的灰階圖的處理:

第一步獲得影象的直方圖與累積分佈函式

    imhist, bins = histogram(im_arr.flatten(), range(256))
    cdf = imhist.cumsum()

這裡是通過numpy庫中的histogram函式獲得直方圖陣列imhist和累積分佈函式cdf

第二步是計算灰度的轉換值

# 定義直方圖均衡化函式,這裡傳入的引數是灰度影象的陣列和累積分佈函式值
def histImageArr(im_arr, cdf):
    cdf_min = cdf[0]
    im_w = len(im_arr[0])
    im_h = len(im_arr)
    im_num = im_w*im_h
    color_list = []
    i=0

    # 通過累積分佈函式計算灰度轉換值
    while i<256:
        if i>len(cdf) - 1:
            color_list.append(color_list[i-1])
            break
        tmp_v = (cdf[i] - cdf_min)*255/(im_num-cdf_min)
        color_list.append(tmp_v)
        i += 1

    # 產生均衡化後的影象資料
    arr_im_hist = []
    for itemL in im_arr:
        tmp_line = []
        for item_p in itemL:
            tmp_line.append(color_list[item_p])
        arr_im_hist.append(tmp_line)

    return arr_im_hist

具體的演算法可以參考 維基,這樣就可以獲得處理後的灰度影象。


下面就是對於彩圖的處理

首先是分離通道,這裡只對三個通道進行處理

arr_im_rgb  = array(im_source)
arr_im_rcolor = []
arr_im_gcolor = []
arr_im_bcolor = []
i = 0
# 分離三原色通道
for itemL in arr_im_rgb:
    arr_im_gcolor.append([])
    arr_im_rcolor.append([])
    arr_im_bcolor.append([])
    for itemC in itemL:
        arr_im_rcolor[i].append(itemC[0])
        arr_im_gcolor[i].append(itemC[1])
        arr_im_bcolor[i].append(itemC[2])
    i = 1+i
第二步是分通道處理,我這裡嘗試了兩種方式一種是三通道都按灰度的累積分佈函式處理,第二種是按各自的分佈函式處理

    # 通過灰度影象的累積分佈函式來進行處理
    im_gray = im_source.convert('L')
    arr_im_gray = array(im_gray)
    imhist, bins = histogram(arr_im_gray.flatten(), range(256))
    cdf = imhist.cumsum()

    arr_im_rcolor_hist = histImageArr(arr_im_rcolor, cdf)
    arr_im_gcolor_hist = histImageArr(arr_im_gcolor, cdf)
    arr_im_bcolor_hist = histImageArr(arr_im_bcolor, cdf)

    # 三個通道通過各自的分佈函式來處理
    arr_im_rcolor_hist = beautyImage(array(arr_im_rcolor))
    arr_im_gcolor_hist = beautyImage(array(arr_im_gcolor))
    arr_im_bcolor_hist = beautyImage(array(arr_im_bcolor))

第三步是合併三通道顏色到圖片

# 合併三個通道顏色到圖片
i = 0
arr_im_hist = []
while i<len(arr_im_rcolor_hist):
    ii = 0
    tmp_line = []
    while ii < len(arr_im_rcolor_hist[i]):
        tmp_point = [arr_im_rcolor_hist[i][ii], arr_im_gcolor_hist[i][ii],arr_im_bcolor_hist[i][ii]]
        tmp_line.append(tmp_point)
        ii += 1
    arr_im_hist.append(tmp_line)
    i += 1

完整的程式碼如下:

# -*-  coding: utf-8 -*-
from PIL import Image
from numpy import *
from pylab import *
from matplotlib import pyplot
#from scipy.misc import *
from scipy.misc import lena, toimage

# 定義直方圖均衡化函式,這裡傳入的引數是灰度影象的陣列和累積分佈函式值
def histImageArr(im_arr, cdf):
    cdf_min = cdf[0]
    im_w = len(im_arr[0])
    im_h = len(im_arr)
    im_num = im_w*im_h
    color_list = []
    i=0

    # 通過累積分佈函式計算灰度轉換值
    while i<256:
        if i>len(cdf) - 1:
            color_list.append(color_list[i-1])
            break
        tmp_v = (cdf[i] - cdf_min)*255/(im_num-cdf_min)
        color_list.append(tmp_v)
        i += 1

    # 產生均衡化後的影象資料
    arr_im_hist = []
    for itemL in im_arr:
        tmp_line = []
        for item_p in itemL:
            tmp_line.append(color_list[item_p])
        arr_im_hist.append(tmp_line)

    return arr_im_hist

# 封裝一下影象處理的函式,cdf是累積分佈函式數值
def beautyImage(im_arr):
    imhist, bins = histogram(im_arr.flatten(), range(256))
    cdf = imhist.cumsum()

    return histImageArr(im_arr, cdf)


im_source = Image.open('images/showover3.jpg')

if True:
    im_source.show()

if True:
    # 灰度影象的轉換
    im_gray = im_source.convert('L')
    im_gray.show()

    arr_im_gray = array(im_gray)
    arr_im_gray_hist = beautyImage(arr_im_gray)
    figure()
    im_conver = toimage(arr_im_gray_hist, 255, 0, None, None, None, 'L')
    im_conver.show()

# 這一部分是對彩圖的直方圖均衡化例子
arr_im_rgb  = array(im_source)
arr_im_rcolor = []
arr_im_gcolor = []
arr_im_bcolor = []
i = 0
# 分離三原色通道
for itemL in arr_im_rgb:
    arr_im_gcolor.append([])
    arr_im_rcolor.append([])
    arr_im_bcolor.append([])
    for itemC in itemL:
        arr_im_rcolor[i].append(itemC[0])
        arr_im_gcolor[i].append(itemC[1])
        arr_im_bcolor[i].append(itemC[2])
    i = 1+i

if False:
    # 通過灰度影象的累積分佈函式來進行處理
    im_gray = im_source.convert('L')
    arr_im_gray = array(im_gray)
    imhist, bins = histogram(arr_im_gray.flatten(), range(256))
    cdf = imhist.cumsum()

    arr_im_rcolor_hist = histImageArr(arr_im_rcolor, cdf)
    arr_im_gcolor_hist = histImageArr(arr_im_gcolor, cdf)
    arr_im_bcolor_hist = histImageArr(arr_im_bcolor, cdf)

if True:
    # 三個通道通過各自的分佈函式來處理
    arr_im_rcolor_hist = beautyImage(array(arr_im_rcolor))
    arr_im_gcolor_hist = beautyImage(array(arr_im_gcolor))
    arr_im_bcolor_hist = beautyImage(array(arr_im_bcolor))

# 合併三個通道顏色到圖片
i = 0
arr_im_hist = []
while i<len(arr_im_rcolor_hist):
    ii = 0
    tmp_line = []
    while ii < len(arr_im_rcolor_hist[i]):
        tmp_point = [arr_im_rcolor_hist[i][ii], arr_im_gcolor_hist[i][ii],arr_im_bcolor_hist[i][ii]]
        tmp_line.append(tmp_point)
        ii += 1
    arr_im_hist.append(tmp_line)
    i += 1

figure()
im_beauty = toimage(array(arr_im_hist), 255)
im_beauty.show()

效果圖

第一排是彩圖的處理,1號是原圖,2是分通道處理的,3是按灰度統一處理

第二排是灰度的處理