likes
comments
collection
share

改变图片尺寸优化opencv人脸识别速度单次耗时减半

作者站长头像
站长
· 阅读数 4

Demo代码简单介绍

项目利用face_recognition模块实现 人脸分辨识别 因为这篇文章主要介绍优化速度所以会以代码片段讲解方法 结尾会放出全部代码 注意以下代码需要一点点opencv的基础 但不多

def face_detector(img, target):
    start = time.time()

    # 人脸检测结果
    faceLocList = face_recognition.face_locations(img)
    if len(faceLocList) == 0:
        print("No face")
        return img
    # 人脸的相似度矩阵
    encodeList = face_recognition.face_encodings(img)

    faceDis = face_recognition.face_distance(encodeList, target)
    result = face_recognition.compare_faces(encodeList, target)
    for i in range(len(faceLocList)):
        successColor = (0, 255, 0)
        errorColor = (0, 0, 255)
        y1,x2,y2,x1 = faceLocList[i][0], faceLocList[i][1], faceLocList[i][2], faceLocList[i][3],
        # 根据结果绘制不同的颜色框和文字
        if result[i] and faceDis[i] < 0.35:
            cv2.putText(img, f'{result[i]}{round(faceDis[i], 2)}', (x1, y1 - 20),
                        cv2.FONT_HERSHEY_COMPLEX, 1, successColor, 2)
            cv2.rectangle(img, (x1, y1),
                          (x2, y2), successColor, 2)
        else:
            cv2.putText(img, f'{result[i]}{round(faceDis[i], 2)}',
                        (x1, y1 - 20),
                        cv2.FONT_HERSHEY_COMPLEX, 1, errorColor, 2)
            cv2.rectangle(img, (x1, y1),
                          (x2, y2), errorColor, 2)
        print(f'一次处理的耗时为: {time.time() - start}')
    return img

上面这个函数接收一张需要处理的img 和 目标人脸target

我们无须关心这函数的具体处理 从代码的3行到30行都是人脸处理代码 我们需要注意的是 上面的代码中 从我们接收到这个img之后 一直都是对img直接进行操作的 并没有预处理img这样虽然可以 但是img是相机直出的 分辨率和尺寸一般都比较大这其实很影响人脸的处理速度 这样的代码 单次处理速度在0.55秒左右 画面是非常卡顿的

改变图片尺寸优化opencv人脸识别速度单次耗时减半

优化

我们只需要将需要处理的img图片大小缩小到4分之一为imgS

然后处理这一张小图片

然后拿到小图片的处理结果在页面上绘制的时候只需要 将坐标*4 补一下大小即可

这样的优化方法大致有以下几种依据

  1. 减少像素数量 当图像被缩小时,其像素数量会显著减少 这意味着处理的数据量大大降低
  2. 加快算法执行速度 许多图像处理和计算机视觉算法的复杂度与图像的尺寸成正比
  3. 保留概貌特征 图像的小尺度版本可能已经足够保留关键信息。通过先在小图上预处理,可以快速排除不感兴趣的区域或大致定位目标
  4. 硬件效率 小图像更适合内存有限的设备 数据传输和并行处理效率也更高

具体代码

def face_detector(img, target):
    start = time.time()
    # 处理缩小后的图片 耗时减少了一半!!!
    imgS = cv2.resize(img, (0, 0), None, 0.25, 0.25)

    # 人脸检测结果
    faceLocList = face_recognition.face_locations(imgS)
    if len(faceLocList) == 0:
        print("No face")
        return img
    # 人脸的相似度矩阵
    encodeList = face_recognition.face_encodings(imgS)

    faceDis = face_recognition.face_distance(encodeList, target)
    result = face_recognition.compare_faces(encodeList, target)
    for i in range(len(faceLocList)):
        successColor = (0, 255, 0)
        errorColor = (0, 0, 255)
        y1,x2,y2,x1 = faceLocList[i][0] * 4, faceLocList[i][1]* 4, faceLocList[i][2]* 4, faceLocList[i][3]* 4,
        # 根据结果绘制不同的颜色框和文字
        if result[i] and faceDis[i] < 0.35:
            cv2.putText(img, f'{result[i]}{round(faceDis[i], 2)}', (x1, y1 - 20),
                        cv2.FONT_HERSHEY_COMPLEX, 1, successColor, 2)
            cv2.rectangle(img, (x1, y1),
                          (x2, y2), successColor, 2)
        else:
            cv2.putText(img, f'{result[i]}{round(faceDis[i], 2)}',
                        (x1, y1 - 20),
                        cv2.FONT_HERSHEY_COMPLEX, 1, errorColor, 2)
            cv2.rectangle(img, (x1, y1),
                          (x2, y2), errorColor, 2)
        # cv2.imshow('Face Detection', img)
        # cv2.waitKey(1)
        print(f'一次处理的耗时为: {time.time() - start}')
    return img

