前言
前些天看到朋友分享的猫咪情绪识别软件
的消息,可能小伙伴们也都跃跃欲试,想要做一个合格的铲屎官
了。但是想要想识别猫的情绪表情,首先从猫脸检测开始吧!
在本项目中,我们将使用 OpenCV
和 Flask
构建检测猫脸的深度学习 Web
应用程序。
猫脸检测
在开始讲解之前,让我们首先快速浏览下项目结构:
cat_detection|——server|├─cat_detection.py|└─image_processing.py└─client├─request_and_draw_rectangle.py└─test_example.png
使用级联检测器检测猫脸
为了更好的进行代码分离,检测程序在 image_processing.py
脚本中执行,其中编码了 ImageProcessing()
类。我们在 ImageProcessing
类中实现 cat_face_detection()
方法,利用 OpenCV
中的 detectMultiScale()
函数执行猫脸检测。
#image_processing.pyclassImageProcessing(object):def__init__(self):#在构造函数中实例化猫脸检测器self.file_cascade=os.path.join(os.path.join(os.path.dirname(__file__),'data'),"haarcascade_frontalcatface_extended.xml")self.cat_cascade=cv2.CascadeClassifier(self.file_cascade)defcat_face_detection(self,image):image_array=np.asarray(bytearray(image),dtype=np.uint8)img_opencv=cv2.imdecode(image_array,-1)output=[]gray=cv2.cvtColor(img_opencv,cv2.COLOR_BGR2GRAY)cats=self.cat_cascade.detectMultiScale(gray,scaleFactor=1.1,minNeighbors=5,minSize=(25,25))forcatincats:#返回检测到的猫脸检测框坐标x,y,w,h=cat.tolist()face={'box':[x,y,x+w,y+h]}output.append(face)returnoutput
使用深度学习模型检测图片中的猫
ImageProcessing
类的 cat_detection()
方法使用预训练的 MobileNet SSD
对象检测执行猫检测,它可以检测 20 个类。在本项目中,我们的目标是检测猫,如果 class_id
是一只猫,我们会将检测结果添加到 output
中:
#在image_processing.py中添加cat_detection()方法classImageProcessing(object):def__init__(self):#在构造函数中实例化猫脸检测器self.file_cascade=os.path.join(os.path.join(os.path.dirname(__file__),'data'),"haarcascade_frontalcatface_extended.xml")self.cat_cascade=cv2.CascadeClassifier(self.file_cascade)#在构造函数中实例化SSD深度学习模型用于检测猫self.file_prototxt=os.path.join(os.path.join(os.path.dirname(__file__),'data'),"MobileNetSSD_deploy.prototxt.txt")self.file_caffemodel=os.path.join(os.path.join(os.path.dirname(__file__),'data'),"MobileNetSSD_deploy.caffemodel")self.classes=["background","aeroplane","bicycle","bird","boat","bottle","bus","car","cat","chair","cow","diningtable","dog","horse","motorbike","person","pottedplant","sheep","sofa","train","tvmonitor"]self.net=cv2.dnn.readNetFromCaffe(self.file_prototxt,self.file_caffemodel)defcat_detection(self,image):image_array=np.asarray(bytearray(image),dtype=np.uint8)img_opencv=cv2.imdecode(image_array,-1)#图像预处理blob=cv2.dnn.blobFromImage(img_opencv,0.007843,(300,300),(127.5,127.5,127.5))#前向计算self.net.setInput(blob)detections=self.net.forward()#预处理后图像尺寸dim=300output=[]foriinrange(detections.shape[2]):confidence=detections[0,0,i,2]ifconfidence>0.1:#获取类别标签class_id=int(detections[0,0,i,1])#获取对象位置的坐标left=int(detections[0,0,i,3]*dim)top=int(detections[0,0,i,4]*dim)right=int(detections[0,0,i,5]*dim)bottom=int(detections[0,0,i,6]*dim)#图像尺寸的比例系数heightFactor=img_opencv.shape[0]/dimwidthFactor=img_opencv.shape[1]/dim#检测框坐标left=int(widthFactor*left)top=int(heightFactor*top)right=int(widthFactor*right)bottom=int(heightFactor*bottom)#检测目标是否是猫ifself.classes[class_id]=='cat':cat={'box':[left,top,right,bottom]}output.append(cat)returnoutput
以上猫检测模型,使用了 MobileNet-SSD
目标检测模型,可以自己构建模型训练获得 MobileNet-SSD
模型参数。
将 OpenCV 猫脸检测程序部署在 Web 端
接下来将使用 OpenCV
创建一个深度学习猫检测 Web API
,cat_detection
项目对 Web
服务器应用程序实现在 Web
端检测猫,cat_detection.py
脚本负责解析请求并构建对客户端的响应:
#cat_detection.pyfromflaskimportFlask,request,jsonifyimporturllib.requestfromimage_processingimportImageProcessingapp=Flask(__name__)ip=ImageProcessing()@app.errorhandler(400)defbad_request(e):returnjsonify({'status':'Notok','message':'Thisservercouldnotunderstandyourrequest'}),400@app.errorhandler(404)defnot_found(e):returnjsonify({'status':'Notfound','message':'Routenotfound'}),404@app.errorhandler(500)defnot_found(e):returnjsonify({'status':'Internalerror','message':'Internalerroroccurredinserver'}),500@app.route('/catfacedetection',methods=['GET','POST','PUT'])defdetect_cat_faces():ifrequest.method=='GET':ifrequest.args.get('url'):withurllib.request.urlopen(request.args.get('url'))asurl:returnjsonify({'status':'Ok','result':ip.cat_face_detection(url.read())}),200else:returnjsonify({'status':'Badrequest','message':'Parameterurlisnotpresent'}),400elifrequest.method=='POST':ifrequest.files.get('image'):returnjsonify({'status':'Ok','result':ip.cat_face_detection(request.files['image'].read())}),200else:returnjsonify({'status':'Badrequest','message':'Parameterimageisnotpresent'}),400else:returnjsonify({'status':'Failure','message':'PUTmethodnotsupportedforAPI'}),405@app.route('/catdetection',methods=['GET','POST','PUT'])defdetect_cats():ifrequest.method=='GET':ifrequest.args.get('url'):withurllib.request.urlopen(request.args.get('url'))asurl:returnjsonify({'status':'Ok','result':ip.cat_detection(url.read())}),200else:returnjsonify({'status':'Badrequest','message':'Parameterurlisnotpresent'}),400elifrequest.method=='POST':ifrequest.files.get('image'):returnjsonify({'status':'Ok','result':ip.cat_detection(request.files['image'].read())}),200else:returnjsonify({'status':'Badrequest','message':'Parameterimageisnotpresent'}),400else:returnjsonify({'status':'Failure','message':'PUTmethodnotsupportedforAPI'}),405if__name__=='__main__':app.run(host='0.0.0.0')
如上所示,使用 route()
装饰器将 detect_cat_faces()
函数绑定到 /catfacedetection URL
,并将detect_cats()
函数绑定到 /catdetection URL
,并且使用 jsonify()
函数创建 application/json MIME
类型的给定参数的 JSON
表示,此 API
支持 GET
和 POST
请求,我们还通过使用 errorhandler()
装饰函数来注册错误处理程序。
构造请求检测图像中的猫和猫脸
为了测试此API,编写 request_and_draw_rectangle.py
程序:
#request_and_draw_rectangle.pyimportcv2importnumpyasnpimportrequestsfrommatplotlibimportpyplotaspltdefshow_img_with_matplotlib(color_img,title,pos):img_RGB=color_img[:,:,::-1]ax=plt.subplot(1,2,pos)plt.imshow(img_RGB)plt.title(title,fontsize=10)plt.axis('off')CAT_FACE_DETECTION_REST_API_URL="http://localhost:5000/catfacedetection"CAT_DETECTION_REST_API_URL="http://localhost:5000/catdetection"IMAGE_PATH="test_example.png"#加载图像构建有效负载image=open(IMAGE_PATH,'rb').read()payload={'image':image}image_array=np.asarray(bytearray(image),dtype=np.uint8)img_opencv=cv2.imdecode(image_array,-1)fig=plt.figure(figsize=(12,7))plt.suptitle("UsingcatdetectionAPI",fontsize=14,fontweight='bold')show_img_with_matplotlib(img_opencv,"sourceimage",1)#发送GET请求r=requests.post(CAT_DETECTION_REST_API_URL,files=payload)#解析返回信息print("statuscode:{}".format(r.status_code))print("headers:{}".format(r.headers))print("content:{}".format(r.json()))json_data=r.json()result=json_data['result']#绘制猫脸检测框forcatinresult:left,top,right,bottom=cat['box']cv2.rectangle(img_opencv,(left,top),(right,bottom),(0,255,0),2)cv2.circle(img_opencv,(left,top),10,(0,0,255),-1)cv2.circle(img_opencv,(right,bottom),10,(255,0,0),-1)#发送GET请求r=requests.post(CAT_FACE_DETECTION_REST_API_URL,files=payload)#解析返回信息print("statuscode:{}".format(r.status_code))print("headers:{}".format(r.headers))print("content:{}".format(r.json()))json_data=r.json()result=json_data['result']#绘制猫检测框forfaceinresult:left,top,right,bottom=face['box']cv2.rectangle(img_opencv,(left,top),(right,bottom),(0,255,255),2)cv2.circle(img_opencv,(left,top),10,(0,0,255),-1)cv2.circle(img_opencv,(right,bottom),10,(255,0,0),-1)#结果可视化show_img_with_matplotlib(img_opencv,"catdetection",2)plt.show()
在以上示例中,我们发送了两个 POST
请求以检测猫脸以及图像中的猫,然后根据结果解析来自两个请求的响应并绘制结果:
后记
可以对以上项目进行修改,例如可以在服务器端直接绘制检测框,返回带有检测框的图像;或者读取摄像头视频帧,从而可以实时看到猫咪的行动状态;或者通过检测到的猫脸进一步进行情绪识别,当然需要首先简单的训练一个猫咪情绪识别模型。