Android opencv 动漫,电影图片人脸识别并另存,级联分类器

opencv的sdk版本3.4.7,模块名openCVLibrary347。

如果分析一个视频的每秒的图片,对于那么大量的图片,但是只想找到有人脸的图片,并保存在另一个文件夹,该怎么做。

这里,想到了用一个比较简便的方法,级联分类器去作为人脸对比,只要有xml文件就可以,比较方便。

这里的两个xml文件,放在main下方的新建的一个assets里面,这样打包成apk方便读取。

 assets读取路径的代码,用的是下面的代码,是将原来的改造了一下,改为一个Context context变量,去读取活动的上下文。

因为在安卓里面,面向的一个操作对象都是一个活动一个活动的,一些函数或者方法没有Context就用不了。

 private String copyAssetGetFilePath(String fileName,Context context) {
        try {
            File cacheDir = context.getCacheDir();
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
            File outFile = new File(cacheDir, fileName);
            if (!outFile.exists()) {
                boolean res = outFile.createNewFile();
                if (!res) {
                    return null;
                }
            } else {
                if (outFile.length() > 10) {//表示已经写入一次
                    return outFile.getPath();
                }
            }
            InputStream is = context.getAssets().open(fileName);
            FileOutputStream fos = new FileOutputStream(outFile);
            byte[] buffer = new byte[1024];
            int byteCount;
            while ((byteCount = is.read(buffer)) != -1) {
                fos.write(buffer, 0, byteCount);
            }
            fos.flush();
            is.close();
            fos.close();
            return outFile.getPath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

上面的级联列表看到了,是有两个的,分别对应的是动漫的人脸,还有一个是电影现实中的人脸。

所以对应的就有两个方法,分别对这两种人脸做对比的。

public  void comic_imgurl_detect(String[] imgurl,Context context,String dirpath){
        CascadeClassifier comic=get_comic_jilian( context);

        per_imgurl(imgurl, dirpath, comic);
    }

    public  void movie_imgurl_detect(String[] imgurl,Context context,String dirpath){
        CascadeClassifier comic=get_movie_jilian( context);

        per_imgurl(imgurl, dirpath, comic);
    }

参数String[] imgurl,是一个字符串的数组,里面是一个图片文件夹里面的所有图片的它们的路径,组成的一个字符串的数组。

参数Context context,活动的上下文,比如说你设置了一个button,并且设置了点击事件,context就是v.getContext(),就像下面这样。

public void onClick(View v) {
v.getContext()
}

参数String dirpath,源文件夹的路径,作用是用来拼接人脸图片所在文件夹及文件图片的。

        String dirpathaa = dirpath+"/人脸";
        File dirpathaa2 = new File(dirpathaa);

        if (!dirpathaa2.exists()) {
            dirpathaa2.mkdirs();
        }

比如另存为文件夹人脸,就要新建这个文件夹,方便保存之后识别出来的含人脸的图片。

获得一个级联分类器的方法如下。

    public CascadeClassifier get_movie_jilian(Context context){
        CascadeClassifier comic_face=new CascadeClassifier();
        String path1=copyAssetGetFilePath("lbpcascade_frontalface_improved.xml",context);
        comic_face.load(path1);
        return comic_face;
    }

上面是得到电影人脸的,如果是动漫人脸的话,就把xml文件名改为lbpcascade_animeface.xml就可以了。

之后还有一个另外的函数方法,就是,路径剪切出图片文件名,也是用来作为保存人脸图片路径用的。

    public static String id_to_picname(String descPath){

        String[] split = descPath.split("/");
        String fileName = split[split.length - 1];
        return fileName;
    }

就是截取最后一个,就是这个图片名。

判断一张图片,是否含人脸的函数如下。

    public boolean detect_face(CascadeClassifier jilian,Mat img1){

        MatOfRect faces=new MatOfRect();
        Mat mat11 = new Mat();
        Imgproc.cvtColor(img1, mat11, Imgproc.COLOR_RGB2GRAY);
        jilian.detectMultiScale(mat11,faces,1.1);
        List<Rect> facelist=faces.toList();
        if(facelist.size()>0){
            mat11.release();

            return true;
        }else {
            return false;
        }

    }

输入一个级联分类器和图片Mat作为参数,如果有人脸,那么facelist的长度是大于0的,然后返回true就可以了。

如果有人脸,想要保存,就用imwrite进行操作。

                String pic_name=id_to_picname(pathaa);
                String outfileimg=dirpathaa+"/"+pic_name;
                imwrite(outfileimg, img1);
                img1.release();

最后给出总的代码如下:

package com.example.agrdf.picturecompare;

import android.content.Context;

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

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import static org.opencv.imgcodecs.Imgcodecs.imwrite;

/**
 * Created by agrdf on 2022/12/14.
 */

public class jilian {

    public  void comic_imgurl_detect(String[] imgurl,Context context,String dirpath){
        CascadeClassifier comic=get_comic_jilian( context);

        per_imgurl(imgurl, dirpath, comic);
    }

    public  void movie_imgurl_detect(String[] imgurl,Context context,String dirpath){
        CascadeClassifier comic=get_movie_jilian( context);

        per_imgurl(imgurl, dirpath, comic);
    }

    public Mat cv_read(String res){
        Mat img = Imgcodecs.imread(res, Imgcodecs.IMREAD_UNCHANGED);
        return img;
    }

    public CascadeClassifier get_comic_jilian(Context context){
        CascadeClassifier comic_face=new CascadeClassifier();
        String path1=copyAssetGetFilePath("lbpcascade_animeface.xml",context);
        comic_face.load(path1);
        return comic_face;
    }

    public CascadeClassifier get_movie_jilian(Context context){
        CascadeClassifier comic_face=new CascadeClassifier();
        String path1=copyAssetGetFilePath("lbpcascade_frontalface_improved.xml",context);
        comic_face.load(path1);
        return comic_face;
    }


    public boolean detect_face(CascadeClassifier jilian,Mat img1){

        MatOfRect faces=new MatOfRect();
        Mat mat11 = new Mat();
        Imgproc.cvtColor(img1, mat11, Imgproc.COLOR_RGB2GRAY);
        jilian.detectMultiScale(mat11,faces,1.1);
        List<Rect> facelist=faces.toList();
        if(facelist.size()>0){
            mat11.release();

            return true;
        }else {
            return false;
        }

    }

    public void per_imgurl(String[] imgurl,String dirpath,CascadeClassifier comic){
        String dirpathaa = dirpath+"/人脸";
        File dirpathaa2 = new File(dirpathaa);

        if (!dirpathaa2.exists()) {
            dirpathaa2.mkdirs();
        }

        for (int b = 0; b < imgurl.length; b++) {
            String pathaa=imgurl[b];
            Mat img1=cv_read(pathaa);
            if(detect_face( comic, img1)){

                String pic_name=id_to_picname(pathaa);
                String outfileimg=dirpathaa+"/"+pic_name;
                imwrite(outfileimg, img1);
                img1.release();

            }

        }

    }



    private String copyAssetGetFilePath(String fileName,Context context) {
        try {
            File cacheDir = context.getCacheDir();
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
            File outFile = new File(cacheDir, fileName);
            if (!outFile.exists()) {
                boolean res = outFile.createNewFile();
                if (!res) {
                    return null;
                }
            } else {
                if (outFile.length() > 10) {//表示已经写入一次
                    return outFile.getPath();
                }
            }
            InputStream is = context.getAssets().open(fileName);
            FileOutputStream fos = new FileOutputStream(outFile);
            byte[] buffer = new byte[1024];
            int byteCount;
            while ((byteCount = is.read(buffer)) != -1) {
                fos.write(buffer, 0, byteCount);
            }
            fos.flush();
            is.close();
            fos.close();
            return outFile.getPath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String id_to_picname(String descPath){


        String[] split = descPath.split("/");
        String fileName = split[split.length - 1];

        return fileName;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值