笔记基于Android+openCV培训进行记录
源码:github
记录不易,喜欢的可以给个三连,感谢感谢!!!
OpenCV概述
什么是OpenCV
OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
OpenCV用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要倾向于实时视觉应用,并在可用时利用MMX和SSE指令, 如今也提供对于C#、Ch、Ruby,GO的支持
OpenCV环境配置
-
下载OpenCV Android SDK(下面以3.4.6版本演示)3.4.6官方下载
-
目录结构
目录 文件 samples OpenCV运行案例 sdk OpenCV API以及依赖库 sdk/etc Haar和LBP级联分类器 sdk/java OpenCV Java Api sdk/libcxx_helper bring libc++_shared.so into packages sdk/native OpenCV静态库、动态库以及JNI文件 -
Android Studio配置
需要配置NDK环境和CMake
-
导入OpenCV前须知
有两种方式- 把sdk/java目录导入项目,但是设备上要安装OpenCV Manager这个第三方软件,这种方式不适合开发通用App
- 把整个sdk目录导入项目,这种方式无需安装第三方软件,一般都是以这种方式进行开发,缺点是这样打包的Apk会比较大,但无伤大雅。
-
新建项目Android 空白项目
-
导入OpenCV SDK
-
创建空白项目后,点击 File-New-import Module,然后选择openCV sdk这个目录
-
-
导入SDK后,需要将opencv的build.gradle里面的版本号与主项目版本号统一
需要将下面三个版本号与主项目统一- compileSdkVersion
- minSdkVersion
- targetSdkVersion
-
在app中的build.gradle导入opencv的依赖
dependencies { ...... implementation project(path: ':opencv') }
-
需要在project structure 中配置ndk版本
-
通过代码查看opencv模块是否加载成功
public void initLoadOpenCV() { boolean success = OpenCVLoader.initDebug(); if (success) { Log.d("init", "initLoadOpenCV: openCV load success"); } else { Log.e("init", "initLoadOpenCV: openCV load failed"); } }
至此,Android OpenCV已近配置完成
OpenCV 简单案例
OpenCV Java Api会经常用到这几个类:
- Mat类,主要用来定义Mat对象,切割Mat对象。常规的Bitmap位图在OpenCV中都要转换为Mat
- Core类,主要用于Mat的运算,提供了很多运算功能的静态函数
- ImgProc类,主要用于图像处理,也提供了很多处理功能的静态函数。
- Utils类,主要用于Mat和Bitmap之间的转换
OpenCV java API参考手册
简单理解
Mat
Mat就是一个图像的矩阵。Mat是由头部与数据部分组成,其中头部还包含了一个指向数据的指针
Bitmap和Mat的转换
bitmap转mat
通过org.opencv.android.Utils来实现相互转换
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.bg_color);
Mat mat = new Mat();
Utils.bitmapToMat(bitmap, mat);
mat转mat
Bitmap newBitmap = Bitmap.createBitmap(mat.width(),mat.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mat,newBitmap);
也可以直接读取源文件获得mat
try {
Mat mat = Utils.loadResource(this,R.mipmap.bg_color);
} catch (IOException e) {
e.printStackTrace();
}
Mat的位运算和算数运算
Mat格式的图像可以直接进行位运算和算数运算。位运算主要支持按位非、按位与、或、异或。算数支持加减乘除。Api如下,下面方法都是Core类的。
方法 | 操作 |
---|---|
bitwise_not(Mat src,Mat dst) | 非 |
bitwise_and(Mat src1,Mat src2,Mat dst) | 与 |
bitwise_or(Mat src1,Mat src2,Mat dst) | 或 |
bitwise_xor(Mat src1,Mat src2,Mat dst) | 异或 |
add(Mat src1,Mat src2,Mat dst) | 矩阵加法 |
subtract(Mat src1,Mat src2,Mat dst) | 矩阵减法 |
multiplf(Mat src1,Mat src2,Mat dst) | 矩阵乘法 |
divide(Mat src1,Mat src2,Mat dst) | 矩阵除法 |
Mat的释放release
定义的Mat一般都要在程序结束前release()释放掉。
protected void onDestroy(){
super.onDestory();
mat.release();
}
例子演示
要注意的是两张源图片像素大小需要是一致的,因为是点对点运算的
使用Utils.loadResource读取源图片
新建一个dst的Mat作为目标Mat
处理完图片后,转换为Bitmap进行UI显示
最后释放掉mat对象
public void xorMat() {
Mat mat1 = null;
Mat mat2 = null;
try {
mat1 = Utils.loadResource(this, R.mipmap.bg_color);
mat2 = Utils.loadResource(this, R.mipmap.bg_1);
} catch (IOException e) {
e.printStackTrace();
return;
}
Mat dst = new Mat();
//运算方法
Core.bitwise_and(mat1, mat2, dst);
//转换回Bitmap
Bitmap newBitmap = Bitmap.createBitmap(dst.width(), dst.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dst, newBitmap);
imageView.setImageBitmap(newBitmap);
mat1.release();
mat2.release();
dst.release();
}
颜色转换
图像色彩模式
**位图模式(二值图):**是图像中最基本的格式,图像只有黑色和白色像素,是色彩模式中占有空间最小的,同样也叫做黑白图,它包含的信息量最少,无法包含图像中的细节,相当于只有0或者1,所以也叫二值图。一副彩色图如果要转換成黑白模式,则一般不能直接转換,需要首先将图像转換成灰度模式。
**灰度模式:**即使用单一色调来表示图像,与位图模式不同,不像位图只有0和1,使用256级的灰度来表示图像,一个像素相当于占用8为一个字节,每个像素值使用0到255的亮度值代表,其中0为黑色, 255为白色,相当于从黑->灰->白的过度,通常我们所说的黑白照片就是这种模式,与位图模式相比,能表现出一定的细节,占用空间也比位图模式较大。
**RGB模式:**为我们经常见到的,被称为真色彩。RGB模式的图像有3个颜色通道,分布为红(Red) ,绿(Green)和蓝(Bule) ,每个都占用8位一个字节来表示颜色信息,这样每个颜色的取值范围为0-255,那么就三种颜色就可以有多种组合,当三种基色的值相等时表现出为灰色,三种颜色都为255即为白色,三种颜色都为0,即为黑色.RGB模式的图像占用空间要比位图,灰度图都要大,但表现出的细节更加明显。
**HSV模式:**是根据日常生活中人眼的视觉对色彩的观察得而制定的一套色彩模式,最接近与人类对色彩的辨认的思考方式,所有的颜色都是用色彩三属性来描述
- H(色相):是指从物体反射或透过物体传播的颜色
- S(饱和度):是指颜色的强度或纯度,表示色相中灰色成分所占的比例
- V(亮度):是指颜色相对明暗程度,通常100%定义为白色;0%定位为黑色
cvtColor()颜色转换函数
OpenCV主要使用cvtColor()进行颜色的转换操作
ImgProc.cvtColor(Mat src,Mat dest,Imgproc.COLOR_CODE)
COLOR_CORE提供了丰富的颜色转换模式
颜色码 | 功能 |
---|---|
Imgproc.COLOR_BGR2RGB | 颜色空间转换 |
Imgproc.COLOR_BGR2GRAY | BGR转换到灰度空间 |
Imgproc.COLOR_GRAY2RGB | 灰度转换到RGB |
Imgproc.COLOR_RGB2HSV | RGB转换到HSV |
Imgproc.COLOR_RGB2RGBA | 添加alpha通道 |
… |
灰度图例子
public void cvtColor() {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.bg_1);
Mat src = new Mat();
Mat dst = new Mat();
Utils.bitmapToMat(bitmap,src);
//转换为灰度图模式
Imgproc.cvtColor(src,dst,Imgproc.COLOR_RGB2GRAY);
//把mat转换回bitmap
Utils.matToBitmap(dst,bitmap);
imageView.setImageBitmap(bitmap);
src.release();
dst.release();
}
二值图例子
也就是位图模式,相当于只有0(即黑色)或者255(即白色),所以也叫二值图。转换二值图关键是确定一个阈值,如果像素点高于阈值,都设置为255,低于则设置为0。就可以呈现出明显黑白效果。
阈值确定有两种方法,一是手动设置,二是自动阈值
手动设置阈值方法
Imgproc.threshold(Mat src,Mat dst,double thresh,double maxval,int type)
src Mat源文件**,仅支持灰度图输入**
dst 输出文件
thresh double第一阈值
maxval double第二阈值
type 阈值类型。
THRESH_BINARY:当像素点灰度值 大于 thresh,像素点值为maxval,反之0
THRESH_BINARY_INV:当像素点灰度值 大于 thresh,像素点值为0,反之maxval
THRESH_TRUNC:当像素点灰度值 大于 thresh,像素点值为thresh,反之不变
THRESH_TOZERO:当像素点灰度值 大于 thresh,像素点值不变,反之为0
THRESH_TOZERO_INV:当像素点灰度值 大于 thresh,像素点值为0,反之不变
Imgproc.threshold(src,dst,125,255,Imgproc.THRESH_BINARY)
自动设置阈值
OpenCV中也可以使用算法来自动计算阈值。OpenCV支持均值算法和高斯均值算法。不是计算全局图像的阈值,而是根据图像不同区域亮度分布,计算其局部阈值,所以对于不同区域,能够自适应计算不同的阈值,所以被叫做自适应阈值法。
如果下面图片因为有暗角的原因,使用手动阈值设置的话会出现这种情况
而这种情况就应该使用自适应阈值法了,适用于文档扫描
自适应阈值方法
Imgporc.adaptiveThreshold(Mat src,Mat dst,double maxValue,int adaptiveMethod,int thresholdType,int blockSize,double c)
- src – 灰度图输入
- dst – 输出
- maxValue – 分配给满足条件的像素的非零值
- adaptiveMethod – 要使用的自适应阈值算法
,ADAPTIVE_THRESH_MEAN_C
(平均计算)或ADAPTIVE_THRESH_GAUSSIAN_C(高斯计算)。
请参阅以下详细信息。 - thresholdType – 必须
THRESH_BINARY
或THRESH_BINARY_INV
的阈值类型。 - blockSize – 用于计算像素阈值的像素邻域的大小:3、5、7 等。
- C – 从平均值或加权平均值中减去的常量。通常,它是正数,但也可以是零或负数。
演示
Imgproc.adaptiveThreshold(src,dst,255,Imgproc.ADAPTIVE_THRESH_MEAN_C,Imgproc.THRESH_BINARY,13,5);
例子演示(根据手动设置阈值)
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;
import androidx.appcompat.app.AppCompatActivity;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
public class ThresholdActivity extends AppCompatActivity {
private ImageView imageView;
private SeekBar seekBar;
private Bitmap bitmap;
private Mat src;
private Mat dst;
@Override
protected void onCreate