Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient way to threshold image array and render - Python / NumPy / OpenCV

I have a camera that is sending the image data to my computer. From there my python script puts the 8bit color info (black and white; ranging from 0 - black - to 255 - white) into a numpy array. The array is 2D, first dimension up to 384 and second dimensions up to 288 Displaying this with a openCV window works great and the live video is more than 24fps.

My aim now is to manipulate the image, so that the live video displays any color value below 200 as 0 (completely black) and any color value above 200 as 255 (completely white). However, my code right now only gives me about 3fps.

My code is doing the following:

  • save the image that comes from the camera in a numpy array
  • open the first for loop to iterate through the x values
  • in that first for loop iterate through the second for loop with the y values
  • check each color value for every pixel and check if it is above 200 or not
  • depending on the if clause make the color value 0 or 255
  • display the new image

This is the decisive part in the code:

processedImage = frame
i = 0
for i in range(0, displayedWidth):
    ii = 0
    for ii in range(0, displayedHeight):
        if frame[ii, i] > 200:
            processedImage[ii, i] = 255
        else: 
            processedImage[ii, i] = 0
cv2.imshow("LiveVideo", processedImage)

I read here that for loops are faster than while loops, but it didn't improve the code's speed significantly, which is why I assume the rewriting of the processedImage takes too long.

Is there a way to make the whole process faster?

Thanks for any answers!

like image 497
X_841 Avatar asked Aug 05 '26 08:08

X_841


2 Answers

Try this:

frame[frame > 200] = 255
frame[frame <= 200] = 0
cv2.imshow("LiveVideo", frame)
like image 63
Seb Avatar answered Aug 07 '26 23:08

Seb


Staying with NumPy, it seems fastest would be -

(frame>200)*np.uint8(255)

Since, you are already using OpenCV, a faster way would be with cv2.threshold -

cv2.threshold(frame,200,255,cv2.THRESH_BINARY)[1]

Sample run to verify results and get timings on 1024X1024 image -

In [2]: np.random.seed(0)
   ...: frame = np.random.randint(0,256,(1024,1024)).astype(np.uint8)

In [3]: %timeit (frame>200)*np.uint8(255)
253 µs ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [4]: %timeit cv2.threshold(frame,200,255,cv2.THRESH_BINARY)[1]
58.2 µs ± 437 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)    

In [7]: out1 = (frame>200)*np.uint8(255)

In [8]: out2 = cv2.threshold(frame,200,255,cv2.THRESH_BINARY)[1]

In [9]: np.allclose(out1, out2)
Out[9]: True

Timings with other solutions on same data -

# @AKX's soln
In [10]: %timeit np.where(frame >= 200, 255, 0)
3.73 ms ± 22.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# @Seb's soln
In [11]: %%timeit
    ...: frame[frame > 200] = 255
    ...: frame[frame <= 200] = 0
10.2 ms ± 15.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

OpenCV's version with cv2.threshold seems the fastest by a big margin among others.

like image 21
Divakar Avatar answered Aug 07 '26 22:08

Divakar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!