Извлечение изображения переднего плана в виде маски с помощью порогового значения

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

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

Изображение с фоновым шумом

Моя попытка состояла в том, чтобы использовать Otsu thresholding. Я сделал это в Python следующим образом:

from skimage.filter import threshold_otsu
import os.path as path
import matplotlib.pyplot as plt

img = io.imread(path.expanduser('~/Desktop/62.jpg'))
r_t = threshold_otsu(img[:, :, 0])
g_t = threshold_otsu(img[:, :, 1])
b_t = threshold_otsu(img[:, :, 2])

m = np.zeros((img.shape[0], img.shape[1]), dtype=np.uint8)
mask = (img[:, :, 0] < r_t) & (img[:, :, 1] < g_t) & (img[:, :, 2] < b_t)
m[~mask] = 255

plt.imshow(m)
plt.show()

Это дает пороговое значение R, G, B как (62 67 64), что немного выше. Результат:

Результат Оцу

Это изображение также является одним из изображений, где Otsu thresholding работал лучше всего. Если я использую ручное пороговое значение, например значение 30, оно работает достаточно хорошо. Результат:

Вручную

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


person Luca    schedule 03.02.2015    source источник


Ответы (1)


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

Глядя на пакет scikit-image.filter есть несколько других пороговых методов. Я попробовал их все и обнаружил, что threshold_isodata работает очень хорошо, давая почти то же изображение, что и желаемое изображение. Поэтому я рекомендую алгоритм изодаты.

Пример:

import numpy as np
import skimage.io as io
import skimage.filter as filter
import matplotlib.pyplot as plt

img = io.imread('62.jpg')
gray = np.sum(img, axis=2) # summed up over red, green, blue
#threshold = filter.threshold_otsu(gray) # delivers very high threshold
threshold = filter.threshold_isodata(gray) # works extremely well
#threshold = filter.threshold_yen(gray) # delivers even higher threshold
print(threshold)

plt.imshow(gray > threshold)
plt.show()

дает:

введите здесь описание изображения

person Trilarion    schedule 03.02.2015
comment
Это очень хорошо. Я попробую с некоторыми другими изображениями и посмотрю, насколько надежным он может быть. - person Luca; 03.02.2015
comment
@Luca, если у вас есть другие изображения, а некоторые из них не работают, просто выберите три худших или около того и спросите еще раз (я бы предпочел в новом вопросе). - person Trilarion; 03.02.2015
comment
Спасибо Триллион. Это очень любезно с вашей стороны. Я буду. У меня есть ощущение, что я могу заставить это работать сейчас - person Luca; 03.02.2015