本系统在matlab验证过后,目标是移植到android上。
通过Android的JNI调用c++实现的算法核心部分。
方法:在安卓开发中,通过JNI调用本地C++代码,使用opencv进行开发处理,本地代码通过NDK进行编译。


MainActivity.class

主要实现功能:Android实现录像主要依靠MediaRecorder和SurfaceView这两个类。另外,因为需要对摄像头参数做一些设定,所以也需要Camera类。它们的作用分别是:MediaRecorder通过控制录像音视频源和输出编码等;surfaceview则是作为View的存在提供用户界面,在surfaceview的不同生命周期实现不同的操作;camera类则用于对摄像头参数做一些设定,再调用MediaRecorder的setCamera()
方法将camera对象带入。

  • 初始化屏幕和layout(activity_main.xml)
  • 创建SurfaceView(Surface的意思是表层,表面的意思,那么SurfaceView就是指一个在表层的View对象。因为它有点特殊跟其他View不一样,其他View是绘制在表层外,而它就是充当表层对象。)
    • 初始化相机设置(Camera类)
    • 监听“录制视频”按钮,生成MediaRecorder类对象,并通过该对象的setCamera() 方法设置相机初始化参数,设置帧率30,打开录像,以时间戳为文件名保存每一帧,延时6000ms后关闭录像。(mp4格式)
  • 由点击“查看视频文件”按钮事件,通过Intent()启动”查看视频文件”活动(ShowVideoActivity.class)
  • 由点击“视频处理”按钮事件,通过Intent()启动”视频处理”活动(ProcessActivity.class)

ShowVideoActivity.class

主要实现功能:获取文件列表——选择文件——Uri类播放视频文件


ProcessActivity.class

主要实现功能:首先通过intent.putExtra()和intent.getStringExtra()传递参数,获取MainActivity.class中录制的视频文件名;然后通过MediaMetadataRetriever类解析媒体文件;点击“处理图像”按钮调用处理函数:首先在for循环中通过getFrameAtTime()获取视频中的一帧,在通过Bitmap类的getPixels()方法获取一帧图像的像素值,然后调用距离测距方法,该方法是通过Android的JNI调用实现的;


Android 的 JNI 调用

  • 先在Android工程新建JNI接口类,该类不需要继承任何Java的接口类,我这里定义为OpenCVHelper.class,在该类中声明我们坐标计算的方法。
  • 编译该接口类:在cmd中进入该工程的目录,输入【javah -classpath bin/classes -d jni com.alanjet.videorecordertest.OpenCVHelper】编译接口类,将会在该工程中自动创建jni文件夹,其中包含编译好的【com_alanjet_videorecordertest_OpenCVHelper.h】头文件。
  • 配置Android工程的NativeSupport,将会在jni文件夹中自动添加一个【Android.mk】文件和【com_alanjet_videorecordertest_OpenCVHelper.cpp】文件,并在该.cpp文件中添加具体的接口实现方法。
  • C++实现
JNIEXPORT jdoubleArray JNICALL Java_com_alanjet_videorecordertest_OpenCVHelper_computeXYZ        (JNIEnv *env, jclass obj, jintArray buf, jint offset){    double rotAngle=(double)offset;    const double pi=3.14;    const double fc=574.860069576728280;    int w=640;    int h=480;    int count=0;    int sumInd=0;    double offsetAngle=-(rotAngle)/360.0*pi;    double ind=0,xDis=0,qChange=0;    double sDis=0.2,sRotation=0.105,pixelSize=0.0000022,angle=82.0/180.0*pi,focal=fc*pixelSize,objY=0.5;    double posX,posY,posZ;    /**获取java传递下来的数组**/    jint *cbuf;    cbuf=env->GetIntArrayElements(buf,JNI_FALSE);    if(NULL==cbuf){        return 0;    }    Mat imgData(h,w,CV_8UC4, (unsigned char*)cbuf);   //原始图像数据    vector channels;    split(imgData,channels);   //图像的通道拆分    Mat binaryImg=channels[0];    threshold(binaryImg,binaryImg,10,255,THRESH_OTSU);  //图像二值化,阈值为10    jdouble *ptr=new jdouble[480*3];  //保存由图像光条计算得到的3D坐标    for(int j=0;j<480;j++) //对480行的每一行操作    {        double surToSurAngle=atan( (-pixelSize*(j-240)) / focal);  //基准面角        double focalTransform=focal/cos(surToSurAngle);   //该行的成像点对应的焦距        sumInd=0;count=0;        uchar* data=binaryImg.ptr(j);  //该行每一个像素点值        for(int i=0;i<640;i++)   //对该行的每一列,即每一个像素点操作        {            int temp=(int)data[i];            if(255==temp && i>320)   //统计该行的光条像素位置之和及个数,用来后面求平均值            {                sumInd+=i+1;//第i列代表加上i+1                count++;            }        }        if(0==count)        {            posX=0;            posY=0;            posZ=0;        }        else        {            ind=(double)sumInd/(double)count;  //光条中心位置            xDis=(ind-320)*pixelSize+focalTransform/tan(angle);               qChange=focalTransform*sDis/xDis;  //计算物体到基线的距离            posY=qChange*cos(surToSurAngle);            posZ=qChange*sin(surToSurAngle);            posX=posY/tan(angle)-sRotation;   //获得物体每个点在旋转中心坐标系下的3D坐标            posY=posY-objY;            posX=posX*cos(offsetAngle)+posY*sin(offsetAngle);            posY=posY*cos(offsetAngle)-posX*sin(offsetAngle);  //获得物体每个点在旋转平台旋转到90°时的坐标系下的3D坐标        }        ptr[j*3+0]=posX;        ptr[j*3+1]=posY;        ptr[j*3+2]=posZ;   //存入数组中    }    jdoubleArray result = env->NewDoubleArray(3*480);    /**将ptr赋值给result,该数组返回给Java层**/    env->SetDoubleArrayRegion(result,0,480*3,ptr);    return result;}

更多相关文章

  1. Android异步加载图像小结(含线程池,缓存方法)[转]
  2. Android自动开关机实现
  3. ubuntu下eclipse Android(安卓)ADT中SDK Manager中安装SDK失败的
  4. Android语音通话实现方案及相关技术介绍
  5. 在Android上实现HttpServer
  6. Android(安卓)使用Thread+Handler实现非UI线程更新UI界面
  7. Android横竖屏切换总结
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Mac系统Android(安卓)M源码编译并导入And
  2. Android Intent 总结
  3. 状态栏去掉机主图标
  4. Flutter Android(安卓)打包发布
  5. android post 乱码问题
  6. 【handler】Android定时每十分钟执行一次
  7. android 中对apache httpclient及httpurl
  8. Android清理设备内存具体完整演示样例(一
  9. android拍照,调用系统相册,相片上传
  10. Android api对应版本(持续更新)