python3 opencv3 实现基本的人脸检测、识别功能
一言不和,先上码子(纯新手,莫嘲笑)
1 # encoding: utf-8 2 #老杨的猫,环境:PYCHARM,python3.6,opencv3 3 4 import cv2,os 5 import cv2.face as fc #此处有坑,找不到脸,这样引用程序可以运行,欢迎大牛指点,CV2和CV3的结构区别没有搞清楚,应该怎么样引用才是正确的 6 import numpy as np 7 from PIL import Image, ImageDraw, ImageFont #pip install pillow 8 9 #由于cv2.putText()不支持汉字,把图像里加入需要显示的文字,可以为汉字 10 def cvtopil(img,posion,txt):#图像数组,文字位置,文字内容 11 pil_im = Image.fromarray(img) 12 draw = ImageDraw.Draw(pil_im) 13 font = ImageFont.truetype("simhei.ttf", 50, encoding="utf-8") # 第一个参数为字体文件路径,第二个为字体大小 14 draw.text(posion, txt, (0, 0, 255), font=font) # 第一个参数为打印的坐标,第二个为打印的文本,第三个为字体颜色,第四个为字体 15 image=cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR) #把图像数组由RGB转为CV2处理的BGR格式 16 return image #返回处理后图像文件 17 #脸部图像采集模块。采集脸部图像,转为200*200的大小后,存到每个人对应的文件夹下 18 def dectface(): 19 #OPENCV3 自带的脸部检测XML文件 20 #D:\Downloads...../haarcascade_frontalface_default.xml 文件所在路径为我的电脑里文件路径,检测脸部,可酌情修改 21 face_cas=cv2.CascadeClassifier('D:\Downloads\opencv-3.3.1-vc14\opencv\sources\data\haarcascades/haarcascade_frontalface_default.xml') 22 #检测眼睛,这里用不到 23 eye_cas=cv2.CascadeClassifier('D:\Downloads\opencv-3.3.1-vc14\opencv\sources\data\haarcascades/haarcascade_eye.xml') 24 cap=cv2.VideoCapture(0)#打开默认摄像头 25 count=0 #初始化计数器,用来生成文件名,如0.pgm,1.pgm,3.pgm..... 26 27 ''' 28 C:\Users\Administrator\.PyCharm2017.2\system\python_stubs\-1184660488\cv2\CascadeClassifier.py 29 连续读取摄像头图像,检测到脸部图像,把脸部图像以PGM的灰度格式格式保存在当前程序路径里的 jm1,jm2...文件夹下 30 采集要求:1光线适中,2脸部正直,3脸部图像大小以刚刚露出头发和下颌最佳,控制距离,太远采集图像精确度差,太近 31 没脸,4有效采集时间5秒左右就够用了,太多影响运行速度。 32 ''' 33 while True: 34 ret,frame=cap.read()#读取图像,RET为判断是否采集到图像,FRAME为采集到的一帧图像 35 #此处最好判断是否采集到图像 if ret:do else:err 偷懒了 36 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #转为灰度图像,用来判断脸部用 37 # 找脸,参数:图像文件,压缩率(越小检测迭代次数越多,越慢,越详细,此处图像大,1.3-1.5均可),矩形个数最小值,flags不知道,最小检测窗口大小,最大检测窗口大小。返回一个脸部区域,左上角为(0,0)坐标系,起始x,y点,w宽,h高 38 faces = face_cas.detectMultiScale(gray, 1.3, 5) 39 #用方框勾画出脸部位置 40 for (x, y, w, h) in faces: 41 img=cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2) #画矩形,位置,大小,颜色,通道 42 #cv2.putText(img,'abc',(x,y-20),cv2.FONT_HERSHEY_SIMPLEX,1,255,2) 不能显示汉字 43 frame=cvtopil(img,(x,y-20),"老杨")#测试汉字用,可采集出图像是灰的,待解决 44 f=cv2.resize(gray[y:y+h,x:x+w],(200,200)) #从灰度图中,扣出脸部,设置固定大小像素 45 #保存到jm1里 46 cv2.imwrite('F:\pytest\cvtest\detectface\jm1\ %s.pgm'%str(count),f) 47 count+=1 48 #眼睛检测 49 # eyes=eye_cas.detectMultiScale(f,1.03,5,0,(40,40)) 50 # for (ex,ey,ew,eh) in eyes: 51 # cv2.rectangle(img,(ex,ey),(ex+ew,ey+eh),(0,0,255),2) 52 cv2.imshow("demo",frame) #显示图像 53 # cv2.waitKey(0) 54 if cv2.waitKey(1) & 0xFF == ord('q'): 55 break 56 # camera.release() 57 # cv2.destroyAllWindows() 58 59 60 #读取样本文件,并加载到一个列表里,返回值包括2部分,[文件列表,对应标签],标签用来对照姓名用。 61 def read_img(path,sz=None): 62 pr_img=[] #图像列表 63 pr_flg=[] #对应标签 64 pr_count=0 #初始化检测到的人数 65 for dirname,dirnames,filenames in os.walk(path):#遍历当前程序目录我的图像文件保存在f:盘下 66 #print(os.walk(path)) 67 #print(dirname,dirnames,filenames) 68 for subdirname in dirnames: #遍历程序文件夹下的各个目录 69 subject_path=os.path.join(dirname,subdirname) 70 print(subject_path) 71 for filename in os.listdir(subject_path): #遍历文件夹下文件 72 print(filename) 73 try: 74 filepath=os.path.join(subject_path,filename) 75 im=cv2.imread(filepath,cv2.IMREAD_GRAYSCALE) #读取JM文件下PGM文件 76 print(filepath) 77 #print(im.shape) 78 if im.shape!=(200,200): #判断像素是否200 79 im=cv2.resize(im,(200,200)) 80 pr_img.append(np.asarray(im,dtype=np.uint8)) #添加图像 81 pr_flg.append(pr_count)#添加标签 82 except: 83 print("io error") 84 pr_count+=1 #另一个人的标签 85 return [pr_img,pr_flg] 86 87 #学习样本,比对样本和实例,根据对应算法返回标签和系数,依据标签对照姓名,系数值提现了准确度。 88 def face_rec(): 89 names=['BAO BAO ','BA BA BA ','Bei Bei','MMMMMMM'] #标签对应的名字0,baobao,1,bbb,2,beibei.... 90 [x,y]=read_img("f:") #调读取函数,返回图像、和标签列表 91 y=np.asarray(y,dtype=np.int32) #转为NUMPY的ARRAY 92 93 #CV自带的三种算法,现用LBPH算法。此处有坑,坑的我差点放弃,原来叫createLBPHFaceRecognizer,为什么我下载的这模样 94 #model=fc.EigenFaceRecognizer_create() 95 #model = fc.FisherFaceRecognizer_create() 96 model = fc.LBPHFaceRecognizer_create() 97 98 # 训练,此处应把训练结果保存,再用到时直接读取结果,效率更高,xml?json?pickle? 99 model.train(np.asarray(x),np.asarray(y)) 100 101 #下面读取摄像头图像,用矩形标识检测到脸部和训练后结果比对,打印出对应标签所对应名字 102 camera=cv2.VideoCapture(0) 103 face_cascade=cv2.CascadeClassifier('D:\Downloads\opencv-3.3.1-vc14\opencv\sources\data\haarcascades/haarcascade_frontalface_default.xml') 104 while True: 105 read,img=camera.read() 106 faces=face_cascade.detectMultiScale(img,1.3,5) 107 for (x,y,w,h) in faces: 108 img=cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) 109 gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 110 roi=gray[x:x+w,y:y+h] 111 try: 112 roi=cv2.resize(roi,(200,200),interpolation=cv2.INTER_LINEAR) 113 114 params=model.predict(roi) #predict()函数做比对,返回一个元祖格式值 (标签,系数)。系数和算法有关, 115 # 前2种算法值低于5000不可靠,LBPH低于50可靠,80-90不可靠,高于90纯蒙 116 #此处有文章可做,通过单位时间内检测到的系数平均值,可以得到更准确结果 117 print(params) 118 #打印标签对应名字,如cvtopil的灰度问题解决,可cvtopil函数替换 119 cv2.putText(img,names[params[0]],(x,y-20),cv2.FONT_HERSHEY_SIMPLEX,1,255,2) 120 except: 121 continue 122 cv2.imshow("abc",img) 123 if cv2.waitKey(1) & 0xFF == ord('q'): 124 break 125 cv2.destroyAllWindows() 126 if __name__=='__main__': 127 ''' 128 1.先用dectface()采集样本,注释掉face_rec(),将采集样本保存到jm文件夹里,现在每次采集不同人样本,需要手动建立JM1,JM2.....以后应完善程序流程为,首先判断是否有此人样本,如没有自动建立文件夹并保存该人的样本。 129 2.采集完成后,注释dectface(),用face_rec()通过比对得到是谁的结果。 130 3.names=['BAO BAO ','BBBBBBB','Bei Bei','MMMMMMM'] 名字和对应标签应该存成文件,对应读取 131 3.真心不会用类啊。。。咋用类实现整个流程呢?? 132 4.从学PYTHON到现在也不过一个月时间,基础很不牢,cv2,CV3从引用到使用的区别搞不清楚呢,恳求大牛各种批评指导啊!! 133 ''' 134 #dectface() 135 face_rec()