2012-10-18 10 views
13

Próbuję odjąć tło od głębokości obrazów uzyskanych za pomocą kinect. Kiedy dowiedziałem się, co to jest otsu- wanie otsu, pomyślałem, że przydałoby się to. Konwertując obraz głębokości na skalę szarości, mam nadzieję, że zastosuję próg otsu do binaryzacji obrazu.Otsuwanie progu dla głębokości obrazu

Jednak zaimplementowałem (próbowałem to) za pomocą OpenCV 2.3, na próżno. Obraz wyjściowy jest jednak binarizowany bardzo nieoczekiwanie. Robiłem progowanie w sposób ciągły (tj. Drukowałem wynik na ekranie, aby analizować dla każdej klatki) i zobaczyłem, że dla niektórych progów ramek jest 160, a czasem jest 0. 0. Nie mogłem całkiem zrozumieć, dlaczego tak się dzieje. Może to być spowodowane wysoką liczbą zer w obrazie głębokości zwróconym przez kinect, który odpowiada pikselom, których nie można zmierzyć. Czy istnieje sposób, żebym mógł powiedzieć algorytmowi, aby ignorował piksele o wartości 0? Czy progowanie otsu nie jest dobre dla tego, co próbuję zrobić?

Oto niektóre wyniki i segment powiązanego kodu. Możesz zauważyć, że drugi zrzut wygląda, jakby mógł zrobić dobrą binaryzację, ale chcę osiągnąć taki, który rozróżnia piksele odpowiadające krześle w scenie i backgroung.

Dzięki.

  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

Aby wykonać zrzut ekranu z jednego okna w prasie Ubuntu 'alt + prtsc'. – ArtemStorozhuk

+0

Jestem zaznajomiony tylko z oficjalnym zestawem Windows SDK, więc nie mogę bezpośrednio odpowiedzieć na to pytanie. Jeśli jednak masz instalację systemu Windows, istnieją przykłady "zielonego ekranu" w oficjalnych przykładach Kinect dla Windows SDK Toolkit. Być może będziesz w stanie zdobyć jakieś pomysły. Może... ? –

+0

proszę wstawić obraz wejściowy – nkint

Odpowiedz

13

Otsu jest prawdopodobnie wystarczająco dobre za to, co staramy się robić, ale trzeba zamaskować się z wartości zerowych przed obliczania optymalnego progu z algorytmem Otsu, inaczej dystrybucja wartości intensywności będą przekrzywione poniżej tego, co chcesz.

OpenCV nie podaje argumentu maski dla funkcji cv::threshold, więc będziesz musiał usunąć te wartości samodzielnie. Zalecam umieszczenie wszystkich niezerowych wartości w macierzy 1 na N i wywołanie funkcji cv::threshold za pomocą CV_THRESH_OTSU i zapisanie wartości zwracanej (która jest szacowanym optymalnym progiem), a następnie ponowne uruchomienie funkcji cv::threshold na oryginalnym obrazie z tylko flaga CV_THRESH_BINARY i obliczona wartość progowa.

Oto jedna możliwa realizacja:

// 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);