OpenCV Java入门二 在Windows10系统上安装OpenCV

Posted TGITCIC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV Java入门二 在Windows10系统上安装OpenCV相关的知识,希望对你有一定的参考价值。

准备好痛苦了没有?

痛苦之后是欢乐。因为必竟大多人还是用的WINDOWS来开发的居多。因此如果OpenCV无法在Win10下安装,一样不能起到普及作用。

而Windows下的编译安装OpenCV也是最痛苦的一件事。原因就在于在编译安装OpenCV时很多Extra的模块是被“墙”掉了。

因此整个过程一会这个错一会那个错,开发机电脑也不太好,导致一次编译,30多分钟,然后报了一堆错网上查了半天解决了一个,又来一个。

如此周而复始,让绝大多数开发者放弃了OpenCV。

本篇就是要着重讲述OpenCV在Windows10下的编译全过程和全部坑的排错。

环境准备

  1. 一台32GB开发机;
  2. I7 CPU;
  3. 必须为固态磁盘否则编译过程可以让你怀疑人生;
  4. 稳定的百兆宽带连接;
  5. Win10;
  6. 安装Visual Studio 14 2015 win64版或者更高也可以并安装时选择“Visual C++“,在此过程还会安装.netframework;
  7. 安装jdk1.8即可,并把JAVA_HOME\\bin加入到环境变量path中去;
  8. 安装Ant1.9或以上,并把ANT_HOME\\bin加入到环境变量path中去;
  9. 安装python3,并把python.exe所在的path,加入到环境变量path中去;
  10. 下载opencv3.4.3稳定版-本人提供了整理的包含全套脱机文件(被墙掉的文件)的安装包在正文中;
  11. 下载opencv3.4.3-contribute本人提供了整理的包含全套脱机文件(被墙掉的文件)的安装包在正文中;
  12. 下载cmake-gui(下载后直接双击即可运行不用安装);

截图-python3

截图-系统path环境变量

开始安装

先了解opencv在windows下编译安装的逻辑过程

opencv在windows下任何版本的编译是如下过程的

  1.  使用cmake进行opencv的configure;
  2. 寻找ant;
  3. 寻找jdk;
  4. 寻找python;
  5. 加入opencv nonfree包;
  6. 加入opencv contrib模块;
  7. 开启opencv java编译项;
  8. 开启opencv xfeatures2d项;
  9. 使用windows10上安装的visual studio的编译器生成visual studio项目.sln;
  10. 使用visual studio打开由cmake gui生成visual studio项目;
  11. 使用ant编译打包opencv jar包;
  12. 使用visual studio的vc引擎编译->Install;

开始Configure OpenCV

千万不要去下载网上提供的已经编译好的这两个文件。如果你为了图个方便,网上去下载别人编译安装好的这两个文件

那么在学习过程中运行死机、运行报错、或者干脆一会header找不到一会什么.h文件找不到,不要怪我没有事先提醒。

OpenCV在编译时的安装目录的设置

opencv在编译时会需要很多第3方依赖包,这些额外包有这么大一陀,我给各位看一下。

每一个第3方安装包,都在墙外,你在编译安装时一个下载时被卡住、过几分钟后再Failed、再一个。。。。。。再一个。。。。。。这些包全部下载Failed后用了几十分钟,然后你直接会觉得有一种“生无可怜”的味道。

我是一个个自己看着编译报错时的log内容,一个个手动用百度云盘方式先下载后再按照了OpenCV编译安装时所需要的目录结构排列后,并且下载了OpenCV3.4.3的源码(不动任何东西)以及OpenCV3.4.3的contribute包。然后我把三个目录打成了一个包,做了一个脱机包给到大家,算是一种福利吧。

完整全套脱机包在此百度网盘内,请笑纳:

链接:https://pan.baidu.com/s/1mXOEfqykUT2TWk6OXtAEVA?pwd=ioti
提取码:ioti
--来自百度网盘超级会员V6的分享

