2015-07-29 2 views
0

я фигура пламя формы показаны ниже:Как обнаружить кольцевую область в изображениях и центрировать ее с помощью Python?

enter image description here

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

Есть ли какие-либо модули в Python, которые могут обнаруживать представление и центрировать его?

Возпроизводимо код

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.image as mpimg 
img=mpimg.imread('flame.png') 
lum_img = img[:,:,0] 
img_plot = plt.imshow(lum_img) 
img_plot.set_cmap('jet') 
plt.axis('Off') 
plt.show() 
+2

Вы могли бы попытаться создать собственное решение. Одна идея была бы вложенным циклом для строк и столбцов пикселей. Найдите минимальный столбец, для которого пиксель не является черным. Затем найдите максимум. Это будет левая и правая стороны вашего круга, давая вам диаметр (чтобы вы могли найти центр), и тогда вы могли бы обрезать ненужные черные пиксели. – Andrew

ответ

2

адаптировано из this answer, сделать края обнаружения и энергично подходят круг к контуру с помощью RANSAC:

from __future__ import print_function 
from skimage import io, feature, color, measure, draw, img_as_float 
import numpy as np 

image = img_as_float(color.rgb2gray(io.imread('flame.png'))) 
edges = feature.canny(image) 
coords = np.column_stack(np.nonzero(edges)) 

model, inliers = measure.ransac(coords, measure.CircleModel, 
           min_samples=3, residual_threshold=1, 
           max_trials=1000) 

print(model.params) 

rr, cc = draw.circle_perimeter(int(model.params[0]), 
           int(model.params[1]), 
           int(model.params[2]), 
           shape=image.shape) 

image[rr, cc] = 1 

import matplotlib.pyplot as plt 
plt.imshow(image, cmap='gray') 
plt.scatter(model.params[1], model.params[0], s=50, c='red') 
plt.axis('off') 
plt.savefig('/tmp/flame_center.png', bbox_inches='tight') 
plt.show() 

Это дает:

center of the flame

+0

Если вы хотите сделать процедуру еще более надежной, получите выпуклую оболочку всех ненулевых пикселей и сделайте круг подходящим к краю этого (или используйте какую-либо другую процедуру для фильтрации внутренних краев). –

4

Я думаю, что у вас есть много вариантов. Два простых подхода, которые приходят мне на ум, будут порождать ваше входное изображение с низким значением интенсивности, которое даст вам белый круг. Затем вы можете запустить преобразование Хафа для кругов на нем, чтобы найти центр.

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

# code derived from watershed example of scikit-image 
# http://scikit-image.org/docs/dev/auto_examples/plot_watershed.html 

import numpy as np 
import matplotlib.pyplot as plt 
from scipy import ndimage as ndi 

from skimage.morphology import watershed 
from skimage.feature import peak_local_max 
from skimage.color import rgb2gray 
from skimage.io import imread 

img = imread('flame.png') 
image = rgb2gray(img) > 0.01 

# Now we want to separate the two objects in image 
# Generate the markers as local maxima of the distance to the background 
distance = ndi.distance_transform_edt(image) 

# get global maximum like described in 
# http://stackoverflow.com/a/3584260/2156909 
max_loc = unravel_index(distance.argmax(), distance.shape) 

fig, axes = plt.subplots(ncols=4, figsize=(10, 2.7)) 
ax0, ax1, ax2, ax3 = axes 

ax0.imshow(img,interpolation='nearest') 
ax0.set_title('Image') 
ax1.imshow(image, cmap=plt.cm.gray, interpolation='nearest') 
ax1.set_title('Thresholded') 
ax2.imshow(-distance, cmap=plt.cm.jet, interpolation='nearest') 
ax2.set_title('Distances') 
ax3.imshow(rgb2gray(img), cmap=plt.cm.gray, interpolation='nearest') 
ax3.set_title('Detected centre') 
ax3.scatter(max_loc[1], max_loc[0], color='red') 

for ax in axes: 
    ax.axis('off') 

fig.subplots_adjust(hspace=0.01, wspace=0.01, top=1, bottom=0, left=0, 
        right=1) 
plt.show() 

plot output

Просто чтобы дать вам представление о том, насколько устойчива этот методе является, если Я выбираю очень плохой порог (image = rgb2gray(img) > 0.001 - слишком низкий, чтобы получить хороший круг), то результат почти такой же: bad result