Django 使用 opencv2 剪切并仅将人脸放在图片字段中

Django cut and put only the face in the picture field using opencv2

我使用 cv2 对 FaceCropped 进行了编码并且它有效!
我想在 ProcessedImageField 模型中通过 facecropped 方法放置 img。
到底有没有 我想要的是上传图片到学生模型的时候自动切脸存入数据库

裁剪方法

import numpy as np
import cv2
import os
import glob

def FaceCropped(full_path, extra='face', show=False):
    face_cascade = cv2.CascadeClassifier('C:../haarcascade_frontalface_default.xml')
    full_path = full_path
    path,file = os.path.split(full_path)


    ff = np.fromfile(full_path, np.uint8)
    img = cv2.imdecode(ff, cv2.IMREAD_UNCHANGED)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3,5)

    for (x,y,w,h) in faces:
        cropped = img[y - int(h/4):y + h + int(h/4), x - int(w/4):x + w + int(w/4)]
        result, encoded_img = cv2.imencode(full_path, cropped)
        if result:
            with open(path + '/' + extra + file, mode='w+b') as f:
                encoded_img.tofile(f)
    if show:
        cv2.imshow('Image view', cropped)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

我的model.py

class Student(models.Model):
    picture = ProcessedImageField(
        verbose_name = 'picture',
        upload_to = 'students/%Y/',
        processors=[ResizeToFill(300,300)],
        options={'quality':80},
        format='JPEG',
        null=True,
        blank=True,
        default='students/no-img.jpg',
    )
    name = models.CharField(max_length=255)

我的views.py

class StudentAdd(FormView):
    model = Student
    template_name = 'student/list_add.html'
    context_object_name = 'student'
    form_class = AddStudent

    def post(self, request):
        form = self.form_class(request.POST, request.FILES)

        if form.is_valid():
            student = form.save(commit=False)
            student.created_by = request.user

            student.save()
            messages.info(request, student.name + ' addddd', extra_tags='info')
            if "save_add" in self.request.POST:
                return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
            return redirect('student_detail', pk=student.pk, school_year=student.school_year)

        return FormView.post(self, request)

有几种方法可以实现。

覆盖模型保存方法

将裁剪图像保存到数据库的一种方法是您需要重写保存方法。
看看 this document.

在将数据保存到数据库之前,您可以对模型数据做任何您想处理的事情。您可以自由覆盖这些方法(以及任何其他模型方法)以改变行为。

以下代码来自django文档

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        do_something()
        super().save(*args, **kwargs)  # Call the "real" save() method.
        do_something_else()

继承字段 class 并覆盖清理方法

我假设您使用的是来自 imagekit

ProcessedImageField
from imagekit.models import ProcessedImageField

您可以继承 ProcessedImageField 并覆盖 class 字段的 clean method

清理方法确保字段中的所有数据都清理。保存前的图像处理可以用干净的方法。

以下代码来自django源码

def clean(self, value):
    """
    Validate the given value and return its "cleaned" value as an
    appropriate Python object. Raise ValidationError for any errors.
    """
    value = self.to_python(value)
    self.validate(value)
    self.run_validators(value)
    return value

覆盖表单清理方法

This question 解释如何覆盖表单清理方法。
清除方法将 运行 在保存方法之前。
这是另一种在保存前更改数据的常用方法。

我解决了!
郝老师加油!
我们可以进一步优化代码吗?

在model.py

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        FaceCropped(self.picture.path)
def FaceCropped(full_path):
    face_cascade = cv2.CascadeClassifier('D:/Dropbox/atom/django/Manage/Project/student/haarcascade_frontalface_default.xml')
    full_path = full_path
    path,file = os.path.split(full_path)


    ff = np.fromfile(full_path, np.uint8)
    img = cv2.imdecode(ff, cv2.IMREAD_UNCHANGED)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3,5)

    for (x,y,w,h) in faces:
        cropped = img[y - int(h/4):y + h + int(h/4), x - int(w/4):x + w + int(w/4)]
        result, encoded_img = cv2.imencode(full_path, cropped)
        if result:
            with open(full_path, mode='w+b') as f:
                encoded_img.tofile(f)