Home > Enterprise >  How to loop through a folder of subfolders and read the images inside each subfolder?
How to loop through a folder of subfolders and read the images inside each subfolder?

Time:10-06

Currently, I have a python program that is able to run without error. However, it is only able to run through a subfolder of images and extract the x, y, z coordinates of the 468 facial landmarks in each image. I want to edit it as such that the program will loop through the many subfolders and read the many images inside each subfolder. What needs to be stated in the "path" function and what needs to be edited in my code stated below? The folder is named as "nopain" and the subfolders are named as "1, 2, 3, etc..."

**import os
import cv2
import mediapipe as mp
import time
from os import listdir
import matplotlib.pyplot as plt
from pathlib import Path
import glob
import numpy
path = glob.glob("C:/Users/Downloads/Mac master DB_no overlap/nopain/1/*.png")
fh = open('out.txt', 'w')
for file in path:
    img = cv2.imread(file)
    mpDraw = mp.solutions.drawing_utils
    mpFaceMesh = mp.solutions.face_mesh
    facemesh = mpFaceMesh.FaceMesh(max_num_faces=1)
    drawSpec = mpDraw.DrawingSpec(thickness=1, circle_radius=2)
    rgb_image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    result = facemesh.process(rgb_image)
    if result.multi_face_landmarks:
        for faceLms in result.multi_face_landmarks:
            mpDraw.draw_landmarks(img, faceLms, mpFaceMesh.FACEMESH_CONTOURS,
            drawSpec, drawSpec)
            for lm in faceLms.landmark:
                print(lm, file, file = fh)
cv2.imshow("image", img)
cv2.destroyAllWindows()
fh.close()**

CodePudding user response:

You need a recursive glob as follows. Note the double asterisk

path = glob.glob("C:/Users/Downloads/Mac master DB_no overlap/nopain/**/*.png", recursive=True)

CodePudding user response:

Checkout the pathlib module https://docs.python.org/3/library/pathlib.html

This should work:

import pathlib
path = pathlib.Path("C:/Users/Downloads/Mac master DB_no overlap/nopain").rglob("*.png")

For example I am using bash to generate some dummy directories and files to show how it works..

$ mkdir -p {1,2,3,4}/dir{1,2,3}
$ touch {1,2,3,4}/dir{1,2,3}/img.png
$ touch {1,2,3,4}/img1.png
$ tree
.
├── 1
│   ├── dir1
│   │   └── img.png
│   ├── dir2
│   │   └── img.png
│   ├── dir3
│   │   └── img.png
│   └── img1.png
├── 2
│   ├── dir1
│   │   └── img.png
│   ├── dir2
│   │   └── img.png
│   ├── dir3
│   │   └── img.png
│   └── img1.png
├── 3
│   ├── dir1
│   │   └── img.png
│   ├── dir2
│   │   └── img.png
│   ├── dir3
│   │   └── img.png
│   └── img1.png
└── 4
    ├── dir1
    │   └── img.png
    ├── dir2
    │   └── img.png
    ├── dir3
    │   └── img.png
    └── img1.png

Here is the output using the pathlib module:

>>> import pathlib
>>> for p in pathlib.Path("./").rglob("*.png"):
...     print(p)
...
2/img1.png
2/dir3/img.png
2/dir1/img.png
2/dir2/img.png
1/img1.png
1/dir3/img.png
1/dir1/img.png
1/dir2/img.png
3/img1.png
3/dir3/img.png
3/dir1/img.png
3/dir2/img.png
4/img1.png
4/dir3/img.png
4/dir1/img.png
4/dir2/img.png

CodePudding user response:

Instead of using a recursive glob as others have suggested, I would recommend using the following code so that you have access to the name of the subfolder currently being processed - which will likely be useful for you to name the output files with the landmarks.

base_path = Path("C:/Users/Downloads/Mac master DB_no overlap/nopain")
subfolders = [item for item in base_path.iterdir() if item.is_dir()]
for subfolder in subfolders:
    fh = open(f'out_{str(subfolder)}.txt', 'w')
    for file in subfolder.glob("*.png"):
        img = cv2.imread(file)
        mpDraw = mp.solutions.drawing_utils
        mpFaceMesh = mp.solutions.face_mesh
        facemesh = mpFaceMesh.FaceMesh(max_num_faces=1)
        drawSpec = mpDraw.DrawingSpec(thickness=1, circle_radius=2)
        rgb_image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        result = facemesh.process(rgb_image)
        if result.multi_face_landmarks:
            for faceLms in result.multi_face_landmarks:
                mpDraw.draw_landmarks(img, faceLms, mpFaceMesh.FACEMESH_CONTOURS,
                drawSpec, drawSpec)
                for lm in faceLms.landmark:
                    print(lm, file, file = fh)
    cv2.imshow("image", img)
    cv2.destroyAllWindows()
    fh.close()

With this code, the output files with landmarks will be named appropriately: e.g., out_1.txt for subfolder 1, out_2.txt for subfolder 2, etc.

You can also save out.txt to the subfolder itself. Since subfolder is a pathlib.Path object, use fh = open(str(subfolder / 'out.txt'), 'w').

  • Related