Matlab move multiple files in a directory - matlab

Using Matlab, I want to move the images present in the same directory in two new directories according to their name.
In the directory there are two set of image' name: 'neg-0.pgm', 'neg-1.pgm', 'neg-2.pgm', ... and 'pos-0.pgm', 'pos-1.pgm', 'pos-2.pgm', ...
I tried different functions to change the image directory but I wasn't able to make the operation successfully.
My code is:
if not(exist('./CarDataset/TrainImages/PosImages', 'dir'))
mkdir ./CarDataset/TrainImages PosImages
end
if not(exist('./CarDataset/TrainImages/NegImages', 'dir'))
mkdir ./CarDataset/TrainImages NegImages
end
trainIm = dir('./CarDataset/TrainImages/*.pgm');
for i = 1:size(trainIm, 1)
if(strcmp(trainIm(i).name, 'neg*.pgm'))
save(fullfile('./CarDataset/TrainImages/NegImages', ['neg-' num2str(i) '.pgm']))
end
end
I don't get any error but the new directories are still empty.

I believe there are two issues going on:
1 - using strcmp in the if statement with a wildcard (*) may not work properly
2 - use movefile instead of save.
https://www.mathworks.com/help/matlab/ref/movefile.html
See below code (use after you have made the new directories):
origDir = './CarDataset/TrainImages/';
trainIm = dir([origDir '*.pgm']);
for i = 1:size(trainIm, 1)
origFile = trainIm(i).name;
if contains(trainIm(i).name, 'neg'))
newDir = './CarDataset/TrainImages/NegImages/';
else
newDir = './CarDataset/TrainImages/PosImages/';
end
movefile([origDir trainIm(i).name], newDir);
end

Related

get 'Documents' path in Matlab

