我有一些代码可以找到图像区域内的所有像素。该区域由共享相同原点的两条直线界定,并一直延伸到图像的边缘(楔形)。我为该函数提供了该区域内部的起点作为参数,并使用递归获取其中的所有像素。问题在于它仅适用于很小的“楔子”。
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)上使用它。
答案 0 :(得分:1)
我认为您实际上是想运行“连接组件分析” 或“标签” ,为每个分配唯一的编号(标签)” blob” (已连接(触摸)像素)。
您可以使用记录在here中的 OpenCV 的findContours()
进行操作,也可以使用 scipy 的{{1} },尝试一下似乎很有趣。
我想确保我的方法可以使用多个“斑点”,因此我又添加了两行与楔形相同颜色的行:
该代码非常不言自明,但是我想提请您注意以下几点。
我制作的遮罩图像到处都是黑色,除了图像与种子像素的颜色相同,而在那些地方为白色:
用于描述哪些像素被视为连接到中心像素的默认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]
现在您已经了解了它的工作原理,再次执行相同的操作,但是这次继续并运行“连接组件分析” :
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]]
您想要的像素包含在这些切片中,不需要递归...我认为。