Histogram matching(согласование гистограмм) на python

Навеяло вот этим вопросом на стэковерфлоу. Вопрошающий интересуется, как сделать цвета картинки похожими на цвета другой картинки. В его примере, вот исходная картинка:

Он хочет взять оттенок из вот этой картинки:

и применить его к исходной.

Предлагаемый алгоритм согласования гистограмм дает на этом примере следующий результат:

до: после:

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

За основу возьмем реализацию метода нормализации гистограммы от Jan Erik Solem

   def histeq(im,nbr_bins=256):

   #get image histogram
   imhist,bins = histogram(im.flatten(),nbr_bins,normed=True)
   cdf = imhist.cumsum() #cumulative distribution function
   cdf = 255 * cdf / cdf[-1] #normalize

   #use linear interpolation of cdf to find new pixel values
   im2 = interp(im.flatten(),bins[:-1],cdf)

   return im2.reshape(im.shape), cdf

И сделаем из нее функцию согласования, работающую как с одноканальными, так и с многоканальными изображениями:

from scipy.misc import imsave, imread
import numpy as np

imsrc = imread("source.jpg")
imtint = imread("tint_target.jpg")

nbr_bins=255
if len(imsrc.shape) < 3:
    imsrc = imsrc[:,:,np.newaxis]
    imtint = imtint[:,:,np.newaxis]

imres = imsrc.copy()
for d in range(imsrc.shape[2]):
    imhist,bins = np.histogram(imsrc[:,:,d].flatten(),nbr_bins,normed=True)
    tinthist,bins = np.histogram(imtint[:,:,d].flatten(),nbr_bins,normed=True)

    cdfsrc = imhist.cumsum() #cumulative distribution function
    cdfsrc = (255 * cdfsrc / cdfsrc[-1]).astype(np.uint8) #normalize

    cdftint = tinthist.cumsum() #cumulative distribution function
    cdftint = (255 * cdftint / cdftint[-1]).astype(np.uint8) #normalize


    im2 = np.interp(imsrc[:,:,d].flatten(),bins[:-1],cdfsrc)



    im3 = np.interp(im2,cdftint, bins[:-1])

    imres[:,:,d] = im3.reshape((imsrc.shape[0],imsrc.shape[1] ))

try:
    imsave("histnormresult.jpg", imres)
except:
    imsave("histnormresult.jpg", imres.reshape((imsrc.shape[0],imsrc.shape[1] )))
Written on May 18, 2015