2015-10-19 8 views
10

Qual è il metodo più veloce e più affidabile per rilevare una linea laser rossa approssimativamente orizzontale in un'immagine usando Python? Sto lavorando a un piccolo progetto relativo alla scansione laser 3D e devo essere in grado di rilevare il laser in un'immagine per calcolare la distanza dalla sua distorsione.Come rilevare una linea laser in un'immagine usando Python

Per iniziare, ho due immagini, un'immagine di riferimento A nota per non contenere alcuna linea laser e un'immagine B che contiene sicuramente una linea laser, probabilmente distorta. per esempio.

Esempio di immagine A:

enter image description here

Esempio di immagine B:

enter image description here

Poiché questi sono RGB, ma il laser è rosso, a rimuovere il rumore dal escludendo l'azzurro e canali verdi utilizzando questa funzione:

from PIL import Image 
import numpy as np 

def only_red(im): 
    """ 
    Strips out everything except red. 
    """ 
    data = np.array(im) 
    red, green, blue, alpha = data.T 
    im2 = Image.fromarray(red.T) 
    return im2 

Questo mi fa queste immagini:

enter image description here

enter image description here

Successivamente, ho cercare di eliminare più rumore prendendo la differenza di queste due immagini utilizzando PIL.ImageChops.difference(). Idealmente, l'esposizione tra le due immagini sarebbe identica, facendo sì che la differenza non contenga nulla tranne la linea laser. Sfortunatamente, poiché il laser aggiunge luce, l'esposizione e la luminosità complessiva di ogni immagine sono significativamente diverse, con una differenza che ha comunque un notevole rumore. per esempio.

enter image description here

mio passo finale è quello di fare una "ipotesi migliore", da dove la linea è. Poiché so che la linea sarà approssimativamente orizzontale e la linea laser dovrebbe essere la cosa più luminosa nell'immagine, scruto ogni colonna e trovo la riga con il pixel più luminoso, che presumo essere la linea laser. Il codice per questo è:

import os 
from PIL import Image, ImageOps 
import numpy as np 

x = Image.open('laser-diff.png', 'r') 
x = x.convert('L') 

out = Image.new("L", x.size, "black") 
pix = out.load() 

y = np.asarray(x.getdata(), dtype=np.float64).reshape((x.size[1], x.size[0])) 
print y.shape 
for col_i in xrange(y.shape[1]): 
    col_max = max([(y[row_i][col_i], row_i) for row_i in xrange(y.shape[0])]) 
    col_max_brightness, col_max_row = col_max 
    print col_i, col_max 
    pix[col_i, col_max_row] = 255 

out.save('laser-line.png') 

Tutto quello che ho davvero bisogno di svolgere il mio calcolo della distanza è la matrice di col_max valori, ma il laser-line.png mi aiuta a visualizzare il successo, e si presenta come:

enter image description here

Come potete vedere, la stima è abbastanza vicina, ma ha ancora un po 'di rumore, soprattutto sul lato sinistro dell'immagine in cui la linea laser viene assorbita da una finitura nera opaca.

Cosa posso fare per migliorare la precisione e/o la velocità? Sto cercando di eseguire questo su una piattaforma ARM come Raspberry Pi, quindi sono preoccupato che il mio codice potrebbe essere troppo inefficiente per funzionare bene.

Non ho completamente familiarità con le funzioni della matrice di Numpy, quindi mi sono dovuto accontentare di un ciclo lento per la scansione di ogni colonna invece di qualcosa di più efficiente. C'è un modo veloce per trovare la riga con il pixel più luminoso per colonna in Numpy?

Inoltre, esiste un modo affidabile per equalizzare le immagini prima di eseguire la differenza senza attenuare la linea laser?

+0

forse alla fine, è possibile rimuovere tutti i punti le cui coordinate y non sono nel quantile 25% ~ 75%. Quindi puoi ottenere un risultato migliore, quindi inserire i valori mancanti usando locf..etc –

+0

@ B.Mr.W., Hai parzialmente ragione. Poiché il laser è stato montato sotto la telecamera e parallelo al suo piano focale, tutti i punti laser dovrebbero essere al di sotto della fila centrale, vale a dire tutti i punti sopra che sono il rumore. Grazie. – Cerin

risposta

1

Per prima cosa è possibile ridimensionare l'intensità dell'immagine negativa prima di sottrarla dal positivo, per rimuovere più rumore. Ad esempio, forse il riscalaggio dei rapporti dell'intesa media potrebbe essere un buon primo tentativo?

Si può anche provare a mettere una soglia: se il massimo in sotto qualunque buon valore, allora è probabilmente non il laser, ma un punto rumorosa ...

Allora sì numpy trovi la migliore riga/Col con la funzione argmax.

1

Inserire innanzitutto il colore che è il laser e lascia solo il colore rosso (in questo caso). Quindi applica gli stessi effetti e controlla il risultato.

In questo caso, si avrà un risultato molto meno inquinato. Result

Si è verificato un problema analizzando il rosso sulla porta, che è stato perso.

+0

Non conosco il colore del laser, a parte il fatto che è approssimativamente rosso. Non posso semplicemente presumere che tutto il rosso sia il laser perché ci possono essere oggetti rossi nella scena. Questa soluzione deve essere automatizzata, quindi non posso indicare manualmente il colore del laser in ogni immagine. – Cerin

+0

quindi utilizzare l'immagine, scorrere un grafico. probabilmente il modo più grande sarà trovare una linea laser. All'ingresso del tuo grafico ci saranno dei pixel che hanno due pixel adiacenti neri e due bianchi. –

1

Ho provato a fare qualcosa. Non penso che sia totalmente robusto. Ma sul tuo esempio funziona relativamente bene.

Ho utilizzato il rilevamento di bordi difficili per rilevare il bordo nella vostra immagine di "differenza". E poi ha applicato la trasformazione della linea Hough come in this tutorial. Così ho iniziato con l'immagine elaborata (che io chiamo lineDetection.jpg nel codice).

enter image description here

Qui è lo script finale

import cv2 
import numpy as np 

img = cv2.imread('lineDetection.jpg') 
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
edges = cv2.Canny(gray,10,100) 
minLineLength = 50 
maxLineGap = 20 
lines = cv2.HoughLinesP(edges,0.05,np.pi/5000,10,minLineLength,maxLineGap) 
print(len(lines)) 
for i in range(len(lines)): 
    x1,y1,x2,y2 = lines[i][0] 
    cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2) 

cv2.imwrite('houghlines5.jpg',img) 

In linea verde rilevato sulla immagine elaborata. (Si potrebbe aggiungere che l'immagine originale per un effetto più bello)

enter image description here

Spero che aiuta.