Android OpenCV 4.6.0 颜色追踪
1. 介绍
通过OpenCV
实现,实时识别摄像头中的固定颜色块的坐标位置,并进行标注。
简而言之,追踪摄像头中纯色物体的运动轨迹。
我们可以通过OpenCV
来识别视频中的纯色物体的移动轨迹。
利用了openCV
中的ColorBlobDetector
功能。
2. 实现
步骤比较简单:
- 获取摄像头拍摄数据,得到ImageProxy 并转为Mat进行计算。
- Android 拍摄的图片默认为rgba格式,将该格式转为HSV。
- 使用Core.inRange() 将指定颜色范围内的色块从图片中分割出来。
- 进行膨胀处理,可以使用morphologyEx 也可以使用dilate。
- 针对膨胀完毕的数据,执行轮廓提取。
- 遍历轮廓数组得到轮廓面积最大的坐标集合。
- 完成
主要步骤为上面这几种。下面,将会介绍如何实现。
2.1 调用摄像头获取Mat
Android CameraX
的初始化就不多赘述了。网上有不少的示例。
我们可以不用预览功能,而单纯使用ImageAnalysis
分析功能。
得到ImageProxy
对象,然后将ImageProxy
对象直接转为Mat对象。
转换方法可以参考:Android ImageProxy 转 OpenCV Mat对象
有完整的介绍。包括图片方向的矫正。
当我们得到Mat后就会开始进行下面的操作了。
PS:本来打算用VideoCapture对象的,但是老是崩溃错误。没办法。
2.2 转HSV
Android拍摄的照片颜色是RGBa格式的。我们需要将该格式转为HSV才能进行下一步。
Mat hsv = new Mat();
Imgproc.cvtColor(mat, hsv, Imgproc.COLOR_RGB2HSV_FULL); //颜色通道转换
将得到的mat对象传进去,然后使用:Imgproc.COLOR_RGB2HSV_FULL
选项进行转换。
可以将得到的hsv对象转为Bitmap,扔给ImageView进行显示,下面的每个步骤都可以将得到的Mat进行显示,这样我们可以了解整个转换过程中的效果。
2.3 inRange 色块提取
我们转换完毕的HSV格式的Mat对象,可以直接进行色块提取。示例:
Mat dst = new Mat();
//颜色检查的上限和下限
Core.inRange(hsv, new Scalar(0,140,121), new Scalar(30,255,255), dst);
其中的两个Scalar 是hsv格式的颜色对象。
第一个是开始值,后面的是结束值。然后openCV就会在这两个颜色范围内进行分割。将属于该颜色范围的地方设置为白色。
不属于的就设置为黑色。
而具体里面的参数应该写多少,就根据大家实际需要采集的颜色进行判断了。
给几个示例:
Core.inRange(hsv, Scalar(30, 40, 50), Scalar(40, 255, 255), dsty); //黄色
Core.inRange(hsv, Scalar(45, 55, 55), Scalar(90, 255, 255), dstg); //绿色
Core.inRange(hsv, Scalar(0,180,121), Scalar(30, 255, 255), dsto); //橙色
大家根据自己的实际需求,可以通过HSV颜色卡,设置不同的颜色。
PS:实在没办法,也可以通过openCV的 samples工程中的 color-blob-detection 示例代码。实现点击触摸获取当前图片的HSV颜色值。 ColorBlobDetector 类中,下面的方法可以打印看看结果值。
public void setHsvColor(Scalar hsvColor) {
double minH = (hsvColor.val[0] >= mColorRadius.val[0]) ? hsvColor.val[0]-mColorRadius.val[0] : 0;
double maxH = (hsvColor.val[0]+mColorRadius.val[0] <= 255) ? hsvColor.val[0]+mColorRadius.val[0] : 255;
mLowerBound.val[0] = minH;
mUpperBound.val[0] = maxH;
mLowerBound.val[1] = hsvColor.val[1] - mColorRadius.val[1];
mUpperBound.val[1] = hsvColor.val[1] + mColorRadius.val[1];
mLowerBound.val[2] = hsvColor.val[2] - mColorRadius.val[2];
mUpperBound.val[2] = hsvColor.val[2] + mColorRadius.val[2];
mLowerBound.val[3] = 0;
mUpperBound.val[3] = 255;
Mat spectrumHsv = new Mat(1, (int)(maxH-minH), CvType.CV_8UC3);
for (int j = 0; j < maxH-minH; j++) {
byte[] tmp = {(byte)(minH+j), (byte)255, (byte)255};
spectrumHsv.put(0, j, tmp);
}
// System.out.println("颜色值 低值:"+ Arrays.toString(mLowerBound.val));
// System.out.println("颜色值 高值:"+ Arrays.toString(mUpperBound.val));
Imgproc.cvtColor(spectrumHsv, mSpectrum, Imgproc.COLOR_HSV2RGB_FULL, 4);
}
2.4 膨胀
我们执行完毕inRange
方法后,就能得到色块了。但是复杂环境下会有一些噪点。我们可以通过膨胀算法进行降噪。
有两种方法:1 通过morphologyEx
进行。2 通过dilate
方法进行
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
Imgproc.morphologyEx(dst, dst, Imgproc.MORPH_OPEN, kernel);//进行开运算
还可以直接通过dilate
进行:
Imgproc.dilate(dst, dst, new Mat());
运算完毕之后,得到的dst对象就是处理结果了。
2.5 轮廓提取
当我们得到膨胀结束后的对,就可以进行轮廓提取findContours
了。示例:
List<MatOfPoint> contours = new ArrayList<MatOfPoint>(); //存储提取后的轮廓对象集合
Mat hireachy = new Mat();//起到一个提取过程中间转换暂存的作用。
Imgproc.findContours(dst, contours, hireachy, Imgproc.RETR_EXTERNAL,
Imgproc.CHAIN_APPROX_SIMPLE); //执行轮廓提取
执行完毕后,contours集合中就存储了各种坐标了。
2.6 最大面积区域提取
我们可以根据区域面积进行区分哪些是我们需要的。哪些是误判的。通常面积最大的就应该是我们需要的物体了。
// 查找最大面积
double maxArea = 0;
Iterator<MatOfPoint> each = contours.iterator();
Rect rect = null;
while (each.hasNext()) {
MatOfPoint wrapper = each.next();
double area = Imgproc.contourArea(wrapper);
if (area > maxArea) {
maxArea = area;
rect = Imgproc.boundingRect(wrapper);//将该区域转为Rect矩形对象
}
}
上面示例中,我是将面积最大的数据,转为了矩形对象。
如果不想转矩形对象。那么可以转为MatOfPoint对象。它绘制的时候将会是多边形,示例:
// 查找最大面积
double maxArea = 0;
Iterator<MatOfPoint> each = contours.iterator();
while (each.hasNext()) {
MatOfPoint wrapper = each.next();
double area = Imgproc.contourArea(wrapper);
if (area > maxArea){
maxArea = area;
}
}
List<MatOfPoint> mContours = new ArrayList<MatOfPoint>();
each = contours.iterator();
while (each.hasNext()) {
MatOfPoint contour = each.next();
if (Imgproc.contourArea(contour) > 0.1*maxArea) {
mContours.add(contour);
}
}
我们可以将数据过滤,得到MatOfPoint对象,也可以是Rect对象。
下一步,就是绘制该对象了
2.7 绘制提取区域
我们得到的数据可能为空,所以要进行判断,如果不为空,那么就绘制一个红色边框的矩形。边框宽度为2。
//得到最大的对象
if (rect != null) {
Imgproc.rectangle(mat, rect, new Scalar(255, 0, 0), 2); //在mat中绘制一个矩形
}
我们如果是MatOfPoint对象,绘制方法如下:
Imgproc.drawContours(mat, mContours, -1, new Scalar(255, 0, 0),2);
2.8 Mat 转 Bitmap
到这一步的时候,就可以将mat转为Bitmap,并给到ImageView进行显示了。OpenCV提供了转换工具:
Bitmap bitmap = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mat, bitmap);
imageView.setImageBitmap(bitmap); //根据自己的ImageView进行替换就可以了。
2.9 release Mat对象
我们在上面的步骤中大量创建和使用了Mat对象,要注意Mat对象的销毁。如果使用完毕后,需要主动调用mat.release()
进行释放对象哦,否则会占用资源。
3. 小结
到这里追踪效果就实现了,我们也可以拿到实时的坐标数据进行其他的业务计算了。
整体实现的代码大部分参考openCV SDK中的samples示例代码。
相关文章
- Android 12 适配升级小结
- Android 显示刷新机制、VSYNC和三重缓存机制
- android移动点餐系统内容和要求,基于Android云计算的移动点餐系统
- android bindservice方法,Android bindservice方法返回false
- android okio使用方法,Android 开源框架 Okio 原理剖析「建议收藏」
- strictmode android,Android中的StrictMode
- android app 退出功能,Android 完美退出 App (Exit)
- Py之cv2:cv2库(OpenCV,opencv-python)的简介、安装、使用方法(常见函数、方法等)最强详细攻略[通俗易懂]
- android短信验证码方案,Android之短信验证码
- Android ListView那些事
- Android为什么不能在子线程更新UI
- android toast全屏,Android Toast实现全屏显示
- Android resource linking failed_android:authorities
- android登录注册跳转的代码_Android开发代码
- android跳转到相册需要权限,Android打开相册获取图片路径[通俗易懂]
- android线程间通信的几种方法_Android进程间和线程间通信方式
- Android OpenCV 4.6 透视变换
- 【Android 异步操作】AsyncTask 异步任务 ( 参数简介 | 方法简介 | 使用方法 | AsyncTask 源码分析 )
- 【Android NDK 开发】NDK C/C++ 代码崩溃调试 - Tombstone 报错信息日志文件分析 ( 获取 tombstone_0X 崩溃日志信息 )
- 【Android 逆向】修改 Android 系统文件 ( ro 只读文件系统 | 系统文件格式 | rootfs | tmpfs | devpts | sysfs |proc | /system )
- 【错误记录】编译 Android 版本的 ijkplayer 报错 ( You must define ANDROID_NDK before starting. | 下载指定版本 NDK )
- 【错误记录】Android Studio 编译报错 ( AAPT: error: failed to read PNG signature: file does not start with PN )
- 【错误记录】Android Studio 集成 ARoute 编译报错 ( 兼容 support 库和 androidx 库 | add ‘tools:replace=“android:appCo )
- 【Android OpenCV】Visual Studio 创建支持 OpenCV 库的 CMake 工程 ① ( 下载 OpenCV 库 | Windows 中安装 OpenCV 库 )
- 【Android OpenCV】Visual Studio 创建支持 OpenCV 库的 CMake 工程 ③ ( CMake 工程中配置 OpenCV 库文件 | 拷贝 OpenCV 函数库文件 )
- Android 自定义View 之 计时文字
- [android] 内容提供者简介详解手机开发
- android FragmentpagerAdapter和FragmentStatePagerAdapter的区别详解手机开发
- 开源新闻综述:谷歌开源 Android 语音转录和手势追踪、Twitter 的遥测工具
- 阿里巴巴旗下平头哥将 Android 10 移植运行在 RISC-V 处理器上
- 一步步搭建Linux环境并安装OpenCV(linux安装opencv)
- android中Invalidate和postInvalidate的更新view区别
- android通用xml解析方法
- Android中动态改变对话框值的方法
- Android笔记之:App自动化之使用Ant编译项目多渠道打包的使用详解
- 在Android中访问WebService接口的方法
- Android开发笔记之:在ImageView上绘制圆环的实现方法
- 基于Android扫描sd卡与系统文件的介绍
- ubuntu用wifi连接android调试程序的步骤