如何使用 python 函数遍历从另一个函数接收的文件

How to use python function to iterate through files received from another function

我的功能遇到了问题。我正在构建一个应该像这样工作的人脸识别系统:

  1. 读取视频文件
  2. 使用opencv和haarcascade识别视频中检测到人脸的帧
  3. 在本地保存这些帧`

至此,一切顺利,这是我用来执行这些步骤的函数:

import cv2
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import os

async def take_snapshots(file):
    cascPath = "haarcascade_frontalface_default.xml"

    faceCascade = cv2.CascadeClassifier(cascPath)


    # construct the argument parse and parse the arguments
    # ap = argparse.ArgumentParser()
    # ap.add_argument("-v", "--video", required=True,
    #                 help="video.mp4")
    # args = vars(ap.parse_args())

    # open a pointer to the video stream and start the FPS timer
    # stream = cv2.VideoCapture(args["video"])
    stream = cv2.VideoCapture(file)
    fps = FPS().start()

    try:

        # creating a folder named data
        if not os.path.exists('data'):
            os.makedirs('data')

    # if not created then raise error
    except OSError:
        print('Error: Creating directory of data')

    # frame
    currentframe = 0

    # loop over frames from the video file stream
    while True:
        # grab the frame from the threaded video file stream
        (grabbed, frame) = stream.read()

        # if the frame was not grabbed, then we have reached the end
        # of the stream
        if not grabbed:
            break

        # resize the frame and convert it to grayscale (while still
        # retaining 3 channels)
        frame = imutils.resize(frame, width=980)
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        frame = np.dstack([frame, frame, frame])
        faces = faceCascade.detectMultiScale(
                            frame,
                            scaleFactor=1.1,
                            minNeighbors=4,
                            minSize=(20, 20),
                            maxSize=(40, 40),
                            # flags=cv2.CASCADE_SCALE_IMAGE
                    )

        for (x, y, w, h) in faces:
                # cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3)
                if grabbed:
                        # Save just the rectangle faces in SubRecFaces
                        # sub_face = frame[y:y+h, x:x+w]
                        name = './data/frame' + str(currentframe) + '.jpg'
                        print('Creating...' + name)

                        # writing the extracted images
                        cv2.imwrite(name, frame)

                        currentframe += 1

                        if cv2.waitKey(1) & 0xFF == ord('q'):
                                break

                else:
                        break


        # show the frame and update the FPS counter
        # cv2.imshow("Frame", frame)
        # cv2.waitKey(1)
        fps.update()

    # stop the timer and display FPS information
    fps.stop()
    print("[INFO] elasped time: {:.2f}".format(fps.elapsed()))
    print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))

    # do a bit of cleanup
    stream.release()
    cv2.destroyAllWindows()
  1. 取一个保存的帧并使用 aws rekognition api 从中检测人脸(如果你想知道为什么,那是因为准确性)
  2. 从包含人脸和边界框的帧中保存一个新副本

第 4 步顺利,没有问题。当代码到达第 5 步时,我遇到了一个问题,我的代码遍历了第 3 步保存的每一帧,它还跳过了没有人脸的前两帧。之后,它将 frame2.jpg 保存为 pic0.jpg,这是应该的。问题是,之后它应该从每一帧保存一张新图片(pic1、pic2 等),但它只是在每一轮中覆盖 pic0.jpg。我知道问题出在我的循环上,但我不知道如何解决它。

以下是我在第 4 步和第 5 步中使用的函数:

import boto3
from pathlib import Path
import os
import cv2
import io
from PIL import Image, ImageDraw, ExifTags, ImageColor


async def detect_faces(photo):
    image = Image.open(open(photo, 'rb'))
    stream = io.BytesIO()
    image.save(stream, format=image.format)
    image_binary = stream.getvalue()

    client = boto3.client('rekognition')
    response = client.detect_faces(
        Image={'Bytes': image_binary}, Attributes=['ALL'])

    draw = ImageDraw.Draw(image)

    print('Detected faces in ' + photo)

    currentpic = 0
    for face in response['FaceDetails']:
        print('Confidence: ' + str(face['Confidence']))


        box = face['BoundingBox']
        imgWidth, imgHeight = image.size
        left = imgWidth * box['Left']
        top = imgHeight * box['Top']
        width = imgWidth * box['Width']
        height = imgHeight * box['Height']

        # print('Left: ' + '{0:.0f}'.format(left))
        # print('Top: ' + '{0:.0f}'.format(top))
        # print('Face Width: ' + "{0:.0f}".format(width))
        # print('Face Height: ' + "{0:.0f}".format(height))

        points = (
            (left, top),
            (left + width, top),
            (left + width, top + height),
            (left, top + height),
            (left, top)

        )
        draw.line(points, fill='#00d400', width=2)


        name = './results/pic' + str(currentpic) + '.jpg'
        print('Creating final pic.....' + name)
        image.save(name)
        currentpic += 1

    return len(response['FaceDetails'])



async def main():
    directory_in_str = './data'
    pathlist = Path(directory_in_str).glob('**/*.jpg')

    try:
        if not os.path.exists('results'):
            os.makedirs('results')

        # if not created then raise error
    except OSError:
        print('Error: Creating directory of data')

    for path in pathlist:
        # path is object not string
        path_in_str = str(path)
        # print(path_in_str)
        photo = path_in_str

        face_count = await detect_faces(photo)
        print("Faces detected: " + str(face_count))

最后,这是我用来 运行 这些函数的主要函数:

import read_frames_slow
import detect_faces
import asyncio


async def main():
  await read_frames_slow.take_snapshots('video.mp4')
  await detect_faces.main()

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

非常感谢帮助解决这个问题。

使用 pathlib.Path 对象而不是字符串 (https://pillow.readthedocs.io/en/stable/reference/Image.html)

喜欢

im.save(os.path.join(r"C:\Users\abc123\Desktop\Movie", f + ext), "JPEG" )

因为 name = './results/pic' + str(currentpic) + '.jpg' 被解释为字符串或文件名,而不是路径(参见 https://pillow.readthedocs.io/en/stable/reference/Image.htmlPython 将 str路径类型?)