人脸裁剪

故事扮演 提交于 2019-12-01 23:41:53

java调用opencv进行人脸裁剪,发现上传8m左右的人脸图片,每进行一次人脸图片裁剪大约消耗5-6g的内存,导致程序很容易崩溃。以下是优化后的代码。 并且在启动的时候指定内存

 nohup java -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -Xms8192m -Xmx8192m -Xmn3072m -jar /dit/management-client.jar > /dit/management.log &


 

package com.ahies.dit.management.service;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.log.LogFactory;
import com.ahies.dit.management.model.File;
import com.google.common.collect.Maps;
import lombok.NonNull;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.awt.*;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * 上传服务.
 *
 * @author chengyuebin
 */
@Service
public class UploadService {

    {
// 加载opencv库
        System.load("/home/opencv/share/java/opencv4/libopencv_java410.so");
    }
    private static final Logger logger = LoggerFactory.getLogger(UploadService.class);

    @Value("${upload.folder.files}")
    private String uploadFolder;

    @Value("${file.visit.prefix}")
    private String fileVisitPrefix;

    @Value("classpath:haarcascade_frontalface_alt.xml")
    private Resource xml;

    @Value("${opencv.libpath}")
    private String opencvLibpath;

    @Autowired
    private FileService fileService;

    private static final ThreadLocal<DateFormat> YYYYMMDDHHMMSS_DATE_FORMATTER = new ThreadLocal<DateFormat>() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    @PostConstruct
    private void init() {
        // 初始化文件上传服务(如果不存在).
        java.io.File uploadDir = new java.io.File(uploadFolder);
        logger.debug("Upload dir {} exists: {}", uploadFolder, uploadDir.exists());
        logger.info("Upload dir {} created: {}", uploadFolder, uploadDir.mkdirs());
    }

    /**
     * multipartFile文件对象上传.
     *
     * @param multipartFile 文件对象.
     * @return uuid
     * @throws Exception
     * @author chengyuebin
     */
    public String uploadFile(final MultipartFile multipartFile)
            throws Exception {
        Map<String, String> map = this.saveOneFile(multipartFile);
        return map.get("id");
    }

    /**
     * multipartFile文件对象上传.
     *
     * @param multipartFile 文件对象.
     * @return uuid
     * @throws Exception
     * @author chengyuebin
     */
    public Map<String, String> uploadFileReturnIdAndNameAndPath(final MultipartFile multipartFile)
            throws Exception {
        return this.saveOneFile(multipartFile);
    }

    /**
     * 保存单个文件.
     *
     * @return
     * @throws Exception
     */
    private Map<String, String> saveOneFile(final MultipartFile multipartFile) throws Exception {
        Map<String, String> map = Maps.newHashMapWithExpectedSize(3);

        String originalFilename = multipartFile.getOriginalFilename();

        logger.info("处理上传文件: {}", originalFilename);

        String uuid = UUID.randomUUID().toString().replace("-", "");

//        String newFilename = this.generateNewFilename(uuid, originalFilename);
        String resourceLocation = uploadFolder + originalFilename;
        String contentType = multipartFile.getContentType();
        Long fileSize = multipartFile.getSize();

        logger.info("路径:{}", resourceLocation);
        logger.info("contentType:{}", contentType);

        java.io.File newFile = new java.io.File(resourceLocation);
        multipartFile.transferTo(newFile);
//        InputStream inputStream = new FileInputStream(file);
//        IOUtils.copy(file, new FileOutputStream(newFile));

        logger.info("存储文件完成");

        File media = File.builder()
                .id(uuid)
                .originalFileName(originalFilename)
                .resourceLocation(resourceLocation)
                .contentType(contentType)
                .size(fileSize)
//                .createUser(createUserId)
                .createTime(YYYYMMDDHHMMSS_DATE_FORMATTER.get().format(new Date()))
                .build();
        this.fileService.save(media);

        logger.info("UUID:{}", uuid);

        map.put("id", uuid);
        map.put("name", originalFilename);
        map.put("path", fileVisitPrefix + originalFilename);

        return map;
    }