下载后并解压是这样的一个文件目录结构内容把它放到一个叫opencvinstall的目录内。

3rdparty为opencv编译安装时必备,这里面我已经把我所有一个个幸苦下载好的文件按照opencv安装时的需要摆放好了。

随后我们单建一个文件夹叫opencvbuild。用来存cmake编译出来的opencv的编译输出的文件夹

届此,即完成了目录设置的准备了。

使用cmake-gui编译

运行起来后是这样的界面

  • where is the souce code:指向D:/opencvbuild/opencv3.4.3.master即源码所在目录节点
  • where to build the binaries:指向编译生成后所在的目录,在些我们用的是D:/opencvbuild,这是一个空目录,你可以任意指定。

把我网盘里下载下来的3个文件夹中的“3rdparty”里的所有的内容

 拷贝到opencv3.4.3.master即源码包下的.cache里,并按照提示覆盖掉里面3rdparty目录内的所有内容。

然后点一下这个界面中的【Configure】按钮。

 然后cmake-gui会提示你选择visual c的编译器,你此时应该事先已经装好了visual studio 14 2015包含visual c++了,请选择visual studio 14 2015。

然后点【Finish】后你会得到一堆红色的列表,没有关系。跟着我的步骤一步步走,不会有问题的。

在红色的列表中进行相应的选择和填充

确保ant被opencv正确找到

否则就要自己手工指定目录

OPENCV_ENABLE_NONFREE的选择

把OPENCV_ENABLE_NONFREE打勾

OPENCV_EXTRA_MODULES_PATH必须被指定否则不可以用人脸识别

记得这边指定的可是/opencvinstall/opencv_contrib-3.4.3/modules目录,很多人指定到了opencv_contrib-3.4.3这一层,会导致点【configure】按钮时出一个.h文件找不到的错的。

确保python的Executable和Include Dir可以被系统找到

否则就手工指定。

然后再次点击【Configure】

然后看到此处的两个Java都要Success。

此时我们来看opencvbuild目录内,出现了这么多东西,好家伙。

此时,我们在进入下一步前需要做一件事,否则你一会会感觉要疯了

那就是在之前OpenCV Java入门一 在MAC系统上安装OpenCV里,我说过:opencv会使用最新的javac compiler编译打包opencv for java

在mac里它打出的jar包我们需要使用jdk17来运行,同时兼顾装有jdk1.8来运行最新版2021-12版的eclipse。

然后:

  • 使用eclipse 2021-12+jdk1.8启动eclipse;
  • opencv工程使用jd17作jre,同时compile version选17就可以在eclipse内进行开发opencv的项目了。

很可惜,windows下的eclipse 2021-12的compile version只支持到 jdk16,这和mac是有极大的区别的,它比mac上的东西慢了半拍。

因此,如果在windows里编译出来的opencv的jar包也是jdk17编译成的,你的eclipse就算是最新的也会在运行时报一个非常恶心的错“need class version 62, but it support to 61”。

所以,一开始我们就要在这个jar包被编译前就指定jdk编译版本把这个jar包用jdk1.8编译出来。这样我们在windows里就可以使用jdk1.8以及eclipse早期版(只要支持jdk1.8的)可以使用opencv jar了。

指定编译出的opencv jar包的编译器为jdk1.8

在opencvbuild即cmake-gui输出的目录中找到如下的这个文件

打开它,然后把这一行加上一个target="1.8":

 改完后的build.xml全文如下范例

