【Android】OpenCV4Android开发技巧


Android开发技巧

1、根据res路径来读取OpenCV的xml人脸检测文件

private CascadeClassifier cascadeClassifier;

//加载人脸检测xml
  try {
    // Copy the resource into a temp file so OpenCV can load it
    InputStream is = getResources().openRawResource(R.raw.haarcascade_frontalface_alt);
    File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
    File mCascadeFile = new File(cascadeDir, "haarcascade_frontalface_alt.xml");
    FileOutputStream os = new FileOutputStream(mCascadeFile);
  
    byte[] buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = is.read(buffer)) != -1) {
        os.write(buffer, 0, bytesRead);
    }
    is.close();
    os.close();
  
    // Load the cascade classifier
    cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
  } catch (Exception e) {
    Log.e("OpenCVActivity", "Error loading cascade", e);
  }

 

2、菜单操作Menu

res-menu建菜单menu_main.xml

xml version="1.0" encoding="utf-8"?>

xmlns:android="http://schemas.android.com/apk/res/android">
           
android:id = "@+id/add_item"
       
android:title = "Add"/>
           
android:id = "@+id/remove_item"
       
android:title = "Remove"/>
           
android:id = "@+id/delete_item"
       
android:title = "Delete"/>

onOptionsItemSelected()方法内实现

@Override
public boolean onOptionsItemSelected(MenuItem item){
   
switch(item.getItemId()){
       
case R.id.add_item:
            Toast.makeText(
this, "You Clicked Add!!", Toast.LENGTH_SHORT).show();
            break;
        case
R.id.remove_item:
            Toast.makeText(
this, "You Clicked Remove!", Toast.LENGTH_SHORT).show();
            break;
        case
R.id.delete_item:
            Toast.makeText(
this, "You Clicked Delete!", Toast.LENGTH_SHORT).show();
            break;
        default
:
           
break;
   
}
   
return true;
}

 

//创建菜单

public boolean onCreateOptionsMenu(Menu menu){
    getMenuInflater().inflate(R.menu.
main, menu);
    return true;
}

 

3、Button按钮控件/子Activity开启

方式一:

findViewById(R.id.btn_online_demo).setOnClickListener(MainActivity.this);
findViewById(R.id.btn_offline_demo).setOnClickListener(MainActivity.this);

@Override
public void onClick(View v) {
   Intent intent =
null;
   switch
(v.getId()) {
  
case R.id.btn_online_demo:
      intent =
new Intent(MainActivity.this, OnlineFaceDemo.class);
     
startActivity(intent);
      break;
   case
R.id.btn_offline_demo:
      intent =
new Intent(MainActivity.this, OfflineFaceDemo.class);
     
startActivity(intent);
      break;
   default
:
     
break;
  
}
}

方式二:

buttonFirst = (Button)findViewById(R.id.button1);
buttonFirst.setOnClickListener(new View.OnClickListener() {
   
@Override
   
public void onClick(View v) {
        Toast.makeText(MainActivity.
this, "You Clicked Button1!", Toast.LENGTH_SHORT).show();
       
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
       
photoPickerIntent.setType("image/*");
       
startActivityForResult(photoPickerIntent, PICTURE_CHOOSE);
   
}
})
;

 

 

4、

private File mPictureFile;

……

// 设置相机拍照后照片保存路径
mPictureFile = new File(Environment.getExternalStorageDirectory(),
     
"picture" + System.currentTimeMillis()/1000 + ".jpg");
// 启动拍照,并保存到临时文件
Intent mIntent = new Intent();
mIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
mIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mPictureFile));
mIntent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
startActivityForResult(mIntent, FaceUtil.REQUEST_CAMERA_IMAGE);

 

5、在Bitmap上绘制区域Canvas(科大讯飞)