    public Map<String, String> uploadFace(final MultipartFile multipartFile) throws IOException {
        return this.saveFaceFile(multipartFile);
    }

//    private Map<String, String> saveFaceFile(final MultipartFile multipartFile) throws IOException  {
//        MatOfRect faceDetections = new MatOfRect();
//        Mat image = null;
//        try {
//            // opencv 人脸裁剪
////        String opencvDllName = "/opencvdemo/libopencv_java410.so";
////        opencvDllName = "D:\\opencv\\opencv\\build\\java\\x64\\opencv_java410.dll";
//            System.load(opencvLibpath);
//            System.out.println("人脸检测开始……");
//            // 创建临时文件,因为boot打包后无法读取文件内的内容
//            java.io.File targetXmlFile = new java.io.File(uploadFolder + xml.getFilename());
//            if(!targetXmlFile.exists()){
//                FileUtils.copyInputStreamToFile(xml.getInputStream(), targetXmlFile);
//            }
//
//            CascadeClassifier faceDetector = new CascadeClassifier(targetXmlFile.toString());
//
//            // 创建图片tempFile
//            java.io.File tempFile = new java.io.File(uploadFolder + multipartFile.getOriginalFilename());
//            FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), tempFile);
//
//            // 读取创建的图片tempFile
//            image = Imgcodecs.imread(tempFile.toString());
//            // 进行人脸检测
//            faceDetector.detectMultiScale(image, faceDetections);
//            System.out.println(String.format("检测到人脸: %s", faceDetections.toArray().length));
//            if(faceDetections.toArray().length < 1){
//                return null;
//            }
//
//            Integer i = 1;
//            String cutImagePath = null;
//            // 制图将图填充到image中
//            for (Rect rect : faceDetections.toArray()) {
//                Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
//                        new Scalar(0, 255, 0), 3);
//                cutImagePath =   imageCut(tempFile.toString(), multipartFile.getOriginalFilename()+i+".jpg", rect.x, rect.y, rect.width, rect.height);// 进行图片裁剪
//                i++;
//            }
//
//
//            if (tempFile.exists() && tempFile.isFile()) {
//                if (tempFile.delete()) {
//                    System.out.println("删除临时文件" + tempFile + "成功!");
//                }
//            }
//
//
//            Map<String, String> map = Maps.newHashMapWithExpectedSize(3);
//
//            String originalFilename = cutImagePath;
//
//            logger.info("处理上传文件: {}", originalFilename);
//
//            String uuid = UUID.randomUUID().toString().replace("-", "");
//
//            String contentType = multipartFile.getContentType();
//            Long fileSize = new java.io.File(uploadFolder+cutImagePath).length();
//
//            logger.info("路径:{}", uploadFolder+cutImagePath);
//            logger.info("contentType:{}", contentType);
//
//
//            logger.info("存储文件完成");
//
//            File media = File.builder()
//                    .id(uuid)
//                    .originalFileName(originalFilename)
//                    .resourceLocation(uploadFolder+cutImagePath)
//                    .contentType(contentType)
//                    .size(fileSize)
//                    .createTime(YYYYMMDDHHMMSS_DATE_FORMATTER.get().format(new Date()))
//                    .build();
//            this.fileService.save(media);
//
//            logger.info("UUID:{}", uuid);
//
//            map.put("id", uuid);
//            map.put("name", originalFilename);
//            map.put("path", fileVisitPrefix + originalFilename);
//
//
//            return map;
//        }catch (Exception e){
//            e.printStackTrace();
//            throw new IOException(e.getMessage());
//        }finally {
//            faceDetections.release();
//            image.release();
//        }
//
//    }

    private Map<String, String> saveFaceFile(final MultipartFile multipartFile) throws IOException {
        LogFactory.get().info("<<<<<<<<<<人脸检测开始>>>>>>>>>>");
        // 创建临时文件,因为boot打包后无法读取文件内的内容
        //读取人脸检测的haarcascade_frontalface_alt.xml 配置文件
        java.io.File targetXmlFile = new java.io.File(uploadFolder + xml.getFilename());
        if(!targetXmlFile.exists()){
            FileUtils.copyInputStreamToFile(xml.getInputStream(), targetXmlFile);
        }

        CascadeClassifier faceDetector = new CascadeClassifier(targetXmlFile.toString());

        // 创建上传的人脸图片 tempFile 
        java.io.File tempFile = new java.io.File(uploadFolder + multipartFile.getOriginalFilename());
        FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), tempFile);

        // 读取创建的图片tempFile
        Mat image = Imgcodecs.imread(tempFile.toString());
        MatOfRect faceDetections = new MatOfRect();
        // 进行人脸检测
        faceDetector.detectMultiScale(image, faceDetections);
        Integer i = 1;
        String cutImagePath = null;
        int x;
        int y;
        int width;
        int height;
        // 制图将图填充到image中
        if(faceDetections.toArray().length <=0 ){
            LogFactory.get().info("没有检测到人脸");
            return null;
        }else if(faceDetections.toArray().length > 1){
            LogFactory.get().info("检测到多张人脸");
            return null;
        }else{
            Rect rect = faceDetections.toArray()[0];
            x = rect.x;
            y = rect.y;
            width = rect.width;
            height = rect.height;
            //释放内存资源 
            image.release();
            faceDetections.release();
          
            image = null;
            faceDetections = null;
        }

        String originalFilename = "cut" +  multipartFile.getOriginalFilename();
        java.io.File outFile =new java.io.File( uploadFolder + multipartFile.getOriginalFilename());

        //图片裁剪
        ImgUtil.cut(tempFile,outFile,new Rectangle(x,y,width,height));

        //把裁剪后图片缩放至50kb左右
        try {
            Thumbnails.of(uploadFolder + multipartFile.getOriginalFilename())
                    .size(300, 300)
                    .outputQuality(1f)
                    .toFile(uploadFolder+ originalFilename);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        Map<String, String> map = Maps.newHashMapWithExpectedSize(3);

        String uuid = UUID.randomUUID().toString().replace("-", "");

        File media = File.builder()
                .id(uuid)
                .originalFileName(originalFilename)
                .resourceLocation(uploadFolder+ originalFilename)
                .contentType( multipartFile.getContentType())
                .size(new java.io.File(uploadFolder+cutImagePath).length())
                .createTime(YYYYMMDDHHMMSS_DATE_FORMATTER.get().format(new Date()))
                .build();
         //保存到数据库
        this.fileService.save(media);

      //调用gc  垃圾回收
        System.gc();

        map.put("id", uuid);
        map.put("name", originalFilename);
        map.put("path", fileVisitPrefix + originalFilename);
        return map;
    }
}

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!