2013-09-23 8 views
7

Ich benutze numpy und scipy, um eine Anzahl von Bildern zu verarbeiten, die mit einer CCD-Kamera aufgenommen wurden. Diese Bilder haben eine Anzahl von heißen (und toten) Pixeln mit sehr großen (oder kleinen) Werten. Diese stören andere Bildverarbeitung, so dass sie entfernt werden müssen. Obwohl ein paar der Pixel auf 0 oder 255 stecken und in allen Bildern immer den gleichen Wert haben, gibt es leider einige Pixel, die vorübergehend für einige Minuten auf anderen Werten stecken bleiben (die Datenspannen) viele Stunden).Automatisch heiße/tote Pixel von einem Bild in Python entfernen

Ich frage mich, ob es eine Methode zum Identifizieren (und Entfernen) der heißen Pixel gibt, die bereits in Python implementiert sind. Wenn nicht, frage ich mich, was wäre eine effiziente Methode dafür. Die heißen/toten Pixel sind relativ leicht zu identifizieren, indem sie mit benachbarten Pixeln verglichen werden. Ich konnte sehen, wie man eine Schleife schreibt, die jedes Pixel betrachtet und seinen Wert mit dem seiner 8 nächsten Nachbarn vergleicht. Oder es scheint netter zu sein, eine Art von Faltung zu verwenden, um ein glatteres Bild zu erzeugen, und dieses dann von dem Bild mit den heißen Pixeln zu subtrahieren, wodurch sie leichter zu identifizieren sind.

Ich habe diese "Unschärfe-Methode" im folgenden Code ausprobiert, und es funktioniert in Ordnung, aber ich bezweifle, dass es am schnellsten ist. Außerdem wird es am Rand des Bildes verwirrt (wahrscheinlich, da die Gaußsche_Filter-Funktion eine Faltung nimmt und die Faltung in der Nähe der Kante merkwürdig wird). Also, gibt es einen besseren Weg, dies zu tun?

Beispielcode:

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() 

Und die Ausgabe: enter image description here

+2

einen einfacheren Fall Versuchen: ein weiteres Bild mit Medianfilterung machen (zum Beispiel durch ein Muster 3x3) und berechnet absoluten Wert von differense zwischen Ihr Bild und gefiltertes Bild. Ersetze Pixel des Originalbildes mit großen Werten dieser Differenz (z. B. 100) durch gefilterte Werte. Der Wert des Grenzwerts kann automatisch durch Differenzstatistiken ermittelt werden. –

+0

@Eddy_Em, vielen Dank für den Median-Filter - das scheint eine bessere Methode als der Gauss-Filter. Außerdem gefällt mir die Idee, den Schwellenwert unter Verwendung der Statistik des Differenzarrays zu setzen. Ich habe versucht, die Standardabweichung zu nehmen, und das schien gut zu funktionieren. (Ich setze den Schwellenwert auf das 5-fache der Standardabweichung.) Ich bin jedoch verwirrt über Ihren Vorschlag, ein Vielfaches des Differenz-Arrays zum Bild-Array hinzuzufügen. Was macht das? – DanHickstein

+0

Oh, nein: Ich meine nur, dass Sie Pixel suchen, um im Differenz-Array um einen Schwellenwert zu bereinigen. –

Antwort

6

Grundsätzlich denke ich, dass der schnellste Weg, mit Hot-Pixel zu behandeln ist nur eine size = 2 Medianfilter zu verwenden. Dann, puh, deine heißen Pixel sind weg und du bringst auch alle möglichen anderen hochfrequenten Sensorrauschen von deiner Kamera weg. nur diese Werte mit den Werten aus dem mittelwertgefilterten Bild

Wenn Sie wirklich NUR die Hotpixel entfernen möchten ersetzen, dann können Sie das Medianfilter aus dem Originalbild subtrahieren, wie ich in der Frage hat, und ersetzen. Dies funktioniert nicht gut an den Kanten, also wenn Sie die Pixel entlang der Kante ignorieren können, wird dies die Dinge viel einfacher machen.

Wenn Sie mit den Kanten umgehen möchten, können Sie den folgenden Code verwenden. Jedoch ist es nicht die schnellste:

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() 

Output: enter image description here

Verwandte Themen