やりたいこと
前回の記事では、AndroidのアプリケーションにOpenCV3.0を導入して、カメラ映像をグレースケールに変換する簡単な例を記述しました。
今回やる内容は、前回の記事の続きと考えて下さい。
カメラ映像の中から肌色部分を抽出して、四角で囲むといった処理を行います。実行した結果は以下のようになります。
SkinDetector
このクラスでは以下のような流れで処理がされています
- RGBからHSVに変換 (HSVなどの方が映像が輝度の影響を受けにくいそうです)
- ノイズがのりやすいので、平滑化します
- 肌色のしきい値内のあたり領域を取り出します
- 領域の中で一番大きい領域を返します
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だけでも簡単な処理であればパフォーマンスが出せることが確認できました。
