65.9K
CodeProject 正在变化。 阅读更多。
Home

Android 中的运动检测 - 操作指南

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (16投票s)

2014 年 6 月 29 日

CPOL

1分钟阅读

viewsIcon

66349

在 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 应用 中的截图。

Motion detection using background subtraction technique

使用背景减除技术,

Motion detection using background subtraction technique

关注点

除了运动和人脸检测之外,OpenCV4Android 肯定可以提供更多功能。 在我接下来的文章中,我将描述我如何使用这个库在我的 Android 应用中进行图像处理。

© . All rights reserved.