'How can I save my processed images in an output folder to be as sorted as they are in the input folder?

I tried to get the edges of some images and output them in a separate folder, but the output files do not correspond to the input files. Please, how can I correct this?

Below is my code:

import glob
import cv2
import os

in_path = "E:\\datasets\\malayakew\\b\\*.jpg"

out_path = "E:\\datasets\\malayakew\\a\\"

cv_img = []

img_path = sorted(glob.glob(in_path))

for i, img in enumerate(img_path):
    n= cv2.imread(img)
    cv_img.append(n)
          
    gray = cv2.cvtColor(n, cv2.COLOR_BGR2GRAY)

    edge = cv2.Canny(gray, 255, 255)
      
    cv2.imwrite(out_path + f'{str(i+1)}.jpg', edge)
    
    cv2.destroyAllWindows()

The code runs without an error, however, most of the output images do not correspond with the input images. Here are samples of the result:

original images

output images



Solution 1:[1]

You're hoping that by sorting the list of paths in glob.glob(in_path) and then using enumerate, the indices will match the numbers in the filenames.

This is dubious. In particular, you're trying to sort a list of strings which contain numbers. Try the following experiment:

print(sorted(map(str, range(14))))
# ['0', '1', '10', '11', '12', '13', '2', '3', '4', '5', '6', '7', '8', '9']

Note how all numbers which begin with the digit '1' appear before all numbers which begin with the digit '2'. In particular, 10 appears before 2.

Now, there are tricks to sort strings that contain numbers. But this is not what you need. What you need is to not sort at all, and not use enumerate at all. Don't try to guess the numbers from the sorting. Instead, just copy the filenames. You can use os.path.split to extract the filename from the path of the input file, then use os.path.join to rebuild the path of the output file.

img_paths = sorted(glob.glob(in_path))

for img_path in img_paths:
    n = cv2.imread(img_path)
    cv_imgs.append(n)
    gray = cv2.cvtColor(n, cv2.COLOR_BGR2GRAY)
    edge = cv2.Canny(gray, 255, 255)
    _, img_filename = os.path.split(img_path)
    cv2.imwrite(os.path.join(out_path, img_filename), edge)
    cv2.destroyAllWindows()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Stef