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

你准备好接受痛苦了吗?

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

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

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

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

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

环境准备

  1. 一台32GB开发机;
  2. I7 CPU;
  3. 一定是固态盘,不然编译过程会让你怀疑人生;
  4. 稳定的100M宽带连接;
  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

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

截图-系统path环境变量

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

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

开始安装

先了解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

不要下载这两个已经在网上编译好的文件。如果你想让它更容易,下载别人在线编译安装的两个文件。

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

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

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

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

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

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

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

全套离线包在本百度网盘,请笑着收下:

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

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

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

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

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

至此,目录设置的准备工作就完成了。

使用cmake-gui编译

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

这是运行后的界面

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

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

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

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

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

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

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

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

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

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

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

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

相应地选择并填写红色列表

确保ant被opencv正确找到

否则需要自己手动指定目录

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

OPENCV_ENABLE_NONFREE的选择

把OPENCV_ENABLE_NONFREE打勾

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

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

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

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

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

否则,请手动指定。

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

然后再次点击【Configure】

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

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

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

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

在这一点上,我们需要在继续下一步之前做一件事,否则你会觉得有一段时间很疯狂。

那就是在之前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输出的目录中找到如下的这个文件

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

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

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

改完后的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]按钮

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

并获得成功的输出。

然后再点击【Open Project】按钮

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

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

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

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

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

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

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

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

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

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

在Windows下使用Eclipse创建OpenCV工程

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

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

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

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

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

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

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

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

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2022年3月21日 下午2:00
下一篇 2022年3月21日 下午3:23

相关推荐