Android+OpenCV实现轨迹识别

    最近在帮朋友搞一个APP,实现:在屏幕上画一条轨迹,然后将各个坐标通过蓝牙发送到下位机。当然,这个坐标是有顺序的,难点也在这里。

    方法一:抓取屏幕点,并实时发送到下位机(已实现)。

	public boolean onTouchEvent(MotionEvent event)
	{
		// 获取触点位置
		float x = event.getX();
		float y = event.getY();
<span style="white-space:pre">		</span>point[0]=x;
<span style="white-space:pre">		</span>point[1]=y;
                ...
                ...
        }
当然了,在这个类里面得定义为public static 变量:
<pre name="code" class="java">public static float[] point=new float[2];
在Client里面,我们开启一个发送数据线程:
		DeliveryThread = new Thread(this);// 连接上了就开始传输吧
		DeliveryThread.start();
重写Runnable接口:

 
 
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {

			try {
				float[] p = DrawView.point;
				byte[] buf0 = intToByteArray((int) p[0]);
				byte[] buf1 = intToByteArray((int) p[1]);
				byte[] buf = new byte[8];
				for (int i = 0; i < 3; i++) {
					buf[i] = buf0[i];
				}
				for (int i = 0; i < 3; i++) {
					buf[i + 4] = buf1[i];
				}

				Log.i("tag", ".." + buf.length + " " + buf[0] + " " + buf[1]
						+ " " + buf[2] + " " + buf[3] + " " + buf[4] + " "
						+ buf[5] + " " + buf[6] + " " + buf[7]);
				mOutStream.write(buf, 0, 8);

			} catch (IOException e) {
				Log.e("tag", "传输错误!");
				break;
			}
			try {
				Thread.sleep(100);//100ms一次
			} catch (InterruptedException e1) {
				break;
			}
		}
	}
这里我们要注意:point数组是float型,首先,我们需强制转换为int型(应该问题不大吧),之后,将int转byte,一个int对应四个byte。一次发一个坐标,两个int,对应8个byte。

	public byte[] intToByteArray(int i) {
		byte[] result = new byte[4];
		// 由高位到低位
		result[0] = (byte) ((i >> 24) & 0xFF);
		result[1] = (byte) ((i >> 16) & 0xFF);
		result[2] = (byte) ((i >> 8) & 0xFF);
		result[3] = (byte) (i & 0xFF);
		return result;
	}
方法二:等画完轨迹之后,对轨迹进行解析,找到关键点并向下位机发送多项式系数(发现不太靠谱!!!)。
这个方法的思想是:1.找轮廓;2.提取关键点;3.曲线拟合;4,将各项系数发送至下位机
关键代码:

处理完图片并开启发送数据的线程:

		if (true == ImageProcess()) {
			DeliveryThread = new Thread(this);// 连接上了就开始传输吧
			DeliveryThread.start();
		}
图片处理:
	public boolean ImageProcess() {
		Log.e("tag", "go into the picture analysis");
		Log.i("tag", "init the matrix");
		mRgba = new Mat();
		mGray = new Mat();
		Utils.bitmapToMat(mImage, mRgba);
		Imgproc.cvtColor(mRgba, mGray, Imgproc.COLOR_RGB2GRAY);

		// 图像二值化
		Mat thresholdImg = mGray;
		Imgproc.adaptiveThreshold(mGray, thresholdImg, 255,
				Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY_INV,
				7, 7);
		// 找轮廓
		List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
		Mat hierarchy = new Mat();
		Imgproc.findContours(thresholdImg, contours, hierarchy,
				Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);
		List<Point> selectPoints = new ArrayList<Point>();// 存储精简后的关键点
		// 将点存入数组当中
		int SampleTime = 20;// 精简倍数
		if (contours != null && contours.size() > 0) {
			Log.i("tag", "轮廓个数=" + contours.size());
			Log.i("tag", "点个数=" + contours.get(0).size().height);
			// Log.i("tag","..="+contours.get(1).size().height);
			keyPoints = new byte[((int) (contours.get(0).size().height))
					/ SampleTime][8];// 两个int,相当于8个byte
			int num = 0;
			int count = 0;
			org.opencv.core.Point[] points = contours.get(0).toArray();//选择最大的轮廓

			try {
				// 在SD卡目录下创建.txt文件,true表示当文件存在时,信息追加在文件尾
				writeFile = new FileOutputStream(
						"/sdcard/Pic.txt", true);
				writer = new OutputStreamWriter(writeFile, "gb2312");
			} catch (Exception e) {
				try {
					writeFile.close();
					writer.close();
				} catch (IOException e1) {

				}
			}
			for (org.opencv.core.Point point : points) {// 遍历每一个point
				// Log.i("tag", "x=" + point.x + ",y=" + point.y);
				count++;
				if (count == SampleTime) {// SampleTime个点采样一个点
					count = 0;
					Point selectPoint = new Point(point.x, point.y);
					selectPoints.add(selectPoint);
					byte[] temp_byte = new byte[4];
					temp_byte = intToByteArray((int) point.x);
					keyPoints[num][0] = temp_byte[0];
					keyPoints[num][1] = temp_byte[1];
					keyPoints[num][2] = temp_byte[2];
					keyPoints[num][3] = temp_byte[3];
					temp_byte = intToByteArray((int) point.y);
					keyPoints[num][4] = temp_byte[0];
					keyPoints[num][5] = temp_byte[1];
					keyPoints[num][6] = temp_byte[2];
					keyPoints[num][7] = temp_byte[3];
					num++;
					// 写入txt文档中
					try {
						writer.write(String.valueOf((int) point.x));
						writer.write(" ");//空格
						writer.write(String.valueOf((int) point.y));
						writer.write("\r\n");//回车换行
						writer.flush();
					} catch (IOException e) {
						try {
							writeFile.close();
							writer.close();
						} catch (IOException e1) {

						}
					}
				}
			}
			try {
				writer.close();
				writeFile.close();
			} catch (Exception e) {

			}
			Log.i("tag", "存储完毕!");
		}

		// 在原来的彩图中画出所有轮廓
		Imgproc.drawContours(mRgba, contours, -1, new Scalar(255, 0, 255));
		// 将关键点画出在原来的彩图中
		for (int i = 0; i < selectPoints.size(); i++) {
			Point center = new Point(selectPoints.get(i).x,
					selectPoints.get(i).y);
			Core.circle(mRgba, center, 4, new Scalar(0, 0, 255), 2);
			Core.putText(mRgba, String.valueOf(i+1), new Point(center.x,
					center.y), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(
					0, 255, 0));
		}
		Core.putText(mRgba, "Key Points Number:"+selectPoints.size(), new Point(0,
				100), Core.FONT_HERSHEY_SIMPLEX, 1, new Scalar(
				255, 0, 255));
		Mat showMat = mRgba;// 要在MainActivity中显示的图像矩阵
		BmpDis = Bitmap.createBitmap(showMat.width(), showMat.height(),
				Config.RGB_565);
		Utils.matToBitmap(showMat, BmpDis);
		MainActivity.mImage = BmpDis;// 在MainActivity中显示

		mAnalysisState = ANALYSIS_OK;
		return true;
	}
发送线程和方法一差不多,这里就不说了。

Android+OpenCV实现轨迹识别_第1张图片
Android+OpenCV实现轨迹识别_第2张图片Android+OpenCV实现轨迹识别_第3张图片

上图为拟合曲线图与关键点图,红线为拟合后的曲线图。可以看出,效果不太好。换一个试试:

Android+OpenCV实现轨迹识别_第4张图片

效果也不太好!!!图形太复杂,拟合不出。之后有待研究~

你可能感兴趣的:(java,android,opencv)