使用PIL查找指定区域中的所有像素坐标,内核崩溃

时间:2018-12-12 23:20:16

标签: python python-imaging-library stack-overflow

我有一些代码可以找到图像区域内的所有像素。该区域由共享相同原点的两条直线界定,并一直延伸到图像的边缘(楔形)。我为该函数提供了该区域内部的起点作为参数,并使用递归获取其中的所有像素。问题在于它仅适用于很小的“楔子”。

import threading
threading.stack_size(99999999)

import sys
sys.setrecursionlimit(2**30)

pix=im.load()
pixels=[]
memo=[]
count=0

def flood_wedge(x,y):
    global count
    count+=1
    #memo records every pixel visited 
    memo.append([x,y])
    if ([x,y] in pixels) or ([x,y] in pixels_1) or ([x,y] in pixels_2):
        pass
    else:
        try:
            #if (x,y) is outside the image, pix[x,y] returns an error 
            pix[x,y]=(256,51,51)
            #pixels is the desired list
            pixels.append([x,y])
        except:
            pass
        else:
            if ([x+1,y] not in memo):
                flood_wedge(x+1,y)
            if ([x-1,y] not in memo):
                flood_wedge(x-1,y)
            if ([x,y+1] not in memo):
                flood_wedge(x,y+1)
            if ([x,y-1] not in memo):
                flood_wedge(x,y-1)

我尝试增加递归限制,尽管深度不一定是问题。如果增加,内核将崩溃。我尝试增加堆栈大小,但没有任何区别。该代码实际上运行速度非常快,但是稍微增加区域的大小会导致此问题。最终,我需要在大图像(.tif)上使用它。

sample small wedge on a 946x710 image

2 个答案:

答案 0 :(得分:1)

我认为您实际上是想运行“连接组件分析” “标签” ,为每个分配唯一的编号(标签)” blob” (已连接(触摸)像素)。

您可以使用记录在here中的 OpenCV findContours()进行操作,也可以使用 scipy 的{{1} },尝试一下似乎很有趣。

我想确保我的方法可以使用多个“斑点”,因此我又添加了两行与楔形相同颜色的行:

enter image description here

该代码非常不言自明,但是我想提请您注意以下几点。

我制作的遮罩图像到处都是黑色,除了图像与种子像素的颜色相同,而在那些地方为白色:

enter image description here

用于描述哪些像素被视为连接到中心像素的默认SE(结构元素)为:

label()

之所以称为4连接,是因为中心像素连接到其北,东,南和西的4个像素。由于您的楔形不是矩形,因此我们还需要将对角线接触的像素视为邻居。这意味着8位连接,如下所示:

SE = 0 1 0
     1 1 1
     0 1 0

代码如下:

SE = 1 1 1
     1 1 1
     1 1 1

以下是输出:

#!/usr/bin/env python3

from scipy import ndimage
from scipy.ndimage import label, generate_binary_structure
import numpy as np
from PIL import Image

# Load image and ensure RGB - just in case palettised
im = Image.open("sky.png").convert("RGB")

# Make numpy array from image
npimage = np.array(im, dtype=np.uint8)

# Assume we were told to take pixel [17,483] as our seed
seed = npimage[17,483]

# If we had been given a seed colour instead, e.g. red, we would do
# seed = np.array((255,0,0), dtype=np.uint8)

# Make greyscale mask image, generally black but white where same colour as seed
mask = (np.all((npimage==seed),axis=-1)*255).astype(np.uint8) 

# The default SE (structuring element) is for 4-connectedness, i.e. only pixels North, South, East and West of another are considered connected.
# Pixels in our wedge are 8-connected, i.e. N, NE, E, SE, S, SW, W, NW, so we need a corresponding SE
SE = generate_binary_structure(2,2)   

# Now run a labelling, or "Connected Components Analysis"
# Each "blob" of connected pixels matching our seed will get assigned a unique number in the new image called "labeled"
labeled, nr_objects = ndimage.label(mask, structure=SE)

print('Num objects found: {}'.format(nr_objects))

# Get label assigned to our blob, and its area
ourlabel = labeled[17,483]
area     = np.bincount(labeled.flat)[ourlabel:ourlabel+1]
print('Our blob got label: {} and has area: {}'.format(ourlabel,area))

