How to batch rename images in several folders? - image

I have 600 images (e.g. images_0, images_1, images_2, ..., images_599) which are saved in 12 folders (e.g. dataset_1, dataset_2, dataset_3, ..., dataset_12).
I am currently using this code to rename images:
mainDirectory = 'C:\Users\Desktop\data';
subDirectory = dir([mainDirectory '/dataset_*']);
for m = 1 : length(subDirectory)
subFolder = dir(fullfile(mainDirectory, subDirectory(m).name, '*.png'));
fileNames = {subFolder.name};
for iFile = 1 : numel( subFolder )
newName = fullfile(mainDirectory, subDirectory(m).name, sprintf('%00d.png', iFile));
movefile(fullfile(mainDirectory, subDirectory(m).name, fileNames{iFile}), newName);
end
end
This code works well but I want to change the format of newName to the following: number-of-dataset_name-of-image (e.g. 1_images_0, 1_images_1, 2_images_0, 2_images_1, etc.). How can I make this change to newName?

You can first split your folder name to get the 1 to 12 number
str = strsplit('dataset_12', '_'); % split along '_'
The folder number will be in str{2}.
Then concatenate this piece of information with
new_name = [str{2} '_' original_image_name]
where original_image_name is the original image name (!) - or use alternatively sprintfas you already did.

Related

Open csv from subdirectories with partially unknown name and save all csv in one big file

I have a bunch of files in different subfolders of the root folder. I want to open all the files with the name 'NBack' AND '.csv' extension but not containing the letter 'X'. Then I want to add two columns in each files and merge/concatenate all concerned files into one big file.
I created so far this code, but for some reason it runs an eternity and seems to process the same files again and again (but not sure on this point). At the end I don't have a concatenated file but only one single file
for root, folders, files in os.walk(path):
for f in files:
filteredResults = [f for f in files if not "X" in f] #exlude files with the letter 'X'
for ff in filteredResults:
dd = [ff for ff in filteredResults if ff.endswith('.csv')] #among remaining files, keep the .csv files
for g in dd:
r = [g for g in dd if 'NBack' in g] #among those, keep those containing 'NBack'
a = pd.DataFrame() #empty dataset for the new big dataset
for i in r:
o = [i for i in r if not '.pdf' in i] #exclude .pdf's (for some reason including only .csv didn't work well enough).
appended = [] #necessary to append files before concatenating them????
for ii in o: #for the final set of files
p = os.path.join(root, ii)
data = pd.read_csv(p) #open .csv with specified characteristics in each subdirectory
split = ii.split("_") #split file name to get additional information
data['Run']=split[3] #add this information as a new column
data['IDcheck']=split[0] #add this information as a new column
appended.append(data) #necessary to apprend? creates a list of files
a = pd.concat([data]) #should create one big file but the variable a just contains one file
I would be happy for any comment or suggestion what to try.... where is the error...
This code works for me, sharing it if ever someone has a similar question:
os.chdir(r'C:\Users\...')
rootdir = os.getcwd()
paths = []
df = pd.DataFrame()
for root, _, files in os.walk(rootdir):
for f in files:
path = root + "\\" + f
if ".csv" and "NBack" in path and not("X" in path):
splitt = f.split('_')
r = pd.read_csv(path)
r['Run'] = splitt[2]
r['IDcheck'] = splitt[0]
df = pd.concat([df, r])
Thanks Yasir for the help!

PYsimpleGUI create a listbox of folders

