I did a search on the previous asked question, but without finding what i need to optimize my code.
For info, I am running on Python 2.7 but could change to 3 if needed
I am converting every pixel of an image and because of some condition i have to do it pixel by pixel. So i have nested for loop with an if-elif-else statement inside, and it takes an awful long time to run. For an image of 1536 x 2640, the whole code takes ~20 seconds and 90% of time is inside this double for loop
I believe there should be a better way to write the below code
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 for additional detail:
@Jean-FrançoisFabre is right and I am applying three different gain/offset depending on which section I am between 0 to 255. But the section are not always evenly space and can be modified. Maybe to give some additional context, i am simply applying a custom S-curve to an image to shift the pixel value up/down. And each column in the image have their own S-curve
my gain1,2,3/offset1,2,3 values are floating point. the gain will always be positive and the offset can be negative or positive.I also have an individual value for each pixel in the width direction, but they are common in the row direction.
Example, all pixel from column 1 with can use gain/offset 1,2,3 from the 1st row in table below. All pixel from column 2 in the image will use gain/offset form the 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 will look at @Jean-FrançoisFabre solution, but in the meantime i was also looking at using some numpy approaches.
Once i get something that compute faster, i'll post my finding here
Since your values are between 0 and 255 and your bounds are evenly spaced, you could use the trick below:
you seem to want to apply 3 different gains depending if you are on the first third, the second third or the third third of the 0-255 range.
Why not computing 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
in this loop there's only one division and no if. Should be much faster (beside the numpy approaches)
You could use finer level with more accurate lookup tables (also avoid the division by generating 256 tuples):
gainsoffsets = [(10,1)]*85+[(20,2)]*85+[(30,3)*86] # add more intervals for more thresholds
Have a try with a lookup-table: you precompute all transformed ADC values in the range [0,255], and the loop body will simplify
for pixel in range(width):
for row in range(height):
img_conv[row, pixel]= LUT[img_original[row, pixel]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With