OpenCV for Android で特定の色を抽出 (NDK)

Feb 2, 2014  

書きました。

・ネイティブメソッドの記述

//色抽出
public static native void colorExtract(long matAddr,int code,
                                        int lowH,int highH,
                                        int lowS,int highS,
                                        int lowV,int highV);
・ネイティブコード
JNIEXPORT void JNICALL Java_com_fc2_blog_zaburoapp_markerdetection_MainActivity_colorExtract
  (JNIEnv * jenv, jclass, jlong matAddr, jint code, jint lowH, jint highH, jint lowS, jint highS, jint lowV, jint highV){
    Mat inputImg;
    inputImg = (Mat) matAddr;
    int height = inputImg->rows;
    int width = inputImg->cols;
    Mat hsvImg = Mat(height,width,CV_8UC3);
    cvtColor(*inputImg,hsvImg,code);
    vector singleCh;
    split(hsvImg,singleCh);
    Mat h1,h2,h,s1,s2,s,v1,v2,v,hs,mask;
    if(lowH<=highH){
        threshold((Mat)singleCh[0],h1,lowH,255,CV_THRESH_BINARY);
        threshold((Mat)singleCh[0],h2,highH,255,CV_THRESH_BINARY_INV);
        bitwise_and(h1,h2,h);
    }else{
        threshold((Mat)singleCh[0],h1,lowH,255,CV_THRESH_BINARY);
        threshold((Mat)singleCh[0],h2,highH,255,CV_THRESH_BINARY_INV);
        bitwise_or(h1,h2,h);
    }
    if(lowS<=highS){
        threshold((Mat)singleCh[1],s1,lowS,255,CV_THRESH_BINARY);
        threshold((Mat)singleCh[1],s2,highS,255,CV_THRESH_BINARY_INV);
        bitwise_and(s1,s2,s);
    }else{
        threshold((Mat)singleCh[1],s1,lowS,255,CV_THRESH_BINARY);
        threshold((Mat)singleCh[1],s2,highS,255,CV_THRESH_BINARY_INV);
        bitwise_or(s1,s2,s);
    }
    if(lowH<=highH){
        threshold((Mat)singleCh[2],v1,lowV,255,CV_THRESH_BINARY);
        threshold((Mat)singleCh[2],v2,highV,255,CV_THRESH_BINARY_INV);
        bitwise_and(v1,v2,v);
    }else{
        threshold((Mat)singleCh[2],v1,lowV,255,CV_THRESH_BINARY);
        threshold((Mat)singleCh[2],v2,highV,255,CV_THRESH_BINARY_INV);
        bitwise_or(v1,v2,v);
    }
    bitwise_and(h,s,hs);
    bitwise_and(hs,v,mask);
    Mat dstImg = Mat(height,width,inputImg->type(),Scalar(0,0,0));
    inputImg->copyTo(dstImg,mask);
    dstImg.copyTo(*inputImg);
}

・使い方・例
Mat matImg = new Mat();
Utils.bitmapToMat(bmp,matImg);
colorExtract(matImg.getNativeObjAddr(),Imgproc.COLOR_RGB2HSV,
            170,10,
            80,255,
            0,255);
Utils.matToBitmap(matImg, bmp);
mImageView.setImageBitmap(bmp);
って感じで使えば
色相(H):0〜10,170〜255
彩度(S):80〜255
明度(V):0〜255
の範囲の色を入力画像と同じサイズの黒背景の画像に抽出します。
第2引数のcodeはBitmapは大抵RGBのイメージだから
こんな感じにしとけば概ね間違いないと思います。
内部で、CV_8UC3(符号無し8bit整数3チャンネル)で画素を扱う都合上
色のパラメータは0〜255の範囲で表現します。
たぶん範囲外の値を渡すと落ちます。
例外投げる部分かけばよかったんですけど、めんどうでした。

このエントリーをはてなブックマークに追加