I understand you can probably use the following code to get the job done in most cases:
mydocpath = fullfile(getenv('USERPROFILE'), 'Documents');
However, if the user has moved 'Doucments' folder to a different location, for example: E:\Documents, the above code won't work, since getenv('USERPROFILE') always returns C:\Users\MY_USER_NAME.
In C#, one can use Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), which always returns the correct path regardless where 'Documents' is. Is there anything similar in Matlab?
My current solution is rather clumsy and probably unsafe:
% search in the MATLAB path lists
% this method assumes that there is always a path containing \Documents\MATLAB registered already
searchPtn = '\Documents\MATLAB';
pathList = strsplit(path,';');
strIdx = strfind(pathList, searchPtn);
candidateIdx = strIdx{find(cellfun(#isempty,strIdx)==0, 1)}(1);
myDocPath = pathList{candidateIdx}(1 : strIdx{candidateIdx}+ numel(searchPtn));
Based on #excaza 's suggestion, I came up with a solution using dos and the cmd command found here to query the registry.
% query the registry
[~,res]=dos('reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Personal');
% parse result
res = strsplit(res, ' ');
myDocPath = strtrim(res{numel(res)});
Edit:
If the document folder in customer's PC has not been relocated or moved to one of the environment path such as %SYSTEMROOT%, the above method would return
%SOME_ENVIRONMENT_PATH%/Documents(Or a custom folder name)
The above path will not work in Matlab's functions such as mkdir or exist, which will take %SOME_ENVIRONMENT_PATH% as a folder name. Therefore we need to check for the existence of environment path in the return value and get the correct path:
[startidx, endidx] = regexp(myDocPath,'%[A-Z]+%');
if ~isempty(startidx)
myDocPath = fullfile(getenv(myDocPath(startidx(1)+1:endidx(1)-1)), myDocPath(endidx(1)+1:end));
end
Full code:
% query the registry
[~,res]=dos('reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Personal');
% parse result
res = strsplit(res, ' ');
% get path
myDocPath = strtrim(res{numel(res)});
% if it returns %AAAAA%/xxxx, meaning the Documents folder is
% in some environment path.
[startidx, endidx] = regexp(myDocPath,'%[A-Z]+%');
if ~isempty(startidx)
myDocPath = fullfile(getenv(myDocPath(startidx(1)+1:endidx(1)-1)), myDocPath(endidx(1)+1:end));
end

Check for existence of array of files

I have a cell array containing file names. I want to check for the existence of all of these files in the subject folder, and if any one does not exist I wish to send a continue to the top-most for-loop (see mock code). Is there a way to do this in a one or two liner, instead of 1) using a for-loop and a double if-statement, or 2) building a function that for-loops over exist().
subjects = {'/data/subject01','/data/subject02','/data/subject03'};
files = {'a.txt','b.txt','c.txt'};
for ii = 1:numel(subjects)
for jj = 1:numel(files)
fileExists = exist([subject{ii} '/' file{jj}],'file')
if ~fileExists
continue
end
end
if ~fileExists
continue
end
% Some code to execute if all files exist.
end
The *fun functions are just loops internally and are generally slower than the explicit loop. They also very often unnecessarily obfuscate the intent and behavior of the code.
You can use ismember with all and dir to make the approach clearer and remove the unnecessary loop:
subjects = {'./data/subject01','./data/subject02'};
files = {'a.txt','b.txt','c.txt'};
for ii = 1:numel(subjects)
filelist = dir(fullfile(subjects{ii}, '*.txt'));
foundfilenames = {filelist(:).name};
if all(ismember(files, foundfilenames))
fprintf('All %u files are here: %s\n', numel(files), subjects{ii})
else
fprintf('All %u files are not here: %s\n', numel(files), subjects{ii})
end
end
With my folder structure:
/data
/subject01
a.txt
b.txt
/subject02
a.txt
b.txt
c.txt
I see the following, as expected:
All 3 files are not here: ./data/subject01
All 3 files are here: ./data/subject02
You could remove the loop by iterating over all combinations of the two arrays:
subjects = {'/data/subject01','/data/subject02','/data/subject03'};
files = {'a.txt','b.txt','c.txt'};
a=numel(subjects);
b=numel(files);
k=a*b;
paths = arrayfun(#(ii)[subjects{mod(ii-1,a)+1} '/' files{ceil(ii/b)}],1:k,'uniformoutput',0);
checkExist = cellfun(#exist, paths, repmat({'file'},1,k));
if all(checkExist)
% Some code to execute if all files exist
end
Resolved it with a cellfun and by string arrays. Technically there is still a for-loop but it resolves the double if-statement. I will leave this question open for better solutions.
subjects = {'/data/subject01','/data/subject02','/data/subject03'};
files = string({'a.txt','b.txt','c.txt'});
for ii = 1:numel(subjects)
paths = subject{ii} + files;
checkExist = cellfun(#exist, cellstr(paths), repmat({'file'},size(paths))
if ~all(checkExist(:))
continue
end
% Some code to execute if all files exist.
end

MATLAB dir without '.' and '..'

the function dir returns an array like
.
..
Folder1
Folder2
and every time I have to get rid of the first 2 items, with methods like :
for i=1:numel(folders)
foldername = folders(i).name;
if foldername(1) == '.' % do nothing
continue;
end
do_something(foldername)
end
and with nested loops it can result in a lot of repeated code.
So can I avoid these "folders" by an easier way?
Thanks for any help!
Edit:
Lately I have been dealing with this issue more simply, like this :
for i=3:numel(folders)
do_something(folders(i).name)
end
simply disregarding the first two items.
BUT, pay attention to #Jubobs' answer. Be careful for folder names that start with a nasty character that have a smaller ASCII value than .. Then the second method will fail. Also, if it starts with a ., then the first method will fail :)
So either make sure you have nice folder names and use one of my simple solutions, or use #Jubobs' solution to make sure.
A loop-less solution:
d=dir;
d=d(~ismember({d.name},{'.','..'}));
TL; DR
Scroll to the bottom of my answer for a function that lists directory contents except . and ...
Detailed answer
The . and .. entries correspond to the current folder and the parent folder, respectively. In *nix shells, you can use commands like ls -lA to list everything but . and ... Sadly, MATLAB's dir doesn't offer this functionality.
However, all is not lost. The elements of the output struct array returned by the dir function are actually ordered in lexicographical order based on the name field. This means that, if your current MATLAB folder contains files/folders that start by any character of ASCII code point smaller than that of the full stop (46, in decimal), then . and .. willl not correspond to the first two elements of that struct array.
Here is an illustrative example: if your current MATLAB folder has the following structure (!hello and 'world being either files or folders),
.
├── !hello
└── 'world
then you get this
>> f = dir;
>> for k = 1 : length(f), disp(f(k).name), end
!hello
'world
.
..
Why are . and .. not the first two entries, here? Because both the exclamation point and the single quote have smaller code points (33 and 39, in decimal, resp.) than that of the full stop (46, in decimal).
I refer you to this ASCII table for an exhaustive list of the visible characters that have an ASCII code point smaller than that of the full stop; note that not all of them are necessarily legal filename characters, though.
A custom dir function that does not list . and ..
Right after invoking dir, you can always get rid of the two offending entries from the struct array before manipulating it. Moreover, for convenience, if you want to save yourself some mental overhead, you can always write a custom dir function that does what you want:
function listing = dir2(varargin)
if nargin == 0
name = '.';
elseif nargin == 1
name = varargin{1};
else
error('Too many input arguments.')
end
listing = dir(name);
inds = [];
n = 0;
k = 1;
while n < 2 && k <= length(listing)
if any(strcmp(listing(k).name, {'.', '..'}))
inds(end + 1) = k;
n = n + 1;
end
k = k + 1;
end
listing(inds) = [];
Test
Assuming the same directory structure as before, you get the following:
>> f = dir2;
>> for k = 1 : length(f), disp(f(k).name), end
!hello
'world
a similar solution from the one suggested by Tal is:
listing = dir(directoryname);
listing(1:2)=[]; % here you erase these . and .. items from listing
It has the advantage to use a very common trick in Matlab, but assumes that you know that the first two items of listing are . and .. (which you do in this case). Whereas the solution provided by Tal (which I did not try though) seems to find the . and .. items even if they are not placed at the first two positions within listing.
Hope that helps ;)
If you're just using dir to get a list of files and and directories, you can use Matlab's ls function instead. On UNIX systems, this just returns the output of the shell's ls command, which may be faster than calling dir. The . and .. directories won't be displayed (unless your shell is set up to do so). Also, note that the behavior of this function is different between UNIX and Windows systems.
If you still want to use dir, and you test each file name explicitly, as in your example, it's a good idea to use strcmp (or one of its relations) instead of == to compare strings. The following would skip all hidden files and folder on UNIX systems:
listing = dir;
for i = 1:length(listing)
if ~strcmp(listing(i).name(1),'.')
% Do something
...
end
end
You may also wanna exclude any other files besides removing dots
d = dir('/path/to/parent/folder')
d(1:2)=[]; % removing dots
d = d([d.isdir]) % [d.isdir] returns a logical array of 1s representing folders and 0s for other entries
I used: a = dir(folderPath);
Then used two short code that return struct:
my_isdir = a([a.isdir]) Get a struct which only has folder info
my_notdir = a(~[a.isdir]) Get a struct which only has non-folder info
Combining #jubobs and #Tal solutions:
function d = dir2(folderPath)
% DIR2 lists the files in folderPath ignoring the '.' and '..' paths.
if nargin<1; folderPath = '.'; elseif nargin == 1
d = dir(folderPath);
d = d(~ismember({d.name},{'.','..'}));
end
None of the above puts together the elements as I see the question having being asked - obtain a list only of directories, while excluding the parents.
Just combining the elements, I would go with:
function d = dirsonly(folderPath)
% dirsonly lists the unhidden directories in folderPath ignoring '.' and '..'
% creating a simple cell array without the rest of the dir struct information
if nargin<1; folderPath = '.'; elseif nargin == 1
d = dir(folderPath);
d = {d([d.isdir] & [~ismember({d.name},{'.','..'})]).name}.';
end
if hidden folders in general aren't wanted the ismember line could be replaced with:
d = {d([d.isdir] & [~strncmp({d.name},'.',1)]).name}.';
if there were very very large numbers of interfering non-directory files it might be more efficient to separate the steps:
d = d([d.isdir]);
d = {d([~strncmp({d.name},'.',1)]).name}.';
We can use the function startsWith
folders = dir("folderPath");
folders = string({folders.name});
folders = folders(~startsWith(folders,"."))
Potential Solution - just remove the fields
Files = dir;
FilesNew = Files(3:end);
You can just remove them as they are the first two "files" in the structure
Or if you are actually looking for specific file types:
Files = dir('*.mat');

Matlab - How to delete only contents from folder

I wanted to know how it is possible to delete only the contents (files and folders) of a specific folder, without deleting this folder. Delete only child folders.
I have tried this, but this will delete the folder too:
rmdir(listFolders,'s')
This function work fine:
function rmSubDir( pathDir )
d = dir(pathDir);
isub = [d(:).isdir];
nameFolds = {d(isub).name}';
nameFolds(ismember(nameFolds,{'.','..'})) = [];
for i=1:size(nameFolds,1)
dir2rm = fullfile(pathDir,nameFolds{i});
rmdir(dir2rm, 's');
end
end

Matlab, Advanced loop in folders and applying a function

i wrote a code that analyze a video file and then plot data on a graph then
save this graph into
excel and jpg.
but my problem is that i have more than 200 video to analyze in around 20 folder,
so i need to automate this code to loop inside folders and analyze each *.avi file inside and
.. So any ideas or suggestions
Really appreciate your help
I need to know how to loop folders and get files inside and the apply a function to these files in that folder
Please note that my function that i also want to save graph result to img, should i then include full path while saving ? and how can i do it ?
The dir and fullfile commands are what you need. Depending on your directory structure, something like this:
video_dir = 'videos';
% I'm not sure if there's a way to directly get a list of directories, but
% this will work
video_dir_children = dir(video_dir);
video_subdirs = [];
for ix = 1 : length(video_dir_children),
% note we're careful to kick out '.' and '..'
% (and any other directory starting with a '.')
if(video_dir_children(ix).isdir && video_dir_children(ix).name(1) ~= '.')
video_subdirs = [video_subdirs; video_dir_children(ix)];
end
end
for ix = 1 : length(video_subdirs),
this_dir = fullfile(video_dir, video_subdirs(ix).name);
avi_files_in_this_dir = dir(fullfile(this_dir, '*.avi'));
for jx = 1 : avi_files_in_this_dir,
doVideoProcessing(fullfile(this_dir, avi_files_in_this_dir(jx).name));
end
end