value in range for big datasets - performance

I have a problem that I can't seem to solve. I want a query to determine whether a given value lies within a predefined range, but my loop is very slow for big datasets. Is there a more efficient way?
clear all
close all
Regression(1,1) = 1.001415645694801;
Regression(1,2) = 0.043822386790753;
FF_Value(:,1) = [24.24 30.77 31.37 29.05 29.20 29.53 29.67 27.78];
FF_Value(:,2) = [24.16 30.54 31.15 29.53 29.39 29.34 29.53 28.17];
FF_Distance = FF_Value(:,2)-(Regression(1,2)+Regression(1,1)*FF_Value(:,1));
FF_Distance_Positiv = sort(FF_Distance(FF_Distance > 0));
FF_Distance_Positiv(FF_Distance_Positiv == 0) = [];
FF_Distance_Negativ = sort(FF_Distance(FF_Distance < 0),'descend');
FF_Distance_Negativ(FF_Distance_Negativ == 0) = [];
A = repmat(FF_Distance_Positiv,length(FF_Distance_Negativ),1);
B = repmat(FF_Distance_Negativ',length(FF_Distance_Positiv),1);
C = reshape(B,[length(FF_Distance_Positiv)*length(FF_Distance_Negativ),1]);
Recognition(:,1) = A;
Recognition(:,2) = C;
FF_Recognition = zeros(length(FF_Value),1);
for i = 1:length(Recognition)
for j = 1:length(FF_Value)
if (Regression(1,2)+Recognition(i,1))+Regression(1,1)*FF_Value(j,1) >= FF_Value(j,2) &&...
(Regression(1,2)+Recognition(i,2))+Regression(1,1)*FF_Value(j,1) <= FF_Value(j,2)
FF_Recognition(j,1) = 1;
end
end
end

Welcome to the world of bsxfun's replacing your world of repmats -
%------------ Original code -----------------------------------------
FF_Distance = FF_Value(:,2)-(Regression(1,2)+Regression(1,1)*FF_Value(:,1));
FF_Distance_Positiv = sort(FF_Distance(FF_Distance > 0));
FF_Distance_Positiv(FF_Distance_Positiv == 0) = [];
%// Note for Performance: If number of elements satisfying `FF_Distance_Positiv == 0`
%// is a lot, consider doing this instead -
%// `FF_Distance_Positiv = FF_Distance_Positiv(FF_Distance_Positiv~=0)`.
%// Follow this strategy for `FF_Distance_Negativ` too.
FF_Distance_Negativ = sort(FF_Distance(FF_Distance < 0),'descend');
FF_Distance_Negativ(FF_Distance_Negativ == 0) = [];
%------- Added vectorization replacing `repmats` and nested loops ------------
mult = Regression(1,1)*FF_Value(:,1);
y1 = bsxfun(#plus,Regression(1,2),FF_Distance_Positiv);
y2 = bsxfun(#plus,y1.',mult); %//'
mc1 = bsxfun(#ge,y2,FF_Value(:,2));
z1 = bsxfun(#plus,Regression(1,2),FF_Distance_Negativ);
z2 = bsxfun(#plus,z1.',mult); %//'
mc2 = bsxfun(#le,z2,FF_Value(:,2));
FF_Recognition = all([any(mc1,2) any(mc2,2)],2);

Related

How to avoid overlapping between title and labels in Matlab's pie chart?

I'm using the next code to plot in a pie chart the percentage of values in a matrix that are greater/smaller than 1. The thing is that when I want to put the title above the graph, it overlaps with the label of one of the groups.
I tried replacing it with text() but it didn't worked, and Documentation on pie say nothing to this. How can I avoid this overlap?
eigen = []; % Modes array
c2 = 170; % Sound speed divided by 2
%% Room dimensions
lx = 5.74;
ly = 8.1;
lz = 4.66;
i = 1; % Index for modes array
for nz = 0:50
for ny = 0:50
for nx = 0:50
aux = c2 * sqrt((nx/lx)^2+(ny/ly)^2+(nz/lz)^2);
if aux < 400 %% If value is into our range of interest
eigen(i) = aux;
i=i+1;
end
end
end
end
eigen = round(sort(eigen'),1);
eigen
% dif = eigen(2:end)-eigen(1:end-1); % Distance between modes
x = 0; %% dif >= 1
y = 0; %% dif <= 1
dif = [];
for i=2:length(eigen)
if eigen(i)-eigen(i-1) >= 1
x = x+1;
else
y = y+1;
end
end
figure
dif = [x,y];
explode = [1 1];
graf = pie(dif,explode);
hText = findobj(graf,'Type','text');
percentValues = get(hText,'String');
txt = {'Smaller than 1 Hz: ';'Greater than 1 Hz: '};
combinedtxt = strcat(txt,percentValues);
oldExtents_cell = get(hText,'Extent');
oldExtents = cell2mat(oldExtents_cell);
hText(1).String = combinedtxt(1);
hText(2).String = combinedtxt(2);
title('Distance between modes')
You can rotate the pie chart so that the figure look better. Further, you can use position to allocate your text as follows,
figure
dif = [x,y];
explode = [1 1];
graf = pie(dif,explode);
hText = findobj(graf,'Type','text');
percentValues = get(hText,'String');
txt = {'Smaller than 1 Hz: ';'Greater than 1 Hz: '};
combinedtxt = strcat(txt,percentValues);
oldExtents_cell = get(hText,'Extent');
oldExtents = cell2mat(oldExtents_cell);
hText(1).String = combinedtxt(1);
hText(2).String = combinedtxt(2);
view([90 90]) % this is to rotate the chart
textPositions_cell = get(hText,{'Position'});
textPositions = cell2mat(textPositions_cell);
textPositions(:,1) = textPositions(:,1) + 0.2; % replace 0.2 with any offset value you want
hText(1).Position = textPositions(1,:);
hText(2).Position = textPositions(2,:);
title('Distance between modes')
You can change only the text position (without rotation) by deleting view command.

Scaling the image using Bilinear Interpolation - matlab

I have written a code that reads an image and does scaling of 2 units in x-axis direction. Scaling matrix is filled by values that are read from a text file.
Scaling Matrix looks like
2 0 0
0 1 0
0 0 1
Original Image
Transformed Image (Scaling of 2 units in X-direction)
Code
file = importdata('transform_c.txt');
fileData = file.data;
image = imread('mecca06.pgm');
[row, col] = size(image);
scalingMatrix = zeros(3,3);
scalingMatrix(1,1) = fileData(2);
scalingMatrix(1,2) = fileData(3);
scalingMatrix(1,3) = fileData(4);
scalingMatrix(2,1) = fileData(5);
scalingMatrix(2,2) = fileData(6);
scalingMatrix(2,3) = fileData(7);
scalingMatrix(3,1) = fileData(8);
scalingMatrix(3,2) = fileData(9);
scalingMatrix(3,3) = fileData(10);
m1Inverse = inv(scalingMatrix);
outputImage = applyTransformation(image, row, col, m1Inverse);
figure
imshow(outputImage);
function outImage = applyTransformation(image, row, col, m1Inverse)
points = zeros(3,1);
for i=1:row
for j=1:col
points(1,1) = i;
points(2,1) = j;
points(3,1) = 1;
m2 = m1Inverse * points;
x = m2(1,1);
y = m2(2,1);
xlb = floor(x);
ylb = floor(y);
if(xlb <= 0)
xlb = 1;
end
if(xlb > row)
xlb = row;
end
if(ylb <= 0)
ylb = 1;
end
if(ylb > col)
ylb = col;
end
xub = xlb+1;
yub = ylb+1;
if(xub <= 0)
xub = 1;
end
if(xub > row)
xub = row;
end
if(yub <= 0)
yub = 1;
end
if(yub > col)
yub = col;
end
exub = xub-x;
eyub = yub-y;
exlb = x-xlb;
eylb = y-ylb;
outImage(i,j) = (exub*eyub*image(xlb,ylb))+(exlb*eyub*image(xub,ylb))+(exub*eylb*image(xlb,yub))+(exlb*eylb*image(xub,yub));
end
end
end
My question is how can i modify the above code to get uncropped image ?
I want to get following image
Try to see if this code produces the result you need:
img = imread('aSxLS.png');
scale = [
2 0 0
0 1 0
0 0 1
];
tform = maketform('affine',inv(scale));
img_tform = imtransform(img,tform,'bilinear');
figure();
imshow(img);
figure();
imshow(img_tform);

Reduce the calculation time for the matlab code

To calculate an enhancement function for an input image I have written the following piece of code:
Ig = rgb2gray(imread('test.png'));
N = numel(Ig);
meanTotal = mean2(Ig);
[row,cal] = size(Ig);
IgTransformed = Ig;
n = 3;
a = 1;
b = 1;
c = 1;
k = 1;
for ii=2:row-1
for jj=2:cal-1
window = Ig(ii-1:ii+1,jj-1:jj+1);
IgTransformed(ii,jj) = ((k*meanTotal)/(std2(window) + b))*abs(Ig(ii,jj)-c*mean2(window)) + mean2(window).^a;
end
end
How can I reduce the calculation time?
Obviously, one of the factors is the small window (3x3) that should be made in the loop each time.
Here you go -
Igd = double(Ig);
std2v = colfilt(Igd, [3 3], 'sliding', #std);
mean2v = conv2(Igd,ones(3),'same')/9;
Ig_out = uint8((k*meanTotal)./(std2v + b).*abs(Igd-cal*mean2v) + mean2v.^a);
This will change the boundary elements too, which if not desired could be set back to the original ones with few additional steps, like so -
Ig_out(:,[1 end]) = Ig(:,[1 end])
Ig_out([1 end],:) = Ig([1 end],:)

Matlab Multivariable Minimization

I'm trying to develop the adaptive unsharp algorithm described by Polesel et al. in the article "Image Enhancement via Adaptive Unsharp Masking" (link to the article). The core of the algorithm is the minimization of a cost function defined as:
J(m,n) = E[e(m,n)^2] = E[(gd(m,n)-gy(m,n))^2]
where E[] is the statistical expectation and gy(m,n) is:
gy(m,n) = gx(m,n) + lambda1(m,n)*gzx(m,n) + lambda2(m,n)*gzy(m,n);
I want to find lambda1 and lambda2 for each pixel in order to minimize the cost function in each pixel.
Here the code that I wrote so far:
function [ o_sharpened_image ] = AdaptativeUnsharpMask( i_image , t1, t2)
%ADAPTATIVEUNSHARPMASK Summary of this function goes here
% Detailed explanation goes here
if isa(i_image,'dip_image')
i_image = dip_array(i_image);
end
if ~isfloat(i_image)
i_image = im2double(i_image);
end
adh = 4;
adl = 3;
g = [-1 -1 -1; -1 8 -1; -1 -1 -1];
dim = size(i_image);
lambda_x = 0.5*ones(dim);
lambda_y = 0.5*ones(dim);
z_x = conv2(i_image,[-1 2 -1],'same');
z_y = conv2(i_image,[-1; 2; -1],'same');
g_x = conv2(i_image,g,'same');
g_zx = conv2(z_x,g,'same');
g_zy = conv2(z_y,g,'same');
a = ones(dim);
variance_map = colfilt(i_image,[3 3],'sliding',#var);
a(variance_map >= t1 & variance_map < t2) = adh;
a(variance_map >= t2) = adl;
g_d = a.*g_x;
lambda = [lambda_x lambda_y];
lambda0 = lambda;
lambda_min = lsqnonlin(#(lambda) UnsharpCostFunction(lambda,g_d,g_zx,g_zy),lambda0);
o_sharpened_image = i_image + lambda_min(:,1:size(i_image,2)).*z_x + lambda_min(:,size(i_image,2)+1:end).*z_y;
end
Here the code of the cost function:
function [ J ] = UnsharpCostFunction( i_lambda, i_gd, i_gzx, i_gzy )
%UNSHARPCOSTFUNCTION Summary of this function goes herek
gy = i_gd + i_lambda(:,1:size(i_gd,2)).*i_gzx + i_lambda(:,size(i_gd,2)+1:end).*i_gzy;
J = mean((i_gd(:) - gy(:)).^2);
end
For each iteration I print on the command window the value of the J function and it is always the same. What am I doing wrong?
Thank you.

Understanding and Implementing Thinning Algorithm in MATLAB

I am trying to implement my own Thinning Algorithm in Matlab to understand the thinning algorithm. I am following http://fourier.eng.hmc.edu/e161/lectures/morphology/node2.html and implementing my own code, but the result is incorrect.
Here is my code:
%for the sake of simplicity, the outermost pixels are ignored.
for x = 2:1:511
for y = 2:1:511
% if this pixel is not black, then, proceed in.
if (frame2(y,x) > 0)
% the pos(1 to 8) here are for the surrounding pixels.
pos(1) = frame2(y-1,x-1);
pos(2) = frame2(y, x-1);
pos(3) = frame2(y+1, x+1);
pos(4) = frame2(y+1, x);
pos(5) = frame2(y+1, x-1);
pos(6) = frame2(y, x-1);
pos(7) = frame2(y-1, x-1);
pos(8) = frame2(y-1, x);
nonZeroNeighbor = 0;
transitSequence = 0;
change = 0;
for n = 1:1:8
% for N(P1)
if (pos(n) >= 1)
nonZeroNeighbor = nonZeroNeighbor + 1;
end
% for S(P1)
if (n > 1)
if (pos(n) ~= change)
change = pos(n);
transitSequence = transitSequence + 1;
end
else
change = pos(n);
end
end
% also for S(P1)
if ((nonZeroNeighbor > 1 && nonZeroNeighbor < 7) || transitSequence >= 2)
markMatrix(y,x) = 1;
fprintf(1, '(%d,%d) nonzero: %d transit: %d\n', y,x, nonZeroNeighbor, transitSequence);
else %this else here is for the reverse.
end
end
end
end
for x = 2:1:511
for y = 2:1:511
if (markMatrix(y,x) > 0)
frame2(y,x) = 0;
end
end
end
savePath = [path header number2 '.bmp'];
imwrite(frame2, savePath, 'bmp'); %output image here, replacing the original
From the site above, it states the function S(P1) as:
"S(P1): number of 0 to 1 (or 1 to 0) transitions in the sequence (P2, P3, ..., P9)"
For this part, my codes are below "% for S(P1)" and "% also for S(P1)" comments. Am I implementing this function correctly? The output image I got is simply blank. Nothing at all.
For the correct output, I am aware that there is a logical problem. Regarding the site, it states:
When part of the shape is only 2-pixel wide, all pixels are boundary points and will be marked and then deleted.
This problem is to be ignored for now.
I've had a go at the problem and think I managed to get the algorithm to work. I've made several small edits along the way (please see the code below for details), but also found two fundamental problems with your initial implementation.
Firstly, you assumed all would be done in the first pass of step 1 and 2, but really you need to let the algorithm work away at the image for some time. This is typical for iterative morphological steps 'eating' away at the image. This is the reason for the added while loop.
Secondly, your way of calculating S() was wrong; it counted both steps from 0 to 1 and 1 to 0, counting twice when it shouldn't and it didn't take care of the symmetry around P(2) and P(9).
My code:
%Preliminary setups
close all; clear all;
set(0,'DefaultFigureWindowStyle','Docked')
%Read image
frame2 = imread('q1.jpg');
%Code for spesific images
%frame2(:,200:end) = [];
%frame2 = rgb2gray(frame2);
%Make binary
frame2(frame2 < 128) = 1;
frame2(frame2 >= 128) = 0;
%Get sizes and set up mark
[Yn Xn] = size(frame2);
markMatrix = zeros(Yn,Xn);
%First visualization
figure();imagesc(frame2);colormap(gray)
%%
%While loop control
cc = 0;
changed = 1;
while changed && cc < 50;
changed = 0;
cc = cc + 1;
markMatrix = zeros(Yn,Xn);
for x = 2:1:Xn-1
for y = 2:1:Yn-1
% if this pixel is not black, then, proceed in.
if (frame2(y,x) > 0)
% the pos(2 to 9) here are for the surrounding pixels.
pos(1) = frame2(y, x);
pos(2) = frame2(y-1, x);
pos(3) = frame2(y-1, x+1);
pos(4) = frame2(y, x+1);
pos(5) = frame2(y+1, x+1);
pos(6) = frame2(y+1, x);
pos(7) = frame2(y+1, x-1);
pos(8) = frame2(y, x-1);
pos(9) = frame2(y-1, x-1);
nonZeroNeighbor = 0;
transitSequence = 0;
change = pos(9);
for n = 2:1:9
%N()
nonZeroNeighbor = sum(pos(2:end));
%S()
if (double(pos(n)) - double(change)) < 0
transitSequence = transitSequence + 1;
end
change = pos(n);
end
%Test if pixel is to be removed
if ~( nonZeroNeighbor == 0 || nonZeroNeighbor == 1 ...
||nonZeroNeighbor == 7 || nonZeroNeighbor == 8 ...
||transitSequence >= 2)
markMatrix(y,x) = 1;
fprintf(1, '(%d,%d) nonzero: %d transit: %d\n', ...
y,x, nonZeroNeighbor, transitSequence);
end
end
end
end
%Mask out all pixels found to be deleted
frame2(markMatrix > 0) = 0;
%Check if anything has changed
if sum(markMatrix(:)) > 0;changed = 1;end
end
%Final visualization
figure();imagesc(frame2);colormap(gray)

Resources