Part1一. 业务背景
我们团队前段时间做了一款小型的智能硬件,它能够自动拍摄一些商品的图片,这些图片将会出现在电商 App 的详情页并进行展示。
基于以上的背景,我们需要一个业务后台用于发送相应的拍照指令,还需要开发一款软件(上位机)用于接收拍照指令和操作硬件设备。
Part2二. 原先的实现方式以及痛点
早期为了快速实现功能,我们团队使用 JavaCV 调用 USB 摄像头(相机)进行实时画面的展示和拍照。这样的好处在于,能够快速实现产品经理提出的功能,并快速上线。当然,也会遇到一些问题。
我列举几个遇到的问题:
软件体积过大
编译速度慢
软件运行时占用大量的内存
对于获取的实时画面,不利于在软件侧(客户端侧)调用机器学习或者深度学习的库,因为整个软件采用 Java/Kotlin 编写的。
Part3三. 使用 OpenCV 进行重构
基于上述的原因,我尝试用 OpenCV 替代 JavaCV 看看能否解决这些问题。
13.1JNI 调用的设计
由于我使用 OpenCV C++ 版本来进行开发,因此在开发之前需要先设计好应用层(我们的软件主要是采用 Java/Kotlin 编写的)如何跟 Native 层进行交互的一些的方法。比如:USB 摄像头(相机)的开启和关闭、拍照、相机相关参数的设置等等。
为此,设计了一个专门用于图像处理的类 WImagesProcess(W 是项目的代号),它包含了上述的方法。
object WImagesProcess {
init {
System.load("${FileUtil.loadPath}WImagesProcess.dll")
}
/**
* 算法的版本号
*/
external fun getVersion():String
/**
* 获取 OpenCV 对应相机的 index id
* @param pidvid 相机的 pid、vid
*/
external fun getCameraIndexIdFromPidVid(pidvid:String):Int
/**
* 开启俯拍相机
* @param index 相机的 index id
* @param cameraParaMap 相机相关的参数
* @param listener jni 层给 Java 层的回调
*/
external fun startTopVideoCapture(index:Int, cameraParaMap:Map<String,String>, listener: VideoCaptureListener)
/**
* 开启侧拍相机
* @param index 相机的 index id
* @param cameraParaMap 相机相关的参数
* @param listener jni 层给 Java 层的回调
*/
external fun startRightVideoCapture(index:Int, cameraParaMap:Map<String,String>, listener: VideoCaptureListener)
/**
* 调用对应的相机拍摄照片,使用时需要将 IntArray 转换成 BufferedImage
* @param cameraId 1:俯拍相机; 2:侧拍相机
*/
external fun takePhoto(cameraId:Int): IntArray
/**
* 设置相机的曝光
* @param cameraId 1:俯拍相机; 2:侧拍相机
*/
external fun exposure(cameraId: Int, value: Double):Double
/**
* 设置相机的亮度
* @param cameraId 1:俯拍相机; 2:侧拍相机
*/
external fun brightness(cameraId: Int, value: Double):Double
/**
* 设置相机的焦距
* @param cameraId 1:俯拍相机; 2:侧拍相机
*/
external fun focus(cameraId: Int, value: Double):Double
/**
* 关闭相机,释放相机的资源
* @param cameraId 1:俯拍相机; 2:侧拍相机
*/
external fun closeVideoCapture(cameraId:Int)
}
其中,VideoCaptureListener 是监听 USB 摄像头(相机)行为的 Listener。
interface VideoCaptureListener {
/**
* Native 层调用相机成功
*/
fun onSuccess()
/**
* jni