I wrote a code to remove the background of 8000 images but that whole code is taking approximately 8 hours to give the result.
How to improve its time complexity as I have to work on a large dataset in future?
Or do I have to write a whole new code? If it is, please suggest some sample codes.
from rembg import remove
import cv2
import glob
for img in glob.glob('../images/*.jpg'):
a = img.split('../images/')
a1 = a[1].split('.jpg')
try:
cv_img = cv2.imread(img)
output = remove(cv_img)
except:
continue
cv2.imwrite('../output image/' + str(a1[0]) + '.png', output)
One simple approach would be to divide the work into multiple threads. See ThreadPoolExecutor for more.
You can play around with max_workers= to see what get's the best results. Note that max-workers can be any number between 1 and 32.
This sample code is ready to run. It assumes the image files are in the same directory as your main.py and the output_image directory exits.
import cv2
import rembg
import sys
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
out_dir = Path("output_image")
in_dir = Path(".")
def is_image(absolute_path: Path):
return absolute_path.is_file and str(absolute_path).endswith('.png')
input_filenames = [p for p in filter(is_image, Path(in_dir).iterdir())]
def process_image(in_dir):
try:
image = cv2.imread(str(in_dir))
if image is None or not image.data:
raise cv2.error("read failed")
output = rembg.remove(image)
in_dir = out_dir / in_dir.with_suffix(".png").name
cv2.imwrite(str(in_dir), output)
except Exception as e:
print(f"{in_dir}: {e}", file=sys.stderr)
executor = ThreadPoolExecutor(max_workers=4)
for result in executor.map(process_image, input_filenames):
print(f"Processing image: {result}")
Check out the U^2Net repository. Like u2net_test.py, Writing your own remove function and using dataloaders can speed up the process. if it is not necessary skip the alpha matting else you can add the alpha matting code from rembg.
def main():
# --------- 1. get image path and name ---------
model_name='u2net'#u2netp
image_dir = os.path.join(os.getcwd(), 'test_data', 'test_images')
prediction_dir = os.path.join(os.getcwd(), 'test_data', model_name + '_results' + os.sep)
model_dir = os.path.join(os.getcwd(), 'saved_models', model_name, model_name + '.pth')
img_name_list = glob.glob(image_dir + os.sep + '*')
print(img_name_list)
#1. dataloader
test_salobj_dataset = SalObjDataset(img_name_list = img_name_list,
lbl_name_list = [],
transform=transforms.Compose([RescaleT(320),
ToTensorLab(flag=0)])
)
test_salobj_dataloader = DataLoader(test_salobj_dataset,
batch_size=1,
shuffle=False,
num_workers=1)
for i_test, data_test in enumerate(test_salobj_dataloader):
print("inferencing:",img_name_list[i_test].split(os.sep)[-1])
inputs_test = data_test['image']
inputs_test = inputs_test.type(torch.FloatTensor)
if torch.cuda.is_available():
inputs_test = Variable(inputs_test.cuda())
else:
inputs_test = Variable(inputs_test)
d1,d2,d3,d4,d5,d6,d7= net(inputs_test)
# normalization
pred = d1[:,0,:,:]
pred = normPRED(pred)
# save results to test_results folder
if not os.path.exists(prediction_dir):
os.makedirs(prediction_dir, exist_ok=True)
save_output(img_name_list[i_test],pred,prediction_dir)
del d1,d2,d3,d4,d5,d6,d7
Try to use parallelization with multiprocessing like Mark Setchell mentioned in his comment. I rewrote your code according to Method 8 from here. Multiprocessing should speed up your execution time. I did not test the code, try if it works.
import glob
from multiprocessing import Pool
import cv2
from rembg import remove
def remove_background(filename):
a = filename.split("../images/")
a1 = a[1].split(".jpg")
try:
cv_img = cv2.imread(filename)
output = remove(cv_img)
except:
continue
cv2.imwrite("../output image/" + str(a1[0]) + ".png", output)
files = glob.glob("../images/*.jpg")
pool = Pool(8)
results = pool.map(remove_background, files)
Ah, you used the example from https://github.com/danielgatis/rembg#usage-as-a-library as template for your code. Maybe try the other example with PIL image instead of OpenCV. The latter is mostly less fast, but who knows. Try it with maybe 10 images and compare execution time.
Here is your code using PIL instead of OpenCV. Not tested.
import glob
from PIL import Image
from rembg import remove
for img in glob.glob("../images/*.jpg"):
a = img.split("../images/")
a1 = a[1].split(".jpg")
try:
cv_img = Image.open(img)
output = remove(cv_img)
except:
continue
output.save("../output image/" + str(a1[0]) + ".png")
Related
I have 180 .nii fMRI images for each patient and I need to flip them from right to left. I've tried using 'for' statement to batch processing these images. But it seems like The following code only produce one result.
Here is the following code:
import nibabel as nib
import numpy as np
import os
NII_DIR='/Users/lena/testtest'
def get_filelist(dir, Filelist):
if os.path.isdir(dir):
for s in os.listdir(dir):
newDir = os.path.join(dir, s)
Filelist.append(newDir)
return Filelist
list = get_filelist(NII_DIR, [])
print(len(list))
type(list)
for i in list:
def read_nii_file1(nii_path):
nii_img=nib.load(nii_path)
return nii_img
nii_img=read_nii_file1(os.path.join(i))
from nilearn.image import new_img_like
print(nii_img.affine.shape)
print(nii_img.affine)
def flip_image(image, axis):
try:
new_data = np.copy(image.get_fdata())
for axis_index in axis:
new_data = np.flip(new_data, axis=axis_index)
except TypeError:
new_data = np.flip(image.get_fdata(), axis=axis)
return new_img_like(image, data=new_data)
new_image = flip_image(nii_img, axis=[0])
affine = new_image.affine.copy()
hdr = new_image.header.copy()
new_data = new_image.get_fdata()
new_nii = nib.Nifti1Image(new_data, affine, hdr)
#the following is the part I have no idea how to write
New_NII_DIR = ('/Users/lena/test_new/001.nii')
nib.save(new_nii, New_NII_DIR)
[here is the example of my data, including 180 phases][1]
[1]: https://i.stack.imgur.com/wDh34.png
I am using this library midi2img to generate midi from images
From this library, this is the file am using:
from PIL import Image
import numpy as np
from music21 import instrument, note, chord, stream
lowerBoundNote = 21
def column2notes(column):
notes = []
for i in range(len(column)):
if column[i] > 255/2:
notes.append(i+lowerBoundNote)
return notes
resolution = 0.25
def updateNotes(newNotes,prevNotes):
res = {}
for note in newNotes:
if note in prevNotes:
res[note] = prevNotes[note] + resolution
else:
res[note] = resolution
return res
def image2midi(image_path):
with Image.open(image_path) as image:
im_arr = np.fromstring(image.tobytes(), dtype=np.uint8)
try:
im_arr = im_arr.reshape((image.size[1], image.size[0]))
except:
im_arr = im_arr.reshape((image.size[1], image.size[0],3))
im_arr = np.dot(im_arr, [0.33, 0.33, 0.33])
""" convert the output from the prediction to notes and create a midi file
from the notes """
offset = 0
output_notes = []
# create note and chord objects based on the values generated by the model
prev_notes = updateNotes(im_arr.T[0,:],{})
for column in im_arr.T[1:,:]:
notes = column2notes(column)
# pattern is a chord
notes_in_chord = notes
old_notes = prev_notes.keys()
for old_note in old_notes:
if not old_note in notes_in_chord:
new_note = note.Note(old_note,quarterLength=prev_notes[old_note])
new_note.storedInstrument = instrument.Piano()
if offset - prev_notes[old_note] >= 0:
new_note.offset = offset - prev_notes[old_note]
output_notes.append(new_note)
elif offset == 0:
new_note.offset = offset
output_notes.append(new_note)
else:
print(offset,prev_notes[old_note],old_note)
prev_notes = updateNotes(notes_in_chord,prev_notes)
# increase offset each iteration so that notes do not stack
offset += resolution
for old_note in prev_notes.keys():
new_note = note.Note(old_note,quarterLength=prev_notes[old_note])
new_note.storedInstrument = instrument.Piano()
new_note.offset = offset - prev_notes[old_note]
output_notes.append(new_note)
prev_notes = updateNotes(notes_in_chord,prev_notes)
midi_stream = stream.Stream(output_notes)
midi_stream.write('midi', fp=image_path.split("/")[-1].replace(".jpeg",".mid"))
import sys
image_path = sys.argv[1]
image2midi(image_path)
and this is the code I execute in terminal to geneate midi from image:
python img2midi.py samples/image.png
I need to make the above code to loop over all input images I put inside samples folder and generate midi for each, not just one file at a time.
Any help would be much appreciated.
You can do this by getting list of images from directory and iterate over them.
import sys
import os
sample_folder_path = sys.argv[1]
images = os.listdir(sample_folder_path) # getting all images stored in sample folder
images_path = [os.path.abspath(f"{sample_folder_path}/{image}") for image in images] # gets absolute path for all images
for image_path in images_path:
image2midi(image_path)
Usage:
python img2midi.py folder_path
Here folder_path is the path of folder that contains images. It can
There is no problem without multiprocessing.
Using multiprocessing alone causes path problems.
No matter how hard I search, I can't find the answer to the content, so I ask for help
import numpy as np
import tensorflow as tf
import pandas as pd
from keras.preprocessing.image import array_to_img, img_to_array, load_img
import time
from multiprocessing import Pool
def b(path):
for f in path:
print (f)
new_img = load_img(f,target_size=(256,256))
arr_img = img_to_array(new_img)
return arr_img
def main():
start = int(time.time())
num_cores = 4
pool = Pool(num_cores)
pool.map(b, 'C:\\Users\\003.png')
print("***run time(sec) :", int(time.time()) - start)
if __name__ == "__main__":
main()
Error message
load_img
with open(path, 'rb') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'C'
The error message is the same even if it is put as a variable as follows.
def main():
start = int(time.time())
num_cores = 4
pool = Pool(num_cores)
bb = 'C:\\Users\\003.png'
pool.map(b, bb)
print("***run time(sec) :", int(time.time()) - start)
this piece of code has the problem.
pool.map(b, 'C:\\Users\\003.png')
you are using map, the first parameter is a function(which is okay for you), and the second need to be iterable, so it need to be like(a list for example) ['C:\\Users\\003.png']
because you gave it like 'C:\\Users\\003.png' map is trying to iterate it like C , then :\ and so on. which is throwing the error. so please change your code to (i.e a list)
pool.map(b, ['C:\\Users\\003.png'])
So far I have been able to ''manually'' process images by replacing 'picture' in
photo = ''directory/picture.jpg''
for every image I'm processing.
This is effective, sure, but it's very slow.
any ideas?
The code i'm using:
from deepdreamer import model, load_image, recursive_optimize
import numpy as np
import PIL.Image
layer_tensor = ...
photo = "directory/picture.jpg"
img_result = load_image(filename='{}'.format(photo))
img_result = recursive_optimize(...)
img_result = np.clip(img_result, 0.0, 255.0)
img_result = img_result.astype(np.uint8)
result = PIL.Image.fromarray(img_result, mode='RGB')
result.save(photo)
Assuming all image files are in the same folder/directory, you can:
Encapsulate your image processing into a function.
Find all the filenames using os.listdir().
Loop over the filenames, passing each into the imageProcessing()
function which takes action on each image.
Python Code:
from deepdreamer import model, load_image, recursive_optimize
import numpy as np
import PIL.Image
import os //for file management stuff
layer_tensor = ...
def imageProcess(aFile):
photo = "directory/{aFile}"
img_result = load_image(filename='{}'.format(photo))
img_result = recursive_optimize(...)
img_result = np.clip(img_result, 0.0, 255.0)
img_result = img_result.astype(np.uint8)
result = PIL.Image.fromarray(img_result, mode='RGB')
result.save(photo)
for filename in os.listdir('dirname'):
imageProcess(filename)
It'll be something like this. Let me know how that works, I didn't run the code.
Am trying to put a timelapse on my OpenCV code but it seems i am doing something that is not right and i don't know why i have the error.
The erorr i got is for this line: filename = f"{timelapse_img_dir}/{i}.jpg" What should i do in order not to have an error?
This is the error i have from my IDE:
File "/Users/Dropbox/OpenCV/src/timelapse.py", line 34
filename = f"{timelapse}/{i}.jpg"
^
SyntaxError: invalid syntax
[Finished in 0.1s with exit code 1]
[shell_cmd: python -u "/Users/Dropbox/OpenCV/src/timelapse.py"]
[dir: /Users/Dropbox/OpenCV/src]
[path: /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin]
My code:
import os
import numpy as np
import cv2
import time
import datetime
from utils import CFEVideoConf, image_resize
import glob
cap = cv2.VideoCapture(0)
frames_per_seconds = 20
save_path='saved-media/timelapse.mp4'
config = CFEVideoConf(cap, filepath=save_path, res='720p')
out = cv2.VideoWriter(save_path, config.video_type, frames_per_seconds, config.dims)
timelapse_img_dir = '/Users/Dropbox/OpenCV/src/images/timelapse/'
seconds_duration = 20
seconds_between_shots = .25
if not os.path.exists(timelapse_img_dir):
os.mkdir(timelapse_img_dir)
now = datetime.datetime.now()
finish_time = now + datetime.timedelta(seconds=seconds_duration)
i = 0
while datetime.datetime.now() < finish_time:
'''
Ensure that the current time is still less
than the preset finish time
'''
ret, frame = cap.read()
# filename = f"{timelapse_img_dir}/{i}.jpg"
filename = f"{timelapse_img_dir}/{i}.jpg"
i += 1
cv2.imwrite(filename, frame)
time.sleep(seconds_between_shots)
if cv2.waitKey(20) & 0xFF == ord('q'):
break
def images_to_video(out, image_dir, clear_images=True):
image_list = glob.glob(f"{image_dir}/*.jpg")
sorted_images = sorted(image_list, key=os.path.getmtime)
for file in sorted_images:
image_frame = cv2.imread(file)
out.write(image_frame)
if clear_images:
'''
Remove stored timelapse images
'''
for file in image_list:
os.remove(file)
images_to_video(out, timelapse_img_dir)
# When everything done, release the capture
cap.release()
out.release()
cv2.destroyAllWindows()
I believe the format you are using is only supported on python 3.6 "Literal String Interpolation":
https://www.python.org/dev/peps/pep-0498/#raw-f-strings
filename = f"{timelapse_img_dir}/{i}.jpg"
here are 2 other options depends on what python you are using:
python 2.7:
filename = '%(timelapse_img_dir)s %(i)s' % locals()
python 3+
filename = '{timelapse_img_dir} {i}'.format(**locals())
Based on:
https://pyformat.info/
I dont know why i was not able to use the f function. I had to do another concatenation to work.
filename = timelapse_img_dir +str(i) +file_format
and for the rest i used the wild card
filetomake = image_dir + "/*.jpg"
image_list = glob.glob(filetomake)