<!-- This is an Apache Ant build file. As part of the desktop java build -->
<!-- process, this config is used to package the autogenerated .java -->
<!-- interface files into OpenCV.jar -->
<project name="OpenCV">

    <tstamp>
      <format property="timestamp" pattern="EEE MMM d yyyy HH:mm:ss z"/>
    </tstamp>

  <target name="jar">
    <!-- This is to make a jar with a source attachment, for e.g. easy -->
    <!-- navigation in Eclipse. See this question: -->
    <!-- http://stackoverflow.com/questions/3584968/ant-how-to-compile-jar-that-includes-source-attachment -->
    <javac target="1.8" sourcepath="" srcdir="java" destdir="build/classes" debug="on" includeantruntime="false" >
      <include name="**/*.java"/>
      <compilerarg line="-encoding utf-8"/>
    </javac>
    <jar destfile="D:/opencv/opencv3.4.3/build/bin/opencv-343.jar">
      <fileset dir="java"/>
      <fileset dir="build/classes"/>
      <manifest>
        <attribute name="Specification-Title" value="OpenCV"/>
        <attribute name="Specification-Version" value="3.4.3"/>
        <attribute name="Implementation-Title" value="OpenCV"/>
        <attribute name="Implementation-Version" value="unknown"/>
        <attribute name="Implementation-Date" value="$timestamp"/>
      </manifest>
    </jar>
  </target>

  <target name="javadoc">
    <javadoc
      packagenames="org.opencv.*"
      sourcepath="java"
      destdir="D:/opencv/opencv3.4.3/build/doc/doxygen/html/javadoc"
      Windowtitle="OpenCV 3.4.3 Java documentation"
      Doctitle="OpenCV Java documentation (3.4.3)"
      bottom="Generated on $timestamp / OpenCV unknown"
      />
  </target>

</project>

 在cmake-gui界面点击[Generate]按钮

并得到成功的输出。

然后再点击【Open Project】按钮

此时,visual studio就被打开了。当全部的项目装载完后先把Debug改成Release,然后点击菜单里的“生成”->“生成解决方案”。

 全部生成成功在我的台式机上大概也就用了4分钟。

然后在右边的这块树型project explorer界面中

点击【INSTALL】,按鼠标右键,选【仅用于项目】

 

 过一会全部编译好的opencv就放置在了opencvbuild\\install目录下了。

java用的两个文件生成在此opencvbuild\\install\\java

在Windows下使用Eclipse创建OpenCV工程

在Native library location处,点击【edit】按钮

把这个路径定位到D:\\opencvbuild\\install\\java目录,这个目录里有opencv-343.jar和opencv_java343.dll文件。

在下面的classpath里点击右边的【Add External JARs】按钮。把它定位到D:\\opencvbuild\\install\\java\\opencv-343.jar文件。

 在windows10的控制面板的系统设置里,在系统变量的Path里加入如下内容:

opencvbuild的\\install\\x64\\vc14\\bin

届此,OpenCV Java工程的环境已经全部搭建完毕。

OpenCV入门样例

我们来读入一张带有人脸的图片,然后在人脸上把他的眼晴部分给标识出来。

OpenCVUtil.java

package org.mk.opencv.util;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.io.File;

import org.apache.log4j.Logger;
import org.opencv.core.CvType;
import org.opencv.core.Mat;


