使用OpenCV开发人脸识别及相关注意事项

来源:互联网 发布:ubuntu默认视频播放器 编辑:程序博客网 时间:2024/06/05 05:55

因工作需要需做一个有关人脸识别的小应用,搞了一周多的时间借助网上一些大神的帖子终于能正常使用了。

注意事项:1.openCV需要的java运行环境是1.8以上的,所以我的JRE必须是1.8。当我打包成exe给同事电脑使用时发现运行保持,找不到openCV相关类,才知道有此限制。

2.另外必须下个opneCV然后安装,其实只是需要安装里面的筛选器、openCV-330.jar和opencv_java330.dll。如果能通过其他方式搞到,不需要安装也行。

这是OpenCV安装目录下的我们开发要用到的opencv-330.jar包,x64文件夹里是64位系统对应的配置文件opencv-330.dll。需要复制一份到我们运行的jre的bin目录下。


开始写代码

import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;


import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.WindowConstants;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDouble;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.objdetect.HOGDescriptor;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;
/**
 * 此类是BS模式下的拍照功能代码;
 * 附带人脸识别功能;人脸识别功能的识别器是安装的OpenCV中的从配置文件lbpcascade_frontalface.xml中创建
 * 需要jar包opeencv-330.jar
 * @author liuha
 *
 */


import utils.FileUtils;
import utils.WRXml;
import utils.WRproperties;


public class MyCl extends JPanel {
private static String frontalface;
private static String filePath;
private static String fileName;
private static BufferedImage mImagShow;
private static BufferedImage mImagSave;
private static String sysImagPath = ".\\res\\img\\";
static int height;
static int width;
static int i = 0;






public static void main(String[] args) {
WRproperties wrproperties = new WRproperties(null);
WRXml wrxml = new WRXml(null);
filePath = wrproperties.getnouploadPath();
frontalface = wrproperties.getFrontalFace();
fileName = wrxml.readXML();
try {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);//加载库
Mat capImg = new Mat();
VideoCapture capture = new VideoCapture(0);
height = (int) capture.get(Videoio.CAP_PROP_FRAME_HEIGHT);
width = (int) capture.get(Videoio.CAP_PROP_FRAME_WIDTH);
if (height == 0 || width == 0) {
JOptionPane.showMessageDialog(null, "错误", "摄像头启动异常!", JOptionPane.ERROR_MESSAGE);
throw new Exception("camera not found!");
}
JFrame frame = new JFrame("照片采集");
frame.setIconImage(new ImageIcon( sysImagPath+ "title1.png").getImage());//标题栏图片
JFrame.setDefaultLookAndFeelDecorated(true);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
MyCl panel = new MyCl();
panel.setLayout(null);
JButton loginButton = new JButton(new ImageIcon( sysImagPath+ "camera.png"));//拍照按钮图片
loginButton.setBorder(BorderFactory.createRaisedBevelBorder()); 

loginButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
FileUtils.createDir(filePath);
String format = "JPEG";
Date date = new Date();
if (fileName == null)
fileName = date.getYear() + (date.getMonth() + 1) + date.getDate() + date.getHours()
+ date.getMinutes() + date.getSeconds() + "";
File filePic = new File(filePath + fileName + ".jpg");
try {
ImageIO.write(mImagSave, format, filePic);
} catch (IOException e) {
e.printStackTrace();
} // 将图片保存为jpeg格式的文件file。也可以保存为jpg格式
}
});

loginButton.setBounds(10, 10, 60, 60);
panel.add(loginButton);
frame.setContentPane(panel);
frame.setVisible(true);
int frameW = width + frame.getInsets().left + frame.getInsets().right;
int frameH = height + frame.getInsets().top + frame.getInsets().bottom;
frame.setSize(frameW, frameH);

int n = 0;
Mat temp = new Mat();
while (frame.isShowing() && n < 500) {
// System.out.println("第"+n+"张");
capture.read(capImg);
Imgproc.cvtColor(capImg, temp, Imgproc.COLOR_RGB2GRAY);
mImagSave = panel.mat2BI(capImg);
panel.mImagShow = panel.mat2BI(detectFace(capImg));
// panel.mImg=panel.mat2BI(detectPeople(capImg));
// panel.mImg=panel.mat2BI(capImg);
panel.repaint();
// n++;
// break;
}
capture.release();
frame.dispose();
} catch (Exception e) {
System.out.println("例外:" + e);
} finally {
System.out.println("--done--");
}


}
/**
* 转换格式,将MAt转图片流
* @param mat
* @return
*/
private BufferedImage mat2BI(Mat mat) {
int dataSize = mat.cols() * mat.rows() * (int) mat.elemSize();
byte[] data = new byte[dataSize];
mat.get(0, 0, data);
int type = mat.channels() == 1 ? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_3BYTE_BGR;


if (type == BufferedImage.TYPE_3BYTE_BGR) {
for (int i = 0; i < dataSize; i += 3) {
byte blue = data[i + 0];
data[i + 0] = data[i + 2];
data[i + 2] = blue;
}
}
BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data);


