@w460461339
2017-06-09T11:30:25.000000Z
字数 13953
阅读 2701
研究生毕业设计 Android
按照 《研究生毕业设计7》中的方法进行本次项目的build时,总是过不了。应该是cmake文件写的有问题,接下来还是需要好好学些cmake文件怎么写才行呀。
这里可以看到,项目中并没有jni文件夹,这也是这个方法和之前方法最不同的一点。
方法和前面一样,这里再说一遍。
opencv用的版本是3.1.0
1、 File -> new -> import module 选择openc目录下sdk下的java文件夹
2、 导入后build会有错误,将左侧android视图切换到project视图,把openCVLibrary310文件夹下的build.gradle打开,修改里面的android平台以及buildtools等参数,使其符合自己的设置。直到不报错
3、 File -> project structure -> app -> dependencies 点击绿色加好,选择3 module 之类的,将openCVLibrary310导入加入到dependencies即可。
至此,opencv添加完成。(注意,这里不需要再导入cpu架构包了)
功能:
1. 通过摄像头拍照获取图像数据。
2. 将图像数据保存,并切换到处理Activity。
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.wzf.face.landmarks2.MainActivity"><Buttonandroid:layout_below="@+id/javaCVLMD"android:onClick="click1"android:layout_width="60dp"android:layout_height="40dp"android:layout_alignParentTop="true"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:text="按钮1"/><org.opencv.android.JavaCameraViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/javaCVLMD"/></RelativeLayout>
public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {public static final String TAG="LMD";JavaCameraView javaCameraView;Mat mRGBA;/*接受onResume里面的回调信息,如果是success,表示opencv加载成功,那么使能显示控件。否则执行默认操作*/BaseLoaderCallback baseLoaderCallback=new BaseLoaderCallback(this) {@Overridepublic void onManagerConnected(int status) {switch (status){case BaseLoaderCallback.SUCCESS:{javaCameraView.enableView();break;}default:{super.onManagerConnected(status);break;}}}};static{System.loadLibrary("MyLibs");}/**获取控件**/@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);javaCameraView=(JavaCameraView)findViewById(R.id.javaCVLMD);javaCameraView.setVisibility(View.VISIBLE);javaCameraView.setCvCameraViewListener(this);}/**三个activity的生命周期方法,用来判断什么时候应该开启opencv的相机,什么时候应该将相机显示控件释放。**/@Overrideprotected void onPause() {super.onPause();if(javaCameraView!=null){javaCameraView.disableView();}}@Overrideprotected void onDestroy() {super.onDestroy();if(javaCameraView!=null){javaCameraView.disableView();}}@Overrideprotected void onResume() {super.onResume();if(OpenCVLoader.initDebug()){Log.i(TAG,"成功");baseLoaderCallback.onManagerConnected(BaseLoaderCallback.SUCCESS);}else{Log.i(TAG,"失败");OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_1_0,this,baseLoaderCallback);}}/**opencv相机监听接口的三个方法的实现,负责将相机帧数据进行初始化,返回到控件以及释放**/@Overridepublic void onCameraViewStarted(int width, int height) {mRGBA=new Mat(height,width, CvType.CV_8UC4);}@Overridepublic void onCameraViewStopped() {mRGBA.release();}@Overridepublic Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {mRGBA=inputFrame.rgba();return mRGBA;}/**按钮点击事件,点击后,先保存数据,再跳转到另一个activity**/public void click1(View view){saveImage(mRGBA);Intent intent=new Intent(this,DetailActivity.class);startActivity(intent);}/**保存图片的方法**/public void saveImage(Mat subImg){Bitmap bmp=null;try{bmp= Bitmap.createBitmap(subImg.cols(),subImg.rows(),Bitmap.Config.ARGB_8888);Utils.matToBitmap(subImg,bmp);}catch (Exception e){Log.d(TAG,e.getMessage());}subImg.release();FileOutputStream out=null;String fileName="frame.png";File sd=new File(Environment.getExternalStorageDirectory()+"/frames");boolean success=true;if(!sd.exists()){success=sd.mkdir();}if(success){File dest=new File(sd,fileName);try{out=new FileOutputStream(dest);bmp.compress(Bitmap.CompressFormat.PNG,100,out);}catch (Exception e){Log.d(TAG,e.getMessage());}finally {try{if(out!=null){out.close();Log.d(TAG,"成功赋值");}}catch (Exception e){Log.d(TAG,e.getMessage());}}}}}
创建完activity后,不要忘了在清单文件中进行注册。
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/iv_detail"/><Buttonandroid:text="来吧!"android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/btn_detail" /></LinearLayout>
public class DetailActivity extends AppCompatActivity {ImageView imageView;Button btnProceess;Bitmap bitmapInput,bitmapOutput;Mat matInput,matOutput;// 加载本地方法库static{System.loadLibrary("MyLibs");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_detail);// 获得控件imageView=(ImageView)findViewById(R.id.iv_detail);btnProceess=(Button)findViewById(R.id.btn_detail);// 获得MainActivity中保存的图片的路径String photoPath= Environment.getExternalStorageDirectory()+"/frames/frame.png";// 设置Bitmap的显示信息BitmapFactory.Options options=new BitmapFactory.Options();options.inPreferredConfig=Bitmap.Config.ARGB_8888;bitmapInput=BitmapFactory.decodeFile(photoPath,options);// 展示原图imageView.setImageBitmap(bitmapInput);// 将Bitmap转化为Mat图片,并创建等大小的新的BitmapmatInput=convertBitmap2Mat(bitmapInput);matOutput=new Mat(matInput.rows(),matInput.cols(), CvType.CV_8UC3);// 按钮事件监听器btnProceess.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {boolean boo= OpenCVLoader.initDebug();if(boo){Toast.makeText(DetailActivity.this,"Calling native function",Toast.LENGTH_SHORT).show();// 调用本地方法,进行landmarks检测NativeClass.LandmarkDetection(matInput.getNativeObjAddr(),matOutput.getNativeObjAddr());Toast.makeText(DetailActivity.this,"Calling native function222",Toast.LENGTH_SHORT).show();// 将Mat转换为Bitmap,并进行显示bitmapOutput=convertMat2Bitmap(matOutput);imageView.setImageBitmap(bitmapOutput);}else{Toast.makeText(DetailActivity.this,"失败",Toast.LENGTH_SHORT).show();}}});}// Mat转换成BitmapBitmap convertMat2Bitmap(Mat img){int width=img.width();int height=img.height();Bitmap bmp;bmp=Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);Mat tmp;tmp=img.channels()==1?new Mat(width,height,CvType.CV_8UC1,new Scalar(1)):new Mat(width,height,CvType.CV_8UC3,new Scalar(3));try{if(img.channels()==3){Imgproc.cvtColor(img,tmp,Imgproc.COLOR_RGB2BGRA);}else if(img.channels()==1){Imgproc.cvtColor(img,tmp,Imgproc.COLOR_GRAY2BGRA);}Utils.matToBitmap(tmp,bmp);}catch(Exception e){Log.d("Exception",e.getMessage());}return bmp;}//bitmap转换成MatMat convertBitmap2Mat(Bitmap rgbaImg){Mat rgbaMat=new Mat(rgbaImg.getHeight(),rgbaImg.getWidth(),CvType.CV_8UC4);Bitmap bmp32=rgbaImg.copy(Bitmap.Config.ARGB_8888,true);Utils.bitmapToMat(bmp32,rgbaMat);Mat rgbNewMat=new Mat(rgbaImg.getHeight(),rgbaImg.getWidth(),CvType.CV_8UC3);Imgproc.cvtColor(rgbaMat,rgbNewMat, Imgproc.COLOR_RGB2BGR,3);return rgbNewMat;}}
package com.wzf.face.landmarks2;public class NativeClass {public native static void LandmarkDetection(long addrInput,long addrOutput);}
从android studio的命令行中,输入
cd app/src/main
javah -d jni -classpath ../../build/intermediates/classes/debuge com.wzf.face.landmarks2.NativeClass (这个是nativeclass的copy reference结果,即包名+类名)
下一步很关键!
在完成上述两个命令后,如果没有出错的话,之后你会获得一个jni文件夹,里面有一个名字还算长的.h文件。将该jni文件夹复制,然后随便找一个地方进行放置。完成后删除项目中的jni文件夹。
比如我就把它放到了一个名为generateLibs的文件夹下。
进入jni文件夹,拷贝.h文件一份,将其重命名为.cpp文件。
/* DO NOT EDIT THIS FILE - it is machine generated */// 以下是需要到的库文件#include <iostream>#include <jni.h>#include <opencv2/opencv.hpp>#include <opencv2/highgui/highgui.hpp>#include <dlib/opencv.h>#include <dlib/image_processing/frontal_face_detector.h>#include <dlib/image_processing/render_face_detections.h>#include <dlib/image_processing.h>#include <dlib/gui_widgets.h>/* Header for class com_wzf_face_landmarks2_NativeClass */// 定义命名空间using namespace cv;using namespace dlib;using namespace std;#ifndef _Included_com_wzf_face_landmarks2_NativeClass#define _Included_com_wzf_face_landmarks2_NativeClass#ifdef __cplusplusextern "C" {#endif// 声明两个方法void faceDetectiononDlib(Mat& img,Mat& dst);void renderToMat(std::vector<full_object_detection>& dets, Mat& dst);/** Class: com_wzf_face_landmarks2_NativeClass* Method: LandmarkDetection* Signature: (JJ)V*/// 仔细看会发下,这个方法就对应于我们在Nativeclass.java中声明的方法JNIEXPORT void JNICALL Java_com_wzf_face_landmarks2_NativeClass_LandmarkDetection(JNIEnv *, jclass, jlong, jlong);#ifdef __cplusplus}#endif#endif
/* DO NOT EDIT THIS FILE - it is machine generated */// 别忘了添加自己的库依赖(com_wzf_face_landmarks2_NativeClass.h)#include <jni.h>#include <com_wzf_face_landmarks2_NativeClass.h>#include "com_wzf_face_landmarks2_NativeClass.h"/* Header for class com_wzf_face_landmarksdetection_NativeClass *//** Class: com_wzf_face_landmarksdetection_NativeClass* Method: LandmarkDetection* Signature: (JJ)V*/// 同理,对应于NativeClass.java中声明的方法JNIEXPORT void JNICALL Java_com_wzf_face_landmarks2_NativeClass_LandmarkDetection(JNIEnv *env, jclass thiz, jlong addrInput, jlong addrOutput){// 获取传入的参数,进行强转Mat& image=*(Mat*) addrInput;Mat& dst=*(Mat*) addrOutput;// 利用dlib进行检测faceDetectiononDlib(image,dst);}void faceDetectiononDlib(Mat& img, Mat& dst){try{// 获取检测器frontal_face_detector detector=get_frontal_face_detector();shape_predictor pose_model;// 加载参数deserialize("storage/emulated/0/shape_predictor_68_face_landmarks.dat")>>pose_model;// 将opencv图像转化为dlib图像cv_image<bgr_pixel> cimg(img);// 检测,面部信息存储在faces中std::vector<dlib::rectangle> faces=detector(cimg);std::vector<full_object_detection> shapes;// 这步不是很懂,存储面部的landmarks信息?for(unsigned long i=0;i<faces.size();i++){shapes.push_back(pose_model(cimg,faces[i]));}// 将结果赋值到dst对象内dst = img.clone();// 将landmarks进行绘图,以便观看显示renderToMat(shapes,dst);}catch(serialization_error& e) {cout<<endl<<e.what()<<endl;}}// 对landmarks进行绘图显示。void renderToMat(std::vector<full_object_detection>& dets, Mat& dst){Scalar color;int sz = 3;color = Scalar(0,255,0);//chin linefor(unsigned long idx = 0; idx < dets.size(); idx++){for (unsigned long i = 1; i <= 16; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);//line on top of nosefor (unsigned long i = 28; i <= 30; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);//left eyebrowfor (unsigned long i = 18; i <= 21; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);//right eyebrowfor (unsigned long i = 23; i <= 26; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);//bottom of nosefor (unsigned long i = 31; i <= 35; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);cv::line(dst, Point(dets[idx].part(30).x(),dets[idx].part(30).y()), Point(dets[idx].part(35).x(), dets[idx].part(35).y()), color, sz);//left eyefor (unsigned long i = 37; i <= 41; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);cv::line(dst, Point(dets[idx].part(36).x(),dets[idx].part(36).y()), Point(dets[idx].part(41).x(), dets[idx].part(41).y()), color, sz);//right eyefor (unsigned long i = 43; i <= 47; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);cv::line(dst, Point(dets[idx].part(42).x(),dets[idx].part(42).y()), Point(dets[idx].part(47).x(), dets[idx].part(47).y()), color, sz);//lips out partfor (unsigned long i = 49; i <= 59; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);cv::line(dst, Point(dets[idx].part(48).x(),dets[idx].part(48).y()), Point(dets[idx].part(59).x(), dets[idx].part(59).y()), color, sz);//lips inside partfor (unsigned long i = 61; i <= 67; ++i)cv::line(dst, Point(dets[idx].part(i).x(), dets[idx].part(i).y()), Point(dets[idx].part(i - 1).x(), dets[idx].part(i - 1).y()), color, sz);cv::line(dst, Point(dets[idx].part(60).x(),dets[idx].part(60).y()), Point(dets[idx].part(67).x(), dets[idx].part(67).y()), color, sz);}}
在复制粘贴别人代码的时候,请千万注意,方法名是否和自己定义的java类中的方法名以及包名对的上。 我就是在这里卡了很久的= - 。
去dlib官网下载dlib,解压即可,我用的是19.1
解压后,将解压出来的文件夹放置在jni文件夹下,如果名字不是dlib的话,重命名为dlib(只是为了写mk文件方便)。

1、与jni文件夹同级时,创建文件夹,名为third_party.
2、在third_party内,创建文件夹,名为opencv
3、将“opencv安装路径”\sdk\native 下的三个文件夹拷贝至2中创建的文件夹内。

至此,导入完成。
LOCAL_PATH := $(call my-dir)# 加载dlib库include $(CLEAR_VARS)LOCAL_MODULE :=dlibLOCAL_C_INCLUDES :=$(LOCAL_PATH)/dlibLOCAL_SRC_FILES += \../$(LOCAL_PATH)/dlib/dlib/threads/threads_kernel_shared.cpp \../$(LOCAL_PATH)/dlib/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp \../$(LOCAL_PATH)/dlib/dlib/base64/base64_kernel_1.cpp \../$(LOCAL_PATH)/dlib/dlib/threads/threads_kernel_1.cpp \../$(LOCAL_PATH)/dlib/dlib/threads/threads_kernel_2.cppLOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)include $(BUILD_STATIC_LIBRARY)#加载opencv库TOP_LEVEL_PATH :=$(abspath $(LOCAL_PATH)/..)####$(info TOP Level Path: $(TOP_LEVEL_PATH))#####EXT_INSTALL_PATH = $(TOP_LEVEL_PATH)/third_partyOPENCV_PATH = $(EXT_INSTALL_PATH)/opencv/jniOPENCV_INCLUDE_DIR = $(OPENCV_PATH)/includeinclude $(CLEAR_VARS)OPENCV_INSTALL_MODULES :=onOPENCV_CAMERA_MODULES :=onOPENCV_LIB_TYPE :=SHAREDinclude $(OPENCV_PATH)/OpenCV.mk# 给自己的库取个名字LOCAL_MODULE := MyLibsLOCAL_C_INCLUDES += \ $(OPENCV_INCLUDE_DIR)# 指定源文件,即之前编写的.cpp文件LOCAL_SRC_FILES := com_wzf_face_landmarks2_NativeClass.cppLOCAL_LDLIBS += -lm -llog -ldl -lz -ljnigraphicsLOCAL_CPPFLAGS += -fexceptions -frtti -std=c++11LOCAL_STATIC_LIBRARIES +=dlibinclude $(BUILD_SHARED_LIBRARY)
NDK_TOOLCHAIN_VERSION := clang#指定自己目标的cpu库APP_ABI := arm64-v8aAPP_CPPFLAGS := -std=c++11 -frtti -fexceptions# 指定目标android levelAPP_PLATFORM := android-23APP_STL := gnustl_static
1、 在jni和third_party所在的文件件内打开命令行窗口。
2、 确保你已经安装了ndk,并可以在任何地方运行(配置环境变量就好),教程自行google.
3、 在命令行窗口内输入ndk-build,若没有错误,等待即可。
4、 若有错误,也是自己编写的.cpp或者.h文件中的问题,根据提示修改即可。
5、完成后即可看见libs和obj两个文件夹。
1、 进入libs文件夹,里面有你目标cpu架构的
2、 在android studio中,右击app,创建JNI文件夹,并命名为jniLibs。
3、 将1中的cpu架构文件夹,粘贴到2中生成的jniLibs文件夹下,即可。

