0
votes

I would like to implement the procedure detailed in the paper Global Contrast Factor - a New Approach to Image Contrast by Krešimir Matkovic, László Neumann, Attila Neumann, Thomas Psik, and Werner Purgathofer in Python using Numpy and OpenCV. However, there is one step I'm struggling with.

The procedure essentially involves some basic multiplication and addition over the pixels of a grayscale image, which can be done fairly easily with Numpy vectorized operations. However, this procedure needs to be repeated for the image at smaller and smaller resolutions, where the superpixels in the smaller images are combined according to a particular formula provided in the paper.

Starting from the original image, each time the dimensions are halved, and "the superpixel value is computed as average linear luminance, and this is then converted to perceptual luminance," given by the formulas:

enter image description here

where gamma = 2.2 and k is the original pixel value [0, 255]. I assume this means that each time I scale down the image, I need to compute the first formula for four pixels at a time (arranged in a square), average them, and then apply the second formula to use as the grayscale value for the smaller image.

My problem is that I'm not sure how I can efficiently scale an image down so that its pixel values are calculated in a way that corresponds to those formulas. OpenCV already has some built in resizing algorithms, but I'm honestly not sure which, if any, would provide a similar result to the one detailed in the paper.

How can you efficiently resize a grayscale image where the pixel values in the smaller image are determined by those formulas?

1

1 Answers

0
votes

OpenCV resize does not perform these operations. You will have to explicitly calculate the linear luminance values for each pixel in the image and then apply resize with linear interpolation (INTER_LINEAR). Linear interpolation will calculate the average. See the following example. It calculates the average of non-overlapping 2x2 blocks.

>>> im = np.random.randint(0, 255, (8, 8)).astype(np.float32)
>>> im
array([[ 74.,  73., 109.,  41., 165.,  24., 165., 189.],
       [143.,  15., 212., 139.,  63., 123., 222., 231.],
       [ 58., 150., 168., 234.,  64., 139., 239., 179.],
       [227.,  11., 142.,  42.,  28., 127., 213.,  52.],
       [187., 232.,  26.,  34.,  63., 104., 197., 155.],
       [ 95., 154.,  69.,  56., 163.,  93.,  37., 136.],
       [ 14., 249., 204.,  15., 182., 226.,  20., 114.],
       [231.,  61., 155., 184., 211., 162.,  62.,  26.]], dtype=float32)
>>> cv2.resize(im, dsize=None, fx=0.5, fy=0.5, interpolation=cv2.INTER_LINEAR)
array([[ 76.25, 125.25,  93.75, 201.75],
       [111.5 , 146.5 ,  89.5 , 170.75],
       [167.  ,  46.25, 105.75, 131.25],
       [138.75, 139.5 , 195.25,  55.5 ]], dtype=float32)
>>> (168+234+142+42)/4
146.5

As I understood, you calculate the linear luminance (l) only for the original image, and then successively reduce the resolution (please correct me if I'm wrong).

You can speedup the linear luminance calculation using a lookup table (LUT) because there will only be a maximum of 256 different pixel values if your image is 8-bit (8U).