赞
踩
以上两节看视频介绍,无代码
以上章节采免安装方式,所以安装章节可以直接跳过,节约点时间用springboot整合OpenCV(也可以用maven项目或者简单的java项目),主要是引入一个jar包和库文件,jar跨平台,库文件不跨平台,所以要区分windows和linux,至于工具idea就ok.
环境安装可以参考:springboot免安装整合Opencv兼容windows和linux
实战代码
/**
* 读取图片并显示
*/
public class P1ReadAndDisplayImage {
public static void main(String[] args) {
// 加载Opencv库 不一定要在项目里面,需要绝对路径
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取图片
Mat img = Imgcodecs.imread("src/main/resources/img/lenna1.png");
// 在hello窗口中显示图片
HighGui.imshow("hello", img);
// 等待按键 不设置设计会一直等待
HighGui.waitKey();
// 销毁所有窗口
HighGui.destroyAllWindows();
// 退出系统
System.exit(0);
}
}
public class P2SaveImage {
public static void main(String[] args) {
// 加载Opencv库 不一定要在项目里面,需要绝对路径
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取图片
Mat img = Imgcodecs.imread("src/main/resources/img/lenna1.png");
// 保存图片 图片格式可以和原图片一致,也可以不一致
String fileName = "src/main/resources/tmp/lenna1.jpg";
Imgcodecs.imwrite(fileName, img);
}
}
public class P3CameraStudy {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 打开默认摄像头(索引为0)
VideoCapture capture = new VideoCapture(0);
// 检查摄像头是否成功打开
if (!capture.isOpened()) {
System.out.println("无法打开摄像头。");
return;
}
// 从摄像头读取并显示每一帧
Mat frame = new Mat();
while (capture.read(frame)) {
// 显示图片 HighGui用户界面相关
HighGui.imshow("Camera", frame);
// 等待3毫秒 也就是每3毫秒从摄像头读取一帧
int key = HighGui.waitKey(3);
// 如果输入q 则释放资源
if (key == 'q' || key == 'Q') {
// 销毁所有窗口
HighGui.destroyAllWindows();
// 释放 VideoCapture 对象
capture.release();
System.exit(0);
break;
}
}
// 销毁所有窗口
HighGui.destroyAllWindows();
// 释放 VideoCapture 对象
capture.release();
System.exit(0);
}
}
public class P4VideoStudy {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取本地视频
VideoCapture capture = new VideoCapture("src/main/resources/video/video.mp4");
// 获取视频的宽度、高度和帧数
double width = capture.get(Videoio.CAP_PROP_FRAME_WIDTH);
double height = capture.get(Videoio.CAP_PROP_FRAME_HEIGHT);
double frameCount = capture.get(Videoio.CAP_PROP_FRAME_COUNT);
// 获取视频的帧数和总时长
double totalSeconds = frameCount / capture.get(Videoio.CAP_PROP_FPS);
// 计算平均帧率
double fps = frameCount / totalSeconds;
// 输出视频信息
System.out.println("视频宽度: " + width);
System.out.println("视频高度: " + height);
System.out.println("视频帧数: " + frameCount);
System.out.println("总时长: " + totalSeconds);
System.out.println("平均帧率: " + fps);
// 定义输出视频文件路径
String outputFilePath = "src/main/resources/tmp/output_video.mp4";
// 定义视频属性 width 和 height 不对写不进去
Size frameSize = new Size(width, height);
// 创建 VideoWriter 对象
VideoWriter videoWriter = new VideoWriter(outputFilePath, VideoWriter.fourcc('H', '2', '6', '4'), fps, frameSize, true);
// 检查视频是否成功打开
if (!capture.isOpened()) {
System.out.println("无法打开视频");
return;
}
// 检查 VideoWriter 对象是否成功初始化
if (!videoWriter.isOpened()) {
System.out.println("错误:无法打开视频文件以进行写入。");
return;
}
// 从视频读取并显示每一帧
Mat frame = new Mat();
while (capture.read(frame)) {
if (!frame.empty()) {
videoWriter.write(frame);
}
// 显示图片 HighGui用户界面相关
HighGui.imshow("Video", frame);
// 输入一次就中断了
int key = HighGui.waitKey(30);
System.out.println("key = " + key+"\t" + (char)key);
if (key == 'q' || key == 'Q') {
HighGui.destroyAllWindows();
capture.release();
videoWriter.release();
System.exit(0);
break;
}
}
HighGui.destroyAllWindows();
capture.release();
videoWriter.release();
System.exit(0);
}
}
以上章节感觉没必要看,可直接忽略
纯理论,可直接看视频
以上三节直接忽略,Java提供了ROI的api(ROI 感兴趣的区域,就是一张图片中自己比较关心的那部分)
插播一个显示图片的工具类,解决图片显示在一起的位置,效果图片在屏幕上排列
public static void show(LinkedHashMap<String, Mat> mats) {
// 获取默认工具包
Toolkit toolkit = Toolkit.getDefaultToolkit();
// 获取屏幕的尺寸
Dimension screenSize = toolkit.getScreenSize();
// 输出屏幕宽度和高度
int i = 0;
int x = 0;
int y = 0;
int xSpacing = 10;
int ySpacing = 40;
for (Map.Entry<String, Mat> entry : mats.entrySet()) {
Mat mat = entry.getValue();
String winName = entry.getKey();
System.out.println("winName = " + winName);
HighGui.imshow(winName, mat);
if (i > 0) {
x += (mat.cols() + xSpacing);
if (x + mat.cols() > screenSize.width) {
x = 0;
y += (mat.rows() + ySpacing);
}
}
HighGui.moveWindow(winName, x, y);
i++;
}
HighGui.waitKey();
}
public class P490MatCopyStudy {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取图片
Mat image = Imgcodecs.imread("src/main/resources/img/lenna1.png");
// 是深拷贝
Mat clone = image.clone();
// 深拷贝
Mat copyTo = new Mat();
image.copyTo(copyTo);
// 在image上上绘制文本
// 文本的位置
Point textPosition = new Point(50, 50);
String text = "Hello, OpenCV!";
// 白色,字体大小为 1.0,线宽为 2
Imgproc.putText(image, text, textPosition, Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar(255, 255, 255), 2);
LinkedHashMap<String, Mat> images = new LinkedHashMap<>();
images.put("原图", image);
images.put("clone", clone);
images.put("copyTo", copyTo);
OpenCVUtil.show(images);
HighGui.destroyAllWindows();
}
}
说明:通过以上代码可以看出,在Java中clone和copyTo均为深拷贝
public class P412MatSplitAndMerge {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取原图
Mat image = Imgcodecs.imread("src/main/resources/img/lenna1.png");
// 显示图片
HighGui.imshow("原图", image);
// 分离通道
List<Mat> channels = new ArrayList<>();
Core.split(image, channels);
for (int i = 0; i < channels.size(); i++) {
Mat mat = channels.get(i);
// 分离出来的3个通道均为单通道,故显示出来都是黑白图片
HighGui.imshow("通道" + i, mat);
}
List<Mat> mergeChannels = new ArrayList<>();
mergeChannels.add(channels.get(0));
mergeChannels.add(channels.get(1));
mergeChannels.add(channels.get(2));
Mat newMat = new Mat();
// 合并通道
Core.merge(mergeChannels,newMat);
HighGui.imshow("合并后的图像", newMat);
HighGui.waitKey();
HighGui.destroyAllWindows();
System.exit(0);
}
}
代码实战
public class P500BasicShapeDrawingExample {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 创建一个黑色背景的图像
Mat image = new Mat(400, 600, CvType.CV_8UC3, new Scalar(0, 0, 0)); // 400x600 大小,3 通道的黑色图像
// 在图像上绘制基本图形
Point center = new Point(300, 200); // 圆心坐标
Scalar color = new Scalar(0, 255, 0); // 颜色 (BGR 格式)
// 绘制圆
Imgproc.circle(image, center, 100, color, 2); // 中心为 (300, 200),半径为 100,边界宽度为 2,绿色
// 绘制矩形
Point topLeft = new Point(100, 100); // 左上角坐标
Point bottomRight = new Point(500, 300); // 右下角坐标
Imgproc.rectangle(image, topLeft, bottomRight, new Scalar(0, 0, 255), 3); // 左上角 (100, 100),右下角 (500, 300),红色,边界宽度为 3
// 绘制直线
Point start = new Point(50, 50); // 起始点坐标
Point end = new Point(550, 350); // 结束点坐标
Imgproc.line(image, start, end, new Scalar(255, 0, 0), 1); // 蓝色,线宽为 1
// 在图像上绘制文本
Point textPosition = new Point(50, 50); // 文本的位置
String text = "Hello, OpenCV!"; // 要绘制的文本
Imgproc.putText(image, text, textPosition, Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar(255, 255, 255), 2); // 白色,字体大小为 1.0,线宽为 2
HighGui.imshow("基本图形的绘制", image);
HighGui.waitKey(0);
HighGui.destroyAllWindows();
System.exit(0);
}
}
效果
public class P620ImageArithmeticExample {
public static void main(String[] args) {
// // 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 加载两个图像
String imagePath1 = "src/main/resources/img/lenna1.png";
Mat image1 = Imgcodecs.imread(imagePath1);
// 检查图像是否成功加载
if (image1.empty()) {
System.out.println("Error: Couldn't load images.");
return;
}
HighGui.imshow("原图", image1);
// 创建与图像1尺寸相同的图像2,每个像素值为100
Mat image2 = new Mat(image1.size(), image1.type(), new Scalar(100));
// 创建一个与图像1尺寸和类型相同的空白图像,用于存储结果
Mat result4add = new Mat(image1.size(), image1.type());
Mat result4subtract = new Mat(image1.size(), image1.type());
// 加法运算
Core.add(image1, image2, result4add);
HighGui.imshow("图像相加", result4add);
// 减法运算
Core.subtract(image1, image2, result4subtract);
HighGui.imshow("图像相减", result4subtract);
HighGui.waitKey(0);
HighGui.destroyAllWindows();
System.exit(0);
}
}
图像的明暗变化(图像加减乘除混合运算)
public class P621DarknessAdjustmentExample {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 加载两个图像
Mat image1 = Imgcodecs.imread("src/main/resources/img/lenna1.png");
// 检查图像是否成功加载
if (image1.empty()) {
System.out.println("Error: Couldn't load images.");
return;
}
HighGui.imshow("原图像", image1);
// 定义暗度调整系数(在 0 到 1 之间)
double darknessFactor = 0.5; // 减少 50%
// 将图像1的每个像素值乘以暗度调整系数
// rtype:转换后的目标数据类型。如果值为 -1,则表示使用与源 Mat 对象相同的数据类型。
// 原像素值*alpha+beta
Mat clone = image1.clone();
clone.convertTo(clone, -1, darknessFactor, 0);
HighGui.imshow("明暗变化后", clone);
HighGui.waitKey(0);
HighGui.destroyAllWindows();
System.exit(0);
}
}
public class P630ImageFusionExample {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取图像1和图像2
Mat image1 = Imgcodecs.imread("src/main/resources/img/dog.jpg");
Mat image2 = Imgcodecs.imread("src/main/resources/img/background.jpg");
// 融合要求两张图片具有相同尺寸
Size size = getSize(image1, image2);
// 图像融合
Mat blendedImage = blendImages(resizeImages(image1, size), resizeImages(image2, size));
// 显示融合后的图像
HighGui.imshow("Blended Image", blendedImage);
HighGui.waitKey(0);
HighGui.destroyAllWindows();
System.exit(0);
}
private static Size getSize(Mat image1, Mat image2) {
int minWidth = Math.min(image1.width(), image2.width());
int minHeight = Math.min(image1.height(), image2.height());
return new Size(minWidth, minHeight);
}
// 将图像调整为size大小
private static Mat resizeImages(Mat image, Size size) {
Mat mat = new Mat(size, image.type());
Imgproc.resize(image, mat, size);
return mat;
}
// 图像融合
private static Mat blendImages(Mat image1, Mat image2) {
double alpha = 0.9; // 调整融合的权重
Mat blendedImage = new Mat();
Core.addWeighted(image1, alpha, image2, 1 - alpha, 0, blendedImage);
return blendedImage;
}
}
原图1
原图2
融合效果
public class P640ImageNegationExample {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取图像
Mat image = Imgcodecs.imread("src/main/resources/img/lenna1.png");
HighGui.imshow("原图", image);
Mat mat = new Mat();
Core.bitwise_not(image, mat);
// 显示融合后的图像
HighGui.imshow("图像的非运算", mat);
HighGui.waitKey(0);
HighGui.destroyAllWindows();
System.exit(0);
}
}
public class P670AddLogo {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 1. 引入图片
Mat background = Imgcodecs.imread("src/main/resources/img/background.jpg");
// 2. 制作logo
Mat logo = new Mat(200, 200, CvType.CV_8UC3, new Scalar(0, 0, 0));
Mat mask = new Mat(200, 200, CvType.CV_8UC1, new Scalar(0, 0, 0));
Point topLeft = new Point(20, 20);
Point bottomRight = new Point(120, 120);
Imgproc.rectangle(logo, topLeft, bottomRight, new Scalar(0, 0, 255), 2);
Imgproc.rectangle(mask, topLeft, bottomRight, new Scalar(255, 255, 255), 2);
topLeft = new Point(80, 80);
bottomRight = new Point(180, 180);
Imgproc.rectangle(logo, topLeft, bottomRight, new Scalar(0, 255, 0), 2);
Imgproc.rectangle(mask, topLeft, bottomRight, new Scalar(255, 255, 255), 2);
Mat m = new Mat();
Core.bitwise_not(mask, m);
HighGui.imshow("logo", logo);
HighGui.imshow("mask", mask);
HighGui.imshow("m", m);
// 3. 计算添加位置,将添加位置变黑
Mat roi = new Mat(background, new Rect(0, 0, 200, 200));
HighGui.imshow("roi", roi);
Mat tmp = new Mat();
Core.bitwise_and(roi, roi, tmp, m);
HighGui.imshow("tmp", tmp);
Mat dst = new Mat();
Core.add(tmp, logo, dst);
HighGui.imshow("dst", dst);
// 4.利用add,将图片和logo叠加到一起
Mat submat = background.submat(new Rect(0, 0, 200, 200));
dst.copyTo(submat);
HighGui.imshow("background", background);
HighGui.waitKey(0);
HighGui.destroyAllWindows();
System.exit(0);
}
}
public class P710Scale {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取图像
Mat originalImage = Imgcodecs.imread("src/main/resources/img/idea.png");
// 定义缩放后的图像大小
Size newSize = new Size(originalImage.width() * 5, originalImage.height() * 5);
// 缩放图像(使用双立方插值)
Mat resizedImage = new Mat();
Imgproc.resize(originalImage, resizedImage, newSize, 0, 0, Imgproc.INTER_AREA);
// 显示原始图像和缩放后的图像
HighGui.imshow("Original Image", originalImage);
HighGui.imshow("Resized Image", resizedImage);
HighGui.waitKey(0);
HighGui.destroyAllWindows();
System.exit(0);
}
}
说明:第一张是原图,第二张是放大5倍的图,放大之后图像会模糊
/**
* 图像的反转
* 0:沿X轴翻转(垂直翻转)
* 1:沿Y轴翻转(水平翻转)
* -1:同时沿X轴和Y轴翻转
*/
public class P730ImageFlipExample {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取图像
Mat originalImage = Imgcodecs.imread("src/main/resources/img/lenna1.png");
// 沿X轴翻转(垂直翻转)
Mat dstX = new Mat();
Core.flip(originalImage, dstX, 0);
// 沿Y轴翻转(水平翻转)
Mat dstY = new Mat();
Core.flip(originalImage, dstY, 1);
Mat dstXY = new Mat();
Core.flip(originalImage, dstXY, -1);
LinkedHashMap<String, Mat> images = new LinkedHashMap<>();
images.put("原图", originalImage);
images.put("沿着X轴翻转", dstX);
images.put("沿着Y轴翻转", dstY);
images.put("同时沿着XY轴翻转", dstXY);
OpenCVUtil.show(images);
HighGui.destroyAllWindows();
System.exit(0);
}
}
效果图
/**
* 仿射变幻
*/
public class P760ImageRotateExample {
public static void main(String[] args) {
// 加载动态库
System.load(new File("src/main/resources/lib/opencv/opencv_java490.dll").getAbsolutePath());
// 读取图像
Mat originalImage = Imgcodecs.imread("src/main/resources/img/lenna1.png");
// 定义旋转角度(逆时针)
double angle = 45.0;
// 获取图像中心点
Point center = new Point(originalImage.cols() / 2, originalImage.rows() / 2);
// 计算旋转矩阵
Mat rotationMatrix = Imgproc.getRotationMatrix2D(center, angle, 1.0);
// 执行旋转变换
Mat rotatedImage = new Mat();
Imgproc.warpAffine(originalImage, rotatedImage, rotationMatrix, new Size(originalImage.cols(), originalImage.rows()));
// 显示原始图像和旋转后的图像
LinkedHashMap<String, Mat> images = new LinkedHashMap<>();
images.put("原图", originalImage);
images.put("逆时针旋转45°", rotatedImage);
OpenCVUtil.show(images);
HighGui.destroyAllWindows();
System.exit(0);
}
}
OpenCV提供了许多不同类型的滤波器,可以用于图像处理的各种任务。以下是一些常用的滤波器类型:
低通滤波:去噪
高通滤波:检测边缘
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。