Я сам пытался реализовать функцию выравнивания гистограммы, но не получал требуемого выходного изображения.

import numpy as np
import cv2
import matplotlib.pyplot as plt
import math
%matplotlib inline

def freq(lst):
    d = {}
    for i in lst:
        for j in i:
            if d.get(j):
                d[j] += 1
            else:
                d[j] = 1

    return d
def probability(d,total_pixels):
    l = {}
    for i in range(256):
        value = d.get(i)
        if value != None:
            l[i] = value/total_pixels
    return l
def equalizer(d, l):
    f_dic = {}
    last_sum = 0
    for i in range(l):
        if d.get(i):
            prob = d.get(i)
            last_sum = last_sum+((l-1)*prob)
            f_dic[i] = math.floor(last_sum)
    return f_dic
def replace_values(f_dic, img):
    print(f_dic)
    for i in range(len(img)):
        for j in range(len(img)):
            vv = f_dic.get(img[i][j])
            if vv != None:
                img[i][j] = vv
    return img
def histogramEqualization(img):
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    freqq = freq(img)
    area = img.shape
    total_pixels = area[0]*area[1]
    prob = probability(freqq, total_pixels)
    f_dic = equalizer(prob,len(img))
    new_img = replace_values(f_dic,img)
    return new_img
pollen_dark = cv2.imread("/home/ahmed/Downloads/dip/DIP_A1_Fall2019/pollen_dark.tif")
new = histogramEqualization(pollen_dark)
plt.imshow(new, cmap='gray')

Я получаю это изображение: output_image

Входное изображение это: input_image

Требуемое выходное изображение: required_output_image. Реализация формулы для решения этой проблемы

Formula implementing

0
Mrcreamio 17 Окт 2019 в 16:20

1 ответ

Лучший ответ

Один из способов сделать это с помощью NumPy - использовать np.unique() для поиска значений, которые нужно изменить, и их функции распределения вероятностей (pdf), которая в основном представляет собой гистограмму. Это можно использовать для генерации соответствующих нормализованных значений в соответствии с кумулятивной функцией распределения (cdf), полученной из np.cumsum() в pdf, используя формулу:

round((cdf - min_cdf) / (num_voxels - min_cdf) * (depth - 1))

Вся идея (как и формула) хорошо наглядно описана в Википедии.

Обычно это более чистый подход, чем цикл по массиву:

DEPTH = 2 ** 8


def hist_equalization(arr, depth=DEPTH):
    vals, pdf = np.unique(arr, return_counts=True)
    cdf = np.cumsum(pdf)
    min_cdf = min(cdf)
    new_vals = (
        np.round((cdf - min_cdf) / (arr.size - min_cdf) * (depth - 1))
        .astype(int))
    result = np.empty_like(arr)
    for i, val in enumerate(vals):
        result[np.nonzero(arr == val)] = new_vals[i]
    return result


plt.imshow(arr, cmap='gray', vmin=0, vmax=DEPTH - 1)
plt.imshow(hist_equalization(arr), cmap='gray', vmin=0, vmax=DEPTH - 1)

Вход:

img_input

Выход:

img_output

(Полный сценарий доступен здесь. Обратите внимание, что вместо этого я использовал PIL cv для ввода-вывода для удобства, но это не имеет отношения к проблеме.)


РЕДАКТИРОВАТЬ

Здесь и там в вашем коде есть ряд сбоев (некоторые менее серьезные, некоторые более серьезные), но тот, который мешает вам получить правильный результат, заключается в том, что equalizer() в корне неверен.

Если вы замените свою версию equalizer() на:

def equalizer(pdf, l, depth=2 ** 8):
    min_cdf = pdf[min(pdf)]
    result = {}
    accumulator = 0
    for k, v in sorted(pdf.items()):
        accumulator += v
        result[k] = int(round((accumulator - min_cdf) / (l - min_cdf) * (depth - 1)))     
    return result

Называть с:

f_dic = equalizer(freqq, total_pixels)

Тогда остальная часть вашего кода должна работать. Обратите внимание, что probability() совершенно не нужен, и вам действительно нужен total_pixels (или img.size), поскольку len(img), примененный к N-мерному массиву, даст вам его длину по 0-му измерению , а не по общему количеству пикселей.

(Это также здесь.)

1
norok2 17 Окт 2019 в 16:33