# Now print list of pixels in our blob
print(*np.argwhere(labeled==ourlabel))

您可以使用 ImageMagick 在命令行中更简单地执行此操作,该工具已安装在大多数Linux发行版中,并且可用于macOS和Windows。

首先,将与楔形不同的所有颜色变成黑色像素:

Num objects found: 3
Our blob got label: 1 and has area: [530]
[  0 475] [  0 476] [  0 477] [  0 478] [  0 479] [  0 480] [  0 481] [  0 482] [  0 483] [  0 484] [  0 485] [  0 486] [  0 487] [  0 488] [  0 489] [  0 490] [  0 491] [  0 492] [  0 493] [  0 494] [  0 495] [  0 496] [  0 497] [  0 498] [  0 499] [  0 500] [  0 501] [  0 502] [  0 503] [  0 504] [  0 505] [  1 475] [  1 476] [  1 477] [  1 478] [  1 479] [  1 480] [  1 481] [  1 482] [  1 483] [  1 484] [  1 485] [  1 486] [  1 487] [  1 488] [  1 489] [  1 490] [  1 491] [  1 492] [  1 493] [  1 494] [  1 495] [  1 496] [  1 497] [  1 498] [  1 499] [  1 500] [  1 501] [  1 502] [  1 503] [  1 504] [  2 475] [  2 476] [  2 477] [  2 478] [  2 479] [  2 480] [  2 481] [  2 482] [  2 483] [  2 484] [  2 485] [  2 486] [  2 487] [  2 488] [  2 489] [  2 490] [  2 491] [  2 492] [  2 493] [  2 494] [  2 495] [  2 496] [  2 497] [  2 498] [  2 499] [  2 500] [  2 501] [  2 502] [  2 503] [  3 475] [  3 476] [  3 477] [  3 478] [  3 479] [  3 480] [  3 481] [  3 482] [  3 483] [  3 484] [  3 485] [  3 486] [  3 487] [  3 488] [  3 489] [  3 490] [  3 491] [  3 492] [  3 493] [  3 494] [  3 495] [  3 496] [  3 497] [  3 498] [  3 499] [  3 500] [  3 501] [  3 502] [  4 475] [  4 476] [  4 477] [  4 478] [  4 479] [  4 480] [  4 481] [  4 482] [  4 483] [  4 484] [  4 485] [  4 486] [  4 487] [  4 488] [  4 489] [  4 490] [  4 491] [  4 492] [  4 493] [  4 494] [  4 495] [  4 496] [  4 497] [  4 498] [  4 499] [  4 500] [  4 501] [  5 475] [  5 476] [  5 477] [  5 478] [  5 479] [  5 480] [  5 481] [  5 482] [  5 483] [  5 484] [  5 485] [  5 486] [  5 487] [  5 488] [  5 489] [  5 490] [  5 491] [  5 492] [  5 493] [  5 494] [  5 495] [  5 496] [  5 497] [  5 498] [  5 499] [  5 500] [  6 475] [  6 476] [  6 477] [  6 478] [  6 479] [  6 480] [  6 481] [  6 482] [  6 483] [  6 484] [  6 485] [  6 486] [  6 487] [  6 488] [  6 489] [  6 490] [  6 491] [  6 492] [  6 493] [  6 494] [  6 495] [  6 496] [  6 497] [  6 498] [  6 499] [  7 475] [  7 476] [  7 477] [  7 478] [  7 479] [  7 480] [  7 481] [  7 482] [  7 483] [  7 484] [  7 485] [  7 486] [  7 487] [  7 488] [  7 489] [  7 490] [  7 491] [  7 492] [  7 493] [  7 494] [  7 495] [  7 496] [  7 497] [  7 498] [  8 475] [  8 476] [  8 477] [  8 478] [  8 479] [  8 480] [  8 481] [  8 482] [  8 483] [  8 484] [  8 485] [  8 486] [  8 487] [  8 488] [  8 489] [  8 490] [  8 491] [  8 492] [  8 493] [  8 494] [  8 495] [  8 496] [  8 497] [  9 475] [  9 476] [  9 477] [  9 478] [  9 479] [  9 480] [  9 481] [  9 482] [  9 483] [  9 484] [  9 485] [  9 486] [  9 487] [  9 488] [  9 489] [  9 490] [  9 491] [  9 492] [  9 493] [  9 494] [  9 495] [  9 496] [ 10 475] [ 10 476] [ 10 477] [ 10 478] [ 10 479] [ 10 480] [ 10 481] [ 10 482] [ 10 483] [ 10 484] [ 10 485] [ 10 486] [ 10 487] [ 10 488] [ 10 489] [ 10 490] [ 10 491] [ 10 492] [ 10 493] [ 10 494] [ 10 495] [ 11 475] [ 11 476] [ 11 477] [ 11 478] [ 11 479] [ 11 480] [ 11 481] [ 11 482] [ 11 483] [ 11 484] [ 11 485] [ 11 486] [ 11 487] [ 11 488] [ 11 489] [ 11 490] [ 11 491] [ 11 492] [ 11 493] [ 11 494] [ 12 475] [ 12 476] [ 12 477] [ 12 478] [ 12 479] [ 12 480] [ 12 481] [ 12 482] [ 12 483] [ 12 484] [ 12 485] [ 12 486] [ 12 487] [ 12 488] [ 12 489] [ 12 490] [ 12 491] [ 12 492] [ 12 493] [ 13 475] [ 13 476] [ 13 477] [ 13 478] [ 13 479] [ 13 480] [ 13 481] [ 13 482] [ 13 483] [ 13 484] [ 13 485] [ 13 486] [ 13 487] [ 13 488] [ 13 489] [ 13 490] [ 13 491] [ 13 492] [ 14 475] [ 14 476] [ 14 477] [ 14 478] [ 14 479] [ 14 480] [ 14 481] [ 14 482] [ 14 483] [ 14 484] [ 14 485] [ 14 486] [ 14 487] [ 14 488] [ 14 489] [ 14 490] [ 14 491] [ 15 475] [ 15 476] [ 15 477] [ 15 478] [ 15 479] [ 15 480] [ 15 481] [ 15 482] [ 15 483] [ 15 484] [ 15 485] [ 15 486] [ 15 487] [ 15 488] [ 15 489] [ 15 490] [ 16 475] [ 16 476] [ 16 477] [ 16 478] [ 16 479] [ 16 480] [ 16 481] [ 16 482] [ 16 483] [ 16 484] [ 16 485] [ 16 486] [ 16 487] [ 16 488] [ 16 489] [ 17 474] [ 17 475] [ 17 476] [ 17 477] [ 17 478] [ 17 479] [ 17 480] [ 17 481] [ 17 482] [ 17 483] [ 17 484] [ 17 485] [ 17 486] [ 17 487] [ 17 488] [ 18 474] [ 18 475] [ 18 476] [ 18 477] [ 18 478] [ 18 479] [ 18 480] [ 18 481] [ 18 482] [ 18 483] [ 18 484] [ 18 485] [ 18 486] [ 18 487] [ 18 488] [ 19 474] [ 19 475] [ 19 476] [ 19 477] [ 19 478] [ 19 479] [ 19 480] [ 19 481] [ 19 482] [ 19 483] [ 19 484] [ 19 485] [ 19 486] [ 19 487] [ 20 474] [ 20 475] [ 20 476] [ 20 477] [ 20 478] [ 20 479] [ 20 480] [ 20 481] [ 20 482] [ 20 483] [ 20 484] [ 20 485] [ 20 486] [ 21 474] [ 21 475] [ 21 476] [ 21 477] [ 21 478] [ 21 479] [ 21 480] [ 21 481] [ 21 482] [ 21 483] [ 21 484] [ 21 485] [ 22 474] [ 22 475] [ 22 476] [ 22 477] [ 22 478] [ 22 479] [ 22 480] [ 22 481] [ 22 482] [ 22 483] [ 22 484] [ 23 474] [ 23 475] [ 23 476] [ 23 477] [ 23 478] [ 23 479] [ 23 480] [ 23 481] [ 23 482] [ 23 483] [ 24 474] [ 24 475] [ 24 476] [ 24 477] [ 24 478] [ 24 479] [ 24 480] [ 24 481] [ 24 482] [ 25 474] [ 25 475] [ 25 476] [ 25 477] [ 25 478] [ 25 479] [ 25 480] [ 25 481] [ 26 474] [ 26 475] [ 26 476] [ 26 477] [ 26 478] [ 26 479] [ 26 480] [ 27 474] [ 27 475] [ 27 476] [ 27 477] [ 27 478] [ 27 479] [ 28 474] [ 28 475] [ 28 476] [ 28 477] [ 28 478] [ 29 474] [ 29 475] [ 29 476] [ 29 477] [ 30 473] [ 30 474] [ 30 475] [ 30 476] [ 31 473] [ 31 474] [ 31 475] [ 32 473] [ 32 474] [ 33 473]

