圖像的直方圖處理


1.直方圖繪制

直方圖顯示圖像數據時會以左暗又亮的分布曲線形式呈現出來,而不是顯示原圖像數據。利用opencv-python中的庫函數繪制彩色圖像直方圖的自定義函數如下

# 直方圖繪制函數
def draw_my_hist(image):
    color = ('b', 'g', 'r')
    for i, color in enumerate(color):
        # calcHist()函數有5個參數:
        # image輸入圖像,傳入時應該用中括號[]括起來
        # channels::傳入圖像的通道,如果是灰度圖像,值為0,如果是彩色圖像(有3個通道),那么值為0,1,2,中選擇一個,對應着BGR各個通道。這個值也得用[]傳入。
        # mask:掩膜圖像。如果統計整幅圖,那么為none。主要是如果要統計部分圖的直方圖,就得構造相應的炎掩膜來計算。
        # histSize:灰度級的個數,需要中括號,比如[256]
        hist = cv.calcHist([image], [i], None, [256], [0, 256])  # 計算直方圖
        plt.plot(hist, color)
        plt.xlim([0, 256])

不同圖像有相差很大的直方圖

 

2.整體直方圖均衡

直方圖均衡是通過調整圖像的直方圖來改變圖像的對比度。用這種方法亮度可以更好地在直方圖上分布,從而就可以增強局部對比度而對整體對比度沒有太大影響。直方圖均衡函數:

# 彩色圖像直方圖均衡函數
# equalizeHist()函數可以直接求解灰度圖的直方圖均衡結果,所以如果是灰度圖像則不需要進行通道分解
def get_equalizeHist_image_color(image):
    (b, g, r) = cv.split(image)  # 通道分解
    bH = cv.equalizeHist(b)
    gH = cv.equalizeHist(g)
    rH = cv.equalizeHist(r)
    result = cv.merge((bH, gH, rH), )  # 通道合成
    return result

圖像均衡效果如下

 

3.局部直方圖均衡

上述的直方圖均衡化可以達到一種全局意義上的均衡化,但是有的時候這種操作並不是很好,會把某些不該調整的部分給調整了。Opencv中還有一種直方圖均衡化方法,它是一種在圖像局部進行均衡化的方法,也就是是說把整個圖像分成許多小塊(比如按7*7作為一個小塊),那么對每個小塊進行均衡化。這種方法主要對於圖像直方圖不是那么單一的(比如存在多峰情況)圖像比較實用。Opencv中的局部均衡化實例如下:

# createCLAHE()函數中clipLimit參數為顏色對比度的閾值,titleGridSize參數為進行像素均衡化的網格大小
def get_part_equalizeHist(image):
    (image_b, image_r, image_g) = cv2.split(image)
    # 創建均衡化對象
    clahe = cv2.createCLAHE(clipLimit=2, tileGridSize=(10, 10))
    # 分別對三個通道進行局部均衡化,當然如果是灰度圖則不需要通道分解操作
    result_b = clahe.apply(image_b)
    result_r = clahe.apply(image_r)
    result_g = clahe.apply(image_g)
    result = cv2.merge((result_b, result_r, result_g))
    return result

局部直方圖均衡效果如下

 

 4.直方圖匹配

雖然直方圖均衡在一定程度上能夠增強圖像的對比度,但是有的時候和我們理想的效果並不一致,如果我們能夠規定變換后直方圖的形狀,進行直方圖匹配,很多情況下要比直方圖均衡中的常量直方圖效果好。查了很多資料都表示Opencv-python中沒有免費的直方圖匹配的函數可以使用,所以這里借鑒博客上的思路自己編寫了一個求解直方圖匹配的函數

 

# 求累積直方圖
def my_get_add_hist(original_hist):
    acc_hist = np.zeros([256, 1], np.float32)
    next_number = 0.
    for i in range(256):
        acc_hist[i, 0] = next_number + original_hist[i, 0]
        next_number = acc_hist[i, 0]

    acc_hist /= next_number
    return acc_hist


def my_hist_match_gray(original_image, target_image):
    # 求原始圖像直方圖
    original_hist = cv.calcHist([original_image], [0], None, [256], [0.0, 255.])
    # 求目標圖像直方圖
    target_hist = cv.calcHist([target_image], [0], None, [256], [0.0, 255.])
    # 求原始圖像累計直方圖
    original_acc_hist = my_get_add_hist(original_hist)
    # 求目標圖像累計直方圖
    target_acc_hist = my_get_add_hist(target_hist)
    # 計算原始圖像和目標圖像在所有點概率密度的差值,並取絕對值
    my_subtract = abs(np.tile(target_acc_hist.reshape((256, 1)), (1, 256)) - original_acc_hist.reshape(1, 256))
    # 得到插值最小處的索引
    my_index = np.argmin(my_subtract, axis=0)
    # 將索引轉化為uint8,對於灰度圖像cv2.LUT的table必須是uint8類型
    my_index = my_index.astype(np.uint8)
    # 將原圖像進行映射
    result = cv.LUT(original_image, my_index)
    # 返回結果
    return result


def my_hist_match_RGB(original_image, target_image):
    # 將RGB圖像進行分解
    (original_image_b, original_image_r, original_image_g) = cv.split(original_image)
    (target_image_b, target_image_r, target_image_g) = cv.split(target_image)

    # 對每個圖像進行灰度圖像匹配
    result_b = my_hist_match_gray(original_image_b, target_image_b)
    result_r = my_hist_match_gray(original_image_r, target_image_r)
    result_g = my_hist_match_gray(original_image_g, target_image_g)

    # 將所有通道匹配結果合並
    result = cv.merge((result_b, result_r, result_g))
    return result

 

圖像進行直方圖匹配后的效果如下

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM