0

I would like to binarize a whole folder of images and save them. I've already found a code that binarizes a single image and store it in the same folder:

import cv2
im_gray = cv2.imread('blurredimg1.png', cv2.IMREAD_GRAYSCALE)
(thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
thresh = 127
im_bw = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite('bw_image.png', im_bw)

Here's the output

The image

Here's the file in the folder

Now, I would like to use the threshold on the entire set at once. How can I do so ?

Fred Guth
  • 1,537
  • 1
  • 15
  • 27
Sabrina
  • 11
  • 1
  • 2
  • 1
    You will need to get the list of images and loop over them thresholding them one-by-one inside the loop. Search Google for examples, such as https://www.quora.com/How-can-I-read-multiple-images-in-Python-presented-in-a-folder – fmw42 Mar 24 '20 at 20:55
  • Unfortunately, I couldn't do such a thing I always get errors – Sabrina Mar 24 '20 at 20:57
  • How can I loop over them ? (I've tried and it didn't work) – Sabrina Mar 24 '20 at 20:58
  • You could not do what? Search Google or apply the example I referenced to read multiply images? If the latter, please show your code attempt. Perhaps you have a simple error. – fmw42 Mar 24 '20 at 20:58
  • Here is another link, https://stackoverflow.com/questions/49537604/how-to-read-multiple-images-from-multiple-folders-in-python and https://answers.opencv.org/question/74459/how-to-get-the-multiple-images-as-a-loop/ and https://medium.com/@basit.javed.awan/resizing-multiple-images-and-saving-them-using-opencv-518f385c28d3 – fmw42 Mar 24 '20 at 21:05
  • Here's my attempt – Sabrina Mar 24 '20 at 21:22
  • from glob import glob import cv2 img_mask = r'C:\Users\Bsi\Desktop\PFE\Mine\*.png' img_names = glob(img_mask) for fn in img_names: print('processing %s...' % fn,) im_gray = cv2.imread(fn, 0) (thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) thresh = 127 im_bw = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY)[1] – Sabrina Mar 24 '20 at 21:22
  • The problem I get is that I don't KNOW how to save them ! What should I add in the end ? – Sabrina Mar 24 '20 at 21:23
  • Please post your code into your original question where it is properly formatted and easy to read. – fmw42 Mar 24 '20 at 21:23
  • To save files, use cv2.imwrite('path\file.suffx', bw). See https://docs.opencv.org/4.1.1/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce – fmw42 Mar 24 '20 at 21:25
  • I did but it's only saving ONE file, I want to save ALL of them you see ? – Sabrina Mar 24 '20 at 21:27
  • Why are you thresholding each image twice, once with OTSU and the second at 127? You should do the OTSU one time. The for all the files in the folder, just do the the simple threshold at the value returns from the OTSU thresholding. Put the cv2.imwrite() inside your loop. – fmw42 Mar 24 '20 at 21:28
  • Okay, i've fixed that. Now what about saving the files ? – Sabrina Mar 24 '20 at 21:30
  • If you are using 127 as the threshold, you could do it at once by loading all images as one numpy ndarray and set to 0 whenever the value of the color is bellow 127. – Fred Guth Mar 24 '20 at 23:26

3 Answers3

0

Here it is :

from glob import glob import cv2 img_mask = r'C:\Users\Bsi\Desktop\PFE\Mine\*.png' img_names = glob(img_mask) for fn in img_names: print('processing %s...' % fn,) im_gray = cv2.imread(fn, 0) (thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) thresh = 127 im_bw = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY)[1]

Sabrina
  • 11
  • 1
  • 2
0

The following is tested and works in Unix path syntax on my Mac in Python/OpenCV. And I am not a Windows user. So you will need to modify the paths appropriately for your OS and change my "/" to "\" where they are specifically shown in the paths

You need to define the path to where you want to put the output directory to hold the created images. I used in_dir and out_dir. the out_dir directory needs to exist already.

So something like the following. Where I get the OTSU threshold outside the loop and save the threshold value from your blurred image. Then I loop over all the images in the input directory via your img_mask. I threshold each image using the threshold that was saved and then write the file to disk inside the loop.

from glob import glob
import os
import cv2

# read your one blurred image and convert to gray
im_gray = cv2.imread('test/lena.png', 0)

# threshold it with OTSU thresholding and get the threshold value
thresh, im_bw = cv2.threshold(im_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
print(thresh)

# define the paths to your input images and to where you want to put the output images    
in_dir = 'test'
out_dir = 'test2'

# read the input image file names with paths into a list
infiles = in_dir + '/*.png'
img_names = glob(infiles)
print(img_names)

# loop over each input image in a for loop
for fn in img_names:
    print('processing %s...' % fn)

    # read an input image as gray
    im_gray = cv2.imread(fn, 0)

    # threshold it with your saved threshold
    im_bw = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY)[1]

    # write the result to disk in the previously created output directory
    name = os.path.basename(fn)
    outfile = out_dir + '/' + name
    cv2.imwrite(outfile, im_bw)


fmw42
  • 46,825
  • 10
  • 62
  • 80
  • Doesn,t work : I get an error on the last line :TypeError: Expected Ptr for argument 'img' – Sabrina Mar 24 '20 at 22:04
  • from glob import glob import cv2 img_mask = r'C:\Users\Bsi\Desktop\PFE\Mine\*.png' out_dir = r'C:\Users\Bsi\Desktop\PFE\Mine\NEWDIR' img_names = glob(img_mask) for fn in img_names: print('processing %s...' % fn,) im_gray = cv2.imread(fn, 0) thresh=127 im_gray = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY) cv2.imwrite(r'out_dir\fn', im_gray) – Sabrina Mar 24 '20 at 22:08
  • Just a minute. The formatting of the output_dir/fn is in error. I am correcting and testing. – fmw42 Mar 24 '20 at 22:19
  • Okay ! I'm still waiting for your comment – Sabrina Mar 24 '20 at 22:39
  • Sorry, it took me so long. I had to debug, because I had accidentally left in a back slash (\) in Window syntax and I need a forward slash on my Mac. I also had forgot that your input names include the input directory path and I needed to remove the path to get just the names of the images and write them to the out_dir. See the changed code in my answer. Change your filenames and paths appropriately for your system and OS. – fmw42 Mar 24 '20 at 22:56
  • Thanks a lot ! I did as you said and I got the images in a folder, binarized, thank you man ! – Sabrina Mar 24 '20 at 23:12
  • You are welcome. If this was of help, please consider up-voting my answer. – fmw42 Mar 24 '20 at 23:18
0

You can use two for loops to do so. I was facing the same issue.

for i, val in enumerate(images_gray):
    ret,thresh1 = cv2.threshold(images_gray[i],110,255,cv2.THRESH_BINARY)
    ret,thresh2 = cv2.threshold(images_gray[i],70,255,cv2.THRESH_BINARY_INV)
    ret,thresh3 = cv2.threshold(images_gray[i],127,255,cv2.THRESH_TRUNC)
    ret,thresh4 = cv2.threshold(images_gray[i],77,255,cv2.THRESH_TOZERO)
    ret,thresh5 = cv2.threshold(images_gray[i],127,255,cv2.THRESH_TOZERO_INV)
    titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
    images = [images_gray[i], thresh1, thresh2, thresh3, thresh4, thresh5]
    for k in range(6):
        plt.rcParams["figure.figsize"] = (20,10)
        plt.subplot(45,6,k+1),plt.imshow(images_gray[i],'gray', vmin=0,vmax=255)
        plt.title(titles[k])
        k+=1
    plt.xticks([]),plt.yticks([])
    plt.show()
    i+=1

I made use of 45 images. And wanted to show a 6 threshold comparison.

Dharman
  • 30,962
  • 25
  • 85
  • 135
  • import glob import cv2 import numpy as np images= [cv2.imread(file) for file in glob.glob("C:/Users/st/Image/*.jpg")] – Starcode1619 Feb 23 '22 at 00:36