enter image description here

现在您已经了解了它的工作原理,再次执行相同的操作,但是这次继续并运行“连接组件分析”

convert sky.png -alpha off -fill black +opaque "srgb(255,51,51)" mask.png

示例输出

convert sky.png -alpha off -fill black +opaque "srgb(255,51,51)"  \
    -define connected-components:verbose=true                     \
    -connected-components 8 -normalize  output.png

这意味着找到了3个红色区域,即最后三行,其中Objects (id: bounding-box centroid area mean-color): 0: 946x707+0+0 472.5,353.1 665950 srgb(0,0,0) 3: 173x341+299+300 385.0,470.0 1531 srgb(255,51,51) 2: 33x201+599+200 615.0,300.0 811 srgb(255,51,51) 1: 33x34+473+0 484.5,11.0 530 srgb(255,51,51) <--- this is your wedge ,最后一个是区域33x34像素,位于左上角的473,0像素处,其面积为530像素与我们在Python中发现的像素相同。

答案 1 :(得分:0)

仅使用一张图像,很难确定它是否可以完全归纳为您的目的,但是在这种情况下它确实有效。如果楔块不总是位于顶部边缘,或者图像内容不太容易过滤掉,IT部门需要进行一些调整。不过,您似乎对将楔形定位在图像噪声中的位置非常了解,因此该部分可能对您无关紧要。为了防万一,我将其包括在内,但对您而言重要的部分可能在代码块的底部。剩下的就是我隔离楔子的方式。您应该能够标记图像中的对象,然后将这些线用作像素的边界点。