I am trying to modify the demoprogram from PYsimpleGUI (Browser_START_HERE_Demo_program_Browser.py) to:
manually select a main folder
list all the subfolders in that folder (but not the files inside them)
make it possible to select a few of those folders, and list them as an output.
I thought I'd do so by editting the code for getting the file list dic, but everything I tried, just makes it
Any ideas? I attached it:
'''def get_file_list_dict():
"""
Returns dictionary of files
Key is short filename
Value is the full filename and path
:return: Dictionary of demo files
:rtype: Dict[str:str]
"""
demo_path = get_demo_path()
demo_files_dict = {}
for dirname, dirnames, filenames in os.walk(demo_path):
for filename in filenames:
if filename.endswith('.py') or filename.endswith('.pyw'):
fname_full = os.path.join(dirname, filename)
if filename not in demo_files_dict.keys():
demo_files_dict[filename] = fname_full
else:
# Allow up to 100 dupicated names. After that, give up
for i in range(1, 100):
new_filename = f'{filename}_{i}'
if new_filename not in demo_files_dict:
demo_files_dict[new_filename] = fname_full
break
return demo_files_dict'''
It's much difficult for me to modify code of Browser_START_HERE_Demo_program_Browser.py to my requirements.
Assume the target is
Select a main directory by a button to call function sg.popup_get_folder
List all subdirectories under main directory in one sg.Listbox
Subdirectories selected shown in another sg.Listbox as output when click Add button
Example Code
from pathlib import Path
import PySimpleGUI as sg
font = ("Courier New", 11)
sg.theme("Dark")
sg.set_options(font=font)
subfolders = []
selected = []
frame_subholders = [[sg.Listbox(subfolders, size=(80, 10), key='Subfolders',
select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED, enable_events=True,
highlight_background_color='blue', highlight_text_color='white')]]
frame_selected = [[sg.Listbox(selected, size=(80, 10), key='Selected')]]
layout = [
[sg.Input(readonly=True, expand_x=True, key='Main',
disabled_readonly_background_color=sg.theme_input_background_color()),
sg.Button("Main Folder")],
[sg.Frame("Subholder", frame_subholders)],
[sg.Frame("Selected subholder", frame_selected)],
[sg.Button('Add')],
]
window = sg.Window('Title', layout, finalize=True)
entry = window['Main'].Widget
input_size = entry.winfo_width()//sg.Text.char_width_in_pixels(font)
print(input_size)
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
elif event == 'Main Folder':
main_folder = sg.popup_get_folder("", no_window=True)
if main_folder and Path(main_folder).is_dir():
main_folder = main_folder.replace("/", '\\') # For Windows
half = input_size//2
text = main_folder if len(main_folder) <= input_size else main_folder[:half-3]+"..."+main_folder[-half:]
window['Main'].update(text)
subfolders = sorted([str(f) for f in Path(main_folder).iterdir() if f.is_dir()])
window['Subfolders'].update(values=subfolders)
selected = []
window['Selected'].update(values=selected)
elif event == 'Add':
selected = sorted([path for path in values['Subfolders']])
window['Selected'].update(values=selected)
window.close()

Batch Commands to find and Replace string

I want batch commands to find and replace string in word file and also renaming that file with same string and that too for a folder.
Multiple files needs to be searched and replaced with string and at the same time file name should be checked also.
There exists no integrated funtction in batch.
Powershell has such functions, but i would consider using fart.exe, which is easier to use.
Here is the link -> http://fart-it.sourceforge.net/
//EDIT: Looks like i have not recognized the "word file".
If thats the case i don't know any possibility to do this with batch/cmd.
Here is a macro script by Allen Wyatt that can do this.
Source
Public Sub MassReplace()
With Application.FileSearch
.LookIn = "C:\" ' where to search
.SearchSubFolders = True ' search the subfolders
.FileName = "*.doc" ' file pattern to match
' if more than one match, execute the following code
If .Execute() > 0 Then
' for each file you find, run this loop
For i = 1 To .FoundFiles.Count
' open the file based on its index position
Documents.Open FileName:=.FoundFiles(i)
' search and replace the address
selection.Find.ClearFormatting
selection.Find.Replacement.ClearFormatting
With selection.Find
.Text = "OldAddress"
.MatchCase = True
.Replacement.Text = "NewAddress"
End With
selection.Find.Execute Replace:=wdReplaceAll
' replace e-mail address
With selection.Find
.Text = "Oldemail"
.Replacement.Text = "Newemail"
End With
selection.Find.Execute Replace:=wdReplaceAll
' save and close the current document
ActiveDocument.Close wdSaveChanges
Next i
Else
' if the system cannot find any files
' with the .doc extension
MsgBox "No files found."
End If
End With
End Sub
Change these 3 lines based on your own needs:
.LookIn = "C:\" ' where to search
.SearchSubFolders = True ' search the subfolders
.FileName = "*.doc" ' file pattern to match
Aside from that, doing this from batch file (specifically because you are talking word documents) is outside of CMD's abilities.

