微信欠你一顶圣诞帽
最近朋友圈流行找微信官方要圣诞帽,微信官方可能还来不及发放。现在我宣布,微信官方欠你的圣诞帽,我给你。
使用方法
点击下面链接,上传有人脸的照片,自动发放圣诞帽。
实现流程
下面教你使用python+opencv实现给头像戴圣诞帽。
开发环境
python + opencv + flask + nginx
安装
- 安装python
- 安装opencv
- 安装flask、opencv等python依赖包
- 安装nginx等搭建服务器的工具
设计网页
主要是上传文件
<form action="/" method="POST" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" value="上传文件" /> </form> {% if has_img %} <br><img style="width:100%;" src="{{pic_url}}"/> {% endif %}
设计后端
***部分需要根据实际情况设置。
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif']) def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS @app.route('/uploads/<filename>') def uploaded_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename) # 圣诞帽子 @app.route("/", methods=['GET', 'POST']) def pic_upload(): if request.method == 'POST': file = request.files['file'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) if not add_hat(filename, "***"+filename): return render_template("upload.html", has_img=False, has_message=True, message=u"制作图片过程中出错!") return render_template("upload.html", has_img=True, pic_url="***") return render_template("upload.html", has_img=False, pic_url="***")
人脸检测&&发圣诞帽
import cv2 # 帽子图片地址,需要背景为白底 hat_file = "***/hat4.jpg" model_file = "/root/tools/opencv-2.4.13.2/data/haarcascades/haarcascade_frontalface_default.xml" face_patterns = cv2.CascadeClassifier(model_file) def add_hat(dst_file, save_file): dst_file = os.path.join("***", dst_file) save_file = os.path.join("***", save_file) main_img = cv2.imread(dst_file) raw_hat_img = cv2.imread(hat_file) faces = face_patterns.detectMultiScale(main_img, scaleFactor=1.1, minNeighbors=5, minSize=(100, 100)) for (x, y, w, h) in faces: ratio = float(w) / raw_hat_img.shape[1] # 需要根据人脸大小,自动调整帽子大小 hat_img = cv2.resize(raw_hat_img, (int(raw_hat_img.shape[0]*ratio), w), interpolation=cv2.INTER_CUBIC) hat_img_gray = cv2.cvtColor(hat_img, cv2.COLOR_BGR2GRAY) # 生成掩膜 ret, hat_img_mask = cv2.threshold(hat_img_gray, 252, 255, cv2.THRESH_BINARY) hat_img_mask_inv = cv2.bitwise_not(hat_img_mask) # 根据实际情况微调 new_x = x - int(hat_img.shape[1] * 0.12) # 防止越界,还有其他需要判断的,这里比较粗糙 if new_x + hat_img.shape[1] > main_img.shape[1]: return False new_y = max(0, y - hat_img.shape[0]/2) # 获取ROI hat_roi = main_img[new_y:(new_y+hat_img.shape[0]), new_x:(new_x+hat_img.shape[1])] hat_roi_bg = cv2.bitwise_and(hat_roi, hat_roi, mask=hat_img_mask) hat_roi_pic = cv2.bitwise_and(hat_img, hat_img, mask=hat_img_mask_inv) dst = cv2.add(hat_roi_bg, hat_roi_pic) # 更新ROI,根据参数可以设置透明度等,这里没有设置 cv2.addWeighted(hat_img, 0.0, dst, 1.0, 0., hat_roi) cv2.imwrite(save_file, main_img) return True