2013-09-23 13 views
7

Używam numpy i scipy do przetwarzania wielu zdjęć wykonanych aparatem CCD. Obrazy te mają wiele gorących (i martwych) pikseli o bardzo dużych (lub małych) wartościach. Zakłóca to inne przetwarzanie obrazu, dlatego należy je usunąć. Niestety, chociaż kilka pikseli utknęło na 0 lub 255 i zawsze mają tę samą wartość na wszystkich obrazach, istnieją pewne piksele, które tymczasowo utknęły w innych wartościach przez okres kilku minut (rozpiętość danych wiele godzin).Automatyczne usuwanie gorących/martwych pikseli z obrazu w pytonie

Zastanawiam się, czy istnieje metoda identyfikacji (i usuwania) gorących pikseli już zaimplementowanych w pythonie. Jeśli nie, zastanawiam się, jaka byłaby to skuteczna metoda. Gorące/martwe piksele są stosunkowo łatwe do zidentyfikowania przez porównanie ich z sąsiednimi pikselami. Widziałem, jak napisałem pętlę, która patrzy na każdy piksel, porównując jej wartość z 8 najbliższymi sąsiadami. Lub, wydaje się, że lepiej jest użyć jakiegoś splotu, aby uzyskać gładszy obraz, a następnie odjąć go od obrazu zawierającego gorące piksele, dzięki czemu łatwiej je zidentyfikować.

Próbowałem tej "metody zamazywania" w kodzie poniżej i działa dobrze, ale wątpię, że jest to najszybszy. Ponadto pojawia się pomyłka na krawędzi obrazu (prawdopodobnie od tego, że funkcja gaussian_filter przyjmuje splot, a splot staje się dziwny blisko krawędzi). Czy istnieje lepszy sposób na zrobienie tego?

Przykładowy kod:

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

plt.figure(figsize=(8,4)) 
ax1 = plt.subplot(121) 
ax2 = plt.subplot(122) 

#make a sample image 
x = np.linspace(-5,5,200) 
X,Y = np.meshgrid(x,x) 
Z = 255*np.cos(np.sqrt(x**2 + Y**2))**2 


for i in range(0,11): 
    #Add some hot pixels 
    Z[np.random.randint(low=0,high=199),np.random.randint(low=0,high=199)]= np.random.randint(low=200,high=255) 
    #and dead pixels 
    Z[np.random.randint(low=0,high=199),np.random.randint(low=0,high=199)]= np.random.randint(low=0,high=10) 

#Then plot it 
ax1.set_title('Raw data with hot pixels') 
ax1.imshow(Z,interpolation='nearest',origin='lower') 

#Now we try to find the hot pixels 
blurred_Z = scipy.ndimage.gaussian_filter(Z, sigma=2) 
difference = Z - blurred_Z 

ax2.set_title('Difference with hot pixels identified') 
ax2.imshow(difference,interpolation='nearest',origin='lower') 

threshold = 15 
hot_pixels = np.nonzero((difference>threshold) | (difference<-threshold)) 

#Don't include the hot pixels that we found near the edge: 
count = 0 
for y,x in zip(hot_pixels[0],hot_pixels[1]): 
    if (x != 0) and (x != 199) and (y != 0) and (y != 199): 
     ax2.plot(x,y,'ro') 
     count += 1 

print 'Detected %i hot/dead pixels out of 20.'%count 
ax2.set_xlim(0,200); ax2.set_ylim(0,200) 


plt.show() 

a wyjście: enter image description here

+2

Spróbuj bardziej prosty przypadek: zrobić kolejne zdjęcie z filtrowaniem środkowej (na przykład przez 3x3 deseń) i obliczyć wartość bezwzględną differense między Twój obraz i filtrowany obraz. Zastąp piksele oryginalnego obrazu dużymi wartościami tej różnicy (powiedzmy 100) przez przefiltrowane wartości. Wartość progu, którą można uzyskać automatycznie, według statystyk różnic. –

+0

@Eddy_Em, dziękuję za sugestię filtra median - to wydaje się lepszą metodą niż filtr Gaussa. Poza tym podoba mi się pomysł ustawienia progu za pomocą statystyk z tablicy różnic. Próbowałem przyjąć odchylenie standardowe i wydawało się, że działa dobrze. (Ustawiłem próg na 5-krotność odchylenia standardowego.) Jednak nie jestem pewien co do sugestii dodania wielokrotności tablicy różnic do tablicy obrazów. Co to robi? – DanHickstein

+0

O, nie: Chodzi mi o to, że piksele są wyszukiwane w tablicy różnic przez pewną wartość progową. –

Odpowiedz

6

Zasadniczo myślę, że najszybszym sposobem radzenia sobie z gorących pikseli jest po prostu użyć size = 2 Filtr mediany. Następnie, poof, twoje gorące piksele zniknęły i zabijasz również wszelkiego rodzaju inne zakłócenia czujnika wysokiej częstotliwości z twojego aparatu.

Jeśli naprawdę chcesz usunąć TYLKO gorące piksele, to możesz zastąpić filtr medianowy z oryginalnego obrazu, tak jak zrobiłem to w pytaniu, i zastąpić tylko te wartości wartościami z medianowego przefiltrowanego obrazu. To nie działa dobrze na krawędziach, więc jeśli zignorujesz piksele wzdłuż krawędzi, to znacznie ułatwi to zadanie.

