Подтвердить что ты не робот

Оттенок Otsu для изображения глубины

Я пытаюсь выставить фон из изображений глубины, полученных с помощью kinect. Когда я узнал, что такое отсуждение, я думал, что это возможно. Преобразование изображения глубины в оттенки серого я могу надеяться применить порог otsu для бинаризации изображения.

Однако я реализовал (попытался реализовать) это с OpenCV 2.3, он пришел напрасно. Выходное изображение бинаризовано, однако, очень неожиданно. Я сделал пороговое значение непрерывно (т.е. Распечатал результат на экране для анализа для каждого кадра) и увидел, что для некоторых кадров пороговое значение установлено равным 160, а иногда оно оказывается равным 0. Я не мог понять, почему это происходит. Возможно, это связано с большим количеством 0 в изображении глубины, возвращаемом kinect, что соответствует пикселам, которые невозможно измерить. Есть ли способ, которым я мог бы сказать алгоритму игнорировать пиксели, имеющие значение 0? Или порог отсу не подходит для того, что я пытаюсь сделать?

Вот несколько выходов и сегментов связанного кода. Вы можете заметить, что второй скриншот выглядит так, как будто он может сделать хорошую бинаризацию, однако я хочу достичь той, которая отличает различия между пикселями, соответствующими стулу в сцене и backgroung.

Спасибо.

            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 1this second screenshot looks like it could do some good binarization

4b9b3361

Ответ 1

Otsu, вероятно, достаточно хорош для того, что вы пытаетесь сделать, но вам нужно замаскировать нулевые значения перед вычислением оптимального порога с помощью алгоритма Otsu, иначе распределение значений интенсивности будет искажено ниже, чем вы хотите.

OpenCV не предоставляет аргумент маски для функции cv::threshold, поэтому вам придется самостоятельно удалить эти значения. Я бы рекомендовал поместить все ненулевые значения в матрицу 1 на N и вызвать функцию cv::threshold с помощью CV_THRESH_OTSU и сохранить возвращаемое значение (которое является оценочным оптимальным порогом), а затем запустить функцию cv::threshold снова на исходном изображении с помощью только флага CV_THRESH_BINARY и вычисленного порога.

Вот одна из возможных реализаций:

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