elif-else runtime optimization
I
searched for the previously asked issue but didn’t find what I needed to optimize the code.
For information, I’m running on Python 2.7, but can change to 3 if needed
I’m converting every pixel of an image and I have to do it pixel by pixel due to some circumstances.
So I nested an if-elif-else statement inside the for loop and it took a long time to run.
For a 1536 x 2640 image, the entire code takes about 20 seconds, and 90% of the time is in this double for loop
I believe there should be a better way to write the code below
for pixel in range(width):
for row in range(height):
ADC = img_original[row, pixel]
if ADC < 84:
gain = gain1
offset = offset1
elif ADC > 153:
gain = gain3
offset = offset3
else:
gain = gain2
offset = offset2
Conv_ADC = int(min(max(ADC * gain + offset, 0),255))
img_conv[row, pixel] = Conv_ADC
Thanks for the help
Edit more details:
@Jean-FrançoisFabre is right, I’m applying three different gains/offsets depending on which part I’m between 0 and 255. However, the section is not always evenly distributed and can be modified.
Maybe to provide some extra context, I just applied a custom S-curve to the image to move the pixel value up/down. And each column in the image has its own S-curve
My gain1,2,3
/offset1,2,3 value is float. The gain will always be positive and the offset can be negative or positive. I also have a separate value for each pixel in the width direction, but they are common in the row direction.
For example, all pixels in column 1 can use gain/offset 1, 2, 3 in row 1 in the table below. All pixels in column 2 in the image will use the gain/offset in row 2 in the table below
Pixel Gain1 Offset1 Gain2 Offset2 Gain3 Offset3
1 0.417722 24.911392 0.623188 7.652176 1.175676 -76.878357
2 0.43038 25.848103 0.623188 9.652176 1.148649 -70.743225
3 0.443038 23.784809 0.637681 7.434776 1.175676 -74.878357
4 0.443038 22.784809 0.652174 5.217384 1.175676 -74.878357
5 0.455696 23.721519 0.637681 8.434776 1.202703 -78.013519
6 0.455696 21.721519 0.637681 6.434776 1.243243 -86.216217
7 0.455696 22.721519 0.623188 8.652176 1.216216 -82.081085
8 0.443038 22.784809 0.623188 7.652176 1.22973 -85.148651
... until pixel 2640 in width direction
I’ll look at @Jean-FrançoisFabre’s solution, but in the meantime I’m also thinking about using some numpy methods.
Once I get something that calculates faster, I’ll post my findings here
Solution
Since your values are between 0 and 255, and your boundaries are evenly spaced, you can use the following trick:
It seems that you want to apply 3 different gains, depending on whether you are in the first third of the 0-255 range, the second third, or the third third.
Why not calculate the index by dividing by 85 (255/3)?
Simple proof of concept:
gainsoffsets = [(10,1),(20,2),(30,3),(30,3)] # [(gain1,offset1),(gain2,offset2),(gain3,offset3)] + extra corner case for value 255
for value in 84,140,250:
index = value // 85
gain,offset = gainsoffsets[index]
print(gain,offset)
Result:
10 1
20 2
30 3
There is only one division in this loop, no if
. Should be much faster (except for the numpy
method).
You can use a finer level and a more accurate lookup table (or you can avoid division by generating 256 tuples):
gainsoffsets = [(10,1)]*85+[(20,2)]*85+[(30,3)*86] # add more intervals for more thresholds