private void drawFaceRects(FaceRect[] faces) {
   Paint paint =
new Paint();
  
paint.setColor(Color.YELLOW);
  
paint.setStrokeWidth(Math.max(mImage.getWidth(), mImage.getHeight()) / 100f);
  
paint.setStyle(Style.STROKE);

  
Bitmap bitmap = Bitmap.createBitmap(mImage.getWidth(), mImage.getHeight(), Config.ARGB_8888);
  
Canvas canvas = new Canvas(bitmap);
  
canvas.drawBitmap(mImage, new Matrix(), null);
  
   for
(FaceRect face: faces) {
      canvas.drawRect(face.
bound, paint);
     
      if
(null != face.point) {
        
for (Point p: face.point) {
            canvas.drawPoint(p.
x, p.y, paint);
        
}
      }
   }
  
   ((ImageView) findViewById(R.id.
offline_img)).setImageBitmap(bitmap);
}

 

6、保存Bitmap图片到指定路径

//保存图片
public static void saveBitmap(Bitmap bm, String picName) {
   File f =
new File("/storage/emulated/0/Pictures/", picName);
   if
(f.exists()) {
      f.delete()
;
  
}
  
try {
      FileOutputStream out =
new FileOutputStream(f);
     
bm.compress(Bitmap.CompressFormat.PNG, 90, out);
     
out.flush();
     
out.close();
  
} catch (FileNotFoundException e) {
     
// TODO Auto-generated catch block
     
e.printStackTrace();
  
} catch (IOException e) {
     
// TODO Auto-generated catch block
     
e.printStackTrace();
  
}
}

 

 

7、随机生成指定长度的字符串

//length用户要求产生字符串的长度
public static String getRandomString(int length){
   String str=
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  
Random random=new Random();
  
StringBuffer sb=new StringBuffer();
   for
(int i=0;i;i++){
     
int number=random.nextInt(62);
     
sb.append(str.charAt(number));
  
}
  
return sb.toString();
}

 

 

8、进度对话框的使用

// 进度对话框
private ProgressDialog mProDialog;

mProDialog = new ProgressDialog(this);
mProDialog.setCancelable(true);
mProDialog.setTitle("请稍后");

mProDialog.setOnCancelListener(new OnCancelListener() {
  
@Override
  
public void onCancel(DialogInterface dialog) {
     
// cancel进度框时,取消正在进行的操作
      if (null != mFaceRequest) {
        
mFaceRequest.cancel();
     
}
   }
})
;

 

mProDialog.setMessage("注册中...");
mProDialog.show();

 

if (null != mProDialog) {
  
mProDialog.dismiss();
}

 

9、RadioGroup单选按钮控件

RadioGroup alignGruop = (RadioGroup) findViewById(R.id.align_mode);
alignGruop.setOnCheckedChangeListener(new OnCheckedChangeListener() {

   
@Override
   
public void onCheckedChanged(RadioGroup arg0, int arg1) {
       
switch (arg1) {
           
case R.id.detect:
               
isAlign = 0;
                break;
            case
R.id.align:
               
isAlign = 1;
                break;
            default
:
               
break;
       
}
    }
})
;

 

 

10、Camera操作

private Camera mCamera;
private int
mCameraId = CameraInfo.CAMERA_FACING_FRONT;
// Camera nv21格式预览帧的尺寸,默认设置640*480
private int PREVIEW_WIDTH = 640;
private int
PREVIEW_HEIGHT = 480;
// 预览帧数据存储数组和缓存数组
private byte[] nv21;
private byte
[] buffer;
// 缩放矩阵
private Matrix mScaleMatrix = new Matrix();
// 加速度感应器,用于获取手机的朝向
private Accelerometer mAcc;

 

nv21 = new byte[PREVIEW_WIDTH * PREVIEW_HEIGHT * 2];
buffer = new byte[PREVIEW_WIDTH * PREVIEW_HEIGHT * 2];
mAcc = new Accelerometer(VideoDemo.this);

 

@Override
public void onClick(View v) {
   
// 只有一个摄相头,不支持切换
   
if (Camera.getNumberOfCameras() == 1) {
        showTip(
"只有后置摄像头,不能切换");
        return;
   
}
    closeCamera()
;
    if
(CameraInfo.CAMERA_FACING_FRONT == mCameraId) {
       
mCameraId = CameraInfo.CAMERA_FACING_BACK;
   
} else {
       
mCameraId = CameraInfo.CAMERA_FACING_FRONT;
   
}
    openCamera()
;
}

 

