簡體   English   中英

如何使用 Python PIL 和 Numpy 檢索其鄰居為黑色的白色像素的索引列表?

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

我一直在尋找幾個小時來找到類似的問題,但沒有什么能讓我滿意。 我的問題是:我有一個 PIL 圖像(代表一條運河)已經轉換成一個 Numpy 數組(使用 PIL 的“L”模式),我想檢索其鄰居為黑色的白色像素(它們的索引在事實上),沒有使用for 循環(圖像真的很大)。 我想到了np.where但我不知道我應該如何使用它來解決我的問題,我也不知道它是否會比使用for 循環更快(因為我的目標是以最快的速度達到這個目標解決方案)。

我希望我足夠清楚,我提前感謝您的回復!

編輯:例如,對於這個圖像(一個簡單的運河,它已經是一個黑白圖像,所以image.convert('L')在這里並不是很有用,但如果可能的話代碼應該是通用的),我會做這樣的事情:

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))

我希望盡快獲得l :) 我在下一張圖片中將我需要的像素標為紅色:此處

EDIT2:謝謝大家的幫助,它成功了!

您可以使用numba即時編譯器來加速循環。

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 

我想到的另一種可能性是使用最小過濾器。 但是,我預計它會比第一個提議的解決方案慢,但在其基礎上構建更多內容可能會有用。

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))

如果不考慮 memory 空間,我更喜歡像下面這樣的掩碼操作。

# 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))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM