how to access values of one matrix coresponding to the matrix of other values - matlab

data=[ 20 25 30 35 40]; and a vector u of specific values for my data vector, where is u=[0.5 0.8 1]; and I want to access values from vector u
for each element of data vector to calculate values of a and c where
b=data+u
c=data.*u
I wrote this program in MATLAB
data=[ 20 25 30 35 40];
u=[0.5 0.8 1];
i=0;
if (data(i+1)<=25)
u=0.5;
elseif (data(i+1)>25 || data(i+1)<35)
u=0.8;
else (data(i+1)>35)
u=1;
end
b=data+u
c=data.*u
but i did not find right answer can u help me to write it properly?

data=[ 20 25 30 35 40];
u=[0.5 0.8 1];
for i = 1:length(data)
if (data(i)<=25)
u_idx=1
elseif (data(i)>25 & data(i)<=35)
u_idx=2;
else (data(i)>35)
u_idx=3;
end
b(i)=data(i)+u(u_idx);
c(i)=data(i).*u(u_idx);
end

Related

Find Array around Maximum Values of an Array

i have a quite complicated question here which i am working on. It's extremely difficult to describe in words, so i will try to explain it with an example.
Assume i have a matrix of values:
A =
[31 85 36 71 51]
[12 33 74 39 12]
[67 11 13 14 18]
[35 36 84 33 57]
Now, i want to first find a maximum vector in the first dimension, which is easy:
[max_vector,~] = max(A,[],1);
max_vector=[67,85, 84, 71,57]
Now i want to get a "slimmed" matrix with values around the maxima (periodical indices):
Desired_Matrix =
[12 36 36 33 18]
[67 85 84 71 57]
[35 33 13 39 51]
This is the matrix with the vectors around the maximum values of matrix A. Can someone tell me how to do this without using a double for loop?
Thank you!
% Input.
A = [31 85 36 71 51; 12 33 74 39 12; 67 11 13 14 18; 35 36 84 33 57]
% Dimensions needed.
nRows = size(A, 1);
nCols = size(A, 2);
% Get maxima and corresponding indices in input.
[max_vector, ind] = max(A);
% Get neighbouring indices.
ind = [ind - 1; ind; ind + 1];
% Modulo indices to prevent dimension overflow.
ind = mod(ind, nRows);
% Correct zero indices.
ind(ind == 0) = nRows;
% Calculate correct indices in A.
temp = repmat(0:nRows:nRows*(nCols-1), 3, 1);
ind = ind + temp;
% Output.
B = A(ind)
Since we have max indices per column, but later want to access these elements in the original array A, we need proper linear indices for A. Here, the trick is to add the number of rows multiplied by the column index (starting by 0). The easiest way to understand might be to remove the semicolons, and inspect the intermediate values of ind.
#HansHirse's answer is more efficient, as it does not create an intermediate matrix.
Try this:
[~, ind_max] = max(A,[],1);
A_ext = A([end 1:end 1],:);
ind_lin = bsxfun(#plus, bsxfun(#plus, ind_max, (0:2).'), (0:size(A_ext,2)-1)*size(A_ext,1));
result = reshape(A_ext(ind_lin), 3, []);
For Matlab R2016b or newer, you can simplify the third line:
[~, ind_max] = max(A,[],1);
A_ext = A([end 1:end 1],:);
ind_lin = ind_max + (0:2).' + (0:size(A_ext,2)-1)*size(A_ext,1);
result = reshape(A_ext(ind_lin), 3, []);
Here is another solution. This is similar to HansHirse's answer, with two improvements:
Slightly more elegantly handles the modular indexing
Is more flexible for specifying which neighbours your want
Code:
% Input
A = [31 85 36 71 51;
12 33 74 39 12;
67 11 13 14 18;
35 36 84 33 57];
% Relative rows of neighbours, i.e. this is [-1, 0, 1] for +/- one row
p = -1:1;
% Get A row and column counts for ease
[nr, nc] = size(A);
% Get max indices
[~,idx] = max( A, [], 1 );
% Handle overflowing indices to wrap around rows
% You don't have to redefine "idx", could use this directly in the indexing line
idx = mod( idx + p.' - 1, nr ) + 1;
% Output B. The "+ ... " is to convert to linear indices, as "idx"
% currently just refers to the row number.
B = A(idx + (0:nr:nr*nc-1));
You can use the Image Processing Toolbox to generate the result, though is less efficient than other solutions.
[~,idx] = max(A, [], 1);
d = imdilate( idx == (1:size(A,1) ).', [1;1;1], 'full');
p = padarray(A, 1, 'circular');
Desired_Matrix = reshape(p(d), 3, []);
just for your information, here is the generalized form for the 3D-Case:
A = zeros(3,5,5);
for id = 1: 20
A(:,:,id) = id;
if id == 10
A(:,:,id) = 100;
end
end
% Relative rows of neighbours, i.e. this is [-1, 0, 1] for +/- one row
p = -1:1;
% Get A row and column counts for ease
[nr, nc, nz] = size(A);
% Get max indices
[~,idx] = max( A, [], 3 );
% Handle overflowing indices to wrap around rows
% You don't have to redefine "idx", could use this directly in the indexing line
idx = mod( idx + reshape(p,1,1,3) - 1, nz ) + 1;
% Output B. The "+ ... " is to convert to linear indices, as "idx"
% currently just refers to the row number.
INDICES = ((idx-1) * (nr*nc)+1 )+ reshape(0:1:nc*nr-1,nr,nc);
B = A(INDICES);

Huge number of intilization a small vector without a for-loop?

I received the code to the initialization the vector A1.
Sc=[75 80 85];
Sp=[60 65 70];
C=[10 20 30 40 50 60;
11 21 31 41 51 61];
% KK=1000000;
% for k=1:KK
k=1;
A1=[];
A1=[-C(k,1)+max(60-Sc(1),0) -C(k,2)+max(60-Sc(2),0) -C(k,3)+max(60-Sc(3),0)
-C(k,4)+max(Sp(1)-60,0) -C(k,5)+max(Sp(2)-60,0) -C(k,6)+max(Sp(3)-60,0)];
%end; %KK
The code above is work, but it isn't optimal (it's very long and I need rewrite it when vector's length, n, is changed). In my task the length of A1 is even, and lies in range 6<=n<=16 typically. But I need to initialize vector A1 the huge number times, k<=10^6.
I'd like to rewrite code. My code is below.
n= size(C,2);
M=60;
%KK=1000000;
% for k=1:KK
k=1;
AU=[];AD=[];
for i=1:n
if i<=n/2
AU=[AU, -C(k,i)+max(M-Sc(i),0)];
else
AD=[AD, -C(k,i)+max(Sp(i-n/2)-M,0)];
end %if
end % i
A1=[AU; AD]
% end; % KK
Question. Is it possible to rewrite the code without for-loop? Does it make sense when the vector's length, n, is substantially less the number of initialization, k?
This is a vectorized form:
Sc=[75 80 85];
Sp=[60 65 70];
C=[10 20 30 40 50 60;
11 21 31 41 51 61];
kk=2;%1000000;
n= 6;
M=60;
[K , I] = meshgrid(1:kk,1:n);
Idx = sub2ind([kk,n], K, I);
condition = I <= n/2;
AU = -C(Idx(condition)) + max(M-Sc(I(condition)),0).';
AD = -C(Idx(~condition)) + max(Sp(I(~condition) - n/2)-M,0).';
A1 = [AU AD].'
note: I changed kk from 1000000 to 2 because number of rows of C is 2 and can not be indexed with numbers greater than 2. So this make sence if number of rows of C would be 1000000

Generate new matrix from old matrix with specific conditions

I have matrix R(100*100) and I want to generate new matrix A(100*100) as below conditions
If I have a frequency to add a new condition(let us say frequency = 20). This mean I will have five conditions inside my domain `(100/20)=5
From 1 to 20, from 21 to 40, from 41 to 60, from 61 to 80, and from 81 to 100.
Let us assume my original matrix is
[1 1 1……..1]
[2 2 2 …….2]
[3 3 3 ………3]
And so on
[100 100 100 …..100]
The new matrix must be
From 1 to 20 same as old matrix
[1 1 1……..1]
[2 2 2 …….2]
[3 3 3………3]
From 21 to 40
A(21,j)=R(21,j)+R(1,j) (row 21 + row 1)
A(22,j)=R(22,j)+R(2,j) (row 22 + row 2)
A(23,j)=R(23,j)+R(3,j) (row 23 + row 3)
And so on
From 41 to 60
A(41,j)=R(41,j)+R(21,j) +R(1,j) (row 41+row 21 + row 1)
A(42,j)=R(42,j)+R(22,j) +R(2,j) (row 42+row 22 + row 2)
And so on
A(81,j)=R(81,j)+R(61,j)+R(41,j)+R(21,j)+R(1,j) (row 81+row 61 + row 41 + row 21+ row 1)
At each time that I reach to the frequency, I will have a new condition.
My question is there any sufficient way to do that? I wrote my code and its work fine but each time I change frequency I will have a new condition. For the case above I have 5 conditions but if I use frequency 5 I will have 20 conditions and I need to change all equations. I mean I need code to be able to handle any frequency
I wrote below code
clc;
clear;
prompt = 'Enter Frequency='; %Frequency=20
N= input(prompt);
Frequency=N;
one_step=1/Frequency; %Frequency
time=Frequency*one_step;
number_of_steps=time/one_step; %Number of steps until next condition
total_steps=100;
R1 = rand(100,100);
Number_of_Lines=(total_steps/number_of_steps)+1; %100/20
A(100,100)=0;
for i=1:100
for j=1:100
if i>=1 && i<=number_of_steps
A(i,j)=R1(i,j);
elseif i>number_of_steps && i<= 2*number_of_steps
A(i,j)=R1(i,j)+R1(i-number_of_steps,j);
elseif i>2*number_of_steps && i<= 3*number_of_steps
A(i,j)=R1(i,j)+R1(i-number_of_steps,j)+R1(i-2*number_of_steps,j);
elseif i>3*number_of_steps && i<= 4*number_of_steps
A(i,j)=R1(i,j)+R1(i-number_of_steps,j)+R1(i-2*number_of_steps,j)...
+R1(i-3*number_of_steps,j);
elseif i>4*number_of_steps && i< 5*number_of_steps
A(i,j)=R1(i,j)+R1(i-number_of_steps,j)+R1(i-2*number_of_steps,j)...
+R1(i-3*number_of_steps,j)+R1(i-4*number_of_steps,j);
end
end
end
Use this template and convert to your case
rows=100; cols=4; split=5;
x=ones(rows,cols);
c=mat2cell(x,repmat([rows/split],1,split),[cols]);
for i=[2:split]
c{i,1}=c{i,1}+c{i-1,1};
end;
now cells of c contains the sums you need. Here I used x matrix of ones to show the sums are being accumulated, replace with your real matrix. Also dimension can be derived from the given matrix.

Fast way to find the neighboor of pixel

I am programming for task that finds the neighbor of a given pixel x in image Dthat can formula as:
The formula shown pixels y which satisfy the distance to pixel x is 1, then they are neighbor of pixel x. This is my matlab code. However, it still takes long time to find. Could you suggest a faster way to do it. Thank you so much
%-- Find the neighborhood of one pixel
% x is pixel coordinate
% nrow, ncol is size of image
function N = find_neighbor(x,nrow,ncol)
i = x(1);
j = x(2);
I1 = i+1;
if (I1 > nrow)
I1 = nrow;
end
I2 = i-1;
if (I2 < 1)
I2 = 1;
end
J1 = j+1;
if (J1 > ncol)
J1 = ncol;
end
J2 = j-1;
if (J2 < 1)
J2 = 1;
end
N = [I1, I2, i, i; j, j, J1, J2];
For example: ncol=128; nrow=128; x =[30;110] then output
N =31 29 30 30; 110 110 111 109]
For calling the function in loop
x=[30 31 32 33; 110 123 122 124]
for i=1:length(x)
N = find_neighbor(x(:,i),nrow,ncol);
end
Here's a vectorized approach using bsxfun:
% define four neighbors as coordinate differences
d = [-1 0 ; 1 0 ; 0 -1 ; 0 1]';
% add to pixel coordinates
N = bsxfun(#plus, x, permute(d, [1 3 2]));
% make one long list for the neighbors of all pixels together
N = reshape(N, 2, []);
% identify out-of-bounds coordinates
ind = (N(1, :) < 1) | (N(1, :) > nrow) | (N(2, :) < 1) | (N(2, :) > ncol);
% and remove those "neighbors"
N(:, ind) = [];
The permute is there to move the "dimension" of four different neighbors into the 3rd array index. This way, using bsxfun, we get the combination of every pair of original pixel coordinates with every pair of relative neighbor coordinates. The out-of-bounds check assumes that nrow belongs to the first coordinate and ncol to the second coordinate.
With
ncol=128;
nrow=128;
x = [30 31 32 33; 110 123 122 124];
the result is
N =
29 30 31 32 31 32 33 34 30 31 32 33 30 31 32 33
110 123 122 124 110 123 122 124 109 122 121 123 111 124 123 125
Different neighbors of different pixels can end up to be the same pixel, so there can be duplicates in the list. If you only want each resulting pixel once, use
% remove duplicates?
N = unique(N', 'rows')';
to get
N =
29 30 30 30 31 31 31 32 32 32 33 33 33 34
110 109 111 123 110 122 124 121 123 124 122 123 125 124
Matlab's performance is horrible when calling small functions many time. The Matlab approach is to do vectorize as much as possible. A vectorized version of your code:
function N = find_neighbor(x,nrow,ncol)
N = [min(x(1,:)+1,nrow), max(x(1,:)-1,1), x(1,:), x(1,:); x(2,:), x(2,:),min(x(2,:)+1,ncol), max(x(2,:)-1,1)];
end
and usage
x=[30 31 32 33; 110 123 122 124]
N = find_neighbor(x,nrow,ncol);
BTW, for pixels on the border , your solution always gives 4 neighbors. This is wrong. the neighbors of (1,1) for examples should be only (2,1) and (1,2), while you add two extra (1,1).
The solution to this is quite simple - delete all neighbors that are outside the image
function N = find_neighbor(x,nrow,ncol)
N = [x(1,:)+1, x(1,:)-1, x(1,:), x(1,:); x(2,:), x(2,:),x(2,:)+1, x(2,:)-1];
N(:,N(1,:)<1 | N(1,:)> nrow | N(2,:)<1 | N(2,:)>ncol)=[];
end

Matrix "Zigzag" Reordering

I have an NxM matrix in MATLAB that I would like to reorder in similar fashion to the way JPEG reorders its subblock pixels:
(image from Wikipedia)
I would like the algorithm to be generic such that I can pass in a 2D matrix with any dimensions. I am a C++ programmer by trade and am very tempted to write an old school loop to accomplish this, but I suspect there is a better way to do it in MATLAB.
I'd be rather want an algorithm that worked on an NxN matrix and go from there.
Example:
1 2 3
4 5 6 --> 1 2 4 7 5 3 6 8 9
7 8 9
Consider the code:
M = randi(100, [3 4]); %# input matrix
ind = reshape(1:numel(M), size(M)); %# indices of elements
ind = fliplr( spdiags( fliplr(ind) ) ); %# get the anti-diagonals
ind(:,1:2:end) = flipud( ind(:,1:2:end) ); %# reverse order of odd columns
ind(ind==0) = []; %# keep non-zero indices
M(ind) %# get elements in zigzag order
An example with a 4x4 matrix:
» M
M =
17 35 26 96
12 59 51 55
50 23 70 14
96 76 90 15
» M(ind)
ans =
17 35 12 50 59 26 96 51 23 96 76 70 55 14 90 15
and an example with a non-square matrix:
M =
69 9 16 100
75 23 83 8
46 92 54 45
ans =
69 9 75 46 23 16 100 83 92 54 8 45
This approach is pretty fast:
X = randn(500,2000); %// example input matrix
[r, c] = size(X);
M = bsxfun(#plus, (1:r).', 0:c-1);
M = M + bsxfun(#times, (1:r).'/(r+c), (-1).^M);
[~, ind] = sort(M(:));
y = X(ind).'; %'// output row vector
Benchmarking
The following code compares running time with that of Amro's excellent answer, using timeit. It tests different combinations of matrix size (number of entries) and matrix shape (number of rows to number of columns ratio).
%// Amro's approach
function y = zigzag_Amro(M)
ind = reshape(1:numel(M), size(M));
ind = fliplr( spdiags( fliplr(ind) ) );
ind(:,1:2:end) = flipud( ind(:,1:2:end) );
ind(ind==0) = [];
y = M(ind);
%// Luis' approach
function y = zigzag_Luis(X)
[r, c] = size(X);
M = bsxfun(#plus, (1:r).', 0:c-1);
M = M + bsxfun(#times, (1:r).'/(r+c), (-1).^M);
[~, ind] = sort(M(:));
y = X(ind).';
%// Benchmarking code:
S = [10 30 100 300 1000 3000]; %// reference to generate matrix size
f = [1 1]; %// number of cols is S*f(1); number of rows is S*f(2)
%// f = [0.5 2]; %// plotted with '--'
%// f = [2 0.5]; %// plotted with ':'
t_Amro = NaN(size(S));
t_Luis = NaN(size(S));
for n = 1:numel(S)
X = rand(f(1)*S(n), f(2)*S(n));
f_Amro = #() zigzag_Amro(X);
f_Luis = #() zigzag_Luis(X);
t_Amro(n) = timeit(f_Amro);
t_Luis(n) = timeit(f_Luis);
end
loglog(S.^2*prod(f), t_Amro, '.b-');
hold on
loglog(S.^2*prod(f), t_Luis, '.r-');
xlabel('number of matrix entries')
ylabel('time')
The figure below has been obtained with Matlab R2014b on Windows 7 64 bits. Results in R2010b are very similar. It is seen that the new approach reduces running time by a factor between 2.5 (for small matrices) and 1.4 (for large matrices). Results are seen to be almost insensitive to matrix shape, given a total number of entries.
Here's a non-loop solution zig_zag.m. It looks ugly but it works!:
function [M,index] = zig_zag(M)
[r,c] = size(M);
checker = rem(hankel(1:r,r-1+(1:c)),2);
[rEven,cEven] = find(checker);
[cOdd,rOdd] = find(~checker.'); %'#
rTotal = [rEven; rOdd];
cTotal = [cEven; cOdd];
[junk,sortIndex] = sort(rTotal+cTotal);
rSort = rTotal(sortIndex);
cSort = cTotal(sortIndex);
index = sub2ind([r c],rSort,cSort);
M = M(index);
end
And a test matrix:
>> M = [magic(4) zeros(4,1)];
M =
16 2 3 13 0
5 11 10 8 0
9 7 6 12 0
4 14 15 1 0
>> newM = zig_zag(M) %# Zig-zag sampled elements
newM =
16
2
5
9
11
3
13
10
7
4
14
6
8
0
0
12
15
1
0
0
Here's a way how to do this. Basically, your array is a hankel matrix plus vectors of 1:m, where m is the number of elements in each diagonal. Maybe someone else has a neat idea on how to create the diagonal arrays that have to be added to the flipped hankel array without a loop.
I think this should be generalizeable to a non-square array.
% for a 3x3 array
n=3;
numElementsPerDiagonal = [1:n,n-1:-1:1];
hadaRC = cumsum([0,numElementsPerDiagonal(1:end-1)]);
array2add = fliplr(hankel(hadaRC(1:n),hadaRC(end-n+1:n)));
% loop through the hankel array and add numbers counting either up or down
% if they are even or odd
for d = 1:(2*n-1)
if floor(d/2)==d/2
% even, count down
array2add = array2add + diag(1:numElementsPerDiagonal(d),d-n);
else
% odd, count up
array2add = array2add + diag(numElementsPerDiagonal(d):-1:1,d-n);
end
end
% now flip to get the result
indexMatrix = fliplr(array2add)
result =
1 2 6
3 5 7
4 8 9
Afterward, you just call reshape(image(indexMatrix),[],1) to get the vector of reordered elements.
EDIT
Ok, from your comment it looks like you need to use sort like Marc suggested.
indexMatrixT = indexMatrix'; % ' SO formatting
[dummy,sortedIdx] = sort(indexMatrixT(:));
sortedIdx =
1 2 4 7 5 3 6 8 9
Note that you'd need to transpose your input matrix first before you index, because Matlab counts first down, then right.
Assuming X to be the input 2D matrix and that is square or landscape-shaped, this seems to be pretty efficient -
[m,n] = size(X);
nlim = m*n;
n = n+mod(n-m,2);
mask = bsxfun(#le,[1:m]',[n:-1:1]);
start_vec = m:m-1:m*(m-1)+1;
a = bsxfun(#plus,start_vec',[0:n-1]*m);
offset_startcol = 2- mod(m+1,2);
[~,idx] = min(mask,[],1);
idx = idx - 1;
idx(idx==0) = m;
end_ind = a([0:n-1]*m + idx);
offsets = a(1,offset_startcol:2:end) + end_ind(offset_startcol:2:end);
a(:,offset_startcol:2:end) = bsxfun(#minus,offsets,a(:,offset_startcol:2:end));
out = a(mask);
out2 = m*n+1 - out(end:-1:1+m*(n-m+1));
result = X([out2 ; out(out<=nlim)]);
Quick runtime tests against Luis's approach -
Datasize: 500 x 2000
------------------------------------- With Proposed Approach
Elapsed time is 0.037145 seconds.
------------------------------------- With Luis Approach
Elapsed time is 0.045900 seconds.
Datasize: 5000 x 20000
------------------------------------- With Proposed Approach
Elapsed time is 3.947325 seconds.
------------------------------------- With Luis Approach
Elapsed time is 6.370463 seconds.
Let's assume for a moment that you have a 2-D matrix that's the same size as your image specifying the correct index. Call this array idx; then the matlab commands to reorder your image would be
[~,I] = sort (idx(:)); %sort the 1D indices of the image into ascending order according to idx
reorderedim = im(I);
I don't see an obvious solution to generate idx without using for loops or recursion, but I'll think some more.