18
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

OpenCVで肌色領域を認識させてみた

Posted at

やりたいこと

前回の記事では、AndroidのアプリケーションにOpenCV3.0を導入して、カメラ映像をグレースケールに変換する簡単な例を記述しました。

今回やる内容は、前回の記事の続きと考えて下さい。

カメラ映像の中から肌色部分を抽出して、四角で囲むといった処理を行います。実行した結果は以下のようになります。

image

SkinDetector

このクラスでは以下のような流れで処理がされています

  1. RGBからHSVに変換 (HSVなどの方が映像が輝度の影響を受けにくいそうです)
  2. ノイズがのりやすいので、平滑化します
  3. 肌色のしきい値内のあたり領域を取り出します
  4. 領域の中で一番大きい領域を返します
public class SkinDetector {
    private static SkinDetector sInstance;

    private static Scalar sLowerb;

    private static Scalar sUpperrb;

    private SkinDetector() {
        sLowerb = new Scalar(0, 58, 88);
        sUpperrb = new Scalar(25,173,229);
    }

    public static SkinDetector getInstance() {
        if (sInstance != null) {
            return null;
        }
        sInstance = new SkinDetector();
        return sInstance;
    }

    public static MatOfPoint getMaxSkinArea(Mat rgba) {
        if (rgba == null) {
            throw new IllegalArgumentException("parameter must not be null");
        }

        Mat hsv = new Mat();
        Imgproc.cvtColor(rgba, hsv, Imgproc.COLOR_RGB2HSV);
        Imgproc.medianBlur(hsv, hsv, 3);

        Core.inRange(hsv, sLowerb, sUpperrb, hsv);

        ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Mat hierarchy = new Mat(hsv.cols(), hsv.rows(), CvType.CV_32SC1);
        Imgproc.findContours(hsv, contours, hierarchy, Imgproc.RETR_LIST,
                Imgproc.CHAIN_APPROX_NONE);

        if (contours == null) {
            return null;
        }

        double maxArea = 0.0f;
        int maxIdx = 0;
        for (int i = 0; i < contours.size(); i++) {
            double tmpArea = Imgproc.contourArea(contours.get(i));
            if (maxArea < tmpArea) {
                maxArea = tmpArea;
                maxIdx = i;
            }
        }

        return contours.get(maxIdx);
    }
}

肌色領域を四角で描画する

onCameraFrameは前回の記事で説明させて頂いた通り、毎フレーム事に呼び出されます。

ここで先ほど作成した、SkinDetectorから肌色領域を取得し、その領域を四角の枠で元映像い付加して出力します。

SkinDetectorで取得される領域から四角の範囲を取得するには、Imgproc.boundingRectを用いることでRectが取得できます。

あとは、Imgproc.rectangleで四角を描画することが可能です。Imgprocにはこれ以外にも円とか、三角とかも記述できる関数が用意されています。

    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
        Mat rgba = inputFrame.rgba();
        MatOfPoint maxArea = SkinDetector.getInstance().getMaxSkinArea(rgba);
        if (maxArea != null) {
            Rect rectOfArea = Imgproc.boundingRect(maxArea);
            Imgproc.rectangle(rgba, rectOfArea.tl(), rectOfArea.br(), RECT_COLOR, 3);
        }
        return rgba;
    }

最後に

OpenCVには簡単に画像認識や画像処理ができる関数郡が用意されており、とても便利です。またNativeのコードを記述しなくてもJavaだけでも簡単な処理であればパフォーマンスが出せることが確認できました。

18
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?