3

What I wanna do here is trying to match the brightness of my source and template images. I found a very good coding example from here. This was done on the grayscale. I tried this on my images in greyscale form and it really give me good result.

I am now trying to repeat it by using colour images, I first converted both my source and template images to HSV colour format as I am only interested in histogram matching the Value(brightness) channel.

I was able to get the matched value, but I am having an error trying to merge the matched value to the source images.

After printing out the value for "source" "template" and "matched". I figure out it might be because my matched value were in float number? I intend to keep the float number because I am afraid rounding off the number to integer might gave me inaccurate matching. Will it be any different? Is there any another way of doing this?

 RESTART: C:\Users\310293649\AppData\Local\Programs\Python\Python36\ImageAnalysisCODING\HistogramMatching.py 
[[119 119 120 ..., 100 100 100]
 [120 120 119 ...,  98  98  99]
 [120 120 119 ...,  97  97  98]
 ..., 
 [ 74  73  73 ...,  61  61  61]
 [ 73  73  73 ...,  61  61  61]
 [ 72  72  73 ...,  61  61  61]]
[[140 140 141 ..., 130 129 130]
 [140 140 140 ..., 129 129 130]
 [139 139 140 ..., 128 128 129]
 ..., 
 [ 85  84  84 ...,  76  76  77]
 [ 84  84  85 ...,  76  75  76]
 [ 82  81  85 ...,  76  75  75]]
[[ 135.50896712  135.50896712  136.35596888 ...,  118.31246023
   118.31246023  118.31246023]
 [ 136.35596888  136.35596888  135.50896712 ...,  116.73808586
   116.73808586  117.51789135]
 [ 136.35596888  136.35596888  135.50896712 ...,  115.96259322
   115.96259322  116.73808586]
 ..., 
 [  90.25379483   89.27703193   89.27703193 ...,   79.3186822    79.3186822
    79.3186822 ]
 [  89.27703193   89.27703193   89.27703193 ...,   79.3186822    79.3186822
    79.3186822 ]
 [  88.30202317   88.30202317   89.27703193 ...,   79.3186822    79.3186822
    79.3186822 ]]
Traceback (most recent call last):
  File "C:\Users\310293649\AppData\Local\Programs\Python\Python36\ImageAnalysisCODING\HistogramMatching.py", line 65, in <module>
    img2 = cv2.merge((img2[:,:,0], img2[:,:,1],matched))
cv2.error: C:\projects\opencv-python\opencv\modules\core\src\convert.cpp:222: error: (-215) mv[i].size == mv[0].size && mv[i].depth() == depth in function cv::merge

Here is the coding which I edited based on the example which I got from another post.

import numpy as np
from matplotlib import pyplot as plt
import cv2

def hist_match(source, template):
    """
    Adjust the pixel values of images such that its histogram
    matches that of a target image

    Arguments:
    -----------
        source: np.ndarray
            Image to transform; the histogram is computed over the flattened
            array
        template: np.ndarray
            Template image; can have different dimensions to source
    Returns:
    -----------
        matched: np.ndarray
            The transformed output image
    """

    oldshape = source.shape
    source = source.ravel()
    template = template.ravel()

    # get the set of unique pixel values and their corresponding indices and
    # counts
    s_values, bin_idx, s_counts = np.unique(source, return_inverse=True,
                                            return_counts=True)

    t_values, t_counts = np.unique(template, return_counts=True)


    # take the cumsum of the counts and normalize by the number of pixels to
    # get the empirical cumulative distribution functions for the source and
    # template images (maps pixel value --> quantile)
    s_quantiles = np.cumsum(s_counts).astype(np.float64)
    s_quantiles /= s_quantiles[-1]
    t_quantiles = np.cumsum(t_counts).astype(np.float64)
    t_quantiles /= t_quantiles[-1]

    # interpolate linearly to find the pixel values in the template image
    # that correspond most closely to the quantiles in the source image
    interp_t_values = np.interp(s_quantiles, t_quantiles, t_values)

    return interp_t_values[bin_idx].reshape(oldshape)




img1 = cv2.imread('IMG_1.png')
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
img1[:,:,0], img1[:,:,1], img1[:,:,2] = cv2.split(img1)
source = img1[:,:,2]

print(source)

img2 = cv2.imread('IMG_2.png')
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV)
img2[:,:,0], img2[:,:,1], img2[:,:,2] = cv2.split(img2)
template = img2[:,:,2]

print(template)

matched = hist_match(source, template)

print(matched)

img2 = cv2.merge((img2[:,:,0], img2[:,:,1],matched))
cv2.imwrite('Matched_1770.png', img2)


def ecdf(x):
    """convenience function for computing the empirical CDF"""
    vals, counts = np.unique(x, return_counts=True)
    ecdf = np.cumsum(counts).astype(np.float64)
    ecdf /= ecdf[-1]
    return vals, ecdf

x1, y1 = ecdf(source.ravel())
x2, y2 = ecdf(template.ravel())
x3, y3 = ecdf(matched.ravel())

fig = plt.figure()
gs = plt.GridSpec(2, 3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1], sharex=ax1, sharey=ax1)
ax3 = fig.add_subplot(gs[0, 2], sharex=ax1, sharey=ax1)
ax4 = fig.add_subplot(gs[1, :])
for aa in (ax1, ax2, ax3):
    aa.set_axis_off()

ax1.imshow(source)
ax1.set_title('Source')
ax2.imshow(template)
ax2.set_title('Template')
ax3.imshow(matched)
ax3.set_title('Matched')

ax4.plot(x1, y1 * 100, '-r', lw=3, label='Source')
ax4.plot(x2, y2 * 100, '-k', lw=3, label='Template')
ax4.plot(x3, y3 * 100, '--r', lw=3, label='Matched')
ax4.set_xlim(x1[0], x1[-1])
ax4.set_xlabel('Pixel value')
ax4.set_ylabel('Cumulative %')
ax4.legend(loc=5)
plt.show()
SacreD
  • 363
  • 1
  • 5
  • 16

0 Answers0