public class OpenCVUtil 
	private static Logger logger = Logger.getLogger(OpenCVUtil.class);

	public static Image matToImage(Mat matrix) 
		int type = BufferedImage.TYPE_BYTE_GRAY;
		if (matrix.channels() > 1) 
			type = BufferedImage.TYPE_3BYTE_BGR;
		
		int bufferSize = matrix.channels() * matrix.cols() * matrix.rows();
		byte[] buffer = new byte[bufferSize];
		matrix.get(0, 0, buffer); // 获取所有的像素点
		BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type);
		final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
		System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
		return image;
	

	public static List<String> getFilesFromFolder(String folderPath) 
		List<String> fileList = new ArrayList<String>();
		File f = new File(folderPath);
		if (f.isDirectory()) 
			File[] files = f.listFiles();
			for (File singleFile : files) 
				fileList.add(singleFile.getPath());
			
		
		return fileList;
	

	public static String randomFileName() 
		StringBuffer fn = new StringBuffer();
		fn.append(System.currentTimeMillis()).append((int) (System.currentTimeMillis() % (10000 - 1) + 1))
				.append(".jpg");
		return fn.toString();
	

	public static List<FileBean> getPicFromFolder(String rootPath) 
		List<FileBean> fList = new ArrayList<FileBean>();
		int fileNum = 0, folderNum = 0;
		File file = new File(rootPath);
		if (file.exists()) 
			LinkedList<File> list = new LinkedList<File>();
			File[] files = file.listFiles();
			for (File file2 : files) 
				if (file2.isDirectory()) 
					// logger.info(">>>>>>文件夹:" + file2.getAbsolutePath());
					list.add(file2);
					folderNum++;
				 else 
					// logger.info(">>>>>>文件:" + file2.getAbsolutePath());
					FileBean f = new FileBean();
					String fileName = file2.getName();
					String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
					File fParent = new File(file2.getParent());
					String parentFolderName = fParent.getName();
					f.setFileFullPath(file2.getAbsolutePath());
					f.setFileType(suffix);
					f.setFolderName(parentFolderName);
					fList.add(f);
					fileNum++;
				
			
			File temp_file;
			while (!list.isEmpty()) 
				temp_file = list.removeFirst();
				files = temp_file.listFiles();
				for (File file2 : files) 
					if (file2.isDirectory()) 
						// System.out.println("文件夹:" + file2.getAbsolutePath());
						list.add(file2);
						folderNum++;
					 else 
						// logger.info(">>>>>>文件:" + file2.getAbsolutePath());
						FileBean f = new FileBean();
						String fileName = file2.getName();
						String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
						File fParent = new File(file2.getParent());
						String parentFolderName = fParent.getName();
						f.setFileFullPath(file2.getAbsolutePath());
						f.setFileType(suffix);
						f.setFolderName(parentFolderName);
						fList.add(f);
						fileNum++;
					
				
			
		 else 
			logger.info(">>>>>>文件不存在!");
		
		// logger.info(">>>>>>文件夹共有:" + folderNum + ",文件共有:" + fileNum);
		return fList;
	

	public static BufferedImage matToBufferedImage(Mat matrix) 
		int cols = matrix.cols();
		int rows = matrix.rows();
		int elemSize = (int) matrix.elemSize();
		byte[] data = new byte[cols * rows * elemSize];
		int type;
		matrix.get(0, 0, data);
		switch (matrix.channels()) 
		case 1:
			type = BufferedImage.TYPE_BYTE_GRAY;
			break;
		case 3:
			type = BufferedImage.TYPE_3BYTE_BGR;
			// bgr to rgb
			byte b;
			for (int i = 0; i < data.length; i = i + 3) 
				b = data[i];
				data[i] = data[i + 2];
				data[i + 2] = b;
			
			break;
		default:
			return null;
		
		BufferedImage image2 = new BufferedImage(cols, rows, type);
		image2.getRaster().setDataElements(0, 0, cols, rows, data);
		return image2;
	

	public static Mat bufferedImageToMat(BufferedImage bi) 
		Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
		byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
		mat.put(0, 0, data);
		return mat;
	

 ImageViewer.java

这是一个JFrame,用于显示OpenCV的Mat格式图像用的通用类,后面好几个例子都会用到这个通用显示图像类

package org.mk.opencv;

import org.mk.opencv.util.OpenCVUtil;
import org.opencv.core.Mat;
import javax.swing.*;
import java.awt.*;

