私の環境は下記のとおりです。
PC:ubuntu desktop 10.04
NDK: AndroidNDK r5b
IDE: Eclipse
Android:IS01(1.6),IS03(2.1)
プロジェクトの作成
1.EclipseでAndroidプロジェクトを作成します。
プロジェクト名 :opencvtest
パッケージ名 :com.opencvtest.test
アクティビティ名 :opencv
プラットフォーム :1.6または2.1
※レイアウトで、linearlayoutを追加しorientationをverticalに設定しておいてください。
Java側のコードは下記のとおりです。
package com.opencvtest.test; import android.app.Activity; import android.os.Bundle; import android.widget.ImageView; import android.widget.LinearLayout; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class main extends Activity { static { //jnitestライブラリを読み込みます System.loadLibrary("jnitest"); } //ネイティブ側で実装している関数 public native void opencvtestfunc(int[] pixels, int x, int y); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //今回はリソースからビットマップを生成し、 //intの配列に変換したあとネイティブ側に処理を任せます。 //処理後の画像と、処理前の画像を上下に並べて表示します。 Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.android); Bitmap subbmp = bmp.copy(Bitmap.Config.RGB_565, true); int width = subbmp.getWidth(); int height = subbmp.getHeight(); int pixels[] = new int[width * height]; int cnt = 0; subbmp.getPixels(pixels, 0, width, 0, 0, width, height); //ネイティブ側で何らかの処理を行う opencvtestfunc(pixels,subbmp.getWidth(),subbmp.getHeight()); subbmp.setPixels(pixels, 0, width, 0, 0, width, height); LinearLayout llayout = (LinearLayout)findViewById(R.id.llayout); ImageView binarizeBmp = new ImageView(this); binarizeBmp.setImageBitmap(subbmp); ImageView normalBmp = new ImageView(this); normalBmp.setImageBitmap(bmp); llayout.addView(normalBmp); llayout.addView(binarizeBmp); } }
2.プロジェクトフォルダに、jniフォルダを作成します。
3.jniフォルダの中に、cまたはc++のソースファイルを作ります。今回は cvtest.cppとします。
cvtest.cppの中身は下記のとおりです。
#include <string.h> #include <jni.h> #include "cv.h" #include "cxcore.h" #ifdef __cplusplus extern "C" { #endif IplImage* pImage = NULL; IplImage* loadPixels(int* pixels, int width, int height); void savePixels(int* pixcels,IplImage* srcImage); JNIEXPORT void JNICALL Java_com_opencvtest_test_opencv_opencvtestfunc (JNIEnv *env, jobject thiz, jintArray colors, jint w, jint h) { int r, g, b; int cnt; //Colorの配列を取り出す(配列のポインタを取得) jint* colorArray = env->GetIntArrayElements(colors,0); //Color(int) の配列から、IplImageを作る if (pImage != NULL) { cvReleaseImage(&pImage); pImage = NULL; } pImage = loadPixels(colorArray,w,h); //画像の作成完了。あとは色々と画像処理をします IplImage *work=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1); IplImage *edge=cvCloneImage(work); //輪郭保存用のストレージを確保 CvMemStorage *storage = cvCreateMemStorage (0); CvSeq *firstcontour=NULL; cvCvtColor(pImage,work,CV_BGR2GRAY); cvThreshold(work,edge,100,255,CV_THRESH_BINARY); //輪郭を探します。Ncには探した輪郭の数が入ります。 //CV_RETR_LISTに設定すると、見つけた輪郭がすべて同じレベルに入ります。。 //first=輪郭1⇔輪郭2⇔輪郭3⇔輪郭4 //これだと内側と外側の両方の輪郭が同じレベルに入るので、外側だけほしい場合はCV_LETR_CCOMPに設定します。 int Nc=cvFindContours (edge, storage, &firstcontour, sizeof (CvContour),CV_RETR_LIST); for(CvSeq * seq=firstcontour;seq!=NULL;seq=seq->h_next) { cvDrawContours(pImage,seq,cvScalar(200,0,50),cvScalar(0,255,0),0,2,8); } //IplImageの値を、int配列に戻す savePixels(colorArray,pImage); //リソースの開放 if(pImage!=NULL) { cvReleaseImage(&pImage); pImage=NULL; } if(work!=NULL) { cvReleaseImage(&work); } if(edge!=NULL) { cvReleaseImage(&edge); } env->ReleaseIntArrayElements(colors, colorArray, 0); } ////////////////////////////////////////////////// //int配列から、3チャネルのIplImageを作成します ////////////////////////////////////////////////// IplImage* loadPixels(int* pixels, int width, int height) { int x, y; IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); unsigned char* base = (unsigned char*) (img->imageData); unsigned char* ptr; for (y = 0; y < height; y++) { ptr = base + y * img->widthStep; for (x = 0; x < width; x++) { // blue ptr[3 * x] = pixels[x + y * width] & 0xFF; // green ptr[3 * x + 1] = pixels[x + y * width] >> 8 & 0xFF; // red ptr[3 * x + 2] = pixels[x + y * width] >> 16 & 0xFF; } } return img; } ///////////////////////////////////////////////////////////////////////// ///3チャネル、IPL_DEPTH_8UのIplImageの画像データを、int配列に反映させます ///////////////////////////////////////////////////////////////////////// void savePixels(int* pixcels,IplImage* srcImage) { int x, y; int w,h; int pixvalue; w=srcImage->width; h=srcImage->height; unsigned char* base = (unsigned char*) (srcImage->imageData); unsigned char* ptr; for (y = 0; y < h; y++) { ptr = base + y * srcImage->widthStep; for (x = 0; x < w; x++) { pixvalue=(ptr[3 * x])|(ptr[3 * x + 1]<<8)|(ptr[3 * x + 2] <<16); pixcels[x + y * w] =pixvalue; } } } #ifdef __cplusplus } #endif
つづく
0 件のコメント:
コメントを投稿