Opening same file names in multiple directories using Ruby

Looking to do the following using Ruby:
Directory A and Directory B will have same number of XML files and also same filenames.
Step 1:
* Go into directory A (directory A has X number of XML files)
* Inside directory A, take the first XML file and save the file name and also open the file
Step 2:
* Go into directory B (directory B will have same number of XML files with the same filenames as directory A)
* Inside directory B, open the same XML filename that was saved and opened in directory A.
Step 3: (I've already completed this part) **
* Compare the two files (I've already completed this part)**
Step 4:
* Repeat this for ALL XML files in both directories.
I've tried a few things, but for some reason the loop is happening for each file and not once, also the second loop for Dir B is not executing:
id_dir = "#{Dir.pwd}"+"/id_responses"
ht_dir = "#{Dir.pwd}"+"/ht_responses"
Dir.foreach(id_dir) do |id_file|
next if id_file == '.' or id_file == '..'
id_file = File.open("#{id_dir}/#{id_file}", 'r')
doc1 = Nokogiri::XML::Document.parse(File.open(id_file))
Dir["#{Dir.pwd}"+"/ht_responses/#{id_file}"].each do |ht_file|
next if id_file == '.' or id_file == '..'
doc2 = Nokogiri::XML::Document.parse(File.open(ht_file))
end
end
No need to loop through the other dir, just see if a file with the same name exists there.
id_dir = "#{Dir.pwd}"+"/id_responses"
ht_dir = "#{Dir.pwd}"+"/ht_responses"
Dir.foreach(id_dir) do |id_file|
next if id_file == '.' or id_file == '..'
id_file_path = File.join(id_dir, id_file)
ht_file_path = File.join(ht_dir, id_file)
next unless File.exist?(ht_file_path)
doc1 = Nokogiri::XML::Document.parse(File.open(id_file_path, 'r'))
doc2 = Nokogiri::XML::Document.parse(File.open(ht_file_path, 'r'))
end

Resizing and saving images on a new directory

I am writing a simple function that reads a sequence of images, re-sizes them and then saves each set of re-sized images to a new folder. Here is my code:
function [ image ] = FrameResize(Folder, ImgType)
Frames = dir([Folder '/' ImgType]);
NumFrames = size(Frames,1);
new_size = 2;
for i = 1 : NumFrames,
image = double(imread([Folder '/' Frames(i).name]));
for j = 2 : 10,
new_size = power(new_size, j);
% Creating a new folder called 'Low-Resolution' on the
% previous directory
mkdir ('.. Low-Resolution');
image = imresize(image, [new_size new_size]);
imwrite(image, 'Low-Resolution');
end
end
end
I have mainly two doubts:
How can I save those images with specific names, like im_1_64, im_2_64, etc. according to the iteration and to the resolution?
How can I make the name of the folder being created change with each iteration so that I save images with the same resolution on the same folder?
Since you know the resolution will be: new_size x new_size, you can use this in the imwrite function:
imwrite(image, ['im_' num2str(i) '_' num2str(new_size) '.' ImgType]);
Assuming that ImgType holds the extension.
To setup the folders you can do something like this:
mkdir(num2str(new_size))
cd(num2str(new_size))
imwrite(image, ['im_' num2str(i) '_' num2str(new_size) '.' ImgType]);
cd ..
You have an answer you are satisfied with, but I strongly suggest doing two things differently:
Use fullfile to create/concatenate file and path names.
For example, instead of:
imread([Folder '/' Frames(i).name])
do
imread(fullfile(Folder,Frames(i).name))
It's good for relative paths too:
fullfile('..','Low-Resolution')
ans =
..\Low-Resolution
Use sprintf to create strings containing numerical data from variables. Instead of:
['im_' num2str(i) '_' num2str(new_size) '.' ImgType]
do
sprintf('im_%d_%d.%s', i, new_size, ImgType)
You can even specify how many digits you want per integer. Compare:
K>> sprintf('im_%d_%d.%s', i, new_size, ImgType)
ans =
im_2_64.png
K>> sprintf('im_%02d_%d.%s', i, new_size, ImgType)
ans =
im_02_64.png

Resources