private void openCamera() {
   
if (null != mCamera) {
       
return;
   
}

   
if (!checkCameraPermission()) {
        showTip(
"摄像头权限未打开,请打开后再试");
       
mStopTrack = true;
        return;
   
}

   
// 只有一个摄相头,打开后置
   
if (Camera.getNumberOfCameras() == 1) {
       
mCameraId = CameraInfo.CAMERA_FACING_BACK;
   
}

   
try {
       
mCamera = Camera.open(mCameraId);
        if
(CameraInfo.CAMERA_FACING_FRONT == mCameraId) {
            showTip(
"前置摄像头已开启,点击可切换");
       
} else {
            showTip(
"后置摄像头已开启,点击可切换");
       
}
    }
catch (Exception e) {
        e.printStackTrace()
;
       
closeCamera();
        return;
   
}

    Parameters params =
mCamera.getParameters();
   
params.setPreviewFormat(ImageFormat.NV21);
   
params.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT);
   
mCamera.setParameters(params);

   
// 设置显示的偏转角度,大部分机器是顺时针90度,某些机器需要按情况设置
    mCamera.setDisplayOrientation(90);
   
mCamera.setPreviewCallback(new PreviewCallback() {

       
@Override
       
public void onPreviewFrame(byte[] data, Camera camera) {
            System.arraycopy(data
, 0, nv21, 0, data.length);
       
}
    })
;

    try
{
       
mCamera.setPreviewDisplay(mPreviewSurface.getHolder());
       
mCamera.startPreview();
   
} catch (IOException e) {
        e.printStackTrace()
;
   
}
}

 

 

private void closeCamera() {
   
if (null != mCamera) {
       
mCamera.setPreviewCallback(null);
       
mCamera.stopPreview();
       
mCamera.release();
       
mCamera = null;
   
}
}

private boolean checkCameraPermission() {
   
int status = checkPermission(permission.CAMERA, Process.myPid(), Process.myUid());
    if
(PackageManager.PERMISSION_GRANTED == status) {
       
return true;
   
}
   
return false;
}

// 长按SurfaceView 500ms后松开,摄相头聚集
mFaceSurface.setOnTouchListener(new OnTouchListener() {

   
@Override
   
public boolean onTouch(View v, MotionEvent event) {
       
switch (event.getAction()) {
           
case MotionEvent.ACTION_DOWN:
               
mLastClickTime = System.currentTimeMillis();
                break;
            case
MotionEvent.ACTION_UP:
               
if (System.currentTimeMillis() - mLastClickTime > 500) {
                   
mCamera.autoFocus(null);
                    return true;
               
}
               
break;

            default
:
               
break;
       
}
       
return false;
   
}
})
;

 

 

 

 

11、读取指定路径的Bitmap

Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.img_01);

 

 

12、double转成String

String str_x = Double.toString(pt.x);
String str_y = Double.toString(pt.y);

 

 

13、创建线程

HandlerThreaddetectThread = null;
Handler detectHandler = null;

 

detectThread = new HandlerThread("detect");
detectThread.start();
detectHandler = new Handler(detectThread.getLooper());

 

detectHandler.post(new Runnable() {
   
@Override
   
public void run() {
       
final Bitmap bit = getFaceInfoBitmap(faceinfo, img);
       
runOnUiThread(new Runnable() {
           
@Override
           
public void run() {
               
imageView.setImageBitmap(bit);
               
System.gc();
               
textView.setText("Waiting runOnUiThread ...");
           
}
        })
;
   
}
})
;

 

 

14、复制Bitmap

Bitmap tmp;
tmp = oribitmap.copy(Bitmap.Config.ARGB_8888, true);

 

 

15、Toast提示功能

Toast.makeText(MainActivity.this, "You Clicked Button1!", Toast.LENGTH_SHORT).show();

 

 

16、选择图片,并显示

Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, PICTURE_CHOOSE);

 

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
   
super.onActivityResult(requestCode, resultCode, intent);

    if
(requestCode == PICTURE_CHOOSE) {
       
if (intent != null) {
           
try {
               
//加载图片并显示
               
ContentResolver resolver = getContentResolver();
               
Uri originalUri = intent.getData();//获得图片的uri
               
img = MediaStore.Images.Media.getBitmap(resolver, originalUri);
               
imageView.setImageBitmap(img);

               
//获取图片的路径
               
Cursor cursor = getContentResolver().query(intent.getData(), null, null, null, null);
               
cursor.moveToFirst();
                int
idx = cursor.getColumnIndex(ImageColumns.DATA);
               
String fileSrc = cursor.getString(idx);
               
textViewDebug.setText("Picture:" + fileSrc);

               
textView.setText("图片加载成功!");
               
buttonDetect.setVisibility(View.VISIBLE);
               
}catch (IOException e) {
               
textView.setText("TAG-->Error" + e.toString());
               
}
        }
       
else {
           
textViewDebug.setText("intent == null");
       
}
    }
}
//onActivityResult()

 

 

17、NDK使用方法:http://blog.csdn.net/taily_duan/article/details/52484583

public static native int[] grayProc(int[] pixels, int w, int h);

static
{
    System.loadLibrary(
"gray-process");
}

 

bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
imageView.setImageBitmap(bmp);

 

int w = bmp.getWidth();
int
h = bmp.getHeight();
int
[] pixels = new int[w*h];
bmp.getPixels(pixels, 0, w, 0, 0, w, h);
int
[] resultInt = grayProc(pixels, w, h);
Bitmap resultImg = Bitmap.createBitmap(w, h, Config.ARGB_8888);
resultImg.setPixels(resultInt, 0, w, 0, 0, w, h);
imageView.setImageBitmap(resultImg);

 

 

18、跳转子页面

Button buttonThree = (Button)findViewById(R.id.button3);
buttonThree.setOnClickListener(new View.OnClickListener() {
   
@Override
   
public void onClick(View v) {
        Toast.makeText(MainActivity.
this, "跳转到子页面!", Toast.LENGTH_SHORT).show();
       
Intent intent = new Intent(MainActivity.this, Main2Activity.class);
       
startActivity(intent);
       
finish();
   
}
})
;

 

 

19、ListView显示:图片+文字

ListView listView = (ListView) findViewById(R.id.listView1);

Map, Object> item1 = new HashMap, Object>();
item1.put("image", R.drawable.vae);
item1.put("name", "duanjjwei");

Map, Object> item2 = new HashMap, Object>();
item2.put("image", R.drawable.smyh);
item2.put("name", "zhuangguangli");

List, Object>> data = new ArrayList, Object>>();
data.add(item1);
data.add(item2);

SimpleAdapter simpleAdapter = new SimpleAdapter(this, data,
     
R.layout.activity_main_item, new String[] { "image", "name" },
      new int
[] { R.id.imageView1, R.id.textView1 });
listView.setAdapter(simpleAdapter);

 

 

20、

 

 

21、

 


 

OpenCV for Android开发技巧

1、实现CvCameraViewListener 需要实现的虚函数,定义BaseLoaderCallback回调函数接口,并实现这个类中的onManagerConnected()方法

private CameraBridgeViewBase mOpenCvCameraView;

 
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(MainActivity.this) {
    @Override
    public void onManagerConnected(int status) {
        switch (status) {
            case LoaderCallbackInterface.SUCCESS:
            {
                Log.i(TAG, "OpenCV loaded successfully");
                imageMat=new Mat();
                //enable camera
                mOpenCvCameraView.enableView();
            } break;
            default:
            {
                super.onManagerConnected(status);
            } break;
        }
    }
};

 

 

2、onResume()中加载OpenCV库(OpenCVLoader);

@Override
public void onResume()
{
   
super.onResume();
    if
(!OpenCVLoader.initDebug()) {
        Log.d(
"OpenCV", "Internal OpenCV library not found. Using OpenCV Manager for initialization");
       
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_10, this, mLoaderCallback);
   
} else {
        Log.d(
"OpenCV", "OpenCV library found inside package. Using it!");
       
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
   
}
}

 

 

3、Mat变量创建

Mat mRgba  = new Mat(height, width, CvType.CV_8UC4);//创建

mRgba.release();//释放

 

 

 

4、根据res路径来读取OpenCV的xml人脸检测文件

private CascadeClassifier cascadeClassifier;

//加载人脸检测xml
  try {
    // Copy the resource into a temp file so OpenCV can load it
    InputStream is = getResources().openRawResource(R.raw.haarcascade_frontalface_alt);
    File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
    File mCascadeFile = new File(cascadeDir, "haarcascade_frontalface_alt.xml");
    FileOutputStream os = new FileOutputStream(mCascadeFile);
  
    byte[] buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = is.read(buffer)) != -1) {
        os.write(buffer, 0, bytesRead);
    }
    is.close();
    os.close();
  
    // Load the cascade classifier
    cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
  } catch (Exception e) {
    Log.e("OpenCVActivity", "Error loading cascade", e);
  }

 

5、人脸检测

private CascadeClassifier cascadeClassifier;


   
//检测并显示
   
MatOfRect faces = new MatOfRect();
    if
(cascadeClassifier != null) {
       
cascadeClassifier.detectMultiScale(mGray, faces, 1.1, 2, 2, new Size(mGray.height()/5, mGray.height()/5), new Size());
   
}

    Rect[] facesArray = faces.toArray()
;
    for
(int i = 0; i length; i++) {
        Core.rectangle(mShow
, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
       
Point pt = new Point();
       
pt.x = facesArray[i].br().x;
       
pt.y = facesArray[i].br().y;
       
String str_x = Double.toString(pt.x);
       
String str_y = Double.toString(pt.y);
       
String str = str_x + ", " + str_y;
       
Core.putText(mShow,str, pt, Core.FONT_HERSHEY_SIMPLEX, 1, new Scalar(255,23,0),2);
   
}

 

6、Bitmap与Mat转换/OpenCV彩色转灰度

//---------------------OpenCV处理------------------------
Mat mat_src = new Mat(bmp.getWidth(), bmp.getHeight(), CvType.CV_8UC4);
Utils.bitmapToMat(bmp, mat_src);
Mat mat_gray = new Mat(bmp.getWidth(), bmp.getHeight(), CvType.CV_8UC1);
Imgproc.cvtColor(mat_src, mat_gray, Imgproc.COLOR_BGRA2GRAY, 1);
Bitmap bmp_dst = Bitmap.createBitmap(mat_gray.cols(), mat_gray.rows(), Bitmap.Config.ARGB_8888 );
Utils.matToBitmap(mat_gray, bmp_dst);

 

7、图片的缩放/或使用resize

//缩放图片大小
public static Bitmap getScaledBitmap(Bitmap m_img, float sx, float sy) {
   Matrix matrix =
new Matrix();
  
matrix.postScale(sx, sy);
  
Bitmap rst = Bitmap.createBitmap(m_img, 0, 0, m_img.getWidth(), m_img.getHeight(), matrix, true);
   return
rst;
}

 

8、Mat中截取Rect部分的图片

Rect[] facesArray = faces.toArray();

Mat copyMat = mGray.submat(facesArray[i]);

 

 

9、使用Core.putText在图像上输入文字

String str = str_x + ", " + str_y + " S1:" + c1 + " S2:"+ c2;
Core.putText(mat_src,str, pt, Core.FONT_HERSHEY_SIMPLEX, 1, new Scalar(255,23,0),2);

 

 

10、Mat、Bitmap、IplImage相互转换

//Mat转成Bitmap
public Bitmap MatToBitmap(Mat src) {
    Bitmap bitmap = Bitmap.createBitmap(src.width()
, src.height(), Bitmap.Config.ARGB_8888);
   
Utils.matToBitmap(src, bitmap);
    return
bitmap;
}

//Bitmap转换成Mat
public Mat bitmapToMat(Bitmap bitmap) {
    Mat rgbMat =
new Mat();
   
Utils.bitmapToMat(bitmap, rgbMat);
    return
rgbMat;
}

//IplImage转换成Bitmap
public Bitmap IplImageToBitmap(opencv_core.IplImage iplImage) {
    Bitmap bitmap =
null;
   
bitmap = Bitmap.createBitmap(iplImage.width(), iplImage.height(), Bitmap.Config.ARGB_8888);
   
bitmap.copyPixelsFromBuffer(iplImage.getByteBuffer());
    return
bitmap;
}

//Bitmap转换成IplImage
public opencv_core.IplImage bitmapToIplImage(Bitmap bitmap) {
    opencv_core.IplImage iplImage
;
   
iplImage = opencv_core.IplImage.create(bitmap.getWidth(), bitmap.getHeight(), opencv_core.IPL_DEPTH_8U, 4);
   
bitmap.copyPixelsToBuffer(iplImage.getByteBuffer());
    return
iplImage;
}

 

 

11、图像的灰度直方图

public double CmpPic(opencv_core.IplImage Image1, opencv_core.IplImage Image2) {
   
int l_bins = 20;
    int
hist_size[] = {l_bins};
    float
v_ranges[] = {0, 100};
    float
ranges[][] = {v_ranges};
   
opencv_core.IplImage imageArr1[] = {Image1};
   
opencv_core.IplImage imageArr2[] = {Image2};
   
opencv_imgproc.CvHistogram Histogram1 = opencv_imgproc.CvHistogram.create(1, hist_size, opencv_imgproc.CV_HIST_ARRAY, ranges, 1);
   
opencv_imgproc.CvHistogram Histogram2 = opencv_imgproc.CvHistogram.create(1, hist_size, opencv_imgproc.CV_HIST_ARRAY, ranges, 1);
   
cvCalcHist(imageArr1, Histogram1, 0, null);
   
cvCalcHist(imageArr2, Histogram2, 0, null);
   
cvNormalizeHist(Histogram1, 100.0);
   
cvNormalizeHist(Histogram2, 100.0);
    return
cvCompareHist(Histogram1, Histogram2, opencv_imgproc.CV_COMP_CORREL);
}

 

 

12、RGB转换成HSV

int nHeight = bitmap.getHeight()/10;
int
nWidth  = bitmap.getWidth()/10;
Mat mat_small = new Mat(nHeight, nWidth, CvType.CV_8UC4);
Imgproc.resize(mat_src, mat_small, new Size(nWidth, nHeight));
Mat mat_gray = new Mat(mat_small.cols(), mat_small.rows(), CvType.CV_8UC1);
Imgproc.cvtColor(mat_small, mat_gray, Imgproc.COLOR_BGRA2GRAY, 1);

//-------------------------------------------------------------------
Mat frame = new Mat(mat_small.cols(), mat_small.rows(), CvType.CV_8UC4);
mat_small.copyTo(frame);

Mat frameHSV = new Mat(mat_small.cols(), mat_small.rows(), CvType.CV_8UC3);;   // hsv空间
Mat mask = new Mat(mat_small.cols(), mat_small.rows(), CvType.CV_8UC1);
Mat dst = new Mat(mat_small.cols(), mat_small.rows(), CvType.CV_8UC3); // 输出图像
//dst.copyTo(frame);
//
中值滤波,去除椒盐噪声
Imgproc.medianBlur(frame, frame, 5);
Imgproc.cvtColor(frame, frameHSV, Imgproc.COLOR_RGB2HSV, 3);
Mat dstTemp1 = new Mat(mat_small.cols(), mat_small.rows(), CvType.CV_8UC1);
Mat dstTemp2 = new Mat(mat_small.cols(), mat_small.rows(), CvType.CV_8UC1);
// 对HSV空间进行量化,得到二值图像,亮的部分为手的形状
Core.inRange(frameHSV, new Scalar(0, 30, 30), new Scalar(40, 170, 256), dstTemp1);
Core.inRange(frameHSV, new Scalar(156, 30, 30), new Scalar(180, 170, 256), dstTemp2);
Core.bitwise_or(dstTemp1, dstTemp2, mask);
//dstTemp1.copyTo(mask);
//
形态学操作,去除噪声,并使手的边界更加清晰
Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
Imgproc.erode(mask, mask, element);
Imgproc.morphologyEx(mask, mask, Imgproc.MORPH_OPEN, element);
Imgproc.dilate(mask, mask, element);
Imgproc.morphologyEx(mask, mask, Imgproc.MORPH_CLOSE, element);

frame.copyTo(dst, mask);

 

 

13、

 

 

14、

 

 

15、

 

 

16、

 

 

17、

 

 

18、

 

 

19、

 

 

 


你可能感兴趣的:(Android,OpenCV)