How to decrease the computation time of this code? - matlab

I am working on computing some features of an image data set and saving the features for later use. Below is the code:
tic
l = 9907 % size of image data set
% pre-allocating space for variables in the for loop
Icolor = cell(1,l);
Iwave = cell(1,l);
IglrlFeatures = cell(1,l);
for i = 1:l % l = size of image data set = 9907
IDB{1,i} = imread(strcat(path,strcat(num2str(i),'.jpg')));
Icolor{1,i} = colorMoments(IDB{1,i}); % 6-features in each cell
Iwave{1,i} = waveletTransform(IDB{1,i}); % 8-features in each cell
IglrlFeatures{1,i} = textureFeatures(IDB{1,i}); % 44-features in each cell
ICW{1,i} = [Icolor{1,i} Iwave{1,i} IglrlFeatures{1,i}];
end
toc
Here the computation time for each function on single image is:
colorMoments(single_image) = Elapsed time is 0.009689 seconds.
waveletTransform(single_image) = Elapsed time is 0.018069 seconds.
textureFeatures(single_image) = Elapsed time is 0.022902 seconds.
l = data set size = 9907 images
Computational times for different data set sizes (l):
l = 10; Elapsed time is 0.402629 seconds.
l = 100; Elapsed time is 2.233971 seconds.
l = 1000; Elapsed time is 21.178395 seconds.
l = 2000; Elapsed time is 44.510071 seconds.
l = 5000; Elapsed time is 111.393866 seconds.
l = 9907; Elapsed time is 238.924998 seconds. approximately (~4 mins)
I want to decrease this computational time, any suggestions?
Thanks,
Gopi

The measured times seem to indicate computational complexity of order O(n). I doubt that the order can be reduced further for this type of problem. So, I believe that, at best, we can only hope for a linear increase in performance.
One thing you should look into is whether the code is using multiple processor cores. If not, try restructuring the for-loop to be able to use parfor instead.

Related

Faster version of length(find()) for selecting elements from some range from vectors (MATLAB)

I have 1Xn cell array of values. and I want to count values that are in given range in matlab.
I implemented it as follows :
count1 = length(find(h{1}<ti & h{1}>ti-INT));
h is my cell array and I want the count of values between ti and ti-INT.
This implementation give correct result, but it is very slow.
Is there any faster function available for the specified operation ?
Sum the occurrence flags:
count1 = sum(h{1}<ti & h{1}>ti-INT);
I know that I will upset the Gods of MATLAB for using tic and toc for code timig, but:
x = rand(10^7,1);
tic; sum(x>0.5); toc;
tic; nnz(x>0.5); toc;
tic; length(find(x>0.5)); toc;
shows on several runs that sum() is twice as fast as nnz(), and 3 times faster than length(find()), e.g.:
Elapsed time is 0.049855 seconds.
Elapsed time is 0.120931 seconds.
Elapsed time is 0.162025 seconds.
This is on my R2012a running on a Windows machine with i5 + 3Gb RAM.
Later edit:
For counting the elements from the entire cell array, one may use:
count_all = sum(cellfun(#(x) sum(x<ti & x>ti-INT), h));

One step reduction in MATLAB increases the execution time

I am doing a comparison and performance test of 3 methods to get the closest index of what i click in the ginput() the first method takes distance from each click and finds the nearest index in the next step the second one is doing the same but through a for loop and 3rd is the exact same copy of the first one but reduction of one step
ax = subplot(1,1,1)
plot(timestamps,datavalue)
hzoom = zoom(ax);
hzoom.Motion = 'horizontal';
[x, ~] = ginput(2);
%1)
tic;
tmp = abs(bsxfun(#minus,x,datenum(timestamps).'));
[~, idx1] = min(tmp,[],2);
toc;
%2)
tic;
for r = 1:length(x)
val = x(r);
tmp = abs(datenum(datenum(timestamps - val)));
[~, idx2] = min(tmp);
closest_indx(r) = idx2;
end
toc;
%3)
tic;
[~, idx3] = min(abs(bsxfun(#minus,x,datenum(timestamps).')),[],2);
toc;
Now when I look at the results
test1)
Elapsed time is 0.009182 seconds.
Elapsed time is 0.019211 seconds.
Elapsed time is 0.011261 seconds.
test2)
Elapsed time is 0.012625 seconds.
Elapsed time is 0.022681 seconds.
Elapsed time is 0.017999 seconds.
test3)
Elapsed time is 0.013053 seconds.
Elapsed time is 0.020170 seconds.
Elapsed time is 0.015248 seconds.
test4)
Elapsed time is 0.011613 seconds.
Elapsed time is 0.018644 seconds.
Elapsed time is 0.015952 seconds.
It takes less time for the first method even though it has one more step of taking all the values and placing in into a 'tmp' matrix. Does anyone have a good explaination for this ?