在代码的第4行 我们把参数img缩小的了一下 为imgS

然后在代码的第7行和12使用imgS处理人脸数据

最后将在第19行将imgS拿到的人脸数据乘4绘制到原图片img上

效果

简简单单加一行代码 改三行代码 速度从0.55 到 0.26 效果非常显著 在未来的图片处理的过程中也可以尝试缩小处理图片 然后将结果放打绘制到原图片中展示结果

改变图片尺寸优化opencv人脸识别速度单次耗时减半

下面为Dome源码

FaceDetection.py 入口文件

import threading
import cv2
import face_recognition
import time
import VideoCapture as vc

# img 需要检测人脸 target 目标人脸的face_encodings值
def face_detector(img, target):
    start = time.time()
    # 处理缩小后的图片 耗时减少了一半!!!
    imgS = cv2.resize(img, (0, 0), None, 0.25, 0.25)

    # 人脸检测结果
    faceLocList = face_recognition.face_locations(imgS)
    if len(faceLocList) == 0:
        print("No face")
        return img
    # 人脸的相似度矩阵
    encodeList = face_recognition.face_encodings(imgS)

    faceDis = face_recognition.face_distance(encodeList, target)
    result = face_recognition.compare_faces(encodeList, target)
    for i in range(len(faceLocList)):
        successColor = (0, 255, 0)
        errorColor = (0, 0, 255)
        y1,x2,y2,x1 = faceLocList[i][0] * 4, faceLocList[i][1]* 4, faceLocList[i][2]* 4, faceLocList[i][3]* 4,
        # 根据结果绘制不同的颜色框和文字
        if result[i] and faceDis[i] < 0.35:
            cv2.putText(img, f'{result[i]}{round(faceDis[i], 2)}', (x1, y1 - 20),
                        cv2.FONT_HERSHEY_COMPLEX, 1, successColor, 2)
            cv2.rectangle(img, (x1, y1),
                          (x2, y2), successColor, 2)
        else:
            cv2.putText(img, f'{result[i]}{round(faceDis[i], 2)}',
                        (x1, y1 - 20),
                        cv2.FONT_HERSHEY_COMPLEX, 1, errorColor, 2)
            cv2.rectangle(img, (x1, y1),
                          (x2, y2), errorColor, 2)
        print(f'一次处理的耗时为: {time.time() - start}')
    return img

def videoTest(target):
    cap = vc.VideoCapture(0)
    def video_capture():
        while True:
            img = cap.read()
            img = face_detector(img, target)# 这是一个很耗时的操作
            cv2.imshow('img',img)
            key = cv2.waitKey(int(1000/24))
            if (key & 0xff) == 27:
                cap.terminate()
                cv2.destroyAllWindows()
                break
    # 创建一个线程来执行视频捕获和处理
    video_thread = threading.Thread(target=video_capture)
    video_thread.start()
    # 主线程等待视频线程结束
    video_thread.join()

if __name__ == '__main__':
    imgTest = face_recognition.load_image_file('imgs/zhujiayi.jpg')  # 目标人脸
    imgTest = cv2.cvtColor(imgTest, cv2.COLOR_BGR2RGB)
    encodeTest = face_recognition.face_encodings(imgTest)[0]
    # 传入目标人脸的encode值 打开摄像头识别
    videoTest(encodeTest)

    exit(0)

VideoCapture类 用来解决连接网络摄像头因为读取帧和显示不一致导致容易崩溃的问题

import queue
import threading
import cv2


class VideoCapture:
    def __init__(self, camera_id):
        self.cap = cv2.VideoCapture(camera_id)
        self.q = queue.Queue(maxsize=3)
        self.stop_threads = False  # 子线程是否关闭
        cv2.setUseOptimized(True)
        cv2.setNumThreads(12)  # 根据你的系统和硬件配置进行调整
        cv2.ocl.setUseOpenCL(True)  # 开启OpenCL加速
        self.cap.set(3, 640)
        self.cap.set(4, 480)
        th = threading.Thread(target=self._reader)
        th.daemon = True  # 设置工作线程为后台运行
        th.start()

    # 实时读帧,只保存最后一帧
    def _reader(self):
        while not self.stop_threads: # 线程没有关闭才进行下面的读取操作
            ret, frame = self.cap.read()
            if not ret:
                break
            if not self.q.empty(): # 如果队列不是空的就是立刻get一个不等待
                try:
                    self.q.get_nowait()
                except queue.Empty:
                    pass
            self.q.put(frame)

    def read(self):
        return self.q.get()

    def terminate(self):
        self.stop_threads = True
        self.cap.release()

最后 如果本篇文章对你有帮助 可以的话请点一个赞 非常感谢 对于上面的代码 有什么问题都是评论或者私信问我 欢迎讨论