OpenCV
概述
OpenCV(开源核算机视觉库)是在BSD(开源协议)答应下发布的。它是一个高度优化的库,专心于实时运用程序。它具有C ++,Python和Java接口,支撑Windows,Linux,Mac OS,iOS和Android。
OpenCV是一个开源的核算机视觉库,它提供了一系列丰厚的图画处理和核算机视觉算法,包括图画读取、显现、滤波、特征检测、方针盯梢等功能。
OpenCV被广泛运用于各种领域,如医疗印象处理、智能交通、安防监控、机器人视觉、虚拟现实等。它能够协助开发者快速构建高效、准确、可靠的核算机视觉运用,而且支撑多种编程言语,如C++、Python、Java等。
在核算机视觉运用中,OpenCV能够用来进行图画预处理、特征提取、物体检测、方针盯梢、三维重建等操作。经过结合深度学习技术,OpenCV还能够用于图画分类、方针分割、姿势估量等愈加杂乱的任务。
官网文档地址:https://docs.opencv.org/4.6.0/df/d65/tutorial_table_of_content_introduction.html
教程参考:https://www.w3cschool.cn/opencv/
教程参考:https://www.yiibai.com/opencv/opencv_adding_text.html
下载与装置
下载地址:https://opencv.org/releases/
下载到本地后,双击进行装置即可
目录阐明
装置目录如下
build :依据window构建
sources:开源,提供源码
build目录阐明
这儿是Java开发重视java目录即可
x64与x86代表给不同的体系运用
opencv-460.jar给java操作openvc的程序包
由所以64位体系,所以重视x64目录
DLL(Dynamic Link Library)文件为动态链接库文件,又称“运用程序拓宽”,是软件文件类型。DLL文件,放置于体系中。当履行某一个程序时,相应的DLL文件就会被调用
项目集成
办法1:
这儿运用IDEA进行开发,导入opencv-460.jar库
运用快捷键 Ctrl+Shift+Alt+S打开 挑选库项,导入Java库。 办法2:
除了上述办法,还能够将
opencv-460.jar
装置到本地仓库或私有仓库,然后在pom.xml中引入依靠。
在项目根目录创立lib
目录,将上述提及的opencv-460.jar
与opencv_java460.dll
放到该目录
在pom.xml
文件中,经过坐标的形式引入
<!-- 加载lib目录下的opencv包 -->
<dependency>
<groupId>org.opencv</groupId>
<artifactId>opencv</artifactId>
<version>4.6.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/opencv-460.jar</systemPath>
</dependency>
验证
public class MyTest {
// 调用OpenCV库文件
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String args[]) {
// 创立一个3X3的对角矩阵
Mat a = Mat.eye(3, 3, CvType.CV_8UC1);
System.out.println(a.dump());
}
}
履行上述代码,不出意外将呈现如下异常:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java460 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:871)
at java.lang.System.loadLibrary(System.java:1122)
处理方案有2种:
1.将D:\Development\opencv\build\java\x64\opencv_java460.dll
文件拷贝至下面2个目录,任选其一即可。
2.经过指定虚拟机参数处理:
-Djava.library.path=D:\WorkSpace\projectName\demo\lib\opencv_java460.dll
Mat类
OpenCV中的Mat类是一个用于标明图画、矩阵和向量的根本数据类型,它能够包含恣意尺度和类型的元素。
创立Mat方针
创立一个Mat方针
# 生成一个空的矩阵
Mat mat = new Mat();
创立Mat方针时一起设置矩阵的根本参数
params1:代表矩阵的行数(rows)
params2:代表矩阵的列数(cols)
params3:代表矩阵中像素点的位数和通道数
Mat a = Mat.eye(3, 3, CvType.CV_8UC1);
其他操作
访问Mat方针中的像素值
double[] pixel = mat.get(row, col); // 获取像素值
修正Mat方针中的像素值
mat.put(row, col, new double[]{255, 255, 255}); // 修正像素值
获取Mat方针的巨细和通道数
int rows = mat.rows(); // 获取行数
int cols = mat.cols(); // 获取列数
int channels = mat.channels(); // 获取通道数
常见图画API
读取与输出图画
在OpenCV中,图象输入与输出运用
imread()
、imwrite()
两个办法
1.imread()
params1:代表输入图片路径
params2:一个标志标明加载图象的色彩类型
从文件读取一张图画并创立一个Mat方针
Mat mat1 = Imgcodecs.imread("D://test.png");
Mat mat2 = Imgcodecs.imread("D://test.png",Imgcodecs.IMREAD_LOAD_GDAL);
2.imwrite()
params1:文件输出方位
params2:将要输出为图片的源矩阵的名字,它是一个咱们读入或处理过的Mat类型的参数
将一个Mat方针保存到文件中
public static void main(String args[]) {
// 加载本地OpenCV库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat mat = Imgcodecs.imread("D://test.png");
boolean imwrite = Imgcodecs.imwrite("D://write.png", mat);
System.out.println("图画是否输出成功: " + imwrite);
}
显现图画
能够经过GUI的办法显现图片,不需求再将图画经过流输出到本地再来检查
public static void main(String args[]) {
// 加载本地OpenCV库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat mat = Imgcodecs.imread("D://test.png");
//显现图画
HighGui.imshow("原图", mat);
//延时多长时间后显现
HighGui.waitKey(0);
}
图画紧缩和解紧缩
OpenCV中的imencode办法和imdecode办法是用于图画紧缩和解紧缩的函数。
1.imencode()
imencode办法将一个OpenCV格局的图画进行编码成指定格局的图画数据流,常用的编码格局有JPEG、PNG等。
办法原型为:
boolean imencode(String ext, Mat img, MatOfByte buf, MatOfInt params);
ext标明编码后的文件类型(例如".jpg"、".png"等)
img标明需求编码的图画
buf标明存储编码成果的字节省
params为可选参数,标明编码参数(例如JPEG的紧缩质量)
将一张Mat方针保存为JPEG格局的文件
public static void main(String args[]) throws IOException {
Mat mat = Imgcodecs.imread("D://test.png");
MatOfByte matOfByte = new MatOfByte();
Imgcodecs.imencode(".png", mat, matOfByte);
# Imgcodecs.imencode(".jpg", mat, matOfByte , new MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, 80));
Files.write(Paths.get("D://write.png"), matOfByte.toArray());
}
2.imdecode()
imdecode办法则是将紧缩后的图画数据流解码成OpenCV格局的图画。
办法原型为:
Mat imdecode(Mat buf, int flags)
buf为需求解码的图画数据流
flags为解码标志,一般运用IMREAD_COLOR标明将图画解码为五颜六色图画。
当已经有了一个编码后的JPEG格局图画数据流,能够运用以下代码将其解码为OpenCV格局的图画:
byte[] bytes = Files.readAllBytes(Paths.get("D://write.jpg"));
Mat matImage = Imgcodecs.imdecode(new MatOfByte(bytes), Imgcodecs.IMREAD_COLOR);
图画转化
1.将RGB图画转为灰度图画
在辨认图画的时分一般用灰度图画,由于五颜六色图片信息量太大,为了提高运算速度,一般选用灰度。假如灰度图还是过大,则选用二值化图画。
比方一个点,灰度则只有256个维度,假如算上RGB色彩,则是1600万以上维度,因而就先降维(灰度)来核算
static {
// 加载本地OpenCV库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
@Test
public void cvtColorTest() {
// 读取图画文件并存储在src变量中作为输入图画
Mat src = Imgcodecs.imread("D://test.png");
// 创立一个空的Mat方针dst,用于存储经过处理调整后的图画
Mat dst = new Mat();
if (src.channels() == 3) {
// 将RGB图画转为灰度图画
Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY);
} else {
System.out.println("图画不是BGR格局");
}
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户封闭窗口 或 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
// 开释内存
src.release();
dst.release();
}
2.将BGR图画转为RGB图画
Mat rgbImage = new Mat();
Imgproc.cvtColor(src, rgbImage, Imgproc.COLOR_BGR2RGB);
图画缩放
1.图画缩小
@Test
public void resizeTest() {
// 读取原始图画
Mat src = Imgcodecs.imread("D://test.png");
// 界说缩放份额
double scale = 0.5;
// 核算新图画尺度
Size newSize = new Size(src.width() * scale, src.height() * scale);
// 创立一个与输入图画src相同巨细和类型的Mat方针
Mat dst = new Mat();
Mat.zeros(src.size(), src.type());
// 对图画进行缩放
Imgproc.resize(src, dst, newSize, 0, 0, Imgproc.INTER_LINEAR);
// 显现原始图画和缩放后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户封闭窗口 或 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
// 开释内存
src.release();
dst.release();
}
@Test
public void resizeTest() {
// 读取原始图画
Mat src = Imgcodecs.imread("D://test.png");
// 创立一个空的Mat方针dst,用于存储经过处理调整后的图画
Mat dst = new Mat();
// 将RGB图画转为灰度图画
Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(dst.cols() / 2, dst.rows() / 2));
Imgproc.resize(dst, dst, new Size(dst.cols() / 2, dst.rows() / 2));
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 延时多长时间后显现
HighGui.waitKey(0);
}
2.图画放大
@Test
public void resizeTest() {
// 读取原始图画
Mat src = Imgcodecs.imread("D://test.png");
// 创立一个与输入图画src相同巨细和类型的Mat方针
Mat dst = new Mat();
Mat.zeros(src.size(), src.type());
// 对图画进行缩放
Imgproc.resize(src, dst, new Size(), 1.1, 1.1, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 延时多长时间后显现
HighGui.waitKey(0);
}
亮度调整
1.亮度提高
当遇到图片比较暗的图画,能够经过亮度提高,然后完成到达更高的辨认率
@Test
public void addWeightedTest() {
Mat src = Imgcodecs.imread("D://test.png");
Mat dst = new Mat();
// 创立一个与输入图画src相同巨细和类型的Mat方针
Mat black = Mat.zeros(src.size(), src.type());
// 运用addWeighted函数将输入图画src和black图画按份额相加,完成亮度调整
// 参数1.2标明亮度添加的份额,0.5标明black图画的权重,0标明亮度调整的偏移量
Core.addWeighted(src, 1.2, black, 0.5, 0, dst);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
Imgproc.resize(dst, dst, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
}
2.亮度下降
当遇到图片亮度很亮,曝光度很高的图画,能够经过下降亮度来提高辨认率
@Test
public void addWeightedTest() {
Mat src = Imgcodecs.imread("D://test.png");
Mat dst = new Mat();
// 创立一个与输入图画src相同巨细和类型的Mat方针
Mat black = Mat.zeros(src.size(), src.type());
// 运用addWeighted函数将输入图画src和black图画按份额相加,完成亮度调整
// 参数0.5标明亮度添加的份额,0.5标明black图画的权重,0标明亮度调整的偏移量
Core.addWeighted(src, 0.5, black, 0.5, 0, dst);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
Imgproc.resize(dst, dst, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
}
图画锐化
图画锐化能够让五颜六色图片看起来更有色彩
@Test
public void sharpenTest() {
Mat src = Imgcodecs.imread("D://test.png");
Mat dst = new Mat();
// 界说一组锐化滤波器的参数值sharper
float[] sharper = new float[]{0, -1, 0, -1, 5, -1, 0, -1, 0};
// 界说一个3x3的卷积核operator
Mat operator = new Mat(3, 3, CvType.CV_32FC1);
// 运用sharper
operator.put(0, 0, sharper);
// 运用filter2D函数将卷积核运用于原始图画src
Imgproc.filter2D(src, dst, -1, operator);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
Imgproc.resize(dst, dst, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
}
图画梯度
图画梯度核算的是图画改变的速度。关于图画的边际部分,其灰度值改变较大,梯度值也较大。一般情况下,图画梯度核算的是图画的边际信息。严格来讲,图画梯度核算需求求导数,但图画梯度一般经过核算像素差值来得到梯度的近似值。
@Test
public void gradientTest() {
Mat src = Imgcodecs.imread("D://test.png");
Mat grad_x = new Mat();
Mat grad_y = new Mat();
Mat abs_grad_x = new Mat();
Mat abs_grad_y = new Mat();
// 运用Sobel滤波器核算其水平和垂直梯度
Imgproc.Sobel(src, grad_x, CvType.CV_32F, 1, 0);
Imgproc.Sobel(src, grad_y, CvType.CV_32F, 0, 1);
Core.convertScaleAbs(grad_x, abs_grad_x);
Core.convertScaleAbs(grad_y, abs_grad_y);
grad_x.release();
grad_y.release();
// 终究的梯度经过加权平均值组合在gradxy中
Mat gradxy = new Mat();
Core.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 10, gradxy);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
Imgproc.resize(gradxy, gradxy, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", gradxy);
// 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
}
图画二值化
图画二值化是将一幅五颜六色或灰度图画转化为只包含两种色彩的图画,其间色彩一般为黑色(灰度为0)和白色(灰 度为255)。二值化图画能够协助咱们更好地分离物体和布景,简化图画处理流程
二值化的好处便是将图片上的有用信息和无用信息区别开来:
比方二值化之后的验证码图片,验证码像素为黑色,布景和干扰点为白色,这样后面临验证码像素处理的时分就会很方便。
常见的二值化办法为固定阀值和自适应阀值:
固定阀值
制定一个固定的数值作为分界点,大于这个阀值的像素就设为255,小于该阀值就设为0,这种办法简单粗犷,可是作用不一定好
自适应阀值
每次依据图片的灰度情况找适宜的阀值。自适应阀值的办法有许多,这儿选用了一种相似K均值的办法,便是先挑选一个值作为阀值,计算大于这个阀值的一切像素的灰度平均值和小于这个阀值的一切像素的灰度平均值,再求这两个值的平均值作为新的阀值。重复上面的核算,直到每次更新阀值后,大于该阀值和小于该阀值的像素数目不变为止。
@Test
public void thresholdTest() {
// 读取灰度化的图画
Mat src = Imgcodecs.imread("D://test.png", Imgcodecs.IMREAD_GRAYSCALE);
// 阈值化
Mat dst = new Mat();
Imgproc.threshold(src, dst, 127, 255, Imgproc.THRESH_BINARY);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
Imgproc.resize(dst, dst, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
}
边际检测
边际检测是指寻找图画中明暗改变的区域,并将这些区域称为边际。这些边际一般标明了图画中物体之间的边界或概括。运用OpenCV进行边际检测,能够协助咱们更好地了解图画中的细节和结构,然后提高图画处理和分析的效率和准确性。
@Test
public void cannyTest() {
Mat src = Imgcodecs.imread("D://test.png");
// 边际检测
Mat dst = new Mat();
Imgproc.Canny(src, dst, 100, 200);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
Imgproc.resize(dst, dst, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
}
图画高斯含糊
高斯含糊本质上是低通滤波器,输出图画的每个像素点是原图画上对应像素点与周围像素点的加权和,原理并不杂乱,便是用高斯分布权值矩阵与原始图画矩阵做卷积运算
@Test
public void gaussianBlurTest() {
Mat src = Imgcodecs.imread("D://test.png");
// 高斯含糊
Mat dst = new Mat();
Imgproc.GaussianBlur(src, dst, new Size(15, 15), 0);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
Imgproc.resize(dst, dst, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
}
图画反色
图画反色是指对图画中的每个像素值进行取反操作,即将原始图画中每个像素的亮度值或色彩值减去255得到的新图画
@Test
public void inverseColorTest() {
Mat src = Imgcodecs.imread("D://test.png");
Mat dst = src.clone();
int width = dst.cols();
int height = dst.rows();
int dims = dst.channels();
byte[] data = new byte[width * height * dims];
dst.get(0, 0, data);
int index, r, g, b;
for (int row = 0; row < height; row++) {
for (int col = 0; col < width * dims; col += dims) {
index = row * width * dims + col;
b = data[index] & 0xff;
g = data[index + 1] & 0xff;
r = data[index + 2] & 0xff;
r = 255 - r;
g = 255 - g;
b = 255 - b;
data[index] = (byte) b;
data[index + 1] = (byte) g;
data[index + 2] = (byte) r;
}
}
dst.put(0, 0, data);
// 运用resize函数将原始图画和方针图画缩小到其一半巨细
Imgproc.resize(src, src, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
Imgproc.resize(dst, dst, new Size(), 0.5, 0.5, Imgproc.INTER_LINEAR);
// 运用HighGui库显现原始图画和修正后的图画
HighGui.imshow("原图", src);
HighGui.imshow("新图", dst);
// 等候用户按下恣意键持续程序履行
HighGui.waitKey(0);
}