Как использовать функцию python для перебора файлов, полученных из другой функции - PullRequest
2 голосов
/ 10 января 2020

У меня проблема с моими функциями. Я создаю систему распознавания лиц, которая должна работать следующим образом:

  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()
Возьмите сохраненный кадр и используйте aws rekognition api для обнаружения лиц с него (если вы хотите знать почему, это из-за точности) Сохраните новую копию из кадров, которые включают лица, с ограничивающие рамки

Шаг 4 проходит хорошо, проблем нет. когда код достигает шага 5, я сталкиваюсь с проблемой, когда мой код проходит через каждый кадр, сохраненный на шаге 3, он также пропускает два первых кадра, где нет граней. После этого он сохраняет frame2.jpg как pic0.jpg, как и положено. Проблема в том, что после этого он должен сохранять новую картинку (pic1, pic2 и c) из каждого кадра, но вместо этого он просто перезаписывает pic0.jpg при каждом раунде. Я знаю, что проблема с моим l oop, я просто не могу понять, как это исправить.

Вот функции, которые я использую для шагов 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()

Буду очень признателен за помощь в решении этой проблемы.

1 Ответ

1 голос
/ 10 января 2020

Используйте объект 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" )

in файл не сохраняется в определенном каталоге с помощью PIL im.save

, поскольку name = './results/pic' + str(currentpic) + '.jpg' интерпретируется как строка или имя файла, а не как путь (см. https://pillow.readthedocs.io/en/stable/reference/Image.html, Python преобразовать str в тип пути? )

...