- 0 前言
- 0.1 一定按照老师给的安装包等去配置环境
- 0.2 运行
- 0.3 修改
- 0.4 资料
- 1 OpenCV概述
- 1.1 什么是OpenCV
- 1.2 opencv环境的配置
- 1.2.1 OpenCV Android SDK
- 1.2.3.4 添加module dependency
- 1.2.3.5 OpenCV库的加载
- 1.2.3.6 Make Project
- 2.OpenCV简单案例
- 2.1 Mat
- 2.1.1 Mat的概念
- 2.1.2 Bitmap和Mat的转换
- 2.1.3 Mat的位运算和算术运算
- 2.1.4 Mat的release
- 2.1.5 例程练习
- 2.2 颜色转换
- 2.2.1 图像色彩模式
- 2.2.2 cvtColor()颜色转换函数
- 2.2.2.1 转换灰度图实例
- 2.2.2.2 转换二值图实例
- 2.2.3 例程练习
- 2.3 几何图形绘制
- 2.3.1 直线绘制
- 2.3.2 矩形绘制
- 2.3.3 多边形绘制
- 2.3.4 圆形绘制
- 2.3.5 文字绘制
本文是安卓开发方面纯纯的新手,最近的项目目的是在android手机上开发一款app,对图像处理后显示处理后的图像。总体功能比较简单。学习过程中受到b站上上海电子信息职业技术学院 沈毓骏老师的视频教程,根据他给的讲义写学习笔记总结如下。大部分内容都来自视频,喜欢的朋友可以对照老师的视频和本讲义 *** 作。
0.1 一定按照老师给的安装包等去配置环境我下载了最新版本的android studio,结果就配置总是出错。
0.2 运行老师运行代码是用的虚拟机,我想在真正的环境上运行。所以就把我的旧手机打开开发者模式,然后去调试的。
0.3 修改建议直接在老师给的demo程序上做修改~
0.4 资料老师给的所有资料都可以扫码获取。在文末
1 OpenCV概述 1.1 什么是OpenCVOpenCV,全称Open Source Computer VisionLibrary,是基于C/C++编写的,是BSD开源许可的计算机视觉开发框架,其开源协议允许在学术研究与商业应用开发中免费使用它。OpenCV支持Windows、Linux、Mac OS、iOS与Android *** 作系统上的应用开发。
OpenCV Android SDK 是OpenCV针对Android平台提供的开发工具包。Android应用开发一般采用Java或者Kotlin语言进行,而OpenCV主要模块采用C、C++语言编制,因在android环境下可以通过JNI技术,实现JAVA或者Kotlin调用OpenCV算法模块的目的。
在android开发环境中配置好OpenCV以后,我们可以方便的调用各种API函数对计算机图像进行各种处理。OpenCV目前可以实现的功能有:
- 图像处理
- 人机互动
- 图像分割
- 人脸检测
- 动作识别
- 运动跟踪
- 运动分析
等等
1.2 opencv环境的配置 1.2.1 OpenCV Android SDKOpenCV-Android-SDK是配置OpenCV环境的重要部分。我们可以到OpenCV的官网进行下载,目前最新版本为4.5.0。OpenCV的[官网链接](https://下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oGHRn(./pic/01.JPG)]
[外链图片转存失败,源站可能有防盗链机制,建议将图g09248414)(cs.2.dn失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img15)(./picn/31失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-19f./pic/04.JPG)]失败,源站可能有防盗链机制,建议将图片保存下来直接上传(7817)(./pic/a的修改配置特别麻烦,容易错。其余我们可以导入整个SDK包,后期的修改和配置特别简单,而且可以脱离OpenCV Manage独立运行。
点击File ->New->import Module。在d出的对话框中定位到SDK位置。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X0w4cpml-1637809248418)(./pic/06.JPG)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WewmNAkL-1637809248418)(./pic/07.JPG)]
确定位置后将Ope9248419)(./pic/08.JPG)]
记住app的compile的值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GrOpdKmF-1637809248419)(./pic/09.JPG)]
然b。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y2zZgHDg-1637809248419)(./pic/10.JPG)]
将该文件中的compile SDK、minSDK、targetSDK版本号改成和app build.gradle中对应的值相同。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iqB6fxxR-1637809248421)(./pic/11.JPG)]
1.2.3.4 添加module dependency之前我们已经把opencv作为一个module导入了project。接下来为project添加module dependency。使我们的Android项目可以识别OpenCV。
点击File -> Project structure…。在d出的对话框的左边栏中选择Dependcies。在中间的Modules中选择app。在右边的Declared Dependcies中选择‘+’号。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x1Th0sQ8-1637809248421)(./pic/12.JPG)]
点击‘+’号以后在下拉选项中选择第三项module dependency。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eX5zcq7s-1637809248422)(./pic/13.JPG)]
在d出的对话框中把SDK选中,这个SDK就是我们之前导入的OpenCV SDK。这一步是添加依赖。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CasY2y3S-1637809248422)(./pic/14.JPG)]
1.2.3.5 OpenCV库的加载可编写一个子函数在程序开始的时候加载OpenCV库。
private void iniLoadOpenCV() { boolean success = OpenCVLoader.initDebug(); if(success) { Toast.makeText(this.getApplicationContext(), "Loading OpenCV Libraries...", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this.getApplicationContext(), "WARNING: Could not load OpenCV Libraries!", Toast.LENGTH_LONG).show(); } }1.2.3.6 Make Project
以上步骤完成后可以点击build -> Make Project编译程序,正常的话编译可以正常通过。
2.OpenCV简单案例OpenCV Java API中我们经常会用到这几个类:
- Mat类主要用来定义Mat对象,切割Mat对象。常规的Bitmap位图在OpenCV中都需要转换为Mat。
- Core类主要用于Mat的运算,提供了很多运算功能的静态函数。
- ImgProc类主要用于图像的处理,也提供了很多处理功能的静态函数。
- Utils类主要用于Mat和/bitmap之间的转换。
OpenCV Java API参考手册可见官网
https://docs.opencv.org/java/3.0.0/
2.1 Mat 2.1.1 Mat的概念Android中对图像是用bitmap格式来进行处理,而OpenCV中是采用Mat格式进行处理。所以我们在Android中使用OpenCV也要将Bitmp转化为Mat格式。Mat类用于表示一个多维的单通道或者多通道的数组。能够用来保存实数或复数的向量、矩阵,灰度或彩色图像,立体元素,张量以及直方图。简而言之,Mat就是用来保存多维的矩阵的。Mat对象中包含了图像的各种基本信息与图像像素数据。Mat是由头部与数据部分组成的,其中头部还包含一个指向数据的指针。我们把Mat可以视作就是图像矩阵。
2.1.2 Bitmap和Mat的转换Bitmap和Mat的转换方法
ory.decodeResource(getResources(), R.drawable.d01);
Mat src = new Mat();
Utils.bitmapToMat(bp, src);
Mat也可以使用以下的代码直接加载图片 srcMat1 = Utils.loadResource(this, R.drawable.d01);
} catch (IOException e) {
e.printStackTrace();
}
Mat也可以转换为Bitmap在Android UI上进行显示,转换代码如下。
bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); Utils.matToBitmap(mat, bitmap);
/
2.1.3 Mat的位运算和算术运算Mat格式的图像可以直接进行位运算和算术运算。
位运算主要支持按位非、按位与、按位或、按位异或。算术运算主要支持加减乘除。这些运算其实实际上都是矩阵的运算。
相应的OpenCV API如下表。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ndok6yw3-1637809248422)(./pic/15.JPG)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-62SKO37d-1637809248423)(./pic/16.JPG)]
比如要对两张图片进行and运算并输出结果可以参考以下的代码。
try { srcMat1 = Utils.loadResource(this, R.drawable.d01); srcMat2 = Utils.loadResource(this, R.drawable.d02); } catch (IOException e) { e.printStackTrace(); } Core.bitwise_and(srcMat1, srcMat2, dstMat); resultBitmap = Bitmap.createBitmap(dstMat.width(), dstMat.height(), Bitmap.Config.ARGB_8888); Utils.matToBitmap(dstMat, resultBitmap); dstImg.setImageBitmap(resultBitmap);2.1.4 Mat的release
用户定义的Mat一般都需要在程序结束时使用release()函数进行内存释放。代码一般放在onDestroy()里,代码如下。
protected void onDestroy() { super.onDestroy(); mat.release(); }2.1.5 例程练习
将两个原图进行按位与、按位或、按位异或、算术加、算术减、算术乘、算术除的运算,并查看结果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4LgQEq5g-1637809248423)(./pic/17.JPG)]
也可以自己找两张原图,注意两张原图应尺寸相同。
2.2 颜色转换 2.2.1 图像色彩模式图像的色彩模式主要有以下几种:
位图模式
位图模式是图像中最基本的格式,图像只有黑色和白色像素,是色彩模式中占有空间最小的,同样也叫做黑白图,它包含的信息量最少,无法包含图像中的细节,相当于只有0或者1。
一副彩色图如果要转换成黑白模式,则一般不能直接转换,需要首先将图像转换成灰度模式。
灰度模式
灰度模式即使用单一色调来表示图像,与位图模式不同,不像位图只有0和1,使用256级的灰度来表示图像,一个像素相当于占用8为一个字节,每个像素值使用0到255的亮度值代表,其中0为黑色,255为白色,相当于从黑->灰->白的过度,通常我们所说的黑白照片就是这种模式,与位图模式相比,能表现出一定的细节,占用空间也比位图模式较大。
RGB模式
RGB模式为我们经常见到的,被称为真色彩。RGB模式的图像有3个颜色通道,分布为红(Red),绿(Green)和蓝(Bule),每个都占用8位一个字节来表示颜色信息,这样每个颜色的取值范围为0~255,那么就三种颜色就可以有多种组合,
当三种基色的值相等时表现出为灰色,三种颜色都为255即为白色,三种颜色都为0,即为黑色。RGB模式的图像占用空间要比位图,灰度图都要大,但表现出的细节更加明显。
HSV模式
是根据日常生活中人眼的视觉对色彩的观察得而制定的一套色彩模式,最接近与人类对色彩的辨认的思考方式,所有的颜色都是用色彩三属性来描述
- H:(色相):是指从物体反射或透过物体传播的颜色
- S:(饱和度):是指颜色的强度或纯度,表示色相中灰色成分所占的比例
- V:(亮度):是指颜色对相对明暗程度,通常 100%定义为白色;0%为黑色
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ArlvFmVJ-1637809248424)(./pic/18.JPG)]
另外还有CMYK模式、YUV模式等。
2.2.2 cvtColor()颜色转换函数OpenCV中主要使用cvtColor()函数进行颜色转换 *** 作。函数原型如下:
Imgproc.cvtColor(source mat, destination mat1, Color_Conversion_Code);
Color_Conversion_Code提供了丰富的颜色转换模式。
Bitmap bp = BitmapFactory.decodeResource(getResources(), R.drawable.d01); Utils.bitmapToMat(bp, src); Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGRA2GRAY); Utils.matToBitmap(dst, bp); iv1.setImageBitmap(bp);
/
转换效果
原图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FtfUIwjd-1637809248425)(./pic/19.JPG)]
转换后
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CaqkQQ6Z-1637809248425)(./pic/20.JPG)]
2.2.2.2 转换二值图实例图像二值化就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。 转换二值图的关键就是确定一个阈值,整张图片中高于阈值的点都置为255,低于阈值的点都置为0,就可以呈现出明显的二值黑白效果。
阈值的确定有两种方法,一种是手动指定,由开发者手动确定一个阈值,在一些专用场景下可以通过实验效果调整。
手动阀值法
手动阈值法所使用的函数的是:Imgproc.threshold()
threshold(Mat src, Mat dst, double thresh, double maxval, int type);
参数 :
-
src : Mat 输入图像
-
dst : Mat 输出图像 阈值 *** 作结果填充在此图像
-
thresh : double 阈值
-
maxval : double 当 type 为 THRESH_BINARY 或 THRESH_BINARY_INV 时的最大值
-
type : int , 阈值类型。对对象取阈值的方式
0:THRESH_BINARY : src(x,y) > thresh ? maxval : 0 。 当前像素点的灰度值 > thresh ,当前像素点值为 maxval ,反之为01:THRESH_BINARY_INV : src(x,y) > thresh ? 0 : maxval 。 当前像素点灰度值 > thresh , 当前像素点值为 0 反之为 maxval
2:THRESH_TRUNC : src(x,y) > thresh ? threshold : src(x,y)。当前像素点灰度值 > thresh , 设定为thresh ,反之保持不变
3:THRESH_TOZERO : src(x,y) > thresh ? src(x,y) : 0 。 当前像素点灰度值 > thresh , 当前像素点值保持不变,其他情况为0
4:THRESH_TOZERO_INV : src(x,y) > thresh ? 0 : src(x,y) 。 当前像素点灰度值 > thresh , 当前像素点值为0 ,其他情况保持不变
手动阈值二值化转换代码
Imgproc.threshold(src,dst,125,255,Imgproc.THRESH_BINARY);
其中125就是我们自己指定的阈值。
效果如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NQJYHzb9-1637809248426)(./pic/21.JPG)]
自动阈值法
OpenCV中也可以使用算法来自动计算阈值。OpenCV支持均值算法和高斯均值算法。它不是计算全局图像的阈值,而是根据图像不同区域亮度分布,计算其局部阈值,所以对于图像不同区域,能够自适应计算不同的阈值,因此被称为自适应阈值法。
如果图像的各处亮度不一致在进行全局阈值二值化的时候会得到不太理想的结果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BdrpH7Gq-1637809248427)(./pic/53.PNG)]
而采用了局部阈值计算的话是计算某个邻域(局部)的均值、高斯加权平均(高斯滤波)来确定阈值。对每个区域来说阈值是不一样的。局部阈值通常会得到较好的二值化效果,上图如果采用局部阈值的话可以得到如下的效果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-69i3gRFY-1637809248427)(./pic/54.PNG)]
自动阈值所使用的函数是Imgproc.adaptiveThreshold(),函数原型如下:
public static adaptiveThreshold(Mat src, Mat dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)
参数说明:
-
src : Mat 输入图像
-
dst : Mat 输出图像 阈值 *** 作结果填充在此图像
-
maxValue : double 分配给满足条件的像素的非零值
-
adaptiveMethod : int 自定义使用的阈值算法,ADAPTIVE_THRESH_MEAN_C 、ADAPTIVE_THRESH_GAUSSIAN_C
ADAPTIVE_THRESH_MEAN_C 时,T(x,y) = blockSize * blockSize【b】
blockSize【b】= 邻域内(x,y) - C
ADAPTIVE_THRESH_GAUSSIAN_C 时,T(x,y) = blockSize * blockSize【b】
blockSize【b】= 邻域内(x,y) - C与高斯窗交叉相关的加权总和 -
thresholdType : int 阈值类型,只能是THRESH_BINARY 、 THRESH_BINARY_INV
-
blockSize : int 用来计算阈值的邻域尺寸 3,5,7等等,奇数
-
C : double 减去平均值或加权平均值的常数,通常情况下,它是正的,但也可能是零或负。
代码实现:
Imgproc.adaptiveThreshold(src,dst,255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 13, 5);
效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wYS4Xcir-1637809248428)(./pic/22.JPG)]
2.2.3 例程练习按本节内容,导入一张图片,编写一个转化灰度图、二值图的APP。可以尝试不同的参数的不同效果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vicVeX0T-1637809248428)(./pic/23.JPG)]
2.3 几何图形绘制 2.3.1 直线绘制几何图形绘制主要使用ImgProc类里的line、rectangle、polylines、circle、ellipse等函数,也可以使用putText函数绘制文字。图形绘制函数一般在APP中起到画面标注的功能。
直线绘制line函数原型
public static void line(Mat img,Point pt1,Point pt2,Scalar color,int thickness);
参数:
- img:需要绘制的图像Mat。
- pt1: 直线起点坐标。
- pt2: 直线终点坐标。
- color:直线的颜色。
- thickness:直线的宽度。
比如我们要在画面的左下到右上画一条红色的宽度为4的直线,可以这样调用。
Imgproc.line(src,new Point(0,src.height()),new Point(src.width(),0),new Scalar(255,0,0),4);
效果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwzqpC1R-1637809248429)(./pic/55.JPG)]
2.3.2 矩形绘制函数原型:
public static void rectangle(Mat img, Point pt1, Point pt2, Scalar color, int thickness);
参数:
- img,需要绘制的图像Mat
- pt1,矩形左上角
- pt2,矩形右下角
- color,绘制直线的颜色
- thickness,直线宽度。若为负值,表示填充
函数原型:
public static void polylines(Mat img, Listpts, boolean isClosed, Scalar color, int thickness);
参数:
- img,输入图像
- pts,多边形端点坐标列表
- isClosed,是否闭合
- color,绘制直线的颜色
- thickness,直线宽度
函数原型:
public static void circle(Mat img, Point center, int radius, Scalar color, int thickness);
参数:
- img,输入图像
- center,圆心坐标
- radius,圆半径
- color,绘制直线的颜色
- thickness,直线宽度。若为负值,表示填充
函数原型:
public static void putText(Mat img, String text, Point org, int fontFace, double fontScale, Scalar color, int thickness);
参数:
- img,输入图像
- text,文字内容
- org,文本字符串的左下角位置
- fontFace,字体类型,可取值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p6YMmlxi-1637809248430)(./pic/56.JPG)]
- fontScale,字体大小
- color,绘制直线的颜色
- thickness,直线宽度
调用代码:
Imgproc.putText(src,"I`m a cat",new Point(src.width() /2,src.height()/3),2,5,new Scalar(0,255,0),3);
效果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4MIRJDdi-1637809248430)(./pic/57.JPG)]
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)