微信欠你一顶圣诞帽

最近朋友圈流行找微信官方要圣诞帽,微信官方可能还来不及发放。现在我宣布,微信官方欠你的圣诞帽,我给你。

使用方法

点击下面链接,上传有人脸的照片,自动发放圣诞帽。

实现流程

下面教你使用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

其它