return image;
}


public void paintComponent(Graphics g) {
if (mImagShow != null) {
g.drawImage(mImagShow, 0, 0, mImagShow.getWidth(), mImagShow.getHeight(), this);
}
}
/**
* opencv实现人脸识别

* @param img
*/
public static Mat detectFace(Mat img) throws Exception {


System.out.println("Running DetectFace ... "+frontalface);
// String path = System.getProperty("java.class.path");
// int first = path.lastIndexOf(System.getProperty("path.separator")) + 1;
// int last = path.lastIndexOf(File.separator) + 1;
// CascadeClassifier  faceDetector = new CascadeClassifier(path.substring(first, last) + "haarcascade_frontalface_alt.xml");
// if(faceDetector.empty()) {

CascadeClassifier faceDetector = new CascadeClassifier(frontalface);
if(faceDetector.empty()) {
return detectPeople(img);
}



// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,该文件位于opencv安装目录中
// CascadeClassifier faceDetector = new
// CascadeClassifier("E:\\LiuH\\Program\\Softer\\OpenCV\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");

// 在图片中检测人脸
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(img, faceDetections);
System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));
Rect[] rects = faceDetections.toArray();
//自己加了个扫面线,显得高科技点,但是……
if (rects != null && rects.length >= 1) {
i = 0;
for (Rect rect : rects) {
Imgproc.rectangle(img, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(255, 191, 0), 2);
}
} else {
i += 7;
Imgproc.rectangle(img, new Point(20, i), new Point(width - 20, i), new Scalar(255, 255, 255, 0), 2);


if (i >= height) {
i = 0;


}
}
return img;
}


/**
* opencv实现人型识别,hog默认的分类器。所以效果不好。

* @param img
*/
public static Mat detectPeople(Mat img) {
// System.out.println("detectPeople...");
if (img.empty()) {
System.out.println("image is exist");
}
HOGDescriptor hog = new HOGDescriptor();
hog.setSVMDetector(HOGDescriptor.getDefaultPeopleDetector());
System.out.println(HOGDescriptor.getDefaultPeopleDetector());
// hog.setSVMDetector(HOGDescriptor.getDaimlerPeopleDetector());
MatOfRect regions = new MatOfRect();
MatOfDouble foundWeights = new MatOfDouble();
// System.out.println(foundWeights.toStringp());
hog.detectMultiScale(img, regions, foundWeights);
for (Rect rect : regions.toArray()) {
Imgproc.rectangle(img, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 0, 255), 2);
}


i += 7;
Imgproc.rectangle(img, new Point(20, i), new Point(width - 20, i), new Scalar(255, 255, 255, 0), 2);


if (i >= height) {
i = 0;
}
return img;
}

}


上面是主程序的代码。另外因为我把图片保存路径还有识别器文件的路径都是用配置文件调用的,所以还有一个读写配置文件的工具类。另外我这样写路径是因为我打包成exe文件是能正常。

这是我应用正常的目录结构,它需要调本录下的config文件夹里的haarcascade_frontalface_alt.xml进行人脸识别,读取config文件夹下的res.properties,此文件写了一些图片保存路径。然后使用的是本目录下的jre,而并不是系统的jre,且此jre下的bin文件夹里已经复制过来一份opencv-330.dll文件。res文件夹下存了一些图片。


读取配置文件的工具类可以自己百度一个,其实就是读写properties文件。需要的可以联想我。搞不定就把路径写死吧。


如果直接复制我的代码肯定跑不起来的,因为很多路径都是用的我自己的,需要改一下,一个是识别器的路径,也就是haarcascade_frontalface_alt.xml。这个文件在openCV的安装目录下有。


好了,如果跑起来就得知道怎么打包了。这个我捣鼓了很久。

一,打成jar包

选择main函数的类,finish.



二。打成exe文件

下载个exe4j工具

使用的说明具体百度一下。我这里讲一下特殊的地方。这一步最好把openCV的jar也打到里面


然后,首先得先把我上面所说的文件目录给建起来,也就是下面的目录



然后特别注意的是这一步,选1.8.。然后点Advanced Options>Search sequence


将其自带的都删掉,然后将jre的目录指配给和我们打好jar同目录下的jre。也就是上面那个图目录下的jre。(打好的jar和此jre在同一目录下)


剩下的就按照百度的教程走就可以了。

原创粉丝点击