2013-04-19 10 views
5

Czy istnieje dobry algorytm wykrywania cząstek na zmieniającym się natężeniu tła? Na przykład, jeśli mam następujący obraz:Zliczanie cząsteczek za pomocą przetwarzania obrazu w pytonie

fluorescence

Czy istnieje sposób policzyć małe białe cząstki, nawet przy wyraźnie różnym tle, który pojawia się w kierunku lewym dolnym rogu?

być trochę bardziej jasne, chciałbym oznaczyć obraz i liczyć cząstki z algorytmu, który znajdzie te cząstki za znaczącą:

labeled_particles

Próbowałem wielu rzeczy z PIL , cv, scipy, numpy, itp. Modułów. Mam kilka wskazówek od this very similar SO question i wydaje się na pierwszy rzut oka, że ​​można podjąć prostą progu tak:

im = mahotas.imread('particles.jpg') 
T = mahotas.thresholding.otsu(im) 

labeled, nr_objects = ndimage.label(im>T) 
print nr_objects 
pylab.imshow(labeled) 

ale ze względu na zmieniającą tle można uzyskać w ten sposób: bad_threshold_image

Mam także próbowałem inne pomysły, takie jak a technique I found for measuring paws, które realizowane w ten sposób:

import numpy as np 
import scipy 
import pylab 
import pymorph 
import mahotas 
from scipy import ndimage 
import cv 


def detect_peaks(image): 
    """ 
    Takes an image and detect the peaks usingthe local maximum filter. 
    Returns a boolean mask of the peaks (i.e. 1 when 
    the pixel's value is the neighborhood maximum, 0 otherwise) 
    """ 

    # define an 8-connected neighborhood 
    neighborhood = ndimage.morphology.generate_binary_structure(2,2) 

    #apply the local maximum filter; all pixel of maximal value 
    #in their neighborhood are set to 1 
    local_max = ndimage.filters.maximum_filter(image, footprint=neighborhood)==image 
    #local_max is a mask that contains the peaks we are 
    #looking for, but also the background. 
    #In order to isolate the peaks we must remove the background from the mask. 

    #we create the mask of the background 
    background = (image==0) 

    #a little technicality: we must erode the background in order to 
    #successfully subtract it form local_max, otherwise a line will 
    #appear along the background border (artifact of the local maximum filter) 
    eroded_background = ndimage.morphology.binary_erosion(background, structure=neighborhood, border_value=1) 

    #we obtain the final mask, containing only peaks, 
    #by removing the background from the local_max mask 
    detected_peaks = local_max - eroded_background 

    return detected_peaks 

im = mahotas.imread('particles.jpg') 
imf = ndimage.gaussian_filter(im, 3) 
#rmax = pymorph.regmax(imf) 
detected_peaks = detect_peaks(imf) 
pylab.imshow(pymorph.overlay(im, detected_peaks)) 
pylab.show() 

ale to nie daje szczęścia albo, pokazując ten wynik:

bad_result_from_detect_peaks

Korzystanie z funkcji max regionalnej uzyskać obrazy, które prawie wydają się podając prawidłową identyfikację cząstek, ale tam są albo zbyt wiele lub zbyt mało cząstek w niewłaściwych miejscach w zależności od mojego Gaussa filtrowania (obrazy posiadają filtr Gaussian 2,3, & 4):

gaussian of 2 gaussian of 3 gaussian of 4

Ponadto musiałby pracować Podobne do tego a także:

fluorescence

Jest to taki sam typ obrazu powyżej, tylko w znacznie wyższej gęstości cząstek.

EDIT: Zrobione rozwiązanie: udało mi się dostać przyzwoity roztwór roboczy tego problemu stosując następujący kod:

import cv2 
import pylab 
from scipy import ndimage 

im = cv2.imread('particles.jpg') 
pylab.figure(0) 
pylab.imshow(im) 

gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) 
gray = cv2.GaussianBlur(gray, (5,5), 0) 
maxValue = 255 
adaptiveMethod = cv2.ADAPTIVE_THRESH_GAUSSIAN_C#cv2.ADAPTIVE_THRESH_MEAN_C#cv2.ADAPTIVE_THRESH_GAUSSIAN_C 
thresholdType = cv2.THRESH_BINARY#cv2.THRESH_BINARY #cv2.THRESH_BINARY_INV 
blockSize = 5 #odd number like 3,5,7,9,11 
C = -3 # constant to be subtracted 
im_thresholded = cv2.adaptiveThreshold(gray, maxValue, adaptiveMethod, thresholdType, blockSize, C) 
labelarray, particle_count = ndimage.measurements.label(im_thresholded) 
print particle_count 
pylab.figure(1) 
pylab.imshow(im_thresholded) 
pylab.show() 

To pokaże obrazy tak:

particles_given (co stanowi podany obrazek)

i

counted_particles

(który jest liczony cząstki)

i obliczyć liczba cząstek 60.

+0

Dokładnie tego, czego szukałem!Dzięki! Aby dodać do rozwiązania, istnieje również [funkcja progu adaptacyjnego w bibliotece obrazów scikit] (http://scikit-image.org/docs/dev/api/skimage.filters.html?highlight=adaptive%20threshold#threshold -adaptive) – jadelord

Odpowiedz

3

Rozwiązałem "zmienną jasność w tle" za pomocą dostrojonego progu różnicy za pomocą techniki o nazwie Adaptive Contrast. Działa poprzez wykonanie kombinacji liniowej (różnicy w przypadku) obrazu w skali szarości z rozmytą wersją samego siebie, a następnie wprowadzenie do niego progu.

  1. Konwersja obrazu za pomocą odpowiedniego operatora statystycznego.
  2. Odejmij oryginał od obrazu splotu, w razie potrzeby skoryguj skalę intensywności/gamma.
  3. Próg obrazu różnicy ze stałą.

(original paper)

Zrobiłem to z dużym powodzeniem z scipy.ndimage w domenie zmiennoprzecinkowej (lepsze wyniki niż całkowitą przetwarzania obrazu), tak:

original_grayscale = numpy.asarray(some_PIL_image.convert('L'), dtype=float) 
blurred_grayscale = scipy.ndimage.filters.gaussian_filter(original_grayscale, blur_parameter) 
difference_image = original_grayscale - (multiplier * blurred_grayscale); 
image_to_be_labeled = ((difference_image > threshold) * 255).astype('uint8') # not sure if it is necessary 

labelarray, particle_count = scipy.ndimage.measurements.label(image_to_be_labeled) 

Nadzieja to pomaga !!

+0

Dzięki za pomoc @heltonbiker! Pomysł ten zwrócił mi uwagę na [tę interesującą ideę rozwiązywania sudoku z obrazków] (http://opencvpython.blogspot.com/2012/06/sudoku-solver-part-2.html) i udało mi się zaimplementować coś podobnego, co opracował ładnie. Zamieść kod w moim pytaniu, jeśli ktoś inny natknie się na ten problem lub coś podobnego. – chase

3

nie mogę dać jednoznacznej odpowiedzi, ale oto kilka wskazówek:

  1. Funkcja mahotas.morph.regmax może być lepsza niż filtr maksymalny, ponieważ usuwa pseudo-maksima. Być może połączyć to z globalnym progiem, z lokalnym progiem (takim jak średnia z okna) lub z obydwoma.

  2. Jeśli masz kilka zdjęć i to samo nierówne tło, to możesz obliczyć średnie tło i znormalizować je, lub użyć pustych obrazów jako oszacowania tła. Tak by było, gdybyś miał mikroskop i jak każdy mikroskop, który widziałem, oświetlenie jest nierówne.

Coś jak:

average = average_of_many(images) 
# smooth it 
average = mahotas.gaussian_filter(average,24) 

Teraz Preprocesuj obrazów, jak:

preproc = image/average 

czy coś takiego.

+0

Dzięki @luispedro, próbowałem regionalnego maksimum, i wygląda to prawie obiecująco, ale pojawia się wiele dodatkowych cząstek, których nie powinienem brać pod uwagę. Również uśrednianie jest dobrym pomysłem, w rzeczywistości jest to po usunięciu tła. – chase

+0

Spróbuj połączyć go z globalnym progiem. – luispedro

Powiązane problemy