Android调用Opencv3.0.0实现对运动目标的跟踪

package com.example.opencv_open_camera_vedio;

import java.util.ArrayList;
import java.util.List;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.Rect;
import org.opencv.core.RotatedRect;
import org.opencv.core.Scalar;
import org.opencv.core.TermCriteria;
import org.opencv.imgproc.Imgproc;
import org.opencv.samples.colorblobdetect.R;
import org.opencv.video.Video;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Toast;

/**
 * 
 * @author Jack_ZGM
 * 
 */
public class MyTracker extends Activity implements OnTouchListener,
		CvCameraViewListener2 {
	// 公共模块
	private CameraBridgeViewBase mOpenCvCameraView;
	private Scalar mColor;
	private Mat mRgba;

	// 跟踪模块
	private boolean mIsColorSelected = false;
	private int winWidth = 130;

	private MatOfFloat rangesH, rangesS, rangesV;// HSV限定值范围
	private MatOfInt chansH, chansS, chansV;// 分别代表h、s、v通道
	private int H_Min = 0, H_Max = 180;
	private int S_Min = 0, S_Max = 180;
	private int V_Min = 0, V_Max = 180;

	private Mat mHist;
	private RotatedRect mRect;
	private Mat mHue;
	private Rect mTrackWindow;
	private Mat mHueImage;
	private List<Mat> planes;
	private MatOfInt histSize;
	private Mat backproject;
	private ArrayList<Mat> images;
	private MatOfInt moi;
	private MatOfFloat mof;
	private TermCriteria term;

	private SeekBar HminBar, HmaxBar;
	private SeekBar SminBar, SmaxBar;
	private SeekBar VminBar, VmaxBar;
	private SeekBar trackBox;

	// 转换摄像头
	private boolean chgCam = false;
	private Button chg_camBtn;

	private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
		@Override
		public void onManagerConnected(int status) {
			switch (status) {
			case LoaderCallbackInterface.SUCCESS: {
				mOpenCvCameraView.enableView();
				mOpenCvCameraView.setOnTouchListener(MyTracker.this);
			}
				break;
			default: {
				super.onManagerConnected(status);
			}
				break;
			}
		}
	};

	public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
		mRgba = inputFrame.rgba();
		if (mIsColorSelected) {
			// 获取hsv颜色空间
			if (mHueImage == null)
				mHueImage = new Mat(mRgba.size(), mRgba.type());
			Imgproc.cvtColor(mRgba, mHueImage, Imgproc.COLOR_RGB2HSV);
			// 获取hsv中的hue分量
			Core.extractChannel(mHueImage, mHue, 0);
			rangesH = new MatOfFloat(H_Min, H_Max);
			rangesS = new MatOfFloat(S_Min, S_Max);
			rangesV = new MatOfFloat(V_Min, V_Max);
			planes.add(mHueImage);
			// 得到直方图
			// Imgproc.calcHist(planes, chans0, new Mat(), mHist, histSize,
			// ranges);
			Imgproc.calcHist(planes, chansH, new Mat(), mHist, histSize,
					rangesH);
			Imgproc.calcHist(planes, chansS, new Mat(), mHist, histSize,
					rangesS);
			Imgproc.calcHist(planes, chansV, new Mat(), mHist, histSize,
					rangesV);
			// 直方图标准化
			Core.normalize(mHist, mHist, 0, 255, Core.NORM_MINMAX);
			// 反向投影图
			images.add(mHue);
			Imgproc.calcBackProject(images, moi, mHist, backproject, mof, 1.0);
			// 获取跟踪框并用椭圆轮廓画出来
			mRect = Video.CamShift(backproject, mTrackWindow, term);
			Imgproc.ellipse(mRgba, mRect, mColor);
			// 通知系统释放内存,但不是实时的,所以并没什么用?
			System.gc();
		} else {
			mHue = new Mat(mRgba.size(), CvType.CV_8UC1);
			backproject = mHue;
		}
		if (mRect != null) {
			int y = (int) mRect.center.y - winWidth / 2;
			int x = (int) mRect.center.x - winWidth / 2;
			mTrackWindow.x = x;
			mTrackWindow.y = y;
			mTrackWindow.width = winWidth;
			mTrackWindow.height = winWidth;
		}
		return mRgba;
	}

	public void onCameraViewStarted(int width, int height) {
		// 公共模块
		mColor = new Scalar(255, 0, 0);
		// 跟踪模块
		mTrackWindow = new Rect();
		mHist = new Mat();
		planes = new ArrayList<Mat>();
		// 设置hsv通道
		chansH = new MatOfInt(0);
		chansS = new MatOfInt(1);
		chansV = new MatOfInt(2);
		histSize = new MatOfInt(10);
		images = new ArrayList<Mat>();
		// 用H分量作为跟踪对象.其余两个做限定条件提高跟踪准确率
		moi = chansH;
		mof = new MatOfFloat(0, 180);
		term = new TermCriteria(TermCriteria.COUNT, 200, 1);
	}

	public boolean onTouch(View v, MotionEvent event) {
		int cols = mRgba.cols();
		int rows = mRgba.rows();

		int xOffset = (mOpenCvCameraView.getWidth() - cols) / 2;
		int yOffset = (mOpenCvCameraView.getHeight() - rows) / 2;

		int x = (int) event.getX() - xOffset;
		int y = (int) event.getY() - yOffset;

		if ((x < 0) || (y < 0) || (x > cols) || (y > rows))
			return false;

		mTrackWindow = new Rect(x - winWidth / 2, y - winWidth / 2, winWidth,
				winWidth);

		mIsColorSelected = true;

		return false; // don't need subsequent touch events
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		setContentView(R.layout.color_blob_detection_surface_view);

		mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.color_blob_detection_activity_surface_view);
		mOpenCvCameraView.setCvCameraViewListener(this);
		mOpenCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);
		// mOpenCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);
		// 获取滚动条,通过设置滑动条监听改变v通道值的范围
		MyseekbarListener sbListen = new MyseekbarListener();
		// H
		HminBar = (SeekBar) findViewById(R.id.HseekBarMin);
		HmaxBar = (SeekBar) findViewById(R.id.HseekBarMax);
		HminBar.setOnSeekBarChangeListener(sbListen);
		HmaxBar.setOnSeekBarChangeListener(sbListen);
		// S
		SminBar = (SeekBar) findViewById(R.id.SseekBarMin);
		SmaxBar = (SeekBar) findViewById(R.id.SseekBarMax);
		SminBar.setOnSeekBarChangeListener(sbListen);
		SmaxBar.setOnSeekBarChangeListener(sbListen);
		// V
		VminBar = (SeekBar) findViewById(R.id.VseekBarMin);
		VmaxBar = (SeekBar) findViewById(R.id.VseekBarMax);
		VminBar.setOnSeekBarChangeListener(sbListen);
		VmaxBar.setOnSeekBarChangeListener(sbListen);
		// 可设置跟踪框的大小
		trackBox = (SeekBar) findViewById(R.id.seekBarTracBox);
		trackBox.setOnSeekBarChangeListener(sbListen);
		// 摄像头转换按钮
		MyOnClickListen click = new MyOnClickListen();
		chg_camBtn = (Button) findViewById(R.id.chg_cam);
		chg_camBtn.setOnClickListener(click);
	}

	// 按钮监听器
	class MyOnClickListen implements OnClickListener {

		@Override
		public void onClick(View v) {
			if (v.equals(chg_camBtn)) {
				if (chgCam) {
					mOpenCvCameraView
							.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);

				} else {
					mOpenCvCameraView
							.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);

				}
				chgCam = !chgCam;
			}
		}
	}

	// 创建一个滑动条监听内部类
	class MyseekbarListener implements OnSeekBarChangeListener {

		@Override
		public void onProgressChanged(SeekBar sb, int progress, boolean arg2) {
			// H
			if (sb.equals(HminBar)) {
				if (progress < H_Max)
					H_Min = progress;
				else {
					Toast.makeText(getApplicationContext(),
							"H分量设置错误:H_Min必须小于H_Max", Toast.LENGTH_SHORT)
							.show();
				}
			}
			if (sb.equals(HmaxBar)) {
				if (progress > H_Min)
					H_Max = progress;
				else {
					Toast.makeText(getApplicationContext(),
							"H分量设置错误:H_Min必须小于H_Max", Toast.LENGTH_SHORT)
							.show();
				}
			}
			// S
			if (sb.equals(SminBar)) {
				if (progress < S_Max)
					S_Min = progress;
				else {
					Toast.makeText(getApplicationContext(),
							"S分量设置错误:S_Min必须小于S_Max", Toast.LENGTH_SHORT)
							.show();
				}
			}
			if (sb.equals(SmaxBar)) {
				if (progress > S_Min)
					S_Max = progress;
				else {
					Toast.makeText(getApplicationContext(),
							"S分量设置错误:S_Min必须小于S_Max", Toast.LENGTH_SHORT)
							.show();
				}
			}
			// V
			if (sb.equals(VminBar)) {
				if (progress < V_Max)
					V_Min = progress;
				else {
					Toast.makeText(getApplicationContext(),
							"V分量设置错误:V_Min必须小于V_Max", Toast.LENGTH_SHORT)
							.show();
				}
			}
			if (sb.equals(VmaxBar)) {
				if (progress > V_Min)
					V_Max = progress;
				else {
					Toast.makeText(getApplicationContext(),
							"V分量设置错误:V_Min必须小于V_Max", Toast.LENGTH_SHORT)
							.show();
				}
			}

			if (sb.equals(trackBox)) {
				if (progress > 0)
					winWidth = progress;
			}
		}

		@Override
		public void onStartTrackingTouch(SeekBar arg0) {

		}

		@Override
		public void onStopTrackingTouch(SeekBar arg0) {

		}
	}

	@Override
	public void onPause() {
		super.onPause();
		if (mOpenCvCameraView != null)
			mOpenCvCameraView.disableView();
	}

	@Override
	public void onResume() {
		super.onResume();
		OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_9, this,
				mLoaderCallback);
	}

	public void onDestroy() {
		super.onDestroy();
		if (mOpenCvCameraView != null)
			mOpenCvCameraView.disableView();
	}

	public void onCameraViewStopped() {
		mRgba.release();
	}
}

 

转载于:https://my.oschina.net/zhanggongming/blog/683587

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值