vs2019 基于pcl和opencv的体积检测算法 zed版本+安卓端新手版(二)

Pcl库安卓端的环境配置和使用jni实现c++算法在安卓端的实现

配置pcl的安卓端,也就是说要在linux环境下运行。第一步必须有pcl的.a或者.so的包,因为pcl库使用c++写的底层,所以只有lib和dll,如果需要.a或者.so只能自己编译了。和windows下的库对应。.lib文件就是linux下的.a,也称为静态库,这种库是在程序编译阶段就会被加载,而.dll文件就是linux下的.so,在程序编译完运行的时候需要加载。

Pcl库的编译

安装ubuntu系统

要将pcl的库编译成.a和.so,首先要安装ubuntu系统,ubuntu一共有三种安装的形式:1. 虚拟环境 2. 双系统 3.ubuntu LTS。

第一种方法是创建一个VMware虚拟机将ubuntu安装进去,这种方法本人是不太建议的,因为这样用的话有时候电脑会比较卡,而且还容易出问题。

第二种就是双系统,这个是本人比较推荐的,安装的方法Ubuntu安装

第三种方法就直接在window的应用商店里面搜ubuntu,可以直接在windows上安装,但是运行的话只能是终端的形式,如果命令行比较熟还可以,如果是新手的话是比较推荐第二种方法的。

编译pcl库

由于pcl库依赖的库比较多,所以编译自己写cmakelists的话将会是一个非常浩大的工程,而且遗憾的是,似乎pcl官方也明白这种库在安卓端的路走不远,所以在17年左右就停止了对安卓端库的更新,所以要用的话只能自己编译,还好在github上找到了编译的方法github

不过由于刚接触ubuntu,太多东西懵逼,所以没编译成功,一开始是手机支持的cpu框架问题没弄对,这个github上的编译方法例子是用的armeabi-v8a的框架,但是我的设备是armeabi-v7a框架,所以弄了半天,换了一下。编译出来了,加载到同事用java编写的安卓工程中还是用不了,原因就是我用的是Android NDK r20编译的,但是我们的工程用的是NDK r16,问了一下楼主,她写的这个东西确实不支持r16编译。似乎遇到的绝境。

其实还有一条思路,老鸟的话可以直接在pcl的官网找到编译的方法(我当时怎么就没试试)pcl官网

还有一种直接到网上下载别人编译好的pcl安卓包,我就在sourceforge,上下载到了安卓的安卓版,然后就可以尝试将编译好的.a和.so加载到安卓的工程中。

在android studio实现jni

现在有了pcl的库了,主要做两件事情。
第一个就是让程序能找到它,并成功调用。
第二个就是用把写好的体积检测算法实现。

由于pcl库比较第三方依赖很多,所以调用起来比较麻烦,其中最关键的就是在工程下写cmakelists文件,说白了就是让你在运行程序需要跑c++代码的时候用能够先通过cmakelists控制把所有需要的库加载进来先编译成so,cmakelists写法jni的入门cmakelists写法,这方面资料还是比较多的,查一查都差不多能自己捣鼓出来。

运行的话会在AS环境下生成.so和.apk,将apk安装到安卓端以后就可以运行一下啦,不过我到最后一部的时候打开程序老是闪退,最终也不知道为什么。很有可能的就是pcl库对安卓端的支持很差。

错误

中间有时候会遇到undefined reference to
XXXX的问题,遇到这种问题的话第一时间要考虑动态库是不是没有加载上,如果动态库加载上了,那么很有可能就是在源头上,就是源代码本身就有问题,在编译库的过程中没有把XXXX编译进来,所以调不到。

pcl体积检测c++算法通过jna实现在linux服务器上的云计算

合作完成这个项目的同事能力很强,在得知我pcl库在安卓端表现不佳的情况下,想出了把这套算法移植到服务器上,只留下算法的接口,手机只传入拍下的深度信息,用服务器来计算的方法。于是,我们又开始了下一场修行。

将c++算法打包成dll

Jna调用c++的算法,最简单的方法就是直接将算法打包成dll,这样依赖的环境就都不用管了,然后就自学如何将我的算法打包成dll同时留出接口。

传统的库打包方法包括调用方法一共有两种,一种是显式调用,一种是隐式调用。

显式调用的方法只需要提供dll就可以实现调用,隐式调用必须同时提供dll、lib、h三件套,由于我们这个要在linux环境下调用,隐式调用的方法无法实现,所以这里主要提供显式的调用参考资料参考资料

这里有一点需要注意,由于在VS2017也就是平台工具集V141以后,创建工程中:Win32项目这个已经找不到了,如果想使用VS的这些版本打dll似乎可以直接创建DLL工程,具体的调用方法和打包方法我不清楚。

调试c++和java的接口

由于需要调用dll,接口就必须写好,c++和java的数据格式不同,想实现接口的调用就必须对两者的数据接口形式比较了解,这个调了好久才弄出来。

由于相机向算法传入的是一个深度图像,在java端显示是一堆char类型的数据,他将这些数据映射成byte[]类型传到c++的输入就是char*类型,不过传过来是二进制数,所以我需要先解析二进制,c++对二进制文件的读写方法

将其中的内容转成float,再进行计算,然后将结果转成char*传给他,就实现了云端的计算。

问题:

  1. 这里面有很多细节需要注意,比方说你得清楚手机拍下照片本质是什么样的数据结构,如果不知道你就不知道二进制文件解析成什么类型。
    这里提供一个方法,手机的像素你是知道的,然后根据像素算出来一共有多少像素点,在根据二进制文件的数量和像素点的数量比较,就大概知道这个数据是多少位了,把可能的几种数据类型放进去试一下然后把数据可视化一下就可以知道到底是不是你想要的了。

  2. 接口跑通了以后在实际使用的时候出现了很诡异的现象,就是假如把我的电脑当成服务器来算,是没有问题的,但是如果使用云端的服务器来算,每次都会报错。
    最后发现是因为dll需要的dll没有放到云端导致的,这个问题其实还是比较偏工程。

  3. 代码里一定要提前申请空间来储存这些导入的变量,不然会报错。pcl在输入坐标点前,也一定要把点的数量申请够。
    参考资料

总结

最后这个项目还是因为相机设备的问题(得到的深度信息错误太多)导致最终没法真正得到应用,还有就是云端计算其实用户量少的时候问题不大,但是一旦用户量上来,可不是加几块显卡就能解决的问题了,成本会很高,所以还是要谨慎使用。

在这个过程中不仅学到了很多东西,还结识远在广州的同事,还是很开心的,等我到广州一定要找他玩耍。

彩蛋

在最后调试pcl算法的时候我发现了pcl库的一个问题,就是当你需要直通滤波的时候,pcl出了根据坐标轴来滤波以外并没有提供条件滤波方法,比方我想把一个斜着的面一边的点滤掉或者把一个球内部的点去掉。

由于我的算法需要去除特定角度的一些点,我就设计了一个根据曲面方程去除点的方法,其实很简单,你只需要提前知道你需要去除的曲面,然后把每个点的坐标输入到方程,做一个判断,看是小于零还是大于零就把这些点去除或者留下就行啦~

最后上图
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41240513/article/details/103189444
今日推荐