2015-04-03 2 views
13

Я представляю изображения в виде двухмерных массивов. У меня есть эта картина:Обнаружение края для изображения, хранящегося в матрице

original

Как я могу получить пикселы, которые непосредственно на границах серой области и раскрасить их?

colorized

Я хочу, чтобы получить координаты матричных элементов в зеленый и красный отдельно. У меня на матрице есть только белые, черные и серые области.

+0

Матрицы, как правило, не являются хорошим способом представления 2D-пиксельных данных ... это не то, на что нацелена их семантика. – Sneftel

+2

@ На самом деле матрицы Sneftel являются наиболее распространенными, если не единственными и лучшими, способ представлять изображения в таких библиотеках, как OpenCV, SimpleCV и т. Д. –

+1

Вы смешиваете матрицы с 2D-массивами. Первые имеют очень специфический набор операций, которые совершенно не имеют смысла применять к данным изображения. – Sneftel

ответ

0

Может быть, есть более элегантный способ сделать это ... , но в случае, если ваш массив является numpy массив с размерами (N,N) (серая шкала), вы можете сделать

import numpy as np 

# assuming black -> 0 and white -> 1 and grey -> 0.5 
black_reg = np.where(a < 0.1, a, 10) 
white_reg = np.where(a > 0.9, a, 10) 

xx_black,yy_black = np.gradient(black_reg) 
xx_white,yy_white = np.gradient(white_reg) 

# getting the coordinates 
coord_green = np.argwhere(xx_black**2 + yy_black**2>0.2) 
coord_red = np.argwhere(xx_white**2 + yy_white**2>0.2) 

Число 0.2 просто порог и его необходимо скорректировать.

+0

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

+0

@ begueradj: oh ... извините. Это требует небольшой модификации. Черный цвет соответствует числу '0' или' 1'? – plonser

+0

вы можете установить любое соглашение для определения элементов черного/белого и серого. –

0

Я думаю, что вы, вероятно, ищете метод обнаружения границ для изображений с серой шкалой. Есть много способов сделать это. Возможно, это может помочь http://en.m.wikipedia.org/wiki/Edge_detection. Для дифференциации краев между белым и серым и краями между черным и серым, попробуйте использовать локальную среднюю интенсивность.

2

Хотя ответ plonser может быть довольно прямым для реализации, я вижу, что он терпит неудачу, когда дело доходит до острых и тонких краев. Тем не менее, я предлагаю вам использовать часть своего подхода в качестве предварительной подготовки.
На втором этапе вы хотите использовать Marching Squares Algorithm. Согласно документации scikit-image, это

