1

I am trying to add batching to a OpenCV python script I am making and I cannot for the life of me see what I am doing wrong. I am a beginner at this so its probably something stupid. In the end I want the script to read every image file in the current working directory of the script and then crop based on the face detect from openCV and output those cropped images with the same name to a folder inside the CWD. Right now all it does though is output the last image in the folder into the output folder. Any ideas from those who know what they are doing?

import cv2
import sys
import os.path
import glob

#Cascade path
cascPath = 'haarcascade_frontalface_default.xml'

# Create the haar cascade
faceCascade = cv2.CascadeClassifier(cascPath)

# Read Images
images = glob.glob('*.jpg')
for i in images:
    image = cv2.imread(i,1)

#Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Find face(s) using cascade
faces = faceCascade.detectMultiScale(
    gray,
    scaleFactor=1.1, #size of groups
    minNeighbors=5, #How many groups around are detected as face for it to be valid
    minSize=(300, 300) #Min size in pixels for face
)

# Outputs number of faces found in image
print('Found {0} faces!'.format(len(faces)))

# Places a rectangle on face (For debugging, wont be in crop version)
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (255, 255, 255), 4)

# Resizes image to fit monitor and displayes it
imOut = cv2.resize(image, (750, 1142))
#cv2.imshow("Faces found", imS)
#cv2.waitKey(0)

#Saves image to output folder and creates folder if it doesnt exist
if not os.path.exists('output'):
    os.makedirs('output')
os.chdir('output')
cv2.imwrite(i, imOut)

2 Answers2

1

There are multiple corrections I have made in the code

    1. You need the give the full path of the haarcascade_frontalface_default.xml

    For instance: in Unix system:

    cascPath = 'opencv/data/haarcascades/haarcascade_frontalface_default.xml'
    
    1. You shouldn't create directories during the loop. You should create it before the loop.
    if not os.path.exists('output'):
      os.makedirs('output')
    
    1. You don't need to change the directory to save the images. Just add the path before the image.
    img_name = "output/out_{}.png".format(c) # c is the counter  
    
    1. Indentation is important, otherwise, you might have difficulties.

Example code:

import cv2
import os.path
import glob

# Cascade path
cascPath = '/opencv/data/haarcascades/haarcascade_frontalface_default.xml'

# Create the haar cascade
faceCascade = cv2.CascadeClassifier(cascPath)

if not os.path.exists('output'):
    os.makedirs('output')

# Read Images
images = glob.glob('images/*.jpg')
for c, i in enumerate(images):
    image = cv2.imread(i, 1)

    # Convert to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Find face(s) using cascade
    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,  # size of groups
        minNeighbors=5,  # How many groups around are detected as face for it to be valid
        minSize=(300, 300)  # Min size in pixels for face
    )

    # Outputs number of faces found in image
    print('Found {0} faces!'.format(len(faces)))

    # Places a rectangle on face (For debugging, wont be in crop version)
    for (x, y, w, h) in faces:
        cv2.rectangle(image, (x, y), (x + w, y + h), (255, 255, 255), 4)

    if len(faces) > 0:
        # Resizes image to fit monitor and displayes it
        imOut = cv2.resize(image, (750, 1142))
        # cv2.imshow("Faces found", imS)
        # cv2.waitKey(0)

        # Saves image to output folder and creates folder if it doesnt exist

        # os.chdir('output')
        img_name = "output/out_{}.png".format(c)
        cv2.imwrite(img_name, imOut)

Example output:

enter image description here

Ahmet
  • 7,527
  • 3
  • 23
  • 47
0
images = glob.glob('*.jpg')
for i in images:
    image = cv2.imread(i,1)

#Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
...

What you are doing is: open every image one by one and when you reach the last image, apply the operations on that last image.

This can be easily fixed if you just include all your operations you want to apply on 1 image, all under the first for loop. Watch for the indentation, that's basically what you are doing wrong here.

images = glob.glob('*.jpg')
for i in images:
    image = cv2.imread(i,1)

    #Convert to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    #do all your operations here
S4rt-H4K
  • 109
  • 6
  • Interesting, I wondered if that was the issue and tried it and got this error: Traceback (most recent call last): File "C:\Users\Order Desk 2\Desktop\FaceDetect\Images\face_detect_cv3.py", line 18, in gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.error: OpenCV(3.4.11) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-157r7wnb\opencv\modules\imgproc\src\color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cv::cvtColor' typically I have been getting this when there it cant read the file. Am I giving it images one at a time or all at once? – Tristan.Beer Aug 20 '20 at 18:40
  • Update: With indents it runs the loop once and edits the first photo, then throws the above error (-215 Assertion failed) and stops. – Tristan.Beer Aug 20 '20 at 18:51
  • use the ret parameter of imread and test whether an image was loaded successfully. Skip the loop on e, of not. – Micka Aug 21 '20 at 05:06
  • and you could print i to see which image file gives that problem – Micka Aug 21 '20 at 05:08