14

kinectで取得した深度画像から背景を差し引こうとしています。大津の二値化とは何かを知ったとき、それでうまくいくと思いました。深度画像をグレースケールに変換すると、大津のしきい値を適用して画像を2値化できると思います。

しかし、私はこれをOpenCV 2.3で実装(実装しようとしました)しましたが、無駄になりました。ただし、非常に予期しないことに、出力イメージは2値化されます。しきい値処理を継続的に実行し(つまり、結果を画面に出力してフレームごとに分析します)、一部のフレームではしきい値が160であることがわかり、場合によっては0であることがわかりました。なぜこれが発生するのかよくわかりませんでした。kinectによって返される深度画像の0の数が多いことが原因である可能性があります。これは、測定できないピクセルに対応します。値が0のピクセルを無視するようにアルゴリズムに指示する方法はありますか?または、大津のしきい値処理は、私がやろうとしていることに適していませんか?

関連するコードのいくつかの出力とセグメントを次に示します。2番目のスクリーンショットは、ある程度の2値化が可能であるように見えるかもしれませんが、シーン内の椅子と背景に対応するピクセルを明確に区別するものを実現したいと思います。

ありがとう。

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

画像1 この2番目のスクリーンショットは、適切な2値化を実行できるように見えます

4

1 に答える 1

13

大津はおそらくあなたがやろうとしていることには十分ですが、大津アルゴリズムで最適なしきい値を計算する前にゼロ値をマスクする必要があります。そうしないと、強度値の分布が必要なものよりも低く歪められます.

OpenCV は関数のマスク引数を提供しないため、cv::thresholdこれらの値を自分で削除する必要があります。ゼロ以外のすべての値を 1 行 N 列の行列に入れ、cv::threshold関数を呼び出しCV_THRESH_OTSUて戻り値 (推定される最適なしきい値) を保存し、フラグcv::thresholdだけを使用して元の画像で関数を再度実行することをお勧めします。CV_THRESH_BINARYおよび計算されたしきい値。

考えられる実装の 1 つを次に示します。

// 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);
于 2013-03-06T19:18:01.040 に答える