частным случаем алгоритма марширующих кубов (Lorensen, Уильям и Harvey E. Cline Маршевые Кубики:.. Высокое разрешение 3D Surface Алгоритм конструирования компьютерной графики (SIGGRAPH 87 Материалы) 21 (4) июля 1987, стр. 163-170

Там даже существует реализация Python как часть scikit-image пакета. Я использую этот алгоритм (мой собственный Fortran реализации, хотя) успешно для обнаружения границ глазных диаграмм в связях машиностроение.

объявления 1: Предварительная подготовка
Создайте копию изображения и сделать его два цвета только, например, черно-белый. Координаты остаются неизменными, но вы убедитесь, что алгоритм может правильно сделать да/нет-решение независимым от значений, которые вы используете в матричном представлении изображения.

Ad 2: Край обнаружения
Wikipedia, а также различные блоги предоставить вам довольно elaborate description алгоритма на различных языках, так что я не буду вдаваться в это детали. Однако позвольте мне дать вам несколько практических советов:

  1. Ваше изображение имеет открытые границы внизу. Вместо изменения алгоритма вы можете искусственно добавить еще одну строку пикселей (черный или серый, чтобы связать белые/серые области).
  2. Выбор начальной точки является критическим.Если обрабатывать не так много изображений, я предлагаю вам выбрать его вручную. В противном случае вам нужно будет определить правила. Поскольку алгоритм Marching Squares может начинаться где угодно внутри ограниченной области, вы можете выбрать любой пиксель заданного цвета/значения для обнаружения соответствующего края (сначала он начнет идти в одном направлении, чтобы найти край).
  3. Алгоритм возвращает точные 2D-позиции, например. (Х/у) -наборов. Вы можете
    • итерации по списку и раскрасить соответствующие пиксели путем присвоения другого значения или
    • создать mask для выбора части вашей матрицы и присвоить значение, которое соответствует другому цвету, например, зеленый или красный.

Наконец: Некоторая Постобработка
Я предложил добавить искусственную границу к изображению. Это имеет два преимущества: 1. Алгоритм маршевых квадратов работает из коробки. 2. Нет необходимости различать границу изображения и интерфейс между двумя областями внутри изображения. Просто удалите искусственную границу, как только вы закончите установку цветных краев - это приведет к удалению цветных линий на границе изображения.

7

Следующие, как мы надеемся, будут в порядке для ваших нужд (или, по крайней мере, помощи). Идея состоит в разделении на различные регионы с использованием логических проверок на основе пороговых значений. Кромки между этими областями, то можно обнаружить с помощью Numpy рулон, чтобы переместить пиксели в х и у и сравнения, чтобы увидеть, если мы на краю,

import matplotlib.pyplot as plt 
import numpy as np 
import scipy as sp 
from skimage.morphology import closing 

thresh1 = 127 
thresh2 = 254 

#Load image 
im = sp.misc.imread('jBD9j.png') 

#Get threashold mask for different regions 
gryim = np.mean(im[:,:,0:2],2) 
region1 = (thresh1<gryim) 
region2 = (thresh2<gryim) 
nregion1 = ~ region1 
nregion2 = ~ region2 

#Plot figure and two regions 
fig, axs = plt.subplots(2,2) 
axs[0,0].imshow(im) 
axs[0,1].imshow(region1) 
axs[1,0].imshow(region2) 

#Clean up any holes, etc (not needed for simple figures here) 
#region1 = sp.ndimage.morphology.binary_closing(region1) 
#region1 = sp.ndimage.morphology.binary_fill_holes(region1) 
#region1.astype('bool') 
#region2 = sp.ndimage.morphology.binary_closing(region2) 
#region2 = sp.ndimage.morphology.binary_fill_holes(region2) 
#region2.astype('bool') 

#Get location of edge by comparing array to it's 
#inverse shifted by a few pixels 
shift = -2 
edgex1 = (region1^np.roll(nregion1,shift=shift,axis=0)) 
edgey1 = (region1^np.roll(nregion1,shift=shift,axis=1)) 
edgex2 = (region2^np.roll(nregion2,shift=shift,axis=0)) 
edgey2 = (region2^np.roll(nregion2,shift=shift,axis=1)) 

#Plot location of edge over image 
axs[1,1].imshow(im) 
axs[1,1].contour(edgex1,2,colors='r',lw=2.) 
axs[1,1].contour(edgey1,2,colors='r',lw=2.) 
axs[1,1].contour(edgex2,2,colors='g',lw=2.) 
axs[1,1].contour(edgey2,2,colors='g',lw=2.) 
plt.show() 

который дает following. Для простоты я использую roll с инверсией каждого региона. Вы можете катить каждую последующую область на следующую, чтобы обнаружить края.

Спасибо @Kabyle за вознаграждение, это проблема, которую я потратил некоторое время на поиск решения. Я пробовал scipy skeletonize, feature.canny, модуль топологии и openCV с ограниченным успехом ... Этот способ был самым надежным для моего случая (отслеживание интерфейса капель). Надеюсь, поможет!

+0

Извините, вы только что видели индексы, их можно получить, используя что-то вроде 'np.ma.nonzero (~ edgex1)' –

+0

Большое вам спасибо за это большое усилие, я попробую ваше решение и посмотрю, работает ли оно –

+1

. Это хорошая попытка, но посмотрите, что происходит вокруг маленького островка серого цвета в середине белой области ... Также рулон имеет немного проблем на края изображения. –

1

В основном по предложению следовать за pyStarter о использовании походного квадратного алгоритма из scikit-изображений, желаемые контуры МОГЛИ могут быть извлечены с помощью следующего кода:

import matplotlib.pyplot as plt 
import numpy as np 
import scipy as sp 
from skimage import measure 
import scipy.ndimage as ndimage 
from skimage.color import rgb2gray 
from pprint import pprint 
#Load image 
im = rgb2gray(sp.misc.imread('jBD9j.png')) 

n, bins_edges = np.histogram(im.flatten(),bins = 100) 
# Skip the black area, and assume two distinct regions, white and grey 
max_counts = np.sort(n[bins_edges[0:-1] > 0])[-2:] 
thresholds = np.select(
    [max_counts[i] == n for i in range(max_counts.shape[0])], 
    [bins_edges[0:-1]] * max_counts.shape[0] 
) 
# filter our the non zero values 
thresholds = thresholds[thresholds > 0] 


fig, axs = plt.subplots() 
# Display image 
axs.imshow(im, interpolation='nearest', cmap=plt.cm.gray) 
colors = ['r','g'] 
for i, threshold in enumerate(thresholds): 
    contours = measure.find_contours(im, threshold) 

    # Display all contours found for this threshold 
    for n, contour in enumerate(contours): 
     axs.plot(contour[:,1], contour[:,0],colors[i], lw = 4) 

axs.axis('image') 
axs.set_xticks([]) 
axs.set_yticks([])   
plt.show() 

Edges!

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

3

Существует очень простое решение: по определению любой пиксель, который имеет как белые, так и серые соседи, находится на вашем «красном» краю, а серые и черные соседи находятся на «зеленом» краю. Самые светлые/самые темные соседи возвращаются максимальными/минимальными фильтрами в skimage.filters.rank, а двоичная комбинация масок пикселей с самым светлым/самым темным соседом белого/серого или серого/черного соответственно создает ребра.

Результат:

enter image description here

проработанный решение:

import numpy 
import skimage.filters.rank 
import skimage.morphology 
import skimage.io 

# convert image to a uint8 image which only has 0, 128 and 255 values 
# the source png image provided has other levels in it so it needs to be thresholded - adjust the thresholding method for your data 
img_raw = skimage.io.imread('jBD9j.png', as_grey=True) 
img = numpy.zeros_like(img, dtype=numpy.uint8) 
img[:,:] = 128 
img[ img_raw < 0.25 ] = 0 
img[ img_raw > 0.75 ] = 255 

# define "next to" - this may be a square, diamond, etc 
selem = skimage.morphology.disk(1) 

# create masks for the two kinds of edges 
black_gray_edges = (skimage.filters.rank.minimum(img, selem) == 0) & (skimage.filters.rank.maximum(img, selem) == 128) 
gray_white_edges = (skimage.filters.rank.minimum(img, selem) == 128) & (skimage.filters.rank.maximum(img, selem) == 255) 

# create a color image 
img_result = numpy.dstack([img,img,img]) 

# assign colors to edge masks 
img_result[ black_gray_edges, : ] = numpy.asarray([ 0, 255, 0 ]) 
img_result[ gray_white_edges, : ] = numpy.asarray([ 255, 0, 0 ]) 

imshow(img_result) 

P.S. Пиксели, у которых есть черные и белые соседи, или все три соседства цветов, находятся в неопределенной категории. Приведенный выше код не окрашивает их. Вам нужно выяснить, как вы хотите, чтобы результат был окрашен в этих случаях; но легко расширить этот подход, чтобы создать для этого еще одну маску или две.

P.S. Края имеют ширину в два пикселя. Об этом не обойтись без дополнительной информации: края находятся между двумя областями, и вы не определили, какую из двух областей вы хотите, чтобы они перекрывались в каждом случае, поэтому единственное симметричное решение состоит в том, чтобы перекрывать обе области одним пиксели.

P.S. Это считает сам пиксель своим соседом. Изолированный белый или черный пиксель на сером или наоборот будет рассматриваться как край (а также все пиксели вокруг него).

Смежные вопросы