import imageio
import skimage
import numpy
import scipy.ndimage.filters
import skimage.io
import skimage.filters
import skimage.morphology


image = imageio.imread(r'C:\Users\Jeremiah\Pictures\wedge.png')
image_array = numpy.float64(image)

R_x = scipy.ndimage.filters.correlate(image_array[:, :, 0], [[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
G_x = scipy.ndimage.filters.correlate(image_array[:, :, 1], [[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
B_x = scipy.ndimage.filters.correlate(image_array[:, :, 2], [[1, 2, 1], [0, 0, 0], [-1, -2, -1]])

R_y = scipy.ndimage.filters.correlate(image_array[:, :, 0], [[1, 0 , -1], [2, 0, -2], [1, 0, -1]])
G_y = scipy.ndimage.filters.correlate(image_array[:, :, 1], [[1, 0 , -1], [2, 0, -2], [1, 0, -1]])
B_y = scipy.ndimage.filters.correlate(image_array[:, :, 2], [[1, 0 , -1], [2, 0, -2], [1, 0, -1]])

Jacobian_x = R_x**2 + G_x**2 + B_x**2
Jacobian_y = R_y**2 + G_y**2 + B_y**2
Jacobian_xy = R_x * R_y + G_x * G_y + B_x * B_y
Determinant = numpy.sqrt(numpy.fabs((Jacobian_x**2) - (2 * Jacobian_x * Jacobian_y) + (Jacobian_y**2) + 4 * (Jacobian_xy**2)))
Maximum_Eigenvalue = (Jacobian_x + Jacobian_y + Determinant) / 2
Edges = numpy.sqrt(Maximum_Eigenvalue)

Threshold = skimage.filters.threshold_mean(Edges)
Binary_Image = Edges > Threshold    
labeled_Edges, features = scipy.ndimage.label(Edges)

sliced = scipy.ndimage.find_objects(labeled_Edges)[0]
slices = image[sliced]

>>>(slice(0, 36, None), slice(471, 508, None))
>>>[[[  0   0   0 255]
   [  0   0   0 255]
   [  0   0   0 255]
   ...
   [255  51  51 255]
   [255 255 255 255]
   [  0   0   0 255]]

您想要的像素包含在这些切片中,不需要递归...我认为。