Найти все пиксельные координаты в указанной области, используя PIL, ядро ​​вылетает - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть код для поиска всех пикселей в пределах области изображения.Эта область ограничена двумя прямыми линиями, имеющими одинаковое происхождение, и продолжается до края изображения (клиновидная форма).Я предоставляю функции начальную точку внутри этой области в качестве параметра и использую рекурсию, чтобы получить все пиксели внутри нее.Проблема в том, что он работает только для очень маленьких «клиньев».

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

образец небольшого клина на изображении 946x710

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Я думаю, что вы действительно хотите запустить «Анализ подключенных компонентов» или «маркировку» , которая присваивает уникальный номер (метку) каждому «blob» подключенных (соприкасающихся) пикселей.

Вы можете сделать это с помощью OpenCV 'findContours(), что задокументировано здесь , или вы можете использовать scipy label(), который кажется забавным, чтобы попробовать.

Я хотел убедиться, что мой метод работает с более чем одним «блобом», поэтому я добавил еще две строки того же цвета, что иВаш клин:

enter image description here

Код довольно понятен, но я хотел обратить ваше внимание на пару вещей.

Изображение маски, которое я создаю, везде черное, кроме случаев, когда изображение того же цвета, что и исходный пиксель, и белое в тех местах:

enter image description here

SE (Структурный элемент) по умолчанию для описания того, какие пиксели считаются подключенными к центральному пикселю:

SE = 0 1 0
     1 1 1
     0 1 0

, который называется 4-conсвязано, потому что центральный пиксель соединен с 4 пикселями к северу, востоку, югу и западу от него.Так как ваш клин не прямоугольный, мы должны также рассматривать пиксели, соприкасающиеся по диагонали, как соседей.Это означает 8 подключений и выглядит так:

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

Вот вывод:

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]

Вы можете сделать это, возможно, проще, просто в командной строке с помощью ImageMagick , который установлен на большинстве дистрибутивов Linux и доступен для macOS и Windows.

Во-первых, сделайте все, что есть.не того же красного цвета, что и ваш клин, в черные пиксели:

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

enter image description here

Теперь, когда вы увидели, как это работает, сделайте то же самое сновано на этот раз продолжайте и запустите «Анализ подключенных компонентов» :

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

Пример вывода

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

Это означает 3были обнаружены красные области, а именно последние три строки, где srgb(255,51,51), а последняя - это область 33x34 пикселей, расположенная в 473,0 пикселей поперек от верхнего левого угла, и она имеет площадь 530 пикселей, точно такую ​​же, как мы нашли сPython.

0 голосов
/ 13 декабря 2018

Имея только одно изображение, трудно сказать, будет ли оно полностью обобщено для ваших целей, но в этом случае оно работает.Это потребует некоторой настройки, если клин не всегда находится на верхнем краю или если содержимое изображения не так легко отфильтровать.Похоже, вы довольно хорошо справляетесь с поиском клина среди шума изображения, так что эта часть, вероятно, не имеет значения для вас.Я включу его на всякий случай, но важная часть для вас, вероятно, находится внизу блока кода.Остальное только то, как я изолировал клин. Вы должны иметь возможность пометить объекты на изображении, а затем использовать линии как ограничивающую точку для пикселей.

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

Пиксели, которые вы хотите, содержатся вэти кусочки, рекурсия не нужна ... я думаю.

...