UnicodeDecodeError issue while looping through all the pictures in a folder using CV2

Viewed 52

My code:

folder_angry = 'C:/Users/User/Desktop/test'
all_vald_img = []
    
for filename_valid in os.listdir(folder_angry):
    img_valid = cv2.imread(os.path.join(folder_angry,filename_valid))
    if img_valid is not None:
        all_vald_img.append(img_valid)

    true_image = image.load_img(img_valid)
    img = image.load_img(img_valid, color_mode="grayscale", target_size=(48, 48))

Error message:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfd in position 1: invalid start byte

I encountered this error while looping through the entire folder of pictures using cv2.imread. I've tried solutions like

with open(path, 'rb') as f:
  contents = f.read()

or any other solutions start with with open like many people suggested, but none of them really works. However, if I use picture one by one without loop, like

filename_valid = "path"
true_image = image.load_img(filename_valid)
img = image.load_img(filename_valid, color_mode="grayscale", target_size=(48, 48))

it works, but I have to do it one by one.

Is there any good way to tackle this down?

1 Answers

You are getting the error because you are passing the image itself (as NumPy array) to image.load_img, while image.load_img expects an image file name as argument.

Basically you are trying to read each image twice:

  • Using OpenCV:
    cv2.imread returns an image (as NumPy array) in case of successful reading, and return None when reading fails.

  • Using Pillow:
    image.load_img(file_name) loads the image using Pillow, and returns an object of type PIL.Image.Image.

The issue is that image.load_img expects a file name as an argument, and you are passing it an image (NumPy array) instead of file name.
The NumPy array is not a valid 'utf-8' string, so you are getting the error:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfd in position 1: invalid start byte.


Assuming that reading each image twice is not an issue...
You may use something like the following code sample:

import os
import cv2
from keras.preprocessing import image


folder_angry = 'C:/Users/User/Desktop/test'
all_vald_img = []
all_vald_img_files = []
    
for filename_valid in os.listdir(folder_angry):
    image_file_name = os.path.join(folder_angry,filename_valid)
    img0 = cv2.imread(image_file_name)  # Return the image as NumPy array in case of valid reading, and None if not valid.
    if img0 is not None:
        all_vald_img_files.append(image_file_name)  # Append file name to the list (not the image).

        true_image = image.load_img(image_file_name)  # Use file name as argument to image.load_img
        img = image.load_img(image_file_name, color_mode="grayscale", target_size=(48, 48))
        all_vald_img.append(img)

# Showing images in all_vald_img for testing:
for img in all_vald_img:
    img.show()

Note: I was guessing that you want to keep only the images loaded by image.load_img.

Related