Skip to content
Advertisement

How to efficiently loop over an image pixel by pixel in python OpenCV?

What I want to do is to loop over an image pixel by pixel using each pixel value to draw a circle in another corresponding image. enter image description here My approach is as follows:

JavaScript

Looping this way is somewhat slow. I tried adding the @njit decorator of numba, but apparently it has problems with opencv.

Input images are 32×32 pixels They map to output images that are 32×32 circles each circle is drawn inside a 20×20 pixels square That is, the output image is 640×640 pixels

A single image takes around 100ms to be transformed to circles, and I was hoping to lower that to 30ms or lower

Any recommendations?

Advertisement

Answer

When:

  • Dealing with drawings

  • The number of possible options does not exceed a common sense value (in this case: 256)

  • Speed is important (I guess that’s always the case)

  • There’s no other restriction preventing this approach

the best way would be to “cache” the drawings (draw them upfront (or on demand depending on the needed overhead) in another array), and when the drawing should normally take place, simply take the appropriate drawing from the cache and place it in the target area (as @ChristophRackwitz stated in one of the comments), which is a very fast NumPy operation (compared to drawing).

As a side note, this is a generic method not necessarily limited to drawings.

But the results you claim you’re getting: ~100 ms per one 32×32 image (to a 640×640 circles one), didn’t make any sense to me (as OpenCV is also fast, and 1024 circles shouldn’t be such a big deal), so I created a program to convince myself.

code00.py:

JavaScript

Notes:

  • Besides your implementation that uses np.nditer (which I placed in a function called draw_img_orig), I created 2 more:

    • One that iterates the input array Pythonicly (draw_img_regular_iter)

    • One that uses cached circles, and also iterates via np.nditer (draw_img_cache)

  • In terms of tests, there are 2 of them – each being performed on every of the 3 (above) approaches:

    • Speed: measure the time took to process a number of images

    • Accuracy: measure the output for a 32×32 input containing the interval [0, 255] (4 times)

Output:

JavaScript

Above there are the speed test results: as seen, your approach took a bit less than a second for 250 images!!! So I was right, I don’t know where your slowness comes from, but it’s not from here (maybe you got the measurements wrong?).
The regular method is a bit slower, while the cached one is ~2X faster.
I ran the code on my laptop:

  • Win 10 pc064
  • CPU: Intel i7 6820HQ @ 2.70GHz (fairly old)
  • GPU: not relevant, as I didn’t notice any spikes during execution

Regarding the accuracy test, all (3) output arrays are identical (there’s no message saying otherwise), here’s one saved image:

img0

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement