Android使用OpenCV CamShift实现目标追踪
CamShift算法基于色值,适用于追踪颜色和背景差异较大的目标。
效果图
以下调试代码,仅供参考:
package com.kongqw;
import android.graphics.Bitmap;
import org.opencv.android.Utils;
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.video.Video;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
/**
* Created by kongqingwei on 2017/4/26.
* ObjectTracker
*/
public abstract class ObjectTracker {
private Mat hsv, hue, mask, prob;
private Rect trackRect;
private RotatedRect rotatedRect;
private Mat hist;
private List<Mat> hsvList, hueList;
private Bitmap bitmap;
private MatOfFloat ranges;
public abstract void onCalcBackProject(Bitmap prob);
public ObjectTracker(Mat rgba) {
hist = new Mat();
trackRect = new Rect();
rotatedRect = new RotatedRect();
hsvList = new Vector<>();
hueList = new Vector<>();
hsv = new Mat(rgba.size(), CvType.CV_8UC3);
mask = new Mat(rgba.size(), CvType.CV_8UC1);
hue = new Mat(rgba.size(), CvType.CV_8UC1);
prob = new Mat(rgba.size(), CvType.CV_8UC1);
bitmap = Bitmap.createBitmap(prob.width(), prob.height(), Bitmap.Config.ARGB_8888);
ranges = new MatOfFloat(0f, 256f);
}
public Bitmap createTrackedObject(Mat mRgba, Rect region) {
//将rgb摄像头帧转化成hsv空间的
rgba2Hsv(mRgba);
updateHueImage();
Mat tempMask = mask.submat(region);
// MatOfFloat ranges = new MatOfFloat(0f, 256f);
MatOfInt histSize = new MatOfInt(25);
List<Mat> images = Collections.singletonList(hueList.get(0).submat(region));
Imgproc.calcHist(images, new MatOfInt(0), tempMask, hist, histSize, ranges);
Bitmap bitmap = Bitmap.createBitmap(hue.width(), hue.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(hue, bitmap);
// 将hist矩阵进行数组范围归一化,都归一化到0~255
Core.normalize(hist, hist, 0, 255, Core.NORM_MINMAX);
trackRect = region;
return bitmap;
}
private void rgba2Hsv(Mat rgba) {
Imgproc.cvtColor(rgba, hsv, Imgproc.COLOR_RGB2HSV);
//inRange函数的功能是检查输入数组每个元素大小是否在2个给定数值之间,可以有多通道,mask保存0通道的最小值,也就是h分量
//这里利用了hsv的3个通道,比较h,0~180,s,smin~256,v,min(vmin,vmax),max(vmin,vmax)。如果3个通道都在对应的范围内,则
//mask对应的那个点的值全为1(0xff),否则为0(0x00).
int vMin = 65, vMax = 256, sMin = 55;
Core.inRange(
hsv,
new Scalar(0, sMin, Math.min(vMin, vMax)),
new Scalar(180, 256, Math.max(vMin, vMax)),
mask
);
}
private void updateHueImage() {
hsvList.clear();
hsvList.add(hsv);
// hue初始化为与hsv大小深度一样的矩阵,色调的度量是用角度表示的,红绿蓝之间相差120度,反色相差180度
hue.create(hsv.size(), hsv.depth());
hueList.clear();
hueList.add(hue);
MatOfInt from_to = new MatOfInt(0, 0);
// 将hsv第一个通道(也就是色调)的数复制到hue中,0索引数组
Core.mixChannels(hsvList, hueList, from_to);
}
public RotatedRect objectTracking(Mat mRgba) {
rgba2Hsv(mRgba);
updateHueImage();
// 计算直方图的反投影。
// Imgproc.calcBackProject(hueList, new MatOfInt(0), hist, prob, ranges, 255);
Imgproc.calcBackProject(hueList, new MatOfInt(0), hist, prob, ranges, 1.0);
// 计算两个数组的按位连接(dst = src1 & src2)计算两个数组或数组和标量的每个元素的逐位连接。
Core.bitwise_and(prob, mask, prob, new Mat());
// 追踪目标
rotatedRect = Video.CamShift(prob, trackRect, new TermCriteria(TermCriteria.EPS, 10, 1));
// 将本次最终到的目标作为下次追踪的对象
trackRect = rotatedRect.boundingRect();
rotatedRect.angle = -rotatedRect.angle;
Imgproc.rectangle(prob, trackRect.tl(), trackRect.br(), new Scalar(255, 255, 0, 255), 6);
Utils.matToBitmap(prob, bitmap);
onCalcBackProject(bitmap);
return rotatedRect;
}
}
使用部分
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
if (null == objectTracker) {
objectTracker = new ObjectTracker(mRgba) {
@Override
public void onCalcBackProject(final Bitmap prob) {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(prob);
}
});
}
};
}
if (null != mTrackWindow) {
Log.i(TAG, "onCameraFrame: objectTracker = " + objectTracker + " mTrackWindow = " + mTrackWindow);
RotatedRect rotatedRect = objectTracker.objectTracking(mRgba);
Imgproc.ellipse(mRgba, rotatedRect, FACE_RECT_COLOR, 6);
Rect rect = rotatedRect.boundingRect();
Imgproc.rectangle(mRgba, rect.tl(), rect.br(), FACE_RECT_COLOR, 3);
}
// System.gc();
return mRgba;
}
int xDown;
int yDown;
@Override
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;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
xDown = (int) event.getX() - xOffset;
yDown = (int) event.getY() - yOffset;
break;
case MotionEvent.ACTION_UP:
int xUp = (int) event.getX() - xOffset;
int yUp = (int) event.getY() - yOffset;
// 获取跟踪目标
mTrackWindow = new Rect(Math.min(xDown, xUp), Math.min(yDown, yUp), Math.abs(xUp - xDown), Math.abs(yUp - yDown));
// 创建跟踪目标
Bitmap bitmap = objectTracker.createTrackedObject(mRgba, mTrackWindow);
imageView.setImageBitmap(bitmap);
Toast.makeText(getApplicationContext(), "已经选中跟踪目标!", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return true;
}
参考

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
移动APP 支付宝快捷支付开发流程
[代码][Java]代码 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 说说开发的心得吧,之前也没接触过支付宝快捷支付,不扯蛋了进入主题。 开发步骤如下 1 :在商家地址申请快捷支付 https: //b.alipay.com 在我的商家服务 申请快捷支付类,然后填写公司信息等等,提交资料进行审核 ,审核通过后会获取到 商家 PID和Key 2 :如何生成私钥,公钥 在支付宝的demo中有openssl文件夹,在bin目录下可以看到openssl.exe文件 ,打开此文件按照文档上说的,如何生成public_pey,private_key,private_psc8 支付宝生成私钥公钥的文档已经说的很清楚了。按照如...
-
下一篇
在iOS应用程序中使用Frida绕过越狱检测
您当前的位置: 安全博客> 技术研究> 在iOS应用程序中使用Frida绕过越狱检测 阿里聚安全在之前的三篇博客中介绍了利用Frida攻击Android应用程序,整个过程仿佛让开发者开启上帝视角,在本篇博客中,我们将会介绍在iOS应用程序中使用Frida绕过越狱检测。即使你从来没有使用过Frida,这篇文章也将会作为进入移动安全开发和分析的入门指南。 相关文章内容: 利用FRIDA攻击Android应用程序(一) 利用FRIDA攻击Android应用程序(二) 利用FRIDA攻击Android应用程序(三) 一、Frida介绍 Frida是一个可以hook App的动态代码工具包,可以向Windows、macOS、Linux、iOS、Android和QNX的本机应用程序中注入JavaScript或自己的库代码。最开始的时候,它是基于谷歌的V8 Javascript运行,但是从版本9开始,Frida已经开始使用其内部的Duktape运行。 列举一些Frida的使用场景: 1、hooking特定函数并更改返回值 2、分析定制协议,同时其动态嗅探/解密 3、应用调试 4、...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- MySQL数据库在高并发下的优化方案
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2整合Thymeleaf,官方推荐html解决方案