「·opencv·」运用传统图像处理的人脸检测

本文采用灰度图—> 二值化 —> 去除孔洞 —> 得到轮廓 —> 轮廓标记—> 批量处理 的方法检测简单证件照人脸。

初学opencv,做个笔记。借鉴以下代码段:(侵删)
https://blog.csdn.net/chenxjhit/article/details/80549194
https://www.cnblogs.com/meadow-glog/p/4709928.html
https://blog.csdn.net/qq_30241709/article/details/78759726

先贴出效果图
在这里插入图片描述
在这里插入图片描述

完整代码

#include<opencv2/opencv.hpp>
#include<string>
#include <iostream>

using namespace cv;
using namespace std;

void fillHole(const Mat srcBw,Mat &dstBw); //孔洞填充函数

int main()
{
        cv::String path = "/home/voluntino/Documents/face/pic/";//待处理图片文件夹地址
        cv::String dest = "/home/voluntino/Documents/face/pic_after/";//处理后图片的保存地址
        cv::String savedfilename;
        std::vector<cv::String> filenames;
        cv::Mat img0,img;
        cv::Mat bw,imgGray,dstbw;
        cv::glob(path, filenames);  //opencv用来读取指定路径下文件名
        for (int i = 0; i < filenames.size(); i++)    //遍历文件夹中的图片
        {
        	img0 = cv::imread(filenames[i]);
        	resize(img0, img, Size(1000,1000)); //指定图片尺寸,方便确定轮廓线长度最大最小值
        	cv::cvtColor(img,imgGray,CV_BGR2GRAY);
        	cv::threshold(imgGray,bw,120,255,CV_THRESH_BINARY);
        	fillHole(bw,dstbw);  //孔洞填充函数
        	vector <vector<Point>>contours;
    		findContours(dstbw, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //获取连通区域
        
    		//在白色图像上绘制黑色轮廓  
    		Mat lunkuo(dstbw.size(), CV_8U, Scalar(255));
    		drawContours(lunkuo, contours, -1, Scalar(0), 2); //轮廓线的黑色,宽度为2   
   			//imshow("contours", lunkuo);   

    		//移除过长或过短的轮廓  
    		int cmin = 1000; //最小轮廓长度  
    		int cmax = 4000;    //最大轮廓长度 
    		vector<vector<Point>>::const_iterator itc = contours.begin();
    		while (itc!=contours.end())
   		 	{
        	if (itc->size() < cmin || itc->size() > cmax)
            	itc = contours.erase(itc);
        	else
            	++itc;
   		 	}

    		//绘制移除后的轮廓  
    		Mat lunkuo_erase(dstbw.size(), CV_8U, Scalar(255));
    		drawContours(lunkuo_erase, contours,-1,Scalar(0), 2);   
    		//imshow("contours", lunkuo_erase);

			//标记轮廓
        	cv::Rect rect = cv::boundingRect(contours[0]); //包围轮廓的最小正矩形
        	cv::rectangle(lunkuo_erase, rect, cv::Scalar(0), 2); //在轮廓图中画矩形
        	cv::rectangle(img,rect,cv::Scalar(0,255,0),2); //在原图中画出绿色矩形
        	//imshow("result",img);
        	//cv::imshow("detected rectangle", lunkuo_erase);
        
        	savedfilename = dest + filenames[i].substr(35);  //对处理后图片批量命名,注意substr()的使用
        	std::cout << "处理:" << savedfilename << std::endl;
        	cv::imwrite(savedfilename, img);  //保存图片
    }
        while(1){
                if(cv::waitKey(20) == 'q'){
                        break;
               		 }
        		}
         return 0;
}

void fillHole(const Mat srcBw, Mat &dstBw)
{
    Size m_Size = srcBw.size();
    Mat Temp=Mat::zeros(m_Size.height+2,m_Size.width+2,srcBw.type());//延展图像
    srcBw.copyTo(Temp(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)));
    cv::floodFill(Temp, Point(0, 0), Scalar(255));
    Mat cutImg;//裁剪延展的图像
    Temp(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)).copyTo(cutImg);
    dstBw = srcBw | (~cutImg);
}

心得:未使用分类器,仅简单使用图片处理方式,可识别单人的证件照,且证件照应身着深色衣服。
学习使用了opencv的一些图像处理函数,重点学习了批量处理的方法,为以后的机器视觉有一定铺垫。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值