Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find nearest white pixel to a given pixel location openCV

Tags:

python

opencv

I've got a binary image where I need to select the nearest white pixel to a given set of pixel coordinates.

For example, if I click on a pixel I need to have Python search for the nearest pixel with a value greater than 0 then return that pixel's coordinates.

Any thoughts?

I figured I should add what I've done so far.

import cv2
import numpy as np

img = cv.imread('depth.png', 0) # reads image as grayscale
edges = cv2.Canny(img, 10, 50)

white_coords = np.argwhere(edges == 255) # finds all of the white pixel coordinates in the image and places them in a list.

# this is where I'm stuck
like image 568
tpubbsGIS Avatar asked Jul 20 '17 21:07

tpubbsGIS


2 Answers

  • First use cv2.findNonZero to get a numpy array of coordinates of all the white pixels.

  • Next, calculate distance from the clicked target point (Pythagoras theorem)

  • Use numpy.argmin to find the position of the lowest distance.

  • Return the coordinates of the corresponding nonzero pixel.

Example script:

import cv2
import numpy as np

# Create a test image
img = np.zeros((1024,1024), np.uint8)

# Fill it with some white pixels
img[10,10] = 255
img[20,1000] = 255
img[:,800:] = 255


TARGET = (255,255)


def find_nearest_white(img, target):
    nonzero = cv2.findNonZero(img)
    distances = np.sqrt((nonzero[:,:,0] - target[0]) ** 2 + (nonzero[:,:,1] - target[1]) ** 2)
    nearest_index = np.argmin(distances)
    return nonzero[nearest_index]

    
print find_nearest_white(img, TARGET)
    

Which prints:

[[10 10]]

and takes around 4ms to complete, since it takes advantage of optimized cv2 and numpy functions.


Alternatively, you could go for a pure numpy solution, and as you have already attempted, use numpy.argwhere instead of cv2.findNonZero:

def find_nearest_white(img, target):
    nonzero = np.argwhere(img == 255)
    distances = np.sqrt((nonzero[:,0] - TARGET[0]) ** 2 + (nonzero[:,1] - TARGET[1]) ** 2)
    nearest_index = np.argmin(distances)
    return nonzero[nearest_index]

Which prints:

[10 10]

However, for me this is slightly slower, at around 9 ms per run.

like image 140
Dan Mašek Avatar answered Oct 12 '22 15:10

Dan Mašek


Thoughts, yes! Start looping from the given pixel, in first iteration check for all the pixels surrounding the given pixel, if a white pixel is not found, increment the distance by 1 and check if any pixel in the circumscribing perimeter of the given pixel is white, continue looping until you find a white pixel or go out of bounds.

like image 28
Enigma Avatar answered Oct 12 '22 14:10

Enigma