昨天公众号中收到多学多看多体会多感悟的留言问在Android OpenCV里是否能能调用稠密光流,由于我也没有试过,所以我们就专门来做了一次这个操作,也感谢留言的小伙伴提出的问题,我们也是在不断地解决问题中学习成长的。
经过自己的测试,Android利用NDK方式实现稠密光流还是可以的,不过和我在《C OpenCV视频操作之稠密光流对象跟踪》里提到过的,稠密光流算法(即图像上所有像素点的光流都计算出来),由于要计算图像上所有点的光流,故计算耗时,速度慢。
视频效果
点击边框调出视频工具条
稠密光流代码实现
稠密光流的API及简单的例子在《C OpenCV视频操作之稠密光流对象跟踪》中已经提到了,这里我就不再提了,主要是说在Android中怎么实现的,源码我会在文章最后贴出地址,主要还是用了《Android通过OpenCV和TesserartOCR实时进行识别》中的程序,以后OpenCV4Android中的实现一般还是在在那个程序中来做测试,主要是从头搭建也比较麻烦。
创建C 文件
我们在CPP下面新建了opticalflow的头文件和源文件
头文件中两个方法,一个是native-lib中调用的方法,一个是在源图上进行绘制的方法
Opticalflow.cpp
定义两个Mat,一个是上一帧的灰度图,一个是稠密光流处理的数据。
绘制结果函数
外部调用稠密光流的方法
上面两个红框,一个是20的参数是把偏移量大于20的才进行绘制处理,另一个是将当前的灰度图存放到前一帧灰度图中等处理,在《C OpenCV视频操作之稠密光流对象跟踪》中我们是只取了第一帧,显示出来的就是从第一帧中不停的进行变化的绘制,但是我们这个Demo中显示的图像只有一个,摄像头也随时可以移动,所以用那篇中只对比第一帧的情况是不行的,所以我这里改为都是当前帧对比前一帧的数据。
核心代码
代码语言:javascript复制//
// Created by 36574 on 2019-08-11.
//
#include "opticalflow.h"
//定义前一帧灰度图
Mat prev_gray;
//定义数据
Mat flowdata;
//绘制结果的函数
void opticalflow::drawcalcFlowHF(Mat &flowdata, Mat &image, int step) {
for (size_t row = 0; row < flowdata.rows; row ) {
for (size_t col = 0; col < flowdata.cols; col ) {
const Point2f fxy = flowdata.at<Point2f>(row, col);
//判断大于输入的step后进入
if (fxy.x > step || fxy.y > step) {
//用绿色画线点到前一帧的差
line(image, Point(col, row),
Point(cvRound(col fxy.x), cvRound(row fxy.y)),
Scalar(0, 255, 0));
//用红色画点为当前的点
circle(image, Point(col, row), 2, Scalar(255, 0, 0), -1);
}
}
}
}
//稠密光流
vector<Mat> opticalflow::dealOpticalFlow(Mat &src) {
Mat gray;
//转为灰度图
cvtColor(src, gray, COLOR_BGRA2GRAY);
//判断是否有前一帧图像
if (!prev_gray.empty()) {
//存在前一帧进行稠密光流操作
calcOpticalFlowFarneback(prev_gray, gray, flowdata,
0.5, 3, 15, 3, 5, 1.2, 0);
//将结果绘画出来,这里参数为20就是变化大的才显示出来
drawcalcFlowHF(flowdata, src, 20);
}
//将前一帧图像存放到
gray.copyTo(prev_gray);
return vector<Mat>();
}
视频截图
源码地址
GitHub:https://github.com/Vaccae/AndroidOpenCVTesserartOCR
-END-