Reputation: 73
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
Upvotes: 0
Views: 591
Reputation: 6075
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.
Upvotes: 2