使用 python 即 opencv 检测裁剪面部的运动模糊

我正在使用 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_threshold0.98(即 98%)。


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


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


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


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


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


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


幕布斯6054654
浏览 251回答 2
2回答

慕码人2483693

您可能可以使用傅立叶变换 (FFT) 或离散余弦变换 (DCT) 来确定您的面部有多模糊。图像中的模糊导致高频消失,只剩下低频。所以你会拍一张你的脸,把它补零到一个适合FFT或DCT的大小,然后看看你在更高频率下有多少光谱功率。您可能不需要 FFT - DCT 就足够了。DCT 的优点是它产生实值结果(没有虚部)。性能方面,FFT 和 DCT 对于 2 的幂的大小以及只有因子 2、3 和 5 的大小非常快(尽管如果你也有 3 和 5,它会慢一点)。

PIPIONE

正如@PlinyTheElder 所提到的,DCT 信息可以为您提供运动模糊。我从下面的repo中附上了代码片段:代码在里面C,我不确定是否有 python 绑定libjpeg。否则,您需要创建一个。/* Fast blur detection using JPEG DCT coefficients&nbsp;*&nbsp;* Based on "Blur Determination in the Compressed Domain Using DCT&nbsp;* Information" by Xavier Marichal, Wei-Ying Ma, and Hong-Jiang Zhang.&nbsp;*&nbsp;* Tweak MIN_DCT_VALUE and MAX_HISTOGRAM_VALUE to adjust&nbsp;* effectiveness.&nbsp; I reduced these values from those given in the&nbsp;* paper because I find the original to be less effective on large&nbsp;* JPEGs.&nbsp;*&nbsp;* Copyright 2010 Julian Squires <julian@cipht.net>&nbsp;*/#include <string.h>#include <stdlib.h>#include <stdio.h>#include <jpeglib.h>static int min_dct_value = 1;&nbsp; &nbsp;/* -d= */static float max_histogram_value = 0.005; /* -h= */static float weights[] = {&nbsp; /* diagonal weighting */&nbsp; &nbsp; 8,7,6,5,4,3,2,1,&nbsp; &nbsp; 1,8,7,6,5,4,3,2,&nbsp; &nbsp; 2,1,8,7,6,5,4,3,&nbsp; &nbsp; 3,2,1,8,7,6,5,4,&nbsp; &nbsp; 4,3,2,1,8,7,6,5,&nbsp; &nbsp; 5,4,3,2,1,8,7,6,&nbsp; &nbsp; 6,5,4,3,2,1,8,7,&nbsp; &nbsp; 7,6,5,4,3,2,1,8};static float total_weight = 344;static inline void update_histogram(JCOEF *block, int *histogram){&nbsp; &nbsp; for(int k = 0; k < DCTSIZE2; k++, block++)&nbsp; &nbsp; &nbsp; &nbsp; if(abs(*block) > min_dct_value) histogram[k]++;}static float compute_blur(int *histogram){&nbsp; &nbsp; float blur = 0.0;&nbsp; &nbsp; for(int k = 0; k < DCTSIZE2; k++)&nbsp; &nbsp; &nbsp; &nbsp; if(histogram[k] < max_histogram_value*histogram[0])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; blur += weights[k];&nbsp; &nbsp; blur /= total_weight;&nbsp; &nbsp; return blur;}static int operate_on_image(char *path){&nbsp; &nbsp; &nbsp; &nbsp; struct jpeg_error_mgr jerr;&nbsp; &nbsp; struct jpeg_decompress_struct cinfo;&nbsp; &nbsp; jvirt_barray_ptr *coeffp;&nbsp; &nbsp; JBLOCKARRAY cs;&nbsp; &nbsp; FILE *in;&nbsp; &nbsp; int histogram[DCTSIZE2] = {0};&nbsp; &nbsp; &nbsp; &nbsp; cinfo.err = jpeg_std_error(&jerr);&nbsp; &nbsp; &nbsp; &nbsp; jpeg_create_decompress(&cinfo);&nbsp; &nbsp; if((in = fopen(path, "rb")) == NULL) {&nbsp; &nbsp; &nbsp; &nbsp; fprintf(stderr, "%s: Couldn't open.\n", path);&nbsp; &nbsp; &nbsp; &nbsp; jpeg_destroy_decompress(&cinfo);&nbsp; &nbsp; &nbsp; &nbsp; return 0;&nbsp; &nbsp; }&nbsp; &nbsp; jpeg_stdio_src(&cinfo, in);&nbsp; &nbsp; jpeg_read_header(&cinfo, TRUE);&nbsp; &nbsp; // XXX might be a little faster if we ask for grayscale&nbsp; &nbsp; coeffp = jpeg_read_coefficients(&cinfo);&nbsp; &nbsp; /* Note: only looking at the luma; assuming it's the first component. */&nbsp; &nbsp; for(int i = 0; i < cinfo.comp_info[0].height_in_blocks; i++) {&nbsp; &nbsp; &nbsp; &nbsp; cs = cinfo.mem->access_virt_barray((j_common_ptr)&cinfo, coeffp[0], i, 1, FALSE);&nbsp; &nbsp; &nbsp; &nbsp; for(int j = 0; j < cinfo.comp_info[0].width_in_blocks; j++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; update_histogram(cs[0][j], histogram);&nbsp; &nbsp; }&nbsp; &nbsp; printf("%f\n", compute_blur(histogram));&nbsp; &nbsp; // output metadata XXX should be in IPTC etc&nbsp; &nbsp; // XXX also need to destroy coeffp?&nbsp; &nbsp; jpeg_destroy_decompress(&cinfo);&nbsp; &nbsp; return 0;}int main(int argc, char **argv){&nbsp; &nbsp; int status, i;&nbsp; &nbsp; for(status = 0, i = 1; i < argc; i++) {&nbsp; &nbsp; &nbsp; &nbsp; if(argv[i][0] == '-') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(argv[i][1] == 'd')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sscanf(argv[i], "-d=%d", &min_dct_value);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if(argv[i][1] == 'h')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sscanf(argv[i], "-h=%f", &max_histogram_value);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; status |= operate_on_image(argv[i]);&nbsp; &nbsp; }&nbsp; &nbsp; return status;}编译代码:gcc -std=c99 blur_detection.c -l jpeg -o blur-detection运行代码:./blur-detection <image path>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python