1

I have this piece of code:

im = Image.open( 'image.png' )

eachPixel = im.load( )
width, height = im.size

for x in range( 0, width ):
    for y in range( 0, height ):
        if eachPixel[ x, y ] == ( 255, 0, 0 ):
            return = True

Works, i only need the position of the first pixel with this color, any way to reduce cpu usage? the image is 800x600, sleep not work because this is for while loop in realtime. Replacing colors, removing, crop, or using another lib, anything. Thanks! Sorry my bad english.

Siewdass Sf
  • 169
  • 1
  • 10
  • Probably replacing the code with a call to native C would speed things up, or there might be an optimised `numpy` function to do this task. – Ken Y-N Oct 29 '18 at 23:37
  • Possible duplicate of [Numpy: find first index of value fast](https://stackoverflow.com/questions/7632963/numpy-find-first-index-of-value-fast) – Ken Y-N Oct 29 '18 at 23:37
  • by first pixel do you mean the first one from the top left corner? Do you ONLY want to return the x,y location or you will do more actions with that data? – mostafazh Oct 29 '18 at 23:40
  • I only need the first pixel from top left corner, to store that location and no more but, in while loop i need speed up a little more. – Siewdass Sf Oct 30 '18 at 00:06

1 Answers1

2

You can do it with numpy like this. I used this image for testing:

enter image description here

The code is:

#!/usr/bin/env python3
import numpy as np                                                                          
from PIL import Image                                                                       

# Load image and make into NumPy array
im=np.array(Image.open('image.png').convert('RGB'),dtype=np.uint8)                          

# Colour we are looking for
red=np.array([255,0,0],dtype=np.uint8)                                                      

# Find the red pixels
np.where(np.all(im==red,axis=-1))                                                          

The result is:

(array([10, 10, 10, 11, 11, 11]), array([10, 11, 12, 10, 11, 12]))

which means the first red pixel is at 10,10, the second at 10,11 etc.

On my Mac, that takes 7.03ms for an 800x600 image.


Just to check, we can dump the image using ImageMagick like this and check where the red pixels are:

convert image.png txt:

Output

# ImageMagick pixel enumeration: 23,22,65535,srgb
0,0: (0,65535,0)  #00FF00  lime
1,0: (0,65535,0)  #00FF00  lime
2,0: (0,65535,0)  #00FF00  lime
...
...
7,10: (0,65535,0)  #00FF00  lime
8,10: (0,65535,0)  #00FF00  lime
9,10: (0,65535,0)  #00FF00  lime
10,10: (65535,0,0)  #FF0000  red    <--- red
11,10: (65535,0,0)  #FF0000  red    <--- red
12,10: (65535,0,0)  #FF0000  red    <--- red
13,10: (0,65535,0)  #00FF00  lime
14,10: (0,65535,0)  #00FF00  lime
...
...
8,11: (0,65535,0)  #00FF00  lime
9,11: (0,65535,0)  #00FF00  lime
10,11: (65535,0,0)  #FF0000  red   <--- red
11,11: (65535,0,0)  #FF0000  red   <--- red
12,11: (65535,0,0)  #FF0000  red   <--- red
13,11: (0,65535,0)  #00FF00  lime
14,11: (0,65535,0)  #00FF00  lime
15,11: (0,65535,0)  #00FF00  lime
...
...

If the red pixels are often near the top of the image, you could do 1/4 of the image at a time, or if you have 4 CPU cores, you could do 1/4 of the image on each core:

np.where(np.all(im[0:height//4,:,:]==red,axis=-1)) 

That takes 1.7ms instead of 7ms.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • My way, is stil more faster than this.. im thinking to build as cython module to se whats is the differents. – Siewdass Sf Oct 31 '18 at 12:50
  • Have you tried timing your code when the red pixel is at coordinates [800,600]? Yours will take longer the further the red pixel is from the top, my time will be constant. – Mark Setchell Oct 31 '18 at 15:52