毕业设计——基于JAVA+OpenCV的人脸识别项目

完整项目,私信博主获取

功能

  1. 人脸检测、识别(图片、视频)
  2. 更换背景图(例如给任务换一张海景背景图)
  3. 图片合成(多张照片合成)
  4. 证件照更换背景色
  5. 年龄识别
  6. 性别识别
  7. 图片修复(可用于水印去除)
  8. 图片分类
  9. 老照片
  10. 素描
  11. 图像色温调整
  12. 图像对比度调整
  13. 图像高光调整
  14. 图像明度调整
  15. 图像饱和度调整
  16. 图像阴影调整
  17. 天空滤镜
  18. 人脸检测、识别(Dlib版本)
  19. 暗通道去雾算法
  20. 中值滤波去雾算法
  21. 人脸美颜磨皮算法

开发环境

  • 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高光
在这里插入图片描述


美颜磨皮算法

在这里插入图片描述


暗通道去雾算法

在这里插入图片描述


中值滤波去雾算法

在这里插入图片描述


  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕业小助手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值