David Fieser
David Fieser

Reputation: 33

Faster way to loop through each pixel in an image in python?

Need to run though an image in python and essentially calculate the average location of all acceptable pixels within a certain boundary. The image is black and white. The acceptable pixels have a value of 255 and the unacceptable pixels have a value of zero. The image is something like 2592x1944 and takes maybe 15 seconds to run. This will need to be looped several times. Is there a faster way to do this?

goodcount = 0
sumx=0
sumy=0
xindex=0
yindex=0

for row in mask:
    yindex+=1
    xindex=0
    for n in row:
        xindex+=1
        if n == 255:
            goodcount += 1
            sumx += xindex
            sumy += yindex

if goodcount != 0:

    y = int(sumy / goodcount)
    x = int(sumx / goodcount)

Upvotes: 2

Views: 666

Answers (2)

Mark Setchell
Mark Setchell

Reputation: 207465

I think you are looking for the centroid of the white pixels, which OpenCV will find for you very fast:

enter image description here

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image as greyscale
im = cv2.imread('star.png')

# Make greyscale version
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

# Ensure binary
_, grey = cv2.threshold(grey,127,255,0)

# Calculate moments
M = cv2.moments(grey)

# Calculate x,y coordinates of centre
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])

# Mark centroid with circle, and tell user
cv2.circle(im, (cX, cY), 10, (0, 0, 255), -1)
print(f'Centroid at location: {cX},{cY}')

# Save output file
cv2.imwrite('result.png', im)

enter image description here

Sample Output

Centroid at location: 1224,344

That takes 381 microseconds on the 1692x816 image above, and rises to 1.38ms if I resize the image to the dimensions of your image... I'm calling that a 10,800x speedup 🤣

Upvotes: 1

yut23
yut23

Reputation: 3064

np.where() will return arrays of the indices where a condition is true, which we can average (adding 1 to match your indexing) and cast to an integer:

if np.any(mask == 255):
    y, x = [int(np.mean(indices + 1)) for indices in np.where(mask == 255)]

Upvotes: 4

Related Questions