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:
Esempio di immagine B:
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:
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.
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:
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?
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 –
@ 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