1

I am trying to work on a code for increasing the contrast on grayscale images to make them clearer. I can't seem to get this code to work. I am trying to get the distribution frequency of each value (without using any modules aside from cv2) in the pixel and get the cumulative distribution frequency so I can then change the value using the equation below. Any idea what is wrong with my code?

import cv2
img=cv2.imread(raw_input())
shape=img.shape
row=shape[0]
col=shape[1]

def df(img): #to make a histogram (count distribution frequency)
    values=[]
    occurances=[]
    for i in range (len(img)):
        for j in img[i]:
            values.append(j)
            if j in values:
                count +=3
                occurances.append(count)
    return occurances

def cdf (img): #cumulative distribution frequency
    values2=[]
    for i in values:
        j=0
        i=i+j
        j+1
        values2.append(i)
    return values2

def h(img): #equation for the new value of each pixel
    h=((cdf(img)-1)/((row*col)-1))*255
    return h

newimage=cv2.imwrite('a.png')

This is an example of what I'm trying to do. enter image description here

Thank you in advance.

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Fat Cat
  • 63
  • 1
  • 8

2 Answers2

1

In case you're not aware, opencv provides a built in function for historgram equalization, documented here.

Also concerning your code:

The distribution frequency (or histogram) isn't calculated properly, since you only count the frequency of colors that do appear in the image. You should count the appearances of all color values, even if they don't appear. Also everytime your color reappears you add a new element of that color to your list, which doesn't make a lot of sense. I'm not quite sure where the +=3 comes from either.

What I would do is something like this:

def df(img): #to make a histogram (count distribution frequency)
    values = [0] * 256
    for i in range(len(img)):
        for j in img[i]:
           values[j] += 1
peterh
  • 11,875
  • 18
  • 85
  • 108
Mefaso
  • 94
  • 9
  • Thank you! Would it be wrong to append those values to a list so I can use it to get the cumulative distribution frequency? – Fat Cat Nov 21 '17 at 10:05
  • Appending something to a list adds it as a new last element to that list, i.e. if `a = [5,2]`, `a.append(6)` results in `a = [5,2,6]`. I'm not sure how you plan to continue from that. The cumulative is defined as the sum of all previous and the current element, a quick way to sum all elements to position n would be `sum(a[0:n])`. – Mefaso Nov 21 '17 at 10:10
  • FWIW, `cv2.equalizeHist()` is designed to be used with greyscale (i.e. single channel) images. If you've got a colour (3-channel) image some more thought is required, see [this question](https://stackoverflow.com/questions/31998428/opencv-python-equalizehist-colored-image). – scrpy Nov 21 '17 at 10:12
1

Here is a solution with some modifications. It gives the following output

Original: original

Equalized: histequalized

Major Modifications:

  1. The df() and cdf() functions have been made simple. Do print their output on execution to check if it matches with what you would expect it to give
  2. The equalize_image() function equalizes the image by interpolating from the normal pixel range (which is range(0,256)) to your cumulative distribution function

Here's the code:

import cv2
img = cv2.imread(raw_input('Please enter the name of your image:'),0) #The ',0' makes it read the image as a grayscale image
row, col = img.shape[:2]


def df(img):  # to make a histogram (count distribution frequency)
    values = [0]*256
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            values[img[i,j]]+=1
    return values


def cdf(hist):  # cumulative distribution frequency
    cdf = [0] * len(hist)   #len(hist) is 256
    cdf[0] = hist[0]
    for i in range(1, len(hist)):
        cdf[i]= cdf[i-1]+hist[i]
    # Now we normalize the histogram
    cdf = [ele*255/cdf[-1] for ele in cdf]      # What your function h was doing before
    return cdf

def equalize_image(image):
    my_cdf = cdf(df(img))
    # use linear interpolation of cdf to find new pixel values. Scipy alternative exists
    import numpy as np
    image_equalized = np.interp(image, range(0,256), my_cdf)
    return image_equalized

eq = equalize_image(img)
cv2.imwrite('equalized.png', eq)
R. S. Nikhil Krishna
  • 3,962
  • 1
  • 13
  • 27
  • Thank you so much for this! Would it be possible to replace the equalize function with h=((cdf(img)-1)/((row*col)-1))*255 instead since I'm trying to do this without importing the numpy module. – Fat Cat Nov 21 '17 at 11:01
  • Will scipy do @I.V.N ? The only place where numpy has been used is in interpolation. We can easily replace the numpy interpolation with a scipy interpolation – R. S. Nikhil Krishna Nov 21 '17 at 13:10
  • Is it possible to do indexing instead of interpolation? – Fat Cat Nov 22 '17 at 09:49