微信欠你一顶圣诞帽
最近朋友圈流行找微信官方要圣诞帽,微信官方可能还来不及发放。现在我宣布,微信官方欠你的圣诞帽,我给你。
使用方法
点击下面链接,上传有人脸的照片,自动发放圣诞帽。
实现流程
下面教你使用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