手の画像を白黒の手の形にしたい。入力と目的の出力のサンプルを次に示します。
しきい値を使用しても、手の内側の色の一部が背景色と同じであるため、目的の出力が得られません。どうすれば目的の出力を得ることができますか?
基本的に、適応しきい値は画像を白黒に変換しますが、各ピクセル周辺の局所的な条件に基づいてしきい値レベルを取得します。これにより、通常のしきい値で発生する問題を回避する必要があります。実際、なぜ通常のしきい値を使用したいのか、私にはよくわかりません。
それがうまくいかない場合、別のアプローチとして、画像内の最大の輪郭を見つけ、それを別のマトリックスに描画し、その中のすべてを黒で塗りつぶします。(Floodfill は、MSPaint のバケツ ツールのようなものです。特定のピクセルから開始し、そのピクセルに接続されているすべてのものを同じ色で、選択した別の色で塗りつぶします。)
おそらく、さまざまな照明条件に対する最も堅牢なアプローチは、すべてを上から順番に実行することです。ただし、敷居または輪郭/塗りつぶしだけで回避できる場合があります。
ちなみに、findContours は MatOfPoints の arraylist/vector/whatever (私が考えるプラットフォームによって異なります) を返すため、おそらく最もトリッキーな部分は実際に輪郭を見つけることです。MatOfPoint は Mat のサブクラスですが、直接描画することはできません。drawContours を使用する必要があります。私が知っているOpenCV4Androidのコードは次のとおりです。
private Mat drawLargestContour(Mat input) {
/** Allocates and returns a black matrix with the
* largest contour of the input matrix drawn in white. */
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(input, contours, new Mat() /* hierarchy */,
Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
double maxArea = 0;
int index = -1;
for (MatOfPoint contour : contours) { // iterate over every contour in the list
double area = Imgproc.contourArea(contour);
if (area > maxArea) {
maxArea = area;
index = contours.indexOf(contour);
}
}
if (index == -1) {
Log.e(TAG, "Fatal error: no contours in the image!");
}
Mat border = new Mat(input.rows(), input.cols(), CvType.CV_8UC1); // initialized to 0 (black) by default because it's Java :)
Imgproc.drawContours(border, contours, index, new Scalar(255)); // 255 = draw contours in white
return border;
}
すぐに試すことができる 2 つの方法:
しきい値処理後、次のことができます。
モルフォロジークロージングを行い、
または、最も簡単な方法:cv::findContours
複数の場合は最大のものを保持し、それを使用して描画するcv::fillConvexPoly
と、このマスクが得られます。(fillConvexPoly
あなたのために穴を埋めます)