【问题标题】:Detect motion blur of a cropped face with python i.e. opencv使用python检测裁剪面部的运动模糊,即opencv
【发布时间】:2019-09-06 07:04:16
【问题描述】:

我正在使用 haarcascade 检测面部,并使用 OpenCV 使用网络摄像头跟踪它们。我需要保存每张被跟踪的脸。但问题是人们何时移动。在这种情况下,脸部会变得模糊。

我尝试使用 opencv 的 dnn 人脸检测器和 Laplacian 来缓解这个问题,代码如下:

blob = cv2.dnn.blobFromImage(cropped_face, 1.0, (300, 300), (104.0, 177.0, 123.0))
net.setInput(blob)
detections = net.forward()
confidence = detections[0, 0, 0, 2]
blur = cv2.Laplacian(cropped_face, cv2.CV_64F).var()
if confidence >= confidence_threshold and blur >= blur_threshold:
    cv2.imwrite('less_blurry_image', cropped_face)

在这里,我尝试将保存的人脸限制为setting blur_threshold 到 500 和 confidence_threshold 到 0.98(即 98%)的运动而不是模糊的。

但问题是,如果我更换相机,我必须再次手动更改阈值。在大多数情况下,设置阈值会忽略大多数人脸。

此外,由于与模糊的面部相比,背景总是清晰的,因此很难检测到。

所以我的问题是如何检测面部的这种运动模糊。我知道我可以训练一个用于面部运动模糊检测的 ML 模型。但这将需要大量处理资源来完成一项小任务。

此外,如果我走这条路,我将需要大量带注释的数据进行训练。这对我这样的学生来说并不容易。

因此,我尝试使用 OpenCV 来检测这一点,与使用 ML 模型进行检测相比,它占用的资源要少得多。

有没有什么资源密集型解决方案可以解决这个问题?

【问题讨论】:

    标签: python opencv face-detection motion-blur


    【解决方案1】:

    您或许可以使用傅里叶变换 (FFT) 或离散余弦变换 (DCT) 来确定您的面部有多模糊。图像模糊导致高频消失,只剩下低频。

    因此,您需要拍摄一张脸部图像,将其补零至适合 FFT 或 DCT 的尺寸,然后查看您在较高频率下的频谱功率。

    您可能不需要 FFT - DCT 就足够了。 DCT 的优点是它产生实值结果(没有虚部)。性能方面,FFT 和 DCT 对于 2 的幂的大小以及只有因子 2、3 和 5 的大小非常快(尽管如果你也有 3 和 5,它会慢一点)。

    【讨论】:

    • 如何使用 python 实现 FFT 或 DCT?如果可能的话,您能否分享代码 sn-p 它是如何完成的或分享需要传递给它的输入
    【解决方案2】:

    正如@PlinyTheElder 所述,DCT 信息可以为您提供运动模糊。我在下面附上repo 的代码 sn-p:

    代码在C 中,我不确定libjpeg 是否有python 绑定。否则你需要创建一个。

    /* Fast blur detection using JPEG DCT coefficients
     *
     * Based on "Blur Determination in the Compressed Domain Using DCT
     * Information" by Xavier Marichal, Wei-Ying Ma, and Hong-Jiang Zhang.
     *
     * Tweak MIN_DCT_VALUE and MAX_HISTOGRAM_VALUE to adjust
     * effectiveness.  I reduced these values from those given in the
     * paper because I find the original to be less effective on large
     * JPEGs.
     *
     * Copyright 2010 Julian Squires <julian@cipht.net>
     */
    
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <jpeglib.h>
    
    static int min_dct_value = 1;   /* -d= */
    static float max_histogram_value = 0.005; /* -h= */
    
    static float weights[] = {  /* diagonal weighting */
        8,7,6,5,4,3,2,1,
        1,8,7,6,5,4,3,2,
        2,1,8,7,6,5,4,3,
        3,2,1,8,7,6,5,4,
        4,3,2,1,8,7,6,5,
        5,4,3,2,1,8,7,6,
        6,5,4,3,2,1,8,7,
        7,6,5,4,3,2,1,8
    };
    static float total_weight = 344;
    
    static inline void update_histogram(JCOEF *block, int *histogram)
    {
        for(int k = 0; k < DCTSIZE2; k++, block++)
            if(abs(*block) > min_dct_value) histogram[k]++;
    }
    
    static float compute_blur(int *histogram)
    {
        float blur = 0.0;
        for(int k = 0; k < DCTSIZE2; k++)
            if(histogram[k] < max_histogram_value*histogram[0])
                blur += weights[k];
        blur /= total_weight;
        return blur;
    }
    
    
    static int operate_on_image(char *path)
    {
            struct jpeg_error_mgr jerr;
        struct jpeg_decompress_struct cinfo;
        jvirt_barray_ptr *coeffp;
        JBLOCKARRAY cs;
        FILE *in;
        int histogram[DCTSIZE2] = {0};
    
            cinfo.err = jpeg_std_error(&jerr);
            jpeg_create_decompress(&cinfo);
        if((in = fopen(path, "rb")) == NULL) {
            fprintf(stderr, "%s: Couldn't open.\n", path);
            jpeg_destroy_decompress(&cinfo);
            return 0;
        }
        jpeg_stdio_src(&cinfo, in);
        jpeg_read_header(&cinfo, TRUE);
        // XXX might be a little faster if we ask for grayscale
        coeffp = jpeg_read_coefficients(&cinfo);
    
        /* Note: only looking at the luma; assuming it's the first component. */
        for(int i = 0; i < cinfo.comp_info[0].height_in_blocks; i++) {
            cs = cinfo.mem->access_virt_barray((j_common_ptr)&cinfo, coeffp[0], i, 1, FALSE);
            for(int j = 0; j < cinfo.comp_info[0].width_in_blocks; j++)
                update_histogram(cs[0][j], histogram);
        }
    
        printf("%f\n", compute_blur(histogram));
        // output metadata XXX should be in IPTC etc
    
        // XXX also need to destroy coeffp?
        jpeg_destroy_decompress(&cinfo);
        return 0;
    }
    
    int main(int argc, char **argv)
    {
        int status, i;
    
        for(status = 0, i = 1; i < argc; i++) {
            if(argv[i][0] == '-') {
                if(argv[i][1] == 'd')
                    sscanf(argv[i], "-d=%d", &min_dct_value);
                else if(argv[i][1] == 'h')
                    sscanf(argv[i], "-h=%f", &max_histogram_value);
                continue;
            }
            status |= operate_on_image(argv[i]);
        }
    
        return status;
    }
    

    编译代码:

    gcc -std=c99 blur_detection.c -l jpeg -o blur-detection
    

    运行代码:

    ./blur-detection <image path>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-06
      • 1970-01-01
      • 2014-07-27
      • 1970-01-01
      • 2015-06-05
      • 1970-01-01
      • 1970-01-01
      • 2016-10-14
      相关资源
      最近更新 更多