介绍
JavaCV首先提供了计算机视觉领域研究人员常用的函数库的封装: OpenCV, FFmpeg, libdc1394, PGRFlyCapture, OpenKinect, videoInput, 和 ARToolKitPlus。
可以在com.googlecode.javacv.cpp包命名空间中找到的类,暴露了它们完整的API。此外,utility类使得它们的功能更易于在包括android在内的Java平台上使用。
JavaCV还带有硬件加速的全屏幕图像显示(CanvasFrame和 GLCanvasFrame),易于在多个内核中执行并行代码(并行),用户友好的几何和色彩的相机和投影仪校准(GeometricCalibrator, ProCamGeometricCalibrator, ProCamColorCalibrator),特征点的检测和匹配(ObjectFinder),一组实现相机投影仪系统直接图像校准的类(主要有GNImageAligner, ProjectiveTransformer, ProjectiveColorTransformer, ProCamTransformer,和 ReflectanceInitializer),一个blob分析软件包(Blobs),以及JavaCV类中的其它功能。这些类也有一个OpenCL和OpenGL的对应副本,它们的名字以CL结尾或者以GL开头,例如JavaCVCL、GLCanvasFrame等等。
由于目前缺少学习如何使用这些API的文档,请参阅下面的#OpenCV和FFmpeg快速入门(Quick Start for OpenCV and FFmpeg)部分以及示例程序,包括两个Android程序(FacePreview.java和RecordActivity.java),也可以在示例目录里找到。你可能会发现,参考ProCamCalib和ProCamTracker的源代码以及从OpenCV2Cookbook书上移植的例子、相关维基页面是很有用的。
所需软件
要使用JavaCV,你将需要下载并安装以下软件:
- 执行的Java SE 6或7
- OpenJDK http://openjdk.java.net/install/或
- Sun JDK http://www.oracle.com/technetwork/java/javase/downloads/或
- IBM JDK http://www.ibm.com/developerworks/java/jdk/或
- Java SE for Mac OS X http://developer.apple.com/java/ 等
- OpenCV 2.4.5 http://sourceforge.net/projects/opencvlibrary/files/
- 针对Linux, Mac OS X, Windows, and Android预编译和打包好的CPPJAR:
- http://code.google.com/p/javacv/downloads/list
同时请确保你的Java和OpenCV具有相同的位数: 32位和64位的组件在任何情况下不要混用。另外,尽管并非总是必要的,一些JavaCV的功能还依赖于::
- FFmpeg 1.2.x http://ffmpeg.org/download.html
- libdc1394 2.1.x 或 2.2.x http://sourceforge.net/projects/libdc1394/files/
- PGR FlyCapture 1.7~2.3 (仅Windows平台) http://www.ptgrey.com/products/pgrflycapture/
- OpenKinect http://openkinect.org/
- CL Eye Platform SDK (仅Windows平台) http://codelaboratories.com/downloads/
- Android SDK API 8 或更高版本 http://developer.android.com/sdk/
- 来自JogAmp的组件JOCL和JOGL http://jogamp.org/
- ARToolKitPlus 2.1.1t http://code.google.com/p/javacv/downloads/list
要修改源代码,请注意这些已被创建的项目文件:
- Maven 2 或 3 http://maven.apache.org/download.html
- JavaCPP 0.5 http://code.google.com/p/javacpp/
要重建的话,只需调用为JavaCPP和JavaCV准备的常用mvn install命令。 默认情况下,所有上面列出的所依赖的东西并不需要,除为了OpenCV和构建JavaCPP的C++编译器(命令行选项可以通过javacpp.options传递,Maven的特性,如那些Android平台需要的)。进一步详情,请参阅pom.xml文件中的注释。
请告诉我你对代码做的更新或修正,让我可以将它们集成到下一版本中。 谢谢!如果您使用软件时遇到任何问题,欢迎在邮件列表页随时提问!我相信它还远远不够完善......
OpenCV和FFmpeg的快速入门
首先,把JavaCV(javacpp.jar,javacv.jar,javacv-*.jar ),OpenCV(OpenCV- 2.4.5*.jar ),FFmpeg( ffmpeg-1.2*.jar)所有JAR文件路径加到CLASSPATH中。 或把你的pom.xml文件指向Maven仓库http://maven2.javacv.googlecode.com/git/ ,并确保FFmpeg和OpenCV的库文件(*.so,*.dylib ,或*.dll )可以在无论是他们的默认安装目录还是系统库的路径PATH中找到,在Windows中也包括当前的工作目录。 (获取在Windows平台上经常遇到的与OpenCV相关的问题答案,请参阅在Windows 7中OpenCV的常见问题)。这里是在通常情况下一些更具体的说明:
NetBeans(Java SE的6或7):
- 在“项目”窗口中,右键单击您的项目的“库”,然后选择“添加JAR /文件夹...”。
- 找到JAR文件,选择它们,然后单击“确定”。
Eclipse(JavaSE 6或7):
- 导航项目>属性> Java创建路径>库,然后单击“添加外部JAR...”。
- 找到JAR文件,选择它们,然后单击“确定”。
Eclipse(Android2.2或更高版本):
- 按照此页面上的指示: http://developer.android.com/training/basics/firstapp/
- 转到文件>新建>文件夹,选择你项目的父文件夹,输入“libs/armeabi”作为文件夹名,然后单击“完成”。
- 复制javacpp.jar和javacv.jar到新创建的“libs”文件夹。
- 把javacv-android-arm.jar,opencv-2.4.5-android-arm.jar和 ffmpeg-1.2-android-arm.jar中的所有*.so文件直接解压到新创建的“libs/armeabi”文件夹,在JAR文件中没有任何创建的子目录。
- 导航项目>属性> Java创建路径>“库”,然后单击“添加JAR文件...”。
- 从新创建的“libs”文件夹中选择javacpp.jar和javacv.jar。
在那之后,OpenCV和FFmpeg的封装类可以自动访问它们的C/C++ API:
类的定义基本是在C原始头文件中的Java端口,加上缺少的功能,只能通过暴露的OpenCV的C++ API,我特意决定保持尽可能多的原始语法。例如,这是一个试图加载图像文件,平滑处理后保存到磁盘的方法:
- import static com.googlecode.javacv.cpp.opencv_core.*;
- import static com.googlecode.javacv.cpp.opencv_imgproc.*;
- import static com.googlecode.javacv.cpp.opencv_highgui.*;
-
- public class Smoother {
- public static void smooth(String filename) {
- IplImage image = cvLoadImage(filename);
- if (image != null) {
- cvSmooth(image, image, CV_GAUSSIAN, 3);
- cvSaveImage(filename, image);
- cvReleaseImage(image);
- }
- }
- }
JavaCV还带有建立在OpenCV和FFmpeg之上的辅助类和方法,以方便把他们集成到Java平台。 这里是一个小演示程序来演示最常见的有用部分:
- import java.io.File;
- import java.net.URL;
- import com.googlecode.javacpp.Loader;
- import com.googlecode.javacv.*;
- import com.googlecode.javacv.cpp.*;
- import static com.googlecode.javacv.cpp.opencv_core.*;
- import static com.googlecode.javacv.cpp.opencv_imgproc.*;
- import static com.googlecode.javacv.cpp.opencv_calib3d.*;
- import static com.googlecode.javacv.cpp.opencv_objdetect.*;
-
- public class Demo {
- public static void main(String[] args) throws Exception {
- String classifierName = null;
- if (args.length > 0) {
- classifierName = args[0];
- } else {
- URL url = new URL("https://raw.github.com/Itseez/opencv/master/data/haarcascades/haarcascade_frontalface_alt.xml");
- File file = Loader.extractResource(url, null, "classifier", ".xml");
- file.deleteOnExit();
- classifierName = file.getAbsolutePath();
- }
-
-
- Loader.load(opencv_objdetect.class);
-
-
- CvHaarClassifierCascade classifier = new CvHaarClassifierCascade(cvLoad(classifierName));
- if (classifier.isNull()) {
- System.err.println("Error loading classifier file \"" + classifierName + "\".");
- System.exit(1);
- }
-
-
-
-
- FrameGrabber grabber = FrameGrabber.createDefault(0);
- grabber.start();
-
-
-
-
-
-
-
-
- IplImage grabbedImage = grabber.grab();
- int width = grabbedImage.width();
- int height = grabbedImage.height();
- IplImage grayImage = IplImage.create(width, height, IPL_DEPTH_8U, 1);
- IplImage rotatedImage = grabbedImage.clone();
-
-
-
-
- CvMemStorage storage = CvMemStorage.create();
-
-
-
- FrameRecorder recorder = FrameRecorder.createDefault("output.avi", width, height);
- recorder.start();
-
-
-
-
- CanvasFrame frame = new CanvasFrame("Some Title", CanvasFrame.getDefaultGamma()/grabber.getGamma());
-
-
- CvMat randomR = CvMat.create(3, 3), randomAxis = CvMat.create(3, 1);
-
-
- randomAxis.put((Math.random()-0.5)/4, (Math.random()-0.5)/4, (Math.random()-0.5)/4);
- cvRodrigues2(randomAxis, randomR, null);
- double f = (width + height)/2.0; randomR.put(0, 2, randomR.get(0, 2)*f);
- randomR.put(1, 2, randomR.get(1, 2)*f);
- randomR.put(2, 0, randomR.get(2, 0)/f); randomR.put(2, 1, randomR.get(2, 1)/f);
- System.out.println(randomR);
-
-
- CvPoint hatPoints = new CvPoint(3);
-
- while (frame.isVisible() && (grabbedImage = grabber.grab()) != null) {
- cvClearMemStorage(storage);
-
-
- cvCvtColor(grabbedImage, grayImage, CV_BGR2GRAY);
- CvSeq faces = cvHaarDetectObjects(grayImage, classifier, storage,
- 1.1, 3, CV_HAAR_DO_CANNY_PRUNING);
- int total = faces.total();
- for (int i = 0; i < total; i++) {
- CvRect r = new CvRect(cvGetSeqElem(faces, i));
- int x = r.x(), y = r.y(), w = r.width(), h = r.height();
- cvRectangle(grabbedImage, cvPoint(x, y), cvPoint(x+w, y+h), CvScalar.RED, 1, CV_AA, 0);
-
-
- hatPoints.position(0).x(x-w/10) .y(y-h/10);
- hatPoints.position(1).x(x+w*11/10).y(y-h/10);
- hatPoints.position(2).x(x+w/2) .y(y-h/2);
- cvFillConvexPoly(grabbedImage, hatPoints.position(0), 3, CvScalar.GREEN, CV_AA, 0);
- }
-
-
- cvThreshold(grayImage, grayImage, 64, 255, CV_THRESH_BINARY);
-
-
- CvSeq contour = new CvSeq(null);
- cvFindContours(grayImage, storage, contour, Loader.sizeof(CvContour.class),
- CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
- while (contour != null && !contour.isNull()) {
- if (contour.elem_size() > 0) {
- CvSeq points = cvApproxPoly(contour, Loader.sizeof(CvContour.class),
- storage, CV_POLY_APPROX_DP, cvContourPerimeter(contour)*0.02, 0);
- cvDrawContours(grabbedImage, points, CvScalar.BLUE, CvScalar.BLUE, -1, 1, CV_AA);
- }
- contour = contour.h_next();
- }
-
- cvWarpPerspective(grabbedImage, rotatedImage, randomR);
-
- frame.showImage(rotatedImage);
- recorder.record(rotatedImage);
- }
- frame.dispose();
- recorder.stop();
- grabber.stop();
- }
- }