简体   繁体   中英

How to retrieve a list of indexes of white pixels whose neighbor are black using Python PIL and Numpy?

I've been looking for hours to find a question similar, but nothing has satisfied me. My problem is: I've a PIL image (representing a canal) already converted into a Numpy array (using the "L" mode of PIL), and I'd like to retrieve the white pixels whose neighbor are black (their indexes in fact), without using for loops (the image is really huge). I thought of np.where but I don't know how I should use it to solve my problem, and I also don't know if it would be faster than using for loops (because my aim would be reaching this goal with the fastest solution).

I hope I'm clear enough, and I thank you in advance for your response!

EDIT: for example, with this image ( a simple canal , it is already a black and white image, so the image.convert('L') isn't really useful here, but the code should be generic if possible), I'd do something like that:

import numpy as np
from PIL import Image

image = Image.open(canal)
image = image.convert("L")
array = np.asarray(image)
l = []
for i in range(1, len(array) - 1):
    for j in range(1, len(array[0]) - 1):
        if array[i][j] == 255 and (array[i+1][j] == 0 or array[i-1][j] == 0 or array[i][j+1] == 0 or array[i][j-1] == 0):
             l.append((i, j))

and I'd hope to obtain l as fast as possible:) I've colored the pixels I need in red in the next image: here .

EDIT2: thank you all for the help, it worked!

You could use the numba just-in-time compiler to speed up your loop.

from numba import njit

@njit
def find_highlow_pixels(img):
    pixels = []
    for j in range(1, img.shape[0]-1):
        for i in range(1, img.shape[1]-1):
            if (
                img[j, i] == 255 and (
                    img[j-1, i]==0 or img[j+1,i]==0 or 
                    img[j, i-1]==0 or img[j, i+1]==0
                )
            ):
                pixels.append((j, i))
    return pixels 

Another possibility that came to my mind would be using the minimum filter. However, I would expect it to be slower than the first proposed solution, but could be useful to build more on top of it.

import numpy as np
from scipy.ndimage import minimum_filter

# create a footprint that only takes the neighbours into account
neighbours = (np.arange(9) % 2 == 1).reshape(3,3)

# create a mask of relevant pixels, img should be your image as array
mask = np.logical_and(
    img == 255,
    minimum_filter(img, footprint=neighbours) == 0
)

# get indexes
indexes = np.where(mask)

# as list
list(zip(*indexes))

If memory space is not considered, I prefer manipulation of masks like the following.

# Step 1: Generate two masks of white and black.
mask_white = img == 255
mask_black = img == 0

# Step 2: Apply 8-neighborhood dilation on black mask
# if you want to use numpy only, you need to implement dilation by yourself.
# define function of 8-neighborhood dilation
def dilate_8nb(m):
    index_row, index_col = np.where(m)
    ext_index_row = np.repeat(index_row,9)
    ext_index_col = np.repeat(index_col,9)
    ext_index_row.reshape(-1,9)[:, :3]  += 1
    ext_index_row.reshape(-1,9)[:, -3:]  -= 1
    ext_index_col.reshape(-1,9)[:, ::3]  += 1
    ext_index_col.reshape(-1,9)[:, 2::3]  -= 1
    ext_index_row = np.clip(ext_index_row, 0, m.shape[0]-1)
    ext_index_col = np.clip(ext_index_col, 0, m.shape[1]-1)
    ret = m.copy()
    ret[ext_index_row, ext_index_col] = True
    return ret

ext_mask_black = dilate_8nb(mask_black)
# or just using dilation in scipy
# from scipy import ndimage
# ext_mask_black = ndimage.binary_dilation(mask_black, structure=ndimage.generate_binary_structure(2, 2))

# Step 3: take the intersection of mask_white and ext_mask_black
mask_target = mask_white & ext_mask_black

# Step 4: take the index using np.where
l = np.where(mask_target)

# modify this type to make it consistency with your result
l = list(zip(*l))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM