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
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<length;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
item1.put("image", R.drawable.vae);
item1.put("name", "duanjjwei");
Map
item2.put("image", R.drawable.smyh);
item2.put("name", "zhuangguangli");
List
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 <facesArray.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、
手机扫一扫
移动阅读更方便
你可能感兴趣的文章