MATLAB: datetime and etime

I need to use etime to calculate how many seconds a computation takes. I thought about something like this:
t1 = datetime('now');
% Do some computation
t2 = datetime('now');
temp = etime(t2, t1)
But I am getting this error message:
Error using etime(line 40), Index exceeds matrix dimensions.
What's wrong with it?
The inputs to etime are expected to be vectors that are the same format as the output of clock and not datetime objects.
t1 = clock;
t2 = clock;
elapsed = etime(t2, t1)
It is likely easier to surround your code with tic and toc which will automatically compute the elapsed time.
tmr = tic;
% do stuff
elapsed = toc(tmr);
That being said, if you want an accurate measurement of execution time, it is far better to use timeit.

Setting sampling rate in MATLAB for Arduino

I'm having trouble getting consistent results with the code I am using. I want to run my Arduino for a specific amount of time (say 20 seconds) and collect data from the analog pin with a specific sampling rate (say four samples a second). The code is as follows.
a_pin = 0;
tic;
i = 0;
while toc < 20
i = i + 1;
time(i) = toc;
v(i) = a.analogRead(a_pin);
pause(.25);
end
Is there a way to set the loop to run a specific time and then in the loop sample at a different rate?
You can try this:
a_pin = 0;
fs = 4; % sampling frequency (samplings per second)
mt = 20; % time for measurements
ind = 1;
nind = 1;
last_beep = 0;
tic;
while toc < mt
time(ind) = toc;
v(ind) = a.analogRead(a_pin);
% wait for appropriate time for next measurement
while( nind == ind )
nind = floor(toc*fs) + 1;
end
ind = nind;
% beep every second
if (ceil(toc) > last_beep)
beep(); % don't know if this one exist, check docs
last_beep = ceil(toc);
end
end
Maximal sampling time for a single Arduino analog read command is around 0.04 s, in practice I'd go minimally 0.05. Adding two read operations is in the order of 2*0.04, in practice more like 0.1 s. I think it is mainly limited by the USB communication speeds.
I am also new at arduino, but having implemented a real time analysis for EEG using it, on practice, I was able to sample 2 analog channels with a samplinf frequency between 57 and 108Hz. It was very variable (calculated through tic/toc), but it is still proper for realtime processing in my case.
My code uses a While loop, a series of memory updates, digital pin manipulations, plot of trace (drawnow) and seems to run smoothly enough
My answer is simply here : 0.0283 sec for sampling 2 analog inputs in my case.
Cheers

Octave/Matlab: Adding new elements to a vector

Having a vector x and I have to add an element (newElem) .
Is there any difference between -
x(end+1) = newElem;
and
x = [x newElem];
?
x(end+1) = newElem is a bit more robust.
x = [x newElem] will only work if x is a row-vector, if it is a column vector x = [x; newElem] should be used. x(end+1) = newElem, however, works for both row- and column-vectors.
In general though, growing vectors should be avoided. If you do this a lot, it might bring your code down to a crawl. Think about it: growing an array involves allocating new space, copying everything over, adding the new element, and cleaning up the old mess...Quite a waste of time if you knew the correct size beforehand :)
Just to add to #ThijsW's answer, there is a significant speed advantage to the first method over the concatenation method:
big = 1e5;
tic;
x = rand(big,1);
toc
x = zeros(big,1);
tic;
for ii = 1:big
x(ii) = rand;
end
toc
x = [];
tic;
for ii = 1:big
x(end+1) = rand;
end;
toc
x = [];
tic;
for ii = 1:big
x = [x rand];
end;
toc
Elapsed time is 0.004611 seconds.
Elapsed time is 0.016448 seconds.
Elapsed time is 0.034107 seconds.
Elapsed time is 12.341434 seconds.
I got these times running in 2012b however when I ran the same code on the same computer in matlab 2010a I get
Elapsed time is 0.003044 seconds.
Elapsed time is 0.009947 seconds.
Elapsed time is 12.013875 seconds.
Elapsed time is 12.165593 seconds.
So I guess the speed advantage only applies to more recent versions of Matlab
As mentioned before, the use of x(end+1) = newElem has the advantage that it allows you to concatenate your vector with a scalar, regardless of whether your vector is transposed or not. Therefore it is more robust for adding scalars.
However, what should not be forgotten is that x = [x newElem] will also work when you try to add multiple elements at once. Furthermore, this generalizes a bit more naturally to the case where you want to concatenate matrices. M = [M M1 M2 M3]
All in all, if you want a solution that allows you to concatenate your existing vector x with newElem that may or may not be a scalar, this should do the trick:
x(end+(1:numel(newElem)))=newElem