毕业设计——基于JAVA+OpenCV的人脸识别项目
opencv
OpenCV: 开源计算机视觉库
项目地址:https://gitcode.com/gh_mirrors/opencv31/opencv
免费下载资源
·
完整项目,私信博主获取
功能
- 人脸检测、识别(图片、视频)
- 更换背景图(例如给任务换一张海景背景图)
- 图片合成(多张照片合成)
- 证件照更换背景色
- 年龄识别
- 性别识别
- 图片修复(可用于水印去除)
- 图片分类
- 老照片
- 素描
- 图像色温调整
- 图像对比度调整
- 图像高光调整
- 图像明度调整
- 图像饱和度调整
- 图像阴影调整
- 天空滤镜
- 人脸检测、识别(Dlib版本)
- 暗通道去雾算法
- 中值滤波去雾算法
- 人脸美颜磨皮算法
开发环境
-
Windows 10(x64)
-
Java 1.8
-
OpenCV 3.4.3
-
JavaCV 1.4.3
-
Dlib 仅仅支持 Linux Or MacOS
例子
package com.biubiu.example;
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import java.math.BigDecimal;
import static org.bytedeco.javacpp.opencv_objdetect.CV_HAAR_DO_CANNY_PRUNING;
public class FaceDetect {
static {
// 加载 动态链接库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
String filepath = "/home/yinyue/opencv/test.JPG";
Mat srcImg = Imgcodecs.imread(filepath);
// 目标灰色图像
Mat dstGrayImg = new Mat();
// 转换灰色
Imgproc.cvtColor(srcImg, dstGrayImg, Imgproc.COLOR_BGR2GRAY);
// OpenCv人脸识别分类器
CascadeClassifier classifier = new CascadeClassifier("/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml");
// 用来存放人脸矩形
MatOfRect faceRect = new MatOfRect();
// 特征检测点的最小尺寸
Size minSize = new Size(32, 32);
// 图像缩放比例,可以理解为相机的X倍镜
double scaleFactor = 1.2;
// 对特征检测点周边多少有效检测点同时检测,这样可以避免选取的特征检测点大小而导致遗漏
int minNeighbors = 3;
// 执行人脸检测
classifier.detectMultiScale(dstGrayImg, faceRect, scaleFactor, minNeighbors, CV_HAAR_DO_CANNY_PRUNING, minSize);
//遍历矩形,画到原图上面
// 定义绘制颜色
Scalar color = new Scalar(0, 0, 255);
for(Rect rect: faceRect.toArray()) {
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
// 单独框出每一张人脸
Imgproc.rectangle(srcImg, new Point(x, y), new Point(x + h, y + w), color, 2);
// 左眼
Imgproc.circle(srcImg, new Point(x + Math.floor(getDivideDouble(w, 4)), y + Math.floor(getDivideDouble(h, 4)) + 15), Math.min(getDivideInt(h, 8), getDivideInt(w, 8)), color);
// 右眼
Imgproc.circle(srcImg, new Point(x + 3 * Math.floor(getDivideDouble(w, 4)), y + Math.floor(getDivideDouble(h, 4)) + 15), Math.min(getDivideInt(h, 8), getDivideInt(w, 8)), color);
// 嘴巴
Imgproc.rectangle(srcImg, new Point(x + 3 * Math.floor(getDivideDouble(w, 8)), y + 3 * Math.floor(getDivideDouble(h, 4)) - 5), new Point(x + 5 * Math.floor(getDivideDouble(w, 8)) + 10, y + 7 * Math.floor(getDivideDouble(h, 8))), color, 2);
}
HighGui.imshow("预览", srcImg);
// 显示图像
HighGui.waitKey(0) ;
// 释放所有的窗体资源
HighGui.destroyAllWindows();
}
/**
* 图片转换成灰色(降低为一维的灰度,减低计算强度)
* @param path
* @return
*/
private static Mat transferToGray(String path) {
// 读取图片
Mat srcImg = Imgcodecs.imread(path);
// 目标灰色图像
Mat dstGrayImg = new Mat();
// 转换灰色
Imgproc.cvtColor(srcImg, dstGrayImg, Imgproc.COLOR_BGR2GRAY);
return dstGrayImg;
}
/**
* 在图片上画矩形
* @param path
*/
private static void drawRect(String path) {
// 读取图片
Mat srcImg = Imgcodecs.imread(path);
// 目标灰色图像
Mat dstGrayImg = new Mat();
// 转换灰色
Imgproc.cvtColor(srcImg, dstGrayImg, Imgproc.COLOR_BGR2GRAY);
// 坐标
double x = 10, y = 10;
// 矩形大小(宽、高)
double w = 100;
// 定义绘制颜色
Scalar color = new Scalar(0, 0, 255);
Imgproc.rectangle(srcImg, new Point(x, y), new Point(x + w, y + w), color, 1);
HighGui.imshow("预览", srcImg);
// 显示图像
HighGui.waitKey(0);
// 释放所有的窗体资源
HighGui.destroyAllWindows();
}
/**
* 计算除法
* @param a
* @param b
* @return
*/
private static double getDivideDouble(int a, int b) {
return new BigDecimal(a).divide(new BigDecimal(b), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 计算除法
* @param a
* @param b
* @return
*/
private static int getDivideInt(int a, int b) {
return new BigDecimal(a).divide(new BigDecimal(b), 2, BigDecimal.ROUND_HALF_UP).intValue();
}
}
package com.biubiu.example;
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
import static org.bytedeco.javacpp.opencv_objdetect.CV_HAAR_DO_CANNY_PRUNING;
/**
* 视频人脸检测
*/
public class VideoDetect {
static {
// 加载 动态链接库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
VideoCapture camera = new VideoCapture();
// 参数0表示,获取第一个摄像头。
camera.open(0);
// 图像帧
Mat frame = new Mat();
for(;;) {
camera.read(frame);
draw(frame);
// 等待用户按esc停止检测
if(HighGui.waitKey(100) == 100) {
break;
}
}
// 释放摄像头
camera.release();
// 释放窗口资源
HighGui.destroyAllWindows();
}
/**
* 逐帧处理
* @param frame
*/
private static void draw(Mat frame) {
Mat grayFrame = new Mat();
Imgproc.cvtColor(frame, grayFrame, Imgproc.COLOR_BGR2GRAY);
// OpenCv人脸识别分类器
CascadeClassifier classifier = new CascadeClassifier("/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml");
// 用来存放人脸矩形
MatOfRect faceRect = new MatOfRect();
// 特征检测点的最小尺寸
Size minSize = new Size(32, 32);
// 图像缩放比例,可以理解为相机的X倍镜
double scaleFactor = 1.2;
// 对特征检测点周边多少有效检测点同时检测,这样可以避免选取的特征检测点大小而导致遗漏
int minNeighbors = 3;
// 执行人脸检测
classifier.detectMultiScale(grayFrame, faceRect, scaleFactor, minNeighbors, CV_HAAR_DO_CANNY_PRUNING, minSize);
Scalar color = new Scalar(0, 0, 255);
for(Rect rect: faceRect.toArray()) {
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
// 框出人脸
Imgproc.rectangle(frame, new Point(x, y), new Point(x + h, y + w), color, 2);
}
HighGui.imshow("预览", frame);
}
}
package com.biubiu.example;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class ReplaceImageBackgroundImage {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
String backPath = "D:\\upload\\back.jpg";
Mat back = Imgcodecs.imread(backPath);
Mat resized = new Mat(back.height(), back.height(), back.type());
Imgproc.resize(back, resized, resized.size(), 0.7, 0.7, Imgproc.INTER_CUBIC);
String imgPath = "D:\\upload\\green_pic.jpg";
Mat img = Imgcodecs.imread(imgPath);
Scalar lowerb = new Scalar(new double[] { 0, 0, 0 });
// RGB 三个值, R和B接近255, 扣到的图越好, 但是 容易产生边缘。
Scalar upperb = new Scalar(new double[] { 254, 255, 254 });
// 转换为hsv图像
Mat hsv = new Mat();
Imgproc.cvtColor(img, hsv, Imgproc.COLOR_BGR2HSV);
// 高斯模糊
Mat thresh = new Mat();
Imgproc.GaussianBlur(hsv, thresh, new Size(1, 1), 0);
// HighGui.imshow("thresh", thresh);
// 二值化
Mat mask = new Mat();
Core.inRange(thresh, lowerb, upperb, mask);
// 形态学开, 膨胀处理
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1, 1));
Mat hiMask = new Mat();
Imgproc.dilate(mask, hiMask, kernel);
// HighGui.imshow("hiMask", hiMask);
// 遍历, 抠图
for(int i = 0; i < img.rows(); i++) {
for(int j = 0; j < img.cols(); j++) {
// 去除白点的。
if(hiMask.get(i, j)[0] != 0) {
back.put(i, j, img.get(i, j));
}
}
}
HighGui.imshow("img", back);
HighGui.waitKey(0);
// 释放所有的窗体资源
HighGui.destroyAllWindows();
}
}
package com.biubiu.example;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
public class ImageSynthesis {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
// 加载图片矩阵
String filePath = "D:\\upload\\background.jpg";
Mat background = Imgcodecs.imread(filePath);
// Mat resized = new Mat(background.height(), background.height(), background.type());
// Imgproc.resize(background, resized, resized.size(), 0.7, 0.7, Imgproc.INTER_CUBIC);
// HighGui.imshow("background", resized);
String imgPath = "D:\\upload\\dog.jpg";
Mat img = Imgcodecs.imread(imgPath);
int imgRows = img.rows();
int imgCols = img.cols();
// HighGui.imshow("img", imgResized);
//
// Mat imgResized = new Mat(img.height(), img.height(), img.type());
// Imgproc.resize(img, imgResized, imgResized.size(), 0.4, 0.4, Imgproc.INTER_CUBIC);
// 灰度
// Mat gray = new Mat();
// Imgproc.cvtColor(imgResized, gray, Imgproc.COLOR_BGRA2GRAY);
// 高斯模糊
// Imgproc.GaussianBlur(gray, gray, new Size(3, 3), 0);
// 二值化
// Mat thresh = new Mat();
// threshold(gray, thresh, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
// Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
// 膨胀操作
// Mat hiMask = new Mat();
// Imgproc.dilate(thresh, hiMask, kernel);
for(int i = 0; i < imgRows; i++) {
for(int j = 0; j < imgCols; j++) {
background.put(200 + i,400 + j, img.get(i, j));
}
}
HighGui.imshow("结果", background);
HighGui.waitKey(0);
// 释放所有的窗体资源
HighGui.destroyAllWindows();
}
}
package com.biubiu.example;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class ReplaceImageBackgroundColor {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
String path = "D:\\upload\\plxjj.jpg";
Mat img = Imgcodecs.imread(path);
if(img.empty()) {
System.out.println("cannot open file");
return;
}
Mat origin = img.clone();
HighGui.imshow("img-origin", origin);
// 缩放
Mat resize = new Mat(img.height(), img.height(), img.type());
/**
* INTER_NEAREST - 最邻近插值
* INTER_LINEAR - 双线性插值,如果最后一个参数你不指定,默认使用这种方法
* INTER_AREA -区域插值 resampling using pixel area relation.
* It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to
* the INTER_NEAREST method.
* INTER_CUBIC - 4x4像素邻域内的双立方插值
* INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值
*/
Imgproc.resize(img, resize, img.size(), 0.5, 0.5);
// 转换为hsv图像
Mat hsv = new Mat();
Imgproc.cvtColor(img, hsv, Imgproc.COLOR_BGR2HSV);
Scalar lowerb = new Scalar(new double[] { 90, 70, 70 });
Scalar upperb = new Scalar(new double[] { 110, 255, 255 });
// 二值化
Mat mask = new Mat();
Core.inRange(hsv, lowerb, upperb, mask);
// 腐蚀膨胀
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
Mat erode = new Mat();
Imgproc.erode(mask, erode, kernel);
// 膨胀操作
Mat dilate = new Mat();
Imgproc.dilate(erode, dilate, kernel);
for(int i = 0; i < img.rows(); i++) {
for(int j = 0; j < img.cols(); j++) {
// 此处替换颜色,为BGR通道。
// double [] arr = dilate.get(i, j);
if(dilate.get(i, j)[0] == 255) {
img.put(i, j, new double[] {0, 0, 255});
}
}
}
HighGui.imshow("img", img);
HighGui.waitKey(0);
// 释放所有的窗体资源
HighGui.destroyAllWindows();
}
}
package com.biubiu.example;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.dnn.Dnn;
import org.opencv.dnn.Net;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
public class ImageAgeDetect {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
/**
* 年龄识别模型
*/
private final static String ageProto = "D:/workspace/opencv/data/models/age_deploy.prototxt";
private final static String ageModel = "D:/workspace/opencv/data/models/age_net.caffemodel";
/**
* 年龄预测返回的是8个年龄的阶段!
*/
private final static List<String> ageList = new ArrayList<>(Arrays.asList("(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)", "(38-43)", "(48-53)", "(60-100)"));
/**
* 模型均值
*/
private final static Scalar MODEL_MEAN_VALUES = new Scalar(78.4263377603, 87.7689143744, 114.895847746);
public static void main(String[] args) {
// 加载网络模型
Net ageNet = Dnn.readNetFromCaffe(ageProto, ageModel);
if (ageNet.empty()) {
System.out.println("无法打开网络模型...\n");
return;
}
// 加载图片矩阵
String filePath = "D:\\upload\\gather.png";
Mat img = Imgcodecs.imread(filePath);
// 人脸检测
MatOfRect faceRects = facePick(img);
// 定义一个颜色
Scalar color = new Scalar(0, 0, 255);
// 遍历检测到的图片
for(Rect rect : faceRects.toArray()) {
// 人脸画矩形框
drawRect(rect, img, color);
// 检测年龄
String gender = getAge(img, rect, ageNet);
// 图片上显示中文的年龄 ,因为原生的 opencv putText 显示中文会乱码, 所以需要特殊处理一下
img = putChineseTxt(img, gender, rect.x + rect.width / 2 - 5, rect.y - 10);
// Imgproc.putText(img, new String(gender.getBytes(StandardCharsets.UTF_8)), new Point(x, y), 2, 2, color);
}
// 显示图像
HighGui.imshow("预览", img);
HighGui.waitKey(0);
// 释放所有的窗体资源
HighGui.destroyAllWindows();
}
/**
* 在图片上的人脸区域画上矩形框
* @param rect
* @param img
* @param color
*/
private static void drawRect(Rect rect, Mat img, Scalar color) {
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
Imgproc.rectangle(img, new Point(x, y), new Point(x + h, y + w), color, 2);
}
/**
* 年龄检测
* @param img
* @param rect
* @param genderNet
* @return
*/
private static String getAge(Mat img, Rect rect, Net genderNet) {
Mat face = new Mat(img, rect);
// Resizing pictures to resolution of Caffe model
Imgproc.resize(face, face, new Size(140, 140));
// 灰度化
Imgproc.cvtColor(face, face, Imgproc.COLOR_RGBA2BGR);
// blob输入网络进行年龄的检测
Mat inputBlob = Dnn.blobFromImage(face, 1.0f, new Size(227, 227), MODEL_MEAN_VALUES, false, false);
genderNet.setInput(inputBlob, "data");
// 年龄检测进行前向传播
Mat probs = genderNet.forward("prob").reshape(1, 1);
Core.MinMaxLocResult mm = Core.minMaxLoc(probs);
// Result of gender recognition prediction.
double index = mm.maxLoc.x;
return ageList.get((int) index);
}
/**
* 图片人脸检测
* @return
*/
private static MatOfRect facePick(Mat img) {
// 存放灰度图
Mat tempImg = new Mat();
// 摄像头获取的是彩色图像,所以先灰度化下
Imgproc.cvtColor(img, tempImg, Imgproc.COLOR_BGRA2GRAY);
// OpenCV人脸识别分类器
CascadeClassifier classifier = new CascadeClassifier("D:\\workspace\\opencv\\data\\haarcascades\\haarcascade_frontalface_default.xml");
// # 调用识别人脸
MatOfRect faceRects = new MatOfRect();
// 特征检测点的最小尺寸, 根据实际照片尺寸来选择, 不然测量结果可能不准确。
Size minSize = new Size(140, 140);
// 图像缩放比例,可理解为相机的X倍镜
double scaleFactor = 1.2;
// 对特征检测点周边多少有效点同时检测,这样可避免因选取的特征检测点太小而导致遗漏
int minNeighbors = 3;
// 人脸检测
// CV_HAAR_DO_CANNY_PRUNING
classifier.detectMultiScale(tempImg, faceRects, scaleFactor, minNeighbors, 0, minSize);
return faceRects;
}
/**
* Mat二维矩阵转Image
* @param matrix
* @param fileExtension
* @return
*/
public static BufferedImage matToImg(Mat matrix, String fileExtension) {
// convert the matrix into a matrix of bytes appropriate for
// this file extension
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(fileExtension, matrix, mob);
// convert the "matrix of bytes" into a byte array
byte[] byteArray = mob.toArray();
BufferedImage bufImage = null;
try {
InputStream in = new ByteArrayInputStream(byteArray);
bufImage = ImageIO.read(in);
} catch (Exception e) {
e.printStackTrace();
}
return bufImage;
}
/**
* BufferedImage转换成 Mat
* @param original
* @param imgType
* @param matType
* @return
*/
public static Mat imgToMat(BufferedImage original, int imgType, int matType) {
if (original == null) {
throw new IllegalArgumentException("original == null");
}
if (original.getType() != imgType){
// Create a buffered image
BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), imgType);
// Draw the image onto the new buffer
Graphics2D g = image.createGraphics();
try {
g.setComposite(AlphaComposite.Src);
g.drawImage(original, 0, 0, null);
} finally {
g.dispose();
}
}
byte[] pixels = ((DataBufferByte) original.getRaster().getDataBuffer()).getData();
Mat mat = Mat.eye(original.getHeight(), original.getWidth(), matType);
mat.put(0, 0, pixels);
return mat;
}
/**
* 在图片上显示中文
* @param img
* @param gender
* @param x
* @param y
* @return
*/
private static Mat putChineseTxt(Mat img, String gender, int x, int y) {
Font font = new Font("微软雅黑", Font.PLAIN, 20);
BufferedImage bufImg = matToImg(img,".png");
Graphics2D g = bufImg.createGraphics();
g.drawImage(bufImg, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);
// 设置字体
g.setColor(new Color(255, 10, 52));
g.setFont(font);
// 设置水印的坐标
g.drawString(gender, x, y);
g.dispose();
// 加完水印再转换回来
return imgToMat(bufImg, BufferedImage.TYPE_3BYTE_BGR, CvType.CV_8UC3);
}
}
package com.biubiu.example;
import org.opencv.core.Point;
import org.opencv.core.*;
import org.opencv.dnn.Dnn;
import org.opencv.dnn.Net;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ImageGenderDetect {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
/**
* 性别识别模型
*/
private final static String genderProto = "D:/workspace/opencv/data/models/gender_deploy.prototxt";
private final static String genderModel = "D:/workspace/opencv/data/models/gender_net.caffemodel";
/**
* 性别预测返回的是一个二分类结果 Male, Female
*/
private final static List<String> genderList = new ArrayList<>(Arrays.asList("男", "女"));
/**
* 模型均值
*/
private final static Scalar MODEL_MEAN_VALUES = new Scalar(78.4263377603, 87.7689143744, 114.895847746);
public static void main(String[] args) {
// 加载网络模型
Net genderNet = Dnn.readNetFromCaffe(genderProto, genderModel);
if (genderNet.empty()) {
System.out.println("无法打开网络模型...\n");
return;
}
// 加载图片矩阵
String filePath = "D:\\upload\\gather.png";
Mat img = Imgcodecs.imread(filePath);
// 人脸检测
MatOfRect faceRects = facePick(img);
// 定义一个颜色
Scalar color = new Scalar(0, 0, 255);
// 遍历检测到的图片
for(Rect rect : faceRects.toArray()) {
// 人脸画矩形框
drawRect(rect, img, color);
// 检测性别
String gender = getGender(img, rect, genderNet);
// 图片上显示中文的性别 ,因为原生的 opencv putText 显示中文会乱码, 所以需要特殊处理一下
img = putChineseTxt(img, gender, rect.x + rect.width / 2 - 5, rect.y - 10);
// Imgproc.putText(img, new String(gender.getBytes(StandardCharsets.UTF_8)), new Point(x, y), 2, 2, color);
}
// 显示图像
HighGui.imshow("预览", img);
HighGui.waitKey(0);
// 释放所有的窗体资源
HighGui.destroyAllWindows();
}
/**
* 在图片上的人脸区域画上矩形框
* @param rect
* @param img
* @param color
*/
private static void drawRect(Rect rect, Mat img, Scalar color) {
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
Imgproc.rectangle(img, new Point(x, y), new Point(x + h, y + w), color, 2);
}
/**
* 性别检测
* @param img
* @param rect
* @param genderNet
* @return
*/
private static String getGender(Mat img, Rect rect, Net genderNet) {
Mat face = new Mat(img, rect);
// Resizing pictures to resolution of Caffe model
Imgproc.resize(face, face, new Size(140, 140));
// 灰度化
Imgproc.cvtColor(face, face, Imgproc.COLOR_RGBA2BGR);
// blob输入网络进行性别的检测
Mat inputBlob = Dnn.blobFromImage(face, 1.0f, new Size(227, 227), MODEL_MEAN_VALUES, false, false);
genderNet.setInput(inputBlob, "data");
// 性别检测进行前向传播
Mat probs = genderNet.forward("prob").reshape(1, 1);
Core.MinMaxLocResult mm = Core.minMaxLoc(probs);
// Result of gender recognition prediction. 1 = FEMALE, 0 = MALE
double index = mm.maxLoc.x;
return genderList.get((int) index);
}
/**
* 图片人脸检测
* @return
*/
private static MatOfRect facePick(Mat img) {
// 存放灰度图
Mat tempImg = new Mat();
// 摄像头获取的是彩色图像,所以先灰度化下
Imgproc.cvtColor(img, tempImg, Imgproc.COLOR_BGRA2GRAY);
// OpenCV人脸识别分类器
CascadeClassifier classifier = new CascadeClassifier("D:\\workspace\\opencv\\data\\haarcascades\\haarcascade_frontalface_default.xml");
// # 调用识别人脸
MatOfRect faceRects = new MatOfRect();
// 特征检测点的最小尺寸, 根据实际照片尺寸来选择, 不然测量结果可能不准确。
Size minSize = new Size(140, 140);
// 图像缩放比例,可理解为相机的X倍镜
double scaleFactor = 1.2;
// 对特征检测点周边多少有效点同时检测,这样可避免因选取的特征检测点太小而导致遗漏
int minNeighbors = 3;
// 人脸检测
// CV_HAAR_DO_CANNY_PRUNING
classifier.detectMultiScale(tempImg, faceRects, scaleFactor, minNeighbors, 0, minSize);
return faceRects;
}
/**
* Mat二维矩阵转Image
* @param matrix
* @param fileExtension
* @return
*/
public static BufferedImage matToImg(Mat matrix, String fileExtension) {
// convert the matrix into a matrix of bytes appropriate for
// this file extension
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(fileExtension, matrix, mob);
// convert the "matrix of bytes" into a byte array
byte[] byteArray = mob.toArray();
BufferedImage bufImage = null;
try {
InputStream in = new ByteArrayInputStream(byteArray);
bufImage = ImageIO.read(in);
} catch (Exception e) {
e.printStackTrace();
}
return bufImage;
}
/**
* BufferedImage转换成 Mat
* @param original
* @param imgType
* @param matType
* @return
*/
public static Mat imgToMat(BufferedImage original, int imgType, int matType) {
if (original == null) {
throw new IllegalArgumentException("original == null");
}
if (original.getType() != imgType){
// Create a buffered image
BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), imgType);
// Draw the image onto the new buffer
Graphics2D g = image.createGraphics();
try {
g.setComposite(AlphaComposite.Src);
g.drawImage(original, 0, 0, null);
} finally {
g.dispose();
}
}
byte[] pixels = ((DataBufferByte) original.getRaster().getDataBuffer()).getData();
Mat mat = Mat.eye(original.getHeight(), original.getWidth(), matType);
mat.put(0, 0, pixels);
return mat;
}
/**
* 在图片上显示中文
* @param img
* @param gender
* @param x
* @param y
* @return
*/
private static Mat putChineseTxt(Mat img, String gender, int x, int y) {
Font font = new Font("微软雅黑", Font.PLAIN, 20);
BufferedImage bufImg = matToImg(img,".png");
Graphics2D g = bufImg.createGraphics();
g.drawImage(bufImg, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);
// 设置字体
g.setColor(new Color(255, 10, 52));
g.setFont(font);
// 设置水印的坐标
g.drawString(gender, x, y);
g.dispose();
// 加完水印再转换回来
return imgToMat(bufImg, BufferedImage.TYPE_3BYTE_BGR, CvType.CV_8UC3);
}
}
功能预览
人脸识别OpenCV/JavaCV版本
人脸识别Dlib版本
年龄识别
性别识别
图片合成
老照片
素描
图片修复(水印去除)
图片分类
证件照更换背景色
色温调整
原图
+50色温
-50色温
对比度调整
+50对比度
饱和度调整
+50饱和度
+50饱和度
高光调整
+50高光
-50高光
美颜磨皮算法
暗通道去雾算法
中值滤波去雾算法
GitHub 加速计划 / opencv31 / opencv
77.36 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:2 个月前 )
898a2a38
ADE update to 0.1.2e 15 小时前
98308641 - 1 天前
更多推荐
已为社区贡献17条内容
所有评论(0)