Jeśli chcesz uporać się z krawędziami, możesz użyć poniższego kodu. Jednak to nie jest najszybszy:

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

plt.figure(figsize=(10,5)) 
ax1 = plt.subplot(121) 
ax2 = plt.subplot(122) 

#make some sample data 
x = np.linspace(-5,5,200) 
X,Y = np.meshgrid(x,x) 
Z = 100*np.cos(np.sqrt(x**2 + Y**2))**2 + 50 

np.random.seed(1) 
for i in range(0,11): 
    #Add some hot pixels 
    Z[np.random.randint(low=0,high=199),np.random.randint(low=0,high=199)]= np.random.randint(low=200,high=255) 
    #and dead pixels 
    Z[np.random.randint(low=0,high=199),np.random.randint(low=0,high=199)]= np.random.randint(low=0,high=10) 

#And some hot pixels in the corners and edges 
Z[0,0] =255 
Z[-1,-1] =255 
Z[-1,0] =255 
Z[0,-1] =255 
Z[0,100] =255 
Z[-1,100]=255 
Z[100,0] =255 
Z[100,-1]=255 

#Then plot it 
ax1.set_title('Raw data with hot pixels') 
ax1.imshow(Z,interpolation='nearest',origin='lower') 

def find_outlier_pixels(data,tolerance=3,worry_about_edges=True): 
    #This function finds the hot or dead pixels in a 2D dataset. 
    #tolerance is the number of standard deviations used to cutoff the hot pixels 
    #If you want to ignore the edges and greatly speed up the code, then set 
    #worry_about_edges to False. 
    # 
    #The function returns a list of hot pixels and also an image with with hot pixels removed 

    from scipy.ndimage import median_filter 
    blurred = median_filter(Z, size=2) 
    difference = data - blurred 
    threshold = 10*np.std(difference) 

    #find the hot pixels, but ignore the edges 
    hot_pixels = np.nonzero((np.abs(difference[1:-1,1:-1])>threshold)) 
    hot_pixels = np.array(hot_pixels) + 1 #because we ignored the first row and first column 

    fixed_image = np.copy(data) #This is the image with the hot pixels removed 
    for y,x in zip(hot_pixels[0],hot_pixels[1]): 
     fixed_image[y,x]=blurred[y,x] 

    if worry_about_edges == True: 
     height,width = np.shape(data) 

     ###Now get the pixels on the edges (but not the corners)### 

     #left and right sides 
     for index in range(1,height-1): 
      #left side: 
      med = np.median(data[index-1:index+2,0:2]) 
      diff = np.abs(data[index,0] - med) 
      if diff>threshold: 
       hot_pixels = np.hstack((hot_pixels, [[index],[0]] )) 
       fixed_image[index,0] = med 

      #right side: 
      med = np.median(data[index-1:index+2,-2:]) 
      diff = np.abs(data[index,-1] - med) 
      if diff>threshold: 
       hot_pixels = np.hstack((hot_pixels, [[index],[width-1]] )) 
       fixed_image[index,-1] = med 

     #Then the top and bottom 
     for index in range(1,width-1): 
      #bottom: 
      med = np.median(data[0:2,index-1:index+2]) 
      diff = np.abs(data[0,index] - med) 
      if diff>threshold: 
       hot_pixels = np.hstack((hot_pixels, [[0],[index]] )) 
       fixed_image[0,index] = med 

      #top: 
      med = np.median(data[-2:,index-1:index+2]) 
      diff = np.abs(data[-1,index] - med) 
      if diff>threshold: 
       hot_pixels = np.hstack((hot_pixels, [[height-1],[index]] )) 
       fixed_image[-1,index] = med 

     ###Then the corners### 

     #bottom left 
     med = np.median(data[0:2,0:2]) 
     diff = np.abs(data[0,0] - med) 
     if diff>threshold: 
      hot_pixels = np.hstack((hot_pixels, [[0],[0]] )) 
      fixed_image[0,0] = med 

     #bottom right 
     med = np.median(data[0:2,-2:]) 
     diff = np.abs(data[0,-1] - med) 
     if diff>threshold: 
      hot_pixels = np.hstack((hot_pixels, [[0],[width-1]] )) 
      fixed_image[0,-1] = med 

     #top left 
     med = np.median(data[-2:,0:2]) 
     diff = np.abs(data[-1,0] - med) 
     if diff>threshold: 
      hot_pixels = np.hstack((hot_pixels, [[height-1],[0]] )) 
      fixed_image[-1,0] = med 

     #top right 
     med = np.median(data[-2:,-2:]) 
     diff = np.abs(data[-1,-1] - med) 
     if diff>threshold: 
      hot_pixels = np.hstack((hot_pixels, [[height-1],[width-1]] )) 
      fixed_image[-1,-1] = med 

    return hot_pixels,fixed_image 


hot_pixels,fixed_image = find_outlier_pixels(Z) 

for y,x in zip(hot_pixels[0],hot_pixels[1]): 
    ax1.plot(x,y,'ro',mfc='none',mec='r',ms=10) 

ax1.set_xlim(0,200) 
ax1.set_ylim(0,200) 

ax2.set_title('Image with hot pixels removed') 
ax2.imshow(fixed_image,interpolation='nearest',origin='lower',clim=(0,255)) 

plt.show() 

wyjściowa: enter image description here