Как подсчитать ошибки в изображении?

У меня есть изображение, как показано ниже, и я хотел бы подсчитать количество ошибок (непрерывных капель цвета/серого), которые отображаются на нем с помощью Python. Как я мог сделать это лучше всего?

Bugs on a noisy background

Я до сих пор смотрел на ImageChops, SciPy и PIL, но я не уверен, что я могу/должен использовать...

Я думаю, что могу использовать ndimage.gaussian_filter(), а затем scipy.ndimage.measurements.label() просто не уверен, как использовать последний, чтобы подсчитать мои голубые точки в гауссовом изображении... он выглядит примерно как enter image description here


Хорошо,

С приведенным выше изображением я получил этот код:

#! /usr/bin/python

import numpy as np
import scipy
import pylab
import pymorph
import mahotas
from PIL import Image
import PIL.ImageOps
from scipy import ndimage

image = Image.open('bugs.jpg')   
inverted_image = PIL.ImageOps.invert(image)    
inverted_image.save('in_bugs.jpg')
dna = mahotas.imread('in_bugs.jpg')
#pylab.imshow(dna)
pylab.gray()
#pylab.show()
T = mahotas.thresholding.otsu(dna)
pylab.imshow(dna > T)
#pylab.show()
dnaf = ndimage.gaussian_filter(dna, 8)
T = mahotas.thresholding.otsu(dnaf)
pylab.imshow(dnaf > T)
#pylab.show()
labeled,nr_objects = ndimage.label(dnaf > T)
print nr_objects
pylab.imshow(labeled)
pylab.jet()
pylab.show()

проблема в том, что это возвращает мне число 5, которое не так плохо, но мне нужно, чтобы он был более точным, я хочу видеть два. Как я могу это сделать? Помогло ли это размыть изображение перед применением гауссового фильтра?

Спасибо за помощь!

Рон

Ответ 1

Ваша гауссовская фильтрация в основном прекрасна, но вы рассматриваете радиус, который больше, чем нужно для задачи. Например, рассмотрим в качестве примера ядро ​​радиуса 15. Вот представление того, что мы получаем:

enter image description here

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

enter image description here

Учитывая только часть гистограммы, мы можем лучше видеть часть интересующих нас данных: темные пятна.

enter image description here

Итак, с простым порогом в 0.5 это результат (который соответствует тому, где находятся ошибки):

enter image description here

В зависимости от того, как вы реализуете (или библиотеки, которые используете внедрение) связанные функции, это пороговое значение будет отличаться. Но, посмотрев на гистограмму, вы сможете обнаружить хороший порог. Теперь, если вы не хотите угадать этот порог, посмотрев на гистограмму, вам нужно предварительно обработать изображение за пределами гауссовой фильтрации. Сделав этот шаг в хорошем манере, ваше изображение станет достаточно простым, чтобы методы, подобные тому, который дал Otsu, могут автоматически найти порог, которым вы пользуетесь. Выполняя морфологическое закрытие с последующим морфологическим открытием, а затем бинаризуя Otsu, это результат:

enter image description here

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

EDIT:

Поскольку вопрос теперь включает некоторый код, я почувствовал необходимость объяснить, почему неправильно использовать Otsu в качестве кода, который он делает. Метод, заданный Otsu для порогового значения, фактически ожидает, что данные будут бимодальными, но, как показывают вышеприведенные графики гистограммы, здесь это не так. Otsu предоставит порог, который слишком близок к огромному пику справа, в то время как хорошая точка в 0.5 находится очень далеко от этого. Чтобы воспроизвести первый результат, показанный в этом ответе, вот какой-то базовый код:

import sys
import numpy
from PIL import Image
from scipy.ndimage import gaussian_filter, label

img = Image.open(sys.argv[1]).convert('L')
im = numpy.array(img)

im_g = gaussian_filter(im, 3)
im_norm = (im_g - im_g.min()) / (float(im_g.max()) - im_g.min())
im_norm[im_norm < 0.5] = 0
im_norm[im_norm >= 0.5] = 1

result = 255 - (im_norm * 255).astype(numpy.uint8)
print u"Objects: %d" % label(result)[1]

Image.fromarray(result).save(sys.argv[2])

Обратите внимание, что этот код использует sigma = 3 (хотя первоначально использовался 7.5) для гауссовского ядра, из которого scipy внутренне строит окно с радиусом, в 4 раза превышающим его. Для этого конкретного изображения большой диапазон sigma работает так же хорошо, начиная с 2 до 10, должны давать одинаковые результаты - обнаружено 2 объекта.

Ответ 2

Это задача компьютерного видения, которую вы могли бы решить с помощью популярного OpenCV.

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


Некоторые ресурсы для изучения: