目录
简介
Maven
软件环境
JavaCV-Examples
OpenCV Cookbook Examples
概述
示例
OpenCV文档
如何使用JavaCV示例
示例代码的组织结构
示例列表
Why Scala?
学习地址
图像简单处理代码示例
1.打开保存一张图
2.画直线
3.画圆圈
4.画折现
5.添加文字水印
6.裁剪并局部放大
7.人脸检测
视频简单处理代码示例
1.打开视频文件
2.抓取视频指定时间的帧保存为图像
3.录屏
4.给视频添加水印
简介
JavaCV使用来自JavaCPP预设库的包装器,这些库是计算机视觉领域的研究人员常用的库(OpenCV, FFmpeg, libdc1394, FlyCapture, Spinnaker, OpenKinect, librealsense, CL PS3 Eye Driver, videoInput, ARToolKitPlus, flandmark, Leptonica和Tesseract),并提供实用程序类,使其功能更容易在Java平台(包括Android)上使用。
JavaCV还具有硬件加速全屏图像显示(CanvasFrame和GLCanvasFrame),易于使用的方法在多核上并行执行代码(parallel),用户友好的相机和投影仪的几何和颜色校准(GeometricCalibrator, ProCamGeometricCalibrator, ProCamColorCalibrator),特征点的检测和匹配(ObjectFinder),一组实现投影仪-相机系统的直接图像对齐的类(主要是GNImageAligner,projectvetransformer, projvecolortransformer, ProCamTransformer和ReflectanceInitializer),一个blob分析包(Blobs),以及JavaCV类中的其他功能。其中一些类也有OpenCL和OpenGL对应的类,它们的名字以CL结尾或以GL开头,例如:JavaCVCL, GLCanvasFrame等。
要学习如何使用API,因为目前缺乏文档,请参考下面的示例用法部分以及示例程序,包括两个Android (FacePreview.java和RecordActivity.java),也可以在samples目录中找到。您还可以参考ProCamCalib和ProCamTracker的源代码,以及从OpenCV2 Cookbook和相关wiki页面移植的示例。
Maven
<dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.8</version></dependency>
软件环境
要使用JavaCV,首先需要下载并安装以下软件:
Java SE 7或更新版本的实现:
-
OpenJDK OpenJDK: Download and install or
-
Oracle JDK http://www.oracle.com/technetwork/java/javase/downloads/ or
-
IBM JDK http://www.ibm.com/developerworks/java/jdk/
此外,虽然并不总是必需的,JavaCV的一些功能也依赖于:
-
CL Eye Platform SDK (Windows only) CL - Downloads - Code Laboratories
CL Eye平台SDK为开发人员提供了对相机使用和操作的完全访问和控制。为了可移植性和易用性,所提供的api作为标准的基于C的函数公开,还包括作为基线测试框架的所有示例应用程序的完整源代码。
-
Android SDK API 21 or newer http://developer.android.com/sdk/
-
JOCL and JOGL from JogAmp JogAmp.org - Java graphics, audio, media and processing libraries exposing OpenGL, OpenCL, OpenAL and OpenMAX
JogAmp是用于3D图形、多媒体和处理的高性能Java™库的家。
JOGL, JOCL和JOAL提供跨平台Java™语言绑定到OpenGL®,OpenCL™,OpenAL和OpenMAX api。
最后,请确保所有内容具有相同的位,32位和64位模块在任何情况下都不能混合。
JavaCV-Examples
这个项目包含使用JavaCV和其他javacpp-presets项目中的库包装器的示例。
-
OpenCV_Cookbook - Robert laganiere的书《OpenCV Computer Vision Application Programming Cookbook》中提供的示例的JavaCV版本。Cookbook中的原始示例是用c++编写的,这里它们被翻译为使用JavaCV API。
-
使用flandmark库的示例。
-
使用JVM包装flr /Point Grey FlyCapture SDK的示例。
-
使用JVM包装Flir/Point Grey Spinnaker SDK的示例
OpenCV Cookbook Examples
概述
OpenCV Cookbook示例说明了OpenCV与JavaCV的使用。这些例子是从Robert laganie:1的书《OpenCV 2计算机视觉应用程序编程指南》中移植的c++代码开始的。后来更新为第四版的书“OpenCV计算机视觉应用程序编程 Cookbook第四版”。书中的示例使用OpenCV c++ API。在这里,它们被转换为使用JavaCV和JavaCPP-Presets api。
OpenCV(开源计算机视觉)是一个包含数百种算法的库,用于计算机视觉和视频分析。OpenCV可以通过两种方式在JVM上运行。首先是由OpenCV提供的Java包装器。第二种是基于JavaCPP (JVM的c++包装器引擎)的包装器,称为OpenCV JavaCPP预置。还有其他计算机视觉相关库的JavaCPP预设,如:FFmpeg, libdc1394, PGR FlyCapture, OpenKinect, videoInput, ARToolKitPlus, landmark等。JavaCV结合了JavaCPP预置中的库,并添加了一些额外的功能,使它们更容易在JVM上使用。
OpenCV Cookbook Examples项目演示了通过JavaCV和OpenCV JavaCPP预设使用OpenCV。当前的版本更新是为了匹配Robert laganie:1的书“OpenCV计算机视觉应用程序编程 Cookbook第二版”的第二版。它旨在与OpenCV .4一起使用(JavaCV 1节)。
虽然示例中的代码主要是用Scala编写的,Scala是领先的JVM语言之一。它可以很容易地转换为Java和运行在JVM上的其他语言,例如Groovy。在大多数JVM语言中,JavaCV API的使用非常相似。在Java版本中提供了一些示例。
示例
下面是一个快速预览,将原始c++示例与使用JavaCV包装器的Scala和Java代码进行比较。
下面是一个原始的c++示例,它打开一个图像(没有错误检查),创建一个窗口,在窗口中显示图像,并等待5秒后退出。
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>int main() {// Read an imagecv::Mat src = cv::imread("data/boldt.jpg");display(src, "Input")// Apply Laplacian filtercv::Mat dest;cv::Laplacian(src, dest, src.depth(), 1, 3, 0, BORDER_DEFAULT);display(dest, "Laplacian");// wait key for 5000 mscv::waitKey(5000);return 1;
}//---------------------------------------------------------------------------void display(Mat image, char* caption) {// Create image window named "My Image"cv::namedWindow(caption);// Show image on windowcv::imshow(caption, image);
}
上面的c++示例使用JavaCV包装器转换为Scala:
import javax.swing._
import org.bytedeco.javacv._
import org.bytedeco.opencv.global.opencv_core._
import org.bytedeco.opencv.global.opencv_imgcodecs._
import org.bytedeco.opencv.global.opencv_imgproc._
import org.bytedeco.opencv.opencv_core._object MyFirstOpenCVApp extends App {// Read an image.val src = imread("data/boldt.jpg")display(src, "Input")// Apply Laplacian filterval dest = new Mat()Laplacian(src, dest, src.depth(), 1, 3, 0, BORDER_DEFAULT)display(dest, "Laplacian")//---------------------------------------------------------------------------/** Display `image` with given `caption`. */def display(image: Mat, caption: String): Unit = {// Create image window named "My Image."val canvas = new CanvasFrame(caption, 1)// Request closing of the application when the image window is closed.canvas.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)// Convert from OpenCV Mat to Java Buffered image for displayval converter = new OpenCVFrameConverter.ToMat()// Show image on windowcanvas.showImage(converter.convert(image))}
}
现在用Java表达相同的例子。请注意,JavaCV API的使用与Scala和Java代码中的完全相同。唯一的实际区别是,在Java代码中更冗长,您必须显式地为每个变量提供类型,而在Scala中这是可选的。
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.opencv.opencv_core.Mat;import javax.swing.*;
import java.awt.image.BufferedImage;import static opencv_cookbook.OpenCVUtilsJava.toBufferedImage;
import static org.bytedeco.opencv.global.opencv_core.BORDER_DEFAULT;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.bytedeco.opencv.global.opencv_imgproc.Laplacian;public class MyFirstOpenCVAppInJava {public static void main(String[] args) {// Read an image.final Mat src = imread("data/boldt.jpg");display(src, "Input");// Apply Laplacian filterfinal Mat dest = new Mat();Laplacian(src, dest, src.depth(), 1, 3, 0, BORDER_DEFAULT);display(dest, "Laplacian");}//---------------------------------------------------------------------------static void display(Mat image, String caption) {// Create image window named "My Image".final CanvasFrame canvas = new CanvasFrame(caption, 1.0);// Request closing of the application when the image window is closed.canvas.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);// Convert from OpenCV Mat to Java Buffered image for displayfinal BufferedImage bi = toBufferedImage(image);// Show image on window.canvas.showImage(bi);}
}
OpenCV文档
如果您正在寻找一个特定的OpenCV操作,请使用OpenCV文档(OpenCV documentation index)。快速搜索框特别有用。该文档包含了C/ c++ OpenCV API可选使用方式的描述。
如何使用JavaCV示例
OpenCV Cookbook示例项目是作为Robert laganie:1的书“OpenCV计算机视觉应用程序编程Cookbook第二版”的伙伴。推荐的方法是在对如何将Cookbook的c++代码转换为JavaCV有疑问时阅读Cookbook并参考JavaCV示例。这本书解释了算法是如何工作的。JavaCV示例只提供了与JavaCV API细节相关的非常简短的注释。
使用JavaCV示例的最简单方法是在线浏览位于[src/main]中的代码。您也可以使用Git或ZIP文件将其下载到计算机上。
通过最小的设置,您可以轻松地在自己的计算机上执行示例。这是JavaCV的好处之一——它提供了在各种平台上运行OpenCV所需的所有二进制文件。在第1章的README中解释了这个设置。
示例代码的组织结构
代码被组织成与Cookbook第1版中的章节相对应的包,例如opencv_cookbook.chapter8。它与第二版非常相似。个别的例子大致对应于书中每一章的章节。
第1章描述了运行这些示例的IDE设置,给出了一个加载和显示图像的基本示例,以及一个执行基本图像处理的基本GUI示例。
示例列表
第一章:使用图像
-
Ex1MyFirstOpenCVApp -加载图像并在窗口中显示它(CanvasFrame)
-
Ex2MyFirstGUIFXApp -使用ScalaFX (JavaFX包装器)构建的简单GUI应用程序。该应用程序在左侧有两个按钮“打开图像”和“处理”。打开的图像显示在中间。当按下“处理”按钮时,图像被翻转过来,其红色和蓝色通道被交换。有关Swing版本,请参阅Ex2MyFirstGUIApp。
-
Ex2MyFirstGUIApp -使用Scala Swing构建的简单GUI应用程序。该应用程序在左侧有两个按钮“打开图像”和“处理”。打开的图像显示在中间。当按下“处理”按钮时,图像被翻转过来,其红色和蓝色通道被交换。有关JavaFX版本,请参阅Ex2MyFirstGUIFXApp。
-
Ex3LoadAndSave -读取,保存,显示和绘制图像。
第二章:操纵像素
-
Ex1Salt -设置个人,随机选择,像素到一个固定的值。使用ImageJ的ImageProcessor来访问像素。
-
Ex2ColorReduce -通过相同的方式修改所有波段的颜色值来减少图像中的颜色。
-
ex3锐化-使用内核卷积锐化图像:filter2D()。
-
Ex4BlendImages -混合两个图像使用加权加法:cvAddWeighted()。
-
ex5roillogo -使用感兴趣的区域将小图像粘贴到较大的图像中:IplROI和cvCopy()。
第三章:用类处理图像
-
Ex1ColorDetector -将RGB颜色与目标颜色进行比较,与目标颜色相似的颜色在输出图像中被分配为白色,其他像素被设置为黑色。
-
Ex2ColorDetectorSimpleApplication—第一个示例的处理过程相同,但演示了一个简单的UI。
-
ex3colordetectormvapplication—相同的处理是第一个示例,但演示了一个更详细的UI。
-
Ex4ConvertingColorSpaces -类似于第一个例子,但是颜色距离是在Lab*颜色空间中计算的。说明cvtColor函数的使用。
第四章:用直方图计算像素
-
Ex1ComputeHistogram -使用实用程序类Histogram1D计算直方图,并将值打印到屏幕上。
-
Ex2ComputeHistogramGraph -显示使用实用程序类Histogram1D创建的直方图的图形。
-
Ex3Threshold -使用OpenCV threshold()方法将图像中的像素分离为前景和背景。
-
Ex4InvertLut—通过反转其查找表来创建倒立的图像。
-
Ex5EqualizeHistogram -使用直方图均衡化增强图像。
-
Ex6ContentDetectionGrayscale -使用灰度图像中区域的直方图来创建“模板”,通过整个图像来检测与该模板相似的像素。举例说明cvCalcBackProject()方法的使用。
-
Ex7ContentDetectionColor -使用区域直方图在彩色图像中创建“模板”,通过整个图像来检测与该模板相似的像素。依赖于工具类ColorHistogram和ContentFinder。
-
Ex8MeanShiftDetector -使用彩色图像中的区域直方图来创建“模板”,使用mean shift算法在另一张图像中找到“模板”的最佳匹配位置。举例说明cvMeanShift()方法的用法。
-
使用辅助类ImageComparator计算图像相似度度量。
-
执行直方图和查找表操作的Helper类,对应于OpenCV Cookbook中部分c++类Histogram1D的样例代码。举例说明OpenCV方法的使用:cvLUT(), cvEqualizeHist(), cvCreateHist(), cvCalcHist(), cvQueryHistValue_1D(), cvReleaseHist()。
-
ColorHistogram -帮助类简化了彩色图像cvCalcHist()方法的使用。
-
使用cvCalcBackProject()方法进行模板匹配的辅助类。
-
ImageComparator -使用cvCompareHist()计算图像相似度的辅助类。
第五章:用形态学操作变换图像
-
侵蚀和扩张-形态侵蚀和扩张:cvErode()和cvDilate()。
-
Ex2OpeningAndClosing -形态学打开和关闭:cvMorphologyEx()。
-
Ex3EdgesAndCorners -使用形态学过滤器检测边缘和角落。
-
Ex4WatershedSegmentation -图像分割使用分水岭算法。
-
Ex5GrabCut -使用grabCut()从背景中分离对象。
-
MorphoFeatures -等价于同名的c++类,包含形态学角检测的方法。
-
WatershedSegmenter -“使用分水岭分割图像”一节的辅助类。
第六章:过滤图像
-
Ex1LowPassFilter -模糊与高斯滤波器。
-
Ex2MedianFilter -用中值滤波器去除噪声。
-
Ex3DirectionalFilters -使用Sobel边缘检测滤波器。
-
使用拉普拉斯滤波器的边缘检测。
-
LaplacianZC -计算Laplacian和过零,用于Ex4Laplacian。
第七章:提取线条、轮廓和组件
-
Ex1CannyOperator -检测轮廓与Canny算子。
-
Ex2HoughLines -使用标准Hough变换方法检测线条。
-
Ex3HoughLineSegments -使用概率霍夫变换方法检测线段。
-
Ex4HoughCircles -使用霍夫变换方法检测圆。
-
Ex5ExtractContours -使用连接的组件从二值图像中提取轮廓。
-
Ex6ShapeDescriptors -计算各种形状描述符:边界框,封闭圆,近似多边形,凸壳,质心。
-
LineFinder -使用概率霍夫变换方法检测线段的辅助类,用于Ex3HoughLineSegments。
第八章:发现兴趣点
-
Ex1HarrisCornerMap -计算哈里斯角强度图像。
-
Ex2HarrisCornerDetector -使用Harris角强度图像来检测定位良好的角,用一个角取代几个位置较近的检测(模糊)。使用HarrisDetector辅助类。
-
Ex3GoodFeaturesToTrack -使用GoodFeatures跟踪检测器的例子。
-
Ex4FAST -使用FAST检测器的示例。
-
Ex5SURF -使用SURF检测器的示例。
-
Ex6SIFT -使用SIFT检测器的示例。
-
帮助类,用于哈里斯角强度图像的检测和定位。距离较近的探测(模糊)被单个探测取代。
第九章:发现兴趣点
-
Ex2TemplateMatching -从第一个图像(模板)和第二个图像中找到一个小补丁之间的最佳匹配。
-
ex7descripbingsurf -计算SURF特征,提取它们的描述符,并在同一物体的两幅图像之间找到最佳匹配的描述符。
第十章:估计图像中的投影关系
-
Ex1FindChessboardCorners -演示了相机校准步骤之一,在校准板中检测棋盘模式。
-
Ex2CalibrateCamera -相机校准示例,展示了如何校正光学器件可能引入的几何变形。使用CameraCalibrator助手类。
-
Ex3ComputeFundamentalMatrix -使用两幅图像之间检测和匹配的特征,计算描述两幅图像之间投影关系的基本矩阵。
-
Ex4MatchingUsingSampleConsensus -说明RANSAC(随机抽样共识)策略的使用。大多数计算是由RobustMatcher helper类完成的。
-
Ex5Homography -描述两个图像中点之间关系的另一种方法,使用homography。展示了如何将一个对象的部分视图的两个图像拼接在一起的示例。大多数计算是由RobustMatcher helper类完成的。
-
实现摄像机校准算法的助手类。
-
RobustMatcher -实现基于RANSAC的算法,例如Ex4MatchingUsingSampleConsensus和Ex5Homography。
第十一章:处理视频序列
-
Ex1ReadVideoSequence -读取并显示视频。
-
Ex2ProcessVideoFrames -使用Canny边缘检测器处理视频文件中的帧;在屏幕上显示输出视频。使用辅助类VideoProcessor。
-
Ex3WriteVideoSequence -使用Canny边缘检测器处理视频文件中的帧;将输出写入视频文件。使用辅助类VideoProcessor。
-
Ex4TrackingFeatures -跟踪视频中的移动对象,标记屏幕上显示的视频中的跟踪点。大部分的实现是在FeatureTracker helper类中完成的。
-
Ex5ForegroundSegmenter -通过背景估计检测视频中的移动对象。背景使用“简单”移动平均方法建模,实现在助手类“BGFBSegmenter”中。
-
Ex6MOGMotionDetector -一个更复杂的运动检测器,使用混合高斯方法建模背景。
-
BGFBSEgmenter -通过使用移动平均线对背景建模,将“静态”背景与“移动”前景分开。使用的例子'Ex5ForegroundSegmenter'。
-
FeatureTracker -使用光流算法跟踪移动特征,例如Ex4TrackingFeatures。
-
VideoProcessor -处理视频文件的辅助类,加载和应用处理到单独的帧,例如:Ex2ProcessVideoFrames, Ex3WriteVideoSequence, Ex4TrackingFeatures和Ex5ForegroundSegmenter。
第十五章:OpenCV高级特性
-
Ex1FaceDetection -使用预训练的深度学习神经网络模型检测图像中的人脸。
其他通用技术
-
OpenCVUtils -读取和写入图像文件,显示图像,绘制图像的特征,OpenCV图像和数据表示之间的转换。
Why Scala?
之所以选择Scala,是因为它比Java更具表现力。您可以用更少的代码获得相同的结果。更小的样板代码使示例更容易阅读和理解。编译后的Scala代码速度很快,类似于Java和c++。
与Java或c++不同,Scala支持编写脚本——无需显式编译即可执行的代码。Scala也有一个控制台,称为REPL,可以在其中输入单行代码并当场执行。这两个特性使得在Scala中构建基于opencv的程序比在Java中更容易。最后但并非最不重要的一点是,IDE对Scala的支持达到了成熟的程度,允许轻松地创建、修改和执行Scala代码。特别是,用于JetBrains IDEA的Scala插件工作得非常好。还有对Eclipse和NetBeans的Scala支持。
学习地址
https://github.com/bytedeco/javacv
Welcome to OpenCV Java Tutorials documentation! — OpenCV Java Tutorials 1.0 documentation
GitHub - bytedeco/javacv-examples: Examples of using JavaCV / OpenCV library on Java Virtual Machine
关于类、API等如果有疑问可以看考openCV、FFmpeg的方法介绍,javaCV只不过是对它们的封装,或者直接问ChatGPT吧,简单高效!
图像简单处理代码示例
图像处理的API主要集中在opencv-4.6.0-1.5.8.jar包下,该包有两个目录“bytedeco.opencv”与“opencv”,两个package下有许多同名的类与静态方法,请尽量采用“bytedeco.opencv”package下的类与方法。
1.打开保存一张图
// 打开一张图
Mat image = imread("D:\\2projects_database\\javacvdemo\\src\\main\\java\\com\\example\\img\\future_city.jpg");
// 保存图像 imwrite("D:\\2projects_database\\javacvdemo\\src\\main\\java\\com\\example\\img\\future_city_add_text.jpg", image);
2.画直线
/*** 画直线* @param image 图片* @param x1 起点横坐标* @param y1 起点纵坐标* @param x2 终点横坐标* @param y2 终点纵坐标* @param color 线条颜色*/
public static void drawLine(Mat image, int x1, int y1, int x2, int y2, Scalar color) {Point pt1 = new Point(x1, y1);Point pt2 = new Point(x2, y2);line(image, pt1, pt2, color);
}
3.画圆圈
/*** 画圆圈* @param image 图像* @param x 圆心横坐标* @param y 圆心纵坐标* @param radius 半径* @param color 线条颜色* @param thickness 线条厚度* @param lineType 线条类型* @param shift 坐标值的小数位数*/
public static void drawCircle(Mat image, int x, int y, int radius, Scalar color, int thickness, int lineType, int shift) {Point center = new Point(x, y);circle(image, center, radius, color, thickness, lineType, shift);
}
4.画折现
/*** 画折现* @param image 图像* @param points 端点数组* @param color 线条颜色*/
public static void drawCurve(Mat image, Point[] points, Scalar color) {for (int i = 0; i < points.length - 1; i++) {line(image, points[i], points[i+1], color);}
}
5.添加文字水印
/*** 添加文字水印* @param image 图像* @param text 文字内容* @param position 文字位置* @param fontFace 字体类型* @param fontScale 字体大小* @param color 字体颜色*/
public static void addTextWatermark(Mat image, String text, Point position, int fontFace, double fontScale, Scalar color) {putText(image, text, position, fontFace, fontScale, color);
}
6.裁剪并局部放大
/*** 裁剪图像并局部放大* @param image 图像* @param x 起始位置横坐标* @param y 起始位置纵坐标* @param width 裁剪宽度* @param height 裁剪高度* @param zoomFactor 放大倍数*/
public static void cropAndZoomImage(Mat image, int x, int y, int width, int height, int zoomFactor) {Rect roi = new Rect(x, y, width, height);Mat croppedImage = new Mat(image, roi);resize(croppedImage, croppedImage, new Size(width*zoomFactor, height*zoomFactor));// 保存图像imwrite("D:\\2projects_database\\javacvdemo\\src\\main\\java\\com\\example\\img\\cropAndZoomImage.png", croppedImage);System.out.println("resize rows:" + croppedImage.rows());System.out.println("resize cols:" + croppedImage.cols());
}
7.人脸检测
package com.example.img.code;import org.bytedeco.opencv.opencv_core.*;
import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;
import static org.bytedeco.opencv.global.opencv_imgproc.LINE_8;
import static org.bytedeco.opencv.global.opencv_imgproc.rectangle;/*** @Author yrz* @create 2023/5/12 11:22* @Description TODO*/public class FaceDetector {public static void main(String[] args) {// Load the imageMat image = imread("D:/2projects_database/javacvdemo/src/main/java/com/example/img/face.jpg");// Load the face cascade classifierCascadeClassifier faceCascade = new CascadeClassifier("D:/2projects_database/javacvdemo/src/main/java/com/example/img/haarcascade_frontalface_alt.xml");// Detect faces in the imageRectVector faceDetections = new RectVector();faceCascade.detectMultiScale(image, faceDetections);// Draw a rectangle around each detected facefor (Rect rect : faceDetections.get()) {rectangle(image, new Point(rect.x(), rect.y()), new Point(rect.x() + rect.width(), rect.y() + rect.height()),new Scalar(0, 255, 0, 0), 2, LINE_8, 0);}// Save the image with the detected facesimwrite("D:/2projects_database/javacvdemo/src/main/java/com/example/img/face_output.jpg", image);}
}
视频简单处理代码示例
视频处理的API主要集中在javacv-1.5.8.jar包下。
1.打开视频文件
/*** 打开视频文件* @param filename*/
public static void readDisplayVideo(String filename){FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(filename);// Open video video filetry {grabber.start();} catch (FFmpegFrameGrabber.Exception e) {e.printStackTrace();}// Prepare window to display framesCanvasFrame canvasFrame = new CanvasFrame("Extracted Frame", 1);canvasFrame.setCanvasSize(grabber.getImageWidth(), grabber.getImageHeight());// Exit the example when the canvas frame is closedcanvasFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);long delay = Math.round(1000d / grabber.getFrameRate());// Read frame by frame, stop early if the display window is closedFrame frame;try {while ((frame = grabber.grab()) != null && canvasFrame.isVisible()) {// Capture and show the framecanvasFrame.showImage(frame);// DelayThread.sleep(delay);}// Close the video filegrabber.release();} catch (FFmpegFrameGrabber.Exception e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}
}
2.抓取视频指定时间的帧保存为图像
/*** 抓取视频指定时间的帧保存为图像* @param videoPath* @param imagePath* @param timeInSeconds*/
public static void grabFrameAtTime(String videoPath, String imagePath, long timeInSeconds) {FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoPath);Java2DFrameConverter converter = new Java2DFrameConverter();try {grabber.start();grabber.setTimestamp(timeInSeconds);Frame grab = grabber.grabImage();BufferedImage bufferedImage = converter.getBufferedImage(grab, converter.getBufferedImageType(grab) ==BufferedImage.TYPE_CUSTOM ? 1.0 : 1.0, false, null);saveImage(bufferedImage, imagePath);grabber.stop();} catch (Exception e) {e.printStackTrace();}
}
public static void saveImage(BufferedImage image, String imagePath) {try {ImageIO.write(image, "jpg", new File(imagePath));} catch (IOException e) {e.printStackTrace();}
}
3.录屏
/*** 录屏* @param filename 文件名称* @param seconds 时长*/
public static void recordScreen(String filename, int seconds) {final int FRAME_RATE = 30;final Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize();// 创建录屏对象,并设置相关属性FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(filename, SCREEN_SIZE.width, SCREEN_SIZE.height);recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);recorder.setFormat("mp4");recorder.setFrameRate(FRAME_RATE);Java2DFrameConverter converter = new Java2DFrameConverter();try {// 初始化录屏对象recorder.start();Robot robot = new Robot();BufferedImage screenShot;// 系统当前时间LocalDateTime now = LocalDateTime.now();System.out.println(now);// 30秒后LocalDateTime plus = now.plus(seconds, ChronoUnit.SECONDS);System.out.println(plus);// 开始录制while (true) {// 获取屏幕截图并写入文件screenShot = robot.createScreenCapture(new Rectangle(SCREEN_SIZE));recorder.record(converter.getFrame(screenShot));// 停止时间LocalDateTime time = LocalDateTime.now();if(plus.isBefore(time)){System.out.println(time);break;}}} catch (Exception e) {e.printStackTrace();} finally {// 关闭录制器try {recorder.stop();} catch (Exception e) {e.printStackTrace();}}
}
4.给视频添加水印
/*** 给视频添加水印* @param filename* @param outname* @param picName* @throws Exception*/public static void addWatermark (String filename, String outname, String picName) throws Exception {// Load the videoFFmpegFrameGrabber grabber = new FFmpegFrameGrabber(filename);grabber.start();// Create a new video recorderFFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outname, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);recorder.setFormat("mp4");recorder.setFrameRate(grabber.getFrameRate());// 开启录制recorder.start();// Create a new Java2DFrameConverterJava2DFrameConverter converter = new Java2DFrameConverter();// Create a new BufferedImage to hold the watermark image// 图片水印BufferedImage watermarkImage = ImageIO.read(new File(picName));// 自定义文字水印
// BufferedImage watermarkImage = createWatermarkImage("Hello, world!", new Font("Arial", Font.BOLD, 50),
// Color.WHITE, new Color(0, 0, 0, 0));// Loop through each frame in the videoFrame frame;while ((frame = grabber.grabFrame()) != null) {// Convert the frame to a BufferedImageBufferedImage image = converter.getBufferedImage(frame);if(image == null){continue;}// Create a new Graphics2D object to draw the watermarkGraphics2D g2d = image.createGraphics();// Draw the watermark on the imageg2d.drawImage(watermarkImage, 0, 0, null);// Dispose of the Graphics2D objectg2d.dispose();// Convert the BufferedImage back to a Frame and write it to the output videorecorder.record(converter.convert(image));}// Stop the grabber and recordergrabber.stop();grabber.release();recorder.stop();recorder.release();}private static BufferedImage createWatermarkImage(String text, Font font, Color foreground, Color background) {FontRenderContext frc = new FontRenderContext(null, true, true);TextLayout layout = new TextLayout(text, font, frc);Rectangle2D bounds = layout.getBounds();BufferedImage image = new BufferedImage((int) bounds.getWidth(), (int) bounds.getHeight(), BufferedImage.TYPE_INT_ARGB);Graphics2D g2d = image.createGraphics();g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);if (background != null) {g2d.setBackground(background);g2d.clearRect(0, 0, image.getWidth(), image.getHeight());}g2d.setFont(font);g2d.setColor(foreground);layout.draw(g2d, 0, -(float) bounds.getY());if (background != null) {ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB),null);colorConvert.filter(image, image);}g2d.dispose();return image;}