Android 中的运动检测 - 操作指南
在 Android 应用中使用 OpenCV4Android
引言
本文描述了如何将 OpenCV4Android 用于我最近开发的一个 Android 应用,以检测捕获的摄像头图像中的运动和人脸。
背景
在开发我的 Android 应用时,我一直在研究一种执行图像处理和运动检测的简单方法。OpenCV 作为一个开源的计算机视觉和机器学习软件库,满足了我的需求,因为它已经被移植到 Android 环境中。
使用代码
关于使用 OpenCV4Android 在 Android 上进行开发,有一个很好的介绍 在这里。 我不会在此处深入探讨细节,而是重点介绍我如何使用这个库。
OpenCV4Android 具有访问内置手机摄像头的接口,以捕获摄像头帧进行进一步处理。 您可以参考 示例 了解代码的使用方式。
在我的应用中,我捕获输入帧,然后使用库提供的运动检测算法。
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
if (isNotRealTimeProcessing()) {
// Check if needs to do real-time motion detection
try {
streamingLock.lock();
capturedFrame = inputFrame.rgba();
} finally {
streamingLock.unlock();
}
if (!frameProcessing && !isUploadInProgress) {
frameProcessing = true;
capturedFrame.copyTo(processingFrame);
fireProcessingAction(ProcessingAction.PROCESS_FRAME);
}
return capturedFrame;
} else {
return processFrame(inputFrame.rgba());
}
}
有几种方法可以检测运动,最简单的方法是将帧转换为灰度,并获取帧之间的差异。
public final class BasicDetector extends BaseDetector implements IDetector {
private static final String TAG = AppConfig.LOG_TAG_APP + ":BasicDetector";
// number of cyclic frame buffer used for motion detection
// (should, probably, depend on FPS)
public static final int N = 4;
// ring image buffer
private Mat[] buf = null;
private int last = 0;
private List<matofpoint> contours = new ArrayList<matofpoint>();
private int threshold;
private Mat hierarchy = new Mat();
public BasicDetector(int threshold) {
this.threshold = threshold;
}
@Override
public Mat detect(Mat source) {
Size size = source.size(); // get current frame size
int i, idx1 = last, idx2;
Mat silh;
// allocate images at the beginning or
// reallocate them if the frame size is changed
if (buf == null || buf[0].width() != size.width || buf[0].height() != size.height) {
if (buf == null) {
buf = new Mat[N];
}
for (i = 0; i < N; i++) {
if (buf[i] != null) {
buf[i].release();
buf[i] = null;
}
buf[i] = new Mat(size, CvType.CV_8UC1);
buf[i] = Mat.zeros(size, CvType.CV_8UC1);
}
}
// convert frame to gray scale
Imgproc.cvtColor(source, buf[last], Imgproc.COLOR_BGR2GRAY);
// index of (last - (N-1))th frame
idx2 = (last + 1) % N;
last = idx2;
silh = buf[idx2];
// get difference between frames
Core.absdiff(buf[idx1], buf[idx2], silh);
// and threshold it
Imgproc.threshold(silh, silh, threshold, 255, Imgproc.THRESH_BINARY);
// Log.i(TAG, "Computed threshold - " + computedThreshold);
contours.clear();
Imgproc.findContours(silh, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Imgproc.drawContours(source, contours, -1, contourColor, contourThickness);
if (contours.size() > 0) {
targetDetected = true;
} else {
targetDetected = false;
}
return source;
}
}
</matofpoint></matofpoint>
或者,您可以使用背景减除技术来检测运动。
public final class BackgroundSubtractorDetector extends BaseDetector implements IDetector {
private static final double LEARNING_RATE = 0.1 ;
private static final int MIXTURES = 4;
private static final int HISTORY = 3;
private static final double BACKGROUND_RATIO = 0.8;
// ring image buffer
private Mat buf = null;
private BackgroundSubtractorMOG bg;
private Mat fgMask = new Mat();
private List<matofpoint> contours = new ArrayList<matofpoint>();
private Mat hierarchy = new Mat();
public BackgroundSubtractorDetector() {
bg = new BackgroundSubtractorMOG(HISTORY, MIXTURES, BACKGROUND_RATIO);
}
public BackgroundSubtractorDetector(int backgroundRatio){
bg = new BackgroundSubtractorMOG(HISTORY, MIXTURES, (backgroundRatio / 100.0));
}
@Override
public Mat detect(Mat source) {
// get current frame size
Size size = source.size();
// allocate images at the beginning or
// reallocate them if the frame size is changed
if (buf == null || buf.width() != size.width || buf.height() != size.height) {
if (buf == null) {
buf = new Mat(size, CvType.CV_8UC1);
buf = Mat.zeros(size, CvType.CV_8UC1);
}
}
// convert frame to gray scale
Imgproc.cvtColor(source, buf, Imgproc.COLOR_RGBA2RGB);
bg.apply(buf, fgMask, LEARNING_RATE); //apply() exports a gray image by definition
//Imgproc.erode(fgMask, fgMask, new Mat());
//Imgproc.dilate(fgMask, fgMask, new Mat());
//Imgproc.cvtColor(fgMask, silh, Imgproc.COLOR_GRAY2RGBA);
contours.clear();
Imgproc.findContours(fgMask, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Imgproc.drawContours(source, contours, -1, contourColor, contourThickness);
if (contours.size() > 0) {
targetDetected = true;
} else {
targetDetected = false;
}
return source;
}
}
</matofpoint></matofpoint>
您可以在 这里 找到这些算法的源代码。
几张使用上述算法在我的 Android 应用 中的截图。
使用背景减除技术,
关注点
除了运动和人脸检测之外,OpenCV4Android 肯定可以提供更多功能。 在我接下来的文章中,我将描述我如何使用这个库在我的 Android 应用中进行图像处理。