ferrelwill
ferrelwill

Reputation: 821

Can not copy files to a new directory - TypeError: os.PathLike object

I am iterating through files in a folder (input) and do some operation and save the results to new files in a new folder (output). However, ending up with this error.

Error

Traceback (most recent call last):
  File "mask_class_modifier.py", line 28, in <module>
    shutil.copy(x, new_mask_dir)
  File "/Users/g/miniconda2/lib/python3.6/shutil.py", line 244, in copy
    dst = os.path.join(dst, os.path.basename(src))
  File "/Users/g/miniconda2/lib/python3.6/posixpath.py", line 146, in basename
    p = os.fspath(p)
TypeError: expected str, bytes or os.PathLike object, not tuple

code

import sys
import os
from PIL import Image
import shutil
import numpy as np

mask_dir = "input/"
new_mask_dir = "output/"

# change the class number of masks in each image
results1 = []

for filename in os.scandir(mask_dir):
    if filename.path.endswith(".png"):
        image = Image.open(filename.path)
        mask = np.array(image)
        mask[mask==3] = 50, 
        mask[mask==4] = 51
        results1.append((filename.path, mask))

# copies files with masks to a new directory
for x in results1:
    shutil.copy(x, new_mask_dir)

Reproducible code

mask1 = Image.open(urlopen('https://user-images.githubusercontent.com/3885659/78411130-24eee380-75fe-11ea-831c-84ca2eae82ac.png'))
mask2 = Image.open(urlopen('https://user-images.githubusercontent.com/3885659/78411130-24eee380-75fe-11ea-831c-84ca2eae82ac.png'))
mask3 = Image.open(urlopen('https://user-images.githubusercontent.com/3885659/78411130-24eee380-75fe-11ea-831c-84ca2eae82ac.png'))

masks_list = [mask1, mask2, mask3]

new_masks=[]

for x in masks_list:
  mask = np.array(x)
  mask[mask==3] = 50, 
  mask[mask==4] = 51
  new_masks.append(mask)

Upvotes: 1

Views: 228

Answers (2)

Ollie in PGH
Ollie in PGH

Reputation: 2629

I think this is what you're trying to do. You were not saving the original image with the new mask and shutil does not save the mask to a new file either. append only adds a value to the end of a list. If you're trying to save the image with the new mask try the code below. In this instance, I've used a file name as a key in a dictionary, but you can just use the original file name.

import sys
import os
from PIL import Image
import shutil
import numpy as np

mask_dir = "input/"
new_mask_dir = "output/"

if not os.path.exists(new_mask_dir):
    os.mkdir(new_mask_dir)

for filename in os.scandir(mask_dir):
    if filename.path.endswith(".png"):
        image = Image.open(filename.path)
        mask = np.array(image)
        mask[mask == 3] = 50
        mask[mask == 4] = 51
        masked_img = Image.fromarray(mask)
        new_img_path = os.path.join(new_mask_dir, filename.name)
        masked_img.save(new_img_path)

Upvotes: 1

incarnadine
incarnadine

Reputation: 700

The problem here is this line results1.append((filename.path, mask)). The use of double brackets means you are adding a tuple to the list results1. When you then iterate over that list, x becomes a tuple and the shutil.copy function cannot take a tuple as it's first parameter.

To fix your error, remove the , mask in the results1.append line. You don't need to add the mask to the list, because you aren't using it later. Removing this, stops this being a tuple and means the function will work as expected when copying.

Another solution, allowing you to retain the presence of the mask in the list would be to add [0] after the x in the copy function call to specify that you are wanting to use the first item in the tuple (the filepath).

If you want to save the new image instead of making a copy, change the final line to be Image.fromarray(x[1]).save(new_mask_dir+x[0]), which saves the new image as the new file. When doing this, ensure the results1.append line is exactly as it was before this answer, when it was giving you an error (it won't anymore)

Upvotes: 2

Related Questions