public class ImageViewer 
	private JLabel imageView;
	private Mat image;
	private String windowName;

	/**
	 * 如果使用junit测试时调用该方法,图像会一闪而过,可通过sleep()等方式暂时显示
	 * 
	 * @param
	 */
	private JFrame frame = null;

	public ImageViewer() 
		frame = createJFrame(windowName, 800, 600);
	

	public ImageViewer(Mat image) 
		this.image = image;
	

	/**
	 * @param image      要显示的mat
	 * @param windowName 窗口标题
	 */
	public ImageViewer(Mat image, String windowName) 
		frame = createJFrame(windowName, 1024, 768);
		this.image = image;
		this.windowName = windowName;
	

	public void setTitle(String windowName) 
		this.windowName = windowName;
	

	public void setImage(Mat image) 
		this.image = image;
	

	/**
	 * 图片显示
	 */
	public void imshow() 
		setSystemLookAndFeel();
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 用户点击窗口关闭
		if (image != null) 
			Image loadedImage = OpenCVUtil.matToImage(image);
			// JFrame frame = createJFrame(windowName, image.width(), image.height());
			imageView.setIcon(new ImageIcon(loadedImage));
			frame.pack();
			// frame.setLocationRelativeTo(null);
			// frame.setVisible(true);
			// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 用户点击窗口关闭
		
	

	private void setSystemLookAndFeel() 
		try 
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		 catch (ClassNotFoundException e) 
			e.printStackTrace();
		 catch (InstantiationException e) 
			e.printStackTrace();
		 catch (IllegalAccessException e) 
			e.printStackTrace();
		 catch (UnsupportedLookAndFeelException e) 
			e.printStackTrace();
		
	

	private JFrame createJFrame(String windowName, int width, int height) 
		JFrame frame = new JFrame(windowName);
		imageView = new JLabel();
		final JScrollPane imageScrollPane = new JScrollPane(imageView);
		imageScrollPane.setPreferredSize(new Dimension(width, height));
		frame.add(imageScrollPane, BorderLayout.CENTER);
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		return frame;
	


 DetectEye.java

这个类就是用来探测人眼的类了。

它作这么几件事:

  1. 读入一个jpg图片;
  2. 调用opencv内置检测器中的眼部检测器,这些检测器一般位于:opencv编译目录如“opencvbuild\\install\\etc”目录内;
  3. 使用检测器把人眼部位识别出来;
  4. 在识别的位置汇制一个矩形;
  5. 然后使用ImageViewer来显示这张图片;
package org.mk.opencv;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

public class DetectEye 
	private static Mat detectEye(Mat src) 
		Mat dst = src.clone();

		// 绾ц仈鍒嗙被鍣ㄧ被鐢ㄤ簬瀵硅薄妫�娴嬨��
		CascadeClassifier objDetector = new CascadeClassifier(
				"D:\\\\opencv\\\\opencv3.4.3\\\\install-mk-pc-with-xfeatures2d\\\\etc\\\\haarcascades\\\\haarcascade_eye.xml");
		MatOfRect objDetections = new MatOfRect();
		objDetector.detectMultiScale(dst, objDetections);
		if (objDetections.toArray().length <= 0) 
			return src;
		
		for (Rect rect : objDetections.toArray()) 
			Imgproc.rectangle(dst, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
					new Scalar(0, 0, 255), 2);
		
		return dst;
	

	public static void main(String[] args) 
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
		Mat src = Imgcodecs.imread("D:\\\\opencv-demo\\\\anold.jpg");
		if (src.dataAddr() == 0) 
			System.out.println("打开文件出错");
		
		Mat eyeDtMat = detectEye(src);
		ImageViewer imageViewer = new ImageViewer(eyeDtMat, "第一幅图片");
		imageViewer.imshow();
	

运行后效果如下

 

以上是关于OpenCV Java入门二 在Windows10系统上安装OpenCV的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV | OpenCV实战从入门到精通系列二 -- OpenCV图像腐蚀

OpenCV | OpenCV实战从入门到精通系列二 -- OpenCV图像腐蚀

史上最全的OpenCV入门教程!这篇够你学习半个月了!万字长文入门

opencv从入门到应用1&2

在Windows上创建CUDA C程序

C/C++ vs2017 OpenCV简单入门