0

I'm still working on a piece of code to polarize an image. The logic of it seems to work with the directions, but when I run the program, it does not work (i.e. colors change, but not actually polarized). It also seems a bit long, as I am more comfortable writing out everything so I can see clearly what is being done, but is there a way to condense it?

def polarize(im):
height=len(im)
width = len(im[0])
red = 0
green = 0
blue = 0
pixels = 0
for row in range(height):
    for col in range(width):
        red += im[row][col][0] #finds the sum of all red values
        green += im[row][col][1] #finds the sum of all green values
        blue += im[row][col][2] #finds the sum of all blue values
        pixels += 1
        avg_value_red = red/pixels
        avg_value_green = green/pixels
        avg_value_blue = blue/pixels
        if im[row][col][0] < avg_value_red:
                im[row][col][0] = 0
        elif im[row][col][0] > avg_value_red:
                im[row][col][0] = 255
        elif im[row][col][1] < avg_value_green:
                im[row][col][1] = 0
        elif im[row][col][1] > avg_value_green:
                im[row][col][1] = 255
        elif im[row][col][2] < avg_value_blue:
                im[row][col][2] = 0
        elif im[row][col][2] > avg_value_blue:
                im[row][col][2] = 255
return im
smci
  • 26,085
  • 16
  • 96
  • 138
abshi
  • 73
  • 1
  • 8
  • Related: [Polarizing an image--how to find the average of each RGB value](http://stackoverflow.com/questions/29188423/polarizing-an-image-how-to-find-the-average-of-each-rgb-value) – smci Mar 22 '15 at 02:23
  • Also related: http://stackoverflow.com/questions/18145712/pil-related-script-picture-not-getting-polarized – smci Mar 22 '15 at 04:35

1 Answers1

2

1) You need to calculate the average values prior to checking each pixels channel and setting values. Currently you are changing the avg_value_red/avg_value_green/avg_value_blue as you read each new pixel, but this is a moving average. The average color values should be based on the entire image, not just the pixels that you've iterated through up to that point.

You could do this by splitting it into two separate loops, and calculating the averages after the first loop rather than each iteration. As well, pixels is simply your width multiplied by your height, so there is little value in counting this for each iteration.

2) Secondly, your red, green, blue and pixel values are integers. In some versions of Python, when you do integer division you will not get a double. Therefore when you calculate avg_value_red etc. it may return an integer value rather than a more precise float or similar.

3) Additionally, you need to split your conditions to check each channel separately. For example, if it is found that im[row][col[0] < avg_value_red is true, a condition is satisfied, so the blue and green channels will not be checked. If we're splitting these conditions, each channel just becomes if value > average, set channel to 255, else 0. So there is no reason to check whether value < average. You can use the ternary conditional operator to do this to keep the code short since you've requested (but it is up to you).

4) Finally, you should also handle the case of when a pixel's channel is equal to the average value. Currently these values will not be altered. This depends on your algorithm of course, but I would expect it to go one way or the other rather than remaining the same.

def polarize(im):
    height = len(im)
    width = len(im[0])
    red = 0
    green = 0
    blue = 0
    pixels = float(width*height)
    for row in range(height):
        for col in range(width):
            red += im[row][col][0] #finds the sum of all red values
            green += im[row][col][1] #finds the sum of all green values
            blue += im[row][col][2] #finds the sum of all blue values
    print numpy.mean(im, axis=(0,1))
    print red/pixels, green/pixels, blue/pixels
    avg_value_red = red/pixels
    avg_value_green = green/pixels
    avg_value_blue = blue/pixels
    for row in range(height):
        for col in range(width):
            im[row][col][0] = 255 if im[row][col][0] >= avg_value_red else 0
            im[row][col][1] = 255 if im[row][col][1] >= avg_value_green else 0
            im[row][col][2] = 255 if im[row][col][2] >= avg_value_blue else 0
    return im

5) As for code length, it's not too long, but there are various ways to shorten and/or optimize this depending on which image/array library you are using. I assume this is Numpy, in which case there are multiple ways to improve this. For example, the entire method can be compressed into a single line using Numpy:

def polarize(im):
    return (im[:,:]>=numpy.mean(im,axis=(0,1)))*255

This will check if each channel is greater or equal to its mean value (across the entire image array). Then this true or false is multiplied by 255 (true*255 will result in 255; false*255 will result in 0). Therefore the end result has values of either 255 or 0 for each pixel's channels. You could break this apart into multiple lines in order to inspect what it is doing.

Community
  • 1
  • 1
grovesNL
  • 5,534
  • 2
  • 18
  • 31