opencv_004_opencv人脸剪切

人脸切剪

对人脸进行一个截切

package cn.guoke.demo02;

import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.io.File;
import java.io.IOException;

public class Test_02 {
 
    private static final String OPENCV_DLL_PATH = "D:\\java\\opencv\\opencv\\build\\java\\x64\\opencv_java3412.dll";

    private static final String OPENCV_XML_PATH = "D:\\java\\opencv\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml";

    public static void main(String[] args) throws IOException {
        String[] strings = detectFaceImage("D:/b8d93909da582e6b47baa0de28e12337.jpg", "D:");
        for (String string : strings) {
            System.out.println(string);
        }

    }

    /**
     * @param imageFilePath 待处理图片路径
     * @param destDir       提前人脸后居中裁剪后的图片存储目录
     * @return 居中裁剪的图片路径
     */
    private static String[] detectFaceImage(String imageFilePath, String destDir) {

        File dir = new File(destDir);


//      1.引入opencv 库 Window引入dll 绝对路径
        System.load(OPENCV_DLL_PATH);
        // 2.引入训练好的XML格式的分类器文件
        CascadeClassifier faceDetector = new CascadeClassifier(OPENCV_XML_PATH);
        if (faceDetector.empty()) {
            return null;
        }
        // 3.读取待处理的图片
        File imgFile = new File(imageFilePath);
        Mat image = Imgcodecs.imread(imgFile.getPath());
        int srcWidth = image.width();
        int srcHeight = image.height();
        // 4.进行人脸检测
        MatOfRect faceDetections = new MatOfRect();
        faceDetector.detectMultiScale(image, faceDetections);
        Rect[] rectFace = faceDetections.toArray();


        String[] targetFiles = new String[rectFace.length];
        // 5.裁剪检测到的人脸图片
        for (int i = 0; i < rectFace.length; i++) {
            Rect rect = rectFace[i];
            // 计算居中裁剪框
            Rect centerCropBox = estimateCenterCropBox(srcWidth, srcHeight, rect);
            // 裁剪框
            targetFiles[i] = destDir + File.separator + i + getImageType(imgFile);
            // 裁剪
            cutCenterImage(imgFile.getPath(), targetFiles[i], centerCropBox);
        }
        return targetFiles;
    }


    /**
     * @param imageFilePath 待处理图片路径
     * @param destDir       提前人脸后居中裁剪后的图片存储目录
     * @return 居中裁剪的图片路径
     */
    private static String[] detectEysImage(String imageFilePath, String destDir) {

        File dir = new File(destDir);


//      1.引入opencv 库 Window引入dll 绝对路径
        System.load(OPENCV_DLL_PATH);
        // 2.引入训练好的XML格式的分类器文件
        CascadeClassifier faceDetector = new CascadeClassifier(OPENCV_XML_PATH);
        if (faceDetector.empty()) {
            return null;
        }
        // 3.读取待处理的图片
        File imgFile = new File(imageFilePath);
        Mat image = Imgcodecs.imread(imgFile.getPath());
        int srcWidth = image.width();
        int srcHeight = image.height();
        // 4.进行人脸检测
        MatOfRect faceDetections = new MatOfRect();
        faceDetector.detectMultiScale(image, faceDetections);
        Rect[] rectFace = faceDetections.toArray();


        String[] targetFiles = new String[rectFace.length];
        // 5.裁剪检测到的人脸图片
        for (int i = 0; i < rectFace.length; i++) {
            Rect rect = rectFace[i];
            // 计算居中裁剪框
            Rect centerCropBox = estimateCenterCropBox(srcWidth, srcHeight, rect);
            // 裁剪框
            targetFiles[i] = destDir + File.separator + i + getImageType(imgFile);
            // 裁剪
            cutCenterImage(imgFile.getPath(), targetFiles[i], centerCropBox);
        }
        return targetFiles;
    }


    /**
     * 获取文件后缀不带.
     *
     * @param file 文件后缀名
     * @return
     */
    private static String getImageType(File file) {
        if (file != null && file.exists() && file.isFile()) {
            String fileName = file.getName();
            int index = fileName.lastIndexOf(".");
            if (index != -1 && index < fileName.length() - 1) {
                return fileName.substring(index);
            }
        }
        return null;
    }

    /**
     * 计算居中裁剪框
     * 在原图边界范围内,以检测的人脸框为中心,向四周等比例放大,最大的裁剪框可保证人脸居中
     *
     * @param srcWidth  原始图像宽度
     * @param srcHeight 原始图像高度
     * @param rect      人脸框位置
     * @return 居中裁剪框
     */
    public static Rect estimateCenterCropBox(int srcWidth, int srcHeight, Rect rect) {

        int w0 = rect.x;
        int w1 = srcWidth - rect.x - rect.width;
        int w2 = (srcHeight - rect.y - rect.height) * rect.width / rect.height;
        int w3 = rect.width * rect.y / rect.height;

        if (w0 < 0 || w1 < 0 || w2 < 0 || w3 < 0) {
            return null;
        }
        int ret = w0;
        if (ret > w1) {
            ret = w1;
        }
        if (ret > w2) {
            ret = w2;
        }
        if (ret > w3) {
            ret = w3;
        }

        return new Rect(rect.x - ret, rect.y - ret * rect.height / rect.width,
                rect.width + 2 * ret, rect.height + 2 * ret * rect.height / rect.width);
    }

    /**
     * @param oriImg  原始图像
     * @param outFile 裁剪的图像输出路径
     * @param rect    剪辑矩形区域
     */
    private static void cutCenterImage(String oriImg, String outFile, Rect rect) {
        System.out.println("cutCenterImage ...");
        // 原始图像
        Mat image = Imgcodecs.imread(oriImg);
        // Mat sub = new Mat(image,rect);
        Mat sub = image.submat(rect);
        Mat mat = new Mat();
        Size size = new Size(rect.width, rect.height);
        // 将人脸进行截图
        Imgproc.resize(sub, mat, size);
        // 截图保存到outFile
        Imgcodecs.imwrite(outFile, mat);
    }

}

截切前 :

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1hQRMGlE-1611189564938)(img\b8d93909da582e6b47baa0de28e12337.jpg)]

剪切后:

脸进行截图
Imgproc.resize(sub, mat, size);
// 截图保存到outFile
Imgcodecs.imwrite(outFile, mat);
}

}

``

截切前 :

这里图片上传不了 bug

剪切后:

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值