2012-10-18 11 views
13

Sto provando a sottrarre lo sfondo dalle immagini di profondità acquisite con kinect. Quando ho appreso che cosa è la soglia di controllo, ho pensato che potesse farlo. Si spera di applicare la soglia di otsu per binarizzare l'immagine, convertendo l'immagine di profondità in scala di grigi.Soglia Otsu per immagine di profondità

Tuttavia ho implementato (provato a implementare) questo con OpenCV 2.3, è venuto invano. L'immagine di output è tuttavia binarizzata, in modo molto inaspettato. Ho fatto la soglia continuamente (cioè, stampo il risultato sullo schermo per analizzare per ogni fotogramma) e ho visto che per alcuni fotogrammi si trova la soglia 160ish e talvolta si scopre che è 0. Non riuscivo a capire perché stia succedendo. Può essere dovuto al numero elevato di 0 nell'immagine di profondità restituita da kinect, che corrisponde a pixel che non possono essere misurati. C'è un modo in cui potrei dire all'algoritmo di ignorare i pixel che hanno il valore 0? O la soglia di otsu non va bene per quello che sto cercando di fare?

Ecco alcune uscite e segmenti del codice correlato. Si può notare che il secondo screenshot sembra fare una buona binarizzazione, tuttavia voglio ottenere uno che distingua distintamente tra i pixel corrispondenti alla sedia nella scena e il backgroung.

Grazie.

  cv::Mat1s depthcv(depth->getHeight(), depth->getWidth()); 
      cv::Mat1b depthcv8(depth->getHeight(), depth->getWidth()); 
      cv::Mat1b depthcv8_th(depth->getHeight(), depth->getWidth()); 
      depthcv.data =(uchar*) depth->getDepthMetaData().Data(); 
      depthcv.convertTo(depthcv8,CV_8U,255/5000.f); 

      //apply otsu thresholding 
      cv::threshold(depthcv8, depthcv8_th, 128, 255, CV_THRESH_BINARY|CV_THRESH_OTSU); 
      std::ofstream output; 
      output.open("output.txt"); 
      //output << "M = "<< endl << " " << depthcv8 << endl << endl; 
      cv::imshow("lab",depthcv8_th); 
      cv::waitKey(1); 

Image 1 this second screenshot looks like it could do some good binarization

+2

Per fare uno screenshot di singola finestra in Ubuntu stampa 'alt + prtsc'. – ArtemStorozhuk

+0

Ho solo familiarità con Windows SDK ufficiale, quindi non posso rispondere direttamente alla domanda. Tuttavia, se si dispone di un'installazione di Windows, vi sono esempi di "schermate verdi" negli esempi ufficiali di Kinect per Windows SDK Toolkit. Potresti essere in grado di ottenere alcune idee da lì. Può essere... ? –

+0

per favore inserisci immagine di input – nkint

risposta

13

Otsu è probabilmente abbastanza buono per quello che si sta cercando di fare, ma si ha bisogno di mascherare i valori zero prima di calcolare la soglia ottimale con l'algoritmo Otsu, in caso contrario la distribuzione dei valori di intensità saranno deviati più in basso di quello che vuoi.

OpenCV non fornisce un argomento maschera per la funzione cv::threshold, quindi sarà necessario rimuovere tali valori da soli. Si consiglia di inserire tutti i valori diversi da zero in una matrice 1 per N e chiamare la funzione cv::threshold con CV_THRESH_OTSU e salvare il valore restituito (che è la soglia ottimale stimata), quindi eseguire nuovamente la funzione cv::threshold sull'immagine originale con solo il flag CV_THRESH_BINARY e la soglia calcolata.

Ecco una possibile implementazione:

// move zeros to the back of a temp array 
cv::Mat copyImg = origImg; 
uint8* ptr = copyImg.datastart; 
uint8* ptr_end = copyImg.dataend; 
while (ptr < ptr_end) { 
    if (*ptr == 0) { // swap if zero 
    uint8 tmp = *ptr_end; 
    *ptr_end = *ptr; 
    *ptr = tmp; 
    ptr_end--; // make array smaller 
    } else { 
    ptr++; 
    } 
} 

// make a new matrix with only valid data 
cv::Mat nz = cv::Mat(std::vector<uint8>(copyImg.datastart,ptr_end),true); 

// compute optimal Otsu threshold 
double thresh = cv::threshold(nz,nz,0,255,CV_THRESH_BINARY | CV_THRESH_OTSU); 

// apply threshold 
cv::threshold(origImg,origImg,thresh,255,CV_THRESH_BINARY_INV); 
Problemi correlati