How to do a pairwise interchange of rows in Matlab? - matlab

I have a sequence in an matrix (computed from sortrows function in Matlab). Say the matrix looks something like this after computing:
A = [5; 3; 4; 1; 2];
[b, c] = size(A)
In lieu of performing permutations on the sequence in A, I would like to peform a pairwise interchange of the cells, so the performance runs better, even though the results won't be exact (it will be very close to answer though). I want the rows to look somewhat like this in the end =>
A1 = [5; 4; 3; 2; 1];
A2 = [4; 5; 3; 1; 2];
A3 = [4; 3; 5; 2; 1];
A4 = [3; 4; 5; 1; 2];
Now, the catch is that the matrix will contain as little or as much elements (it will vary). Matrix 'A' is just an example. How do I perform [b-1] pairwise interchanges on A (or any other matrix)?

A = [5; 3; 4; 1; 2];
swapIndexLeft = [1,2,3,4,5];
swapIndexRight = [2,3,4,5,1];
%// make sure the dimension of indices agree
assert(numel(swapIndexLeft) == numel(swapIndexRight))
%// ... and values do not exceed dimensions of the vector A
assert(max(swapIndexLeft)<=numel(A) )
assert(max(swapIndexRight)<=numel(A) )
%// swap iteratively
for ii = 1:numel(swapIndexLeft)
temp = A( swapIndexLeft(ii) );
A( swapIndexLeft(ii) ) = A( swapIndexRight(ii) );
A( swapIndexRight(ii) ) = temp;
%// now you have an array where the element swapIndexLeft(ii)
%// has been swapped with swapIndexRight(ii)
%// do your calculations here
end

Related

Extract column data of table in a struct array

Summary / TLDR
How do I extract all rows of one table-column if the table is in a struct array and I want to combine alle struct-array-elements to one big matrix?
First Approch
I have a table (Values) with multiple columns and rows stored in a struct. Multiple of these structs are stored in an array (Data):
Data(1).Values = table([1; 2; 3; 4; 8], 'VariableNames', {'Rk'});
Data(2).Values = table([3; 6; 10; 8], 'VariableNames', {'Rk'});
Data(3).Values = table([2; 10; 11; 7], 'VariableNames', {'Rk'});
There are many more variables in the struct and also in the table, so it is just a simplified example. As you can see the height of the table can vary. I want to plot the columns Rk in a boxplot. So i need to create a matrix like this:
matrix = [1 1; 2 1; 3 1; 4 1; 8 1; 3 2; 6 2; 10 2; 8 2; 2 3; 10 3; 11 3; 7 3];
I use the following code to create the matrix:
matrix = zeros(0, 2);
for i=1:length(Data)
l = height(Data(1, i).Values(:, 'Rk'));
e = length(matrix) + 1;
% Reshape the data into an array
matrix((end+1):(end+l), 1) = table2array(Data(1, i).Values(:, 'Rk'));
% Creating the index of each data-row
matrix(e:end, 2) = i;
end
% Plot the boxplot
boxplot(matrix(:, 1), matrix(:, 2))
I really don't like this for-loop-version, especially because it becomes slow for big Data-Arrays and also because I don't know the size of matrix, so I can't reserve the space. Theoretically I could run through the whole data-array, counting the elements, initalizing the matrix-variable and then fill it.
Is there a more elegant version without a for-loop?
Second approach
I already tried another solution by changing the structure of the struct. Semantically, this really makes no sense, but this way I found a more elegant solution, creating the matrix-Variable without the problems of the first solution:
% Creating Data
Data(1).Values.Rk = [1; 2; 3; 4; 8];
Data(2).Values.Rk = [3; 6; 10; 8];
Data(3).Values.Rk = [2; 10; 11; 7];
% Reshape the data into an array
a = {cell2mat({Data.Values}).Rk};
b = vertcat(a{:});
% Creating the index of each data (b)-row
c = cumsum(cellfun('length', a(1, :)));
d = meshgrid(1:c(end), 1:length(c));
e = d>c';
f = sum(e);
% Plot the boxplot
boxplot(b, f);
Questions
I would apreciate a solution combining both approaches (having a table, no for-loop, no need of matrix-size-calculation) but:
I don't know how to extract the data of the table in a struct in an array.
I am asking myself if there is a more elegant solution creating the boxplot-indexes.
Whole code
%% Boxplot of Table
clear
% Creating Data
Data(1).Values = table([1; 2; 3; 4; 8], 'VariableNames', {'Rk'});
Data(2).Values = table([3; 6; 10; 8], 'VariableNames', {'Rk'});
Data(3).Values = table([2; 10; 11; 7], 'VariableNames', {'Rk'});
matrix = zeros(0, 2);
for i=1:length(Data)
l = height(Data(1, i).Values(:, 'Rk'));
e = length(matrix) + 1;
% Reshape the data into an array
matrix((end+1):(end+l), 1) = table2array(Data(1, i).Values(:, 'Rk'));
% Creating the index of each data
matrix(e:end, 2) = i;
end
boxplot(matrix(:, 1), matrix(:, 2));
%% Boxplot of Arrays
clear
% Creating Data
Data(1).Values.Rk = [1; 2; 3; 4; 8];
Data(2).Values.Rk = [3; 6; 10; 8];
Data(3).Values.Rk = [2; 10; 11; 7];
% Reshape the data into an array
a = {cell2mat({Data.Values}).Rk};
b = vertcat(a{:});
% Creating the index of each data (b)-row
c = cumsum(cellfun('length', a(1, :)));
d = meshgrid(1:c(end), 1:length(c));
e = d>c';
f = sum(e);
% Plot the boxplot
boxplot(b, f);
I have a partial answer if you are allowed to change the dimensions on your input table. If you transpose your input values, such that you have a row vector
Data(1).Values.Rk = [1; 2; 3; 4; 8]';
...
You can use the following commands to concatenate all the elements:
tmp = [Data.Values];
allvals = [tmp.Rk]'; %output is a column vector of your aggregated values
If you eliminate the Rk field (if it is not informative), you don't need the first step and can do the operation in one step.
If you aggregate the values into a column vector in this manner you now know the dimensions of the second column and can initialize that column before executing a for loop to populate the second column with a monotonically increasing index for each element of data.
I cannot think of a way to get the total number of elements and corresponding value for your box plot in the second column (without a for loop) unless you have the flexibility to add another field to your data structure (e.g. Data(1).nVals = 5, etc.), in which case you can get the total number of elements via sum([Data.nVals])

Counting the same rows of 2D matrix

I have a two column matrix. I need to make it three column, where the third column shows the number of appearance of the first two as a row in the input matrix.
Basically: Input
[1 1;
1 1;
1 2;
1 2;
1 3]
Desired output:
[1 1 2;
1 2 2;
1 3 1]
I know already that a proper combination of accumarray and unique should do the charm. I just don't know how to properly combine them.
You are right, unique and accumarray are perfectly suited for this task:
x = [1 1; 1 1; 1 2; 1 2; 1 3]; % input
[~, v, w] = unique(x, 'rows', 'stable'); % unique indices and labels
c = accumarray(w, 1); % counts
y = [x(v,:) c]; % output
Remove the 'stable' flag if you want the ouput rows sorted in lexicographical order.
You can also replace accumarray by bsxfun to obtain the counts:
c = sum(bsxfun(#eq, unique(w), w.'), 2);
For the special case that the entries of x are positive integers and you want the ouput in lexicographical order, you can also use sparse and find as follows:
x = [1 1; 1 1; 1 2; 1 2; 1 3]; % input
[ii,jj,vv] = find(sparse(x(:,1), x(:,2), 1));
y = [ii(:), jj(:), vv(:)]; % output
One possible solution:
clear
a=...
[1 1;
1 1;
1 2;
1 2;
1 3]
[U,~,ic]=unique(a,'rows');
[C] = histc(ic,unique(ic));
Result=[U,C]

copy move forgery detection stuck with algorithm

I am trying to implement the paper detection of copy move forgery using histogram of oriented gradients.
The algorithm is:
Divide the image into overlapping blocks.
Calculate feature vectors for each block and store them in a matrix.
Sorting the matrix lexicographically
Using block matching to identify forged regions.
https://www.researchgate.net/publication/276518650_Detection_of_copy-move_image_forgery_using_histogram_of_orientated_gradients
I am stuck with the 3rd step and can't proceed.
The code I have implemented is:
clc;
clear all;
close all;
%read image
img = imread('006_F.png');
img=rgb2gray(img);
img=imresize(img, 1/4);
figure(1);
imshow(img);
b=16; %block size
nrc=5; %no. of rows to check
td=416; %threshold
[r, c]=size(img);%Rows and columns;
column=(r-b+1)*(c-b+1);
M= zeros(column,4);
Mi = zeros(1,2);
i=1;
disp('starting extraction of features');
for r1 = 1:r-b+1
for c1 = 1:c-b+1
% Extract each block
B = img(r1:r1+b-1,c1:c1+b-1);
features = extractHOGFeatures(B);%extracting features
M(i, :) = features;
Mi(i,:) = [r1 c1];
i=i+1;
end
end
[S, index] = sortrows(M , [ 1 2 3 4]);
P= zeros(1,6);
b2=r-b+1;
disp('Finding Duplicates');
for i = 1:column
iv = index(i);
xi=mod(iv,b2) + 1;
yi=ceil(iv/b2);
j = i+1;
while j < column && abs(i - j) < 5
jv=index(j);
xj=mod(jv,b2) + 1;
yj=ceil(jv/b2);
z=sqrt(power(xi-xj,2) + power(yi-yj,2));
% only process those whose size is above Nd
if z > 16
offset = [xi-xj yi-yj];
P = [P;[xi yi xj yj xi-xj yi-yj]];
end
j = j + 1;
end
end
rows = size(P,1);
P(:,6) = P(:,6) - min(P(:,6));
P(:,5) = P(:,5) - min(P(:,5));
maxValP = max(P(:,6)) + 1;
P(:,5) = maxValP .* P(:,5) + P(:,6);
mostfrequentval = mode(P(:,5));
disp('Creating Image');
idx = 2;
% Create a copy of the image and mask it
RI = img;
while idx < rows
x1 = P(idx,1);
y1 = P(idx,2);
x2 = P(idx,3);
y2 = P(idx,4);
if (P(idx,5) == mostfrequentval)
RI(y1:y1,x1:x1) = 0;
RI(y2:y2,x2:x2) = 0;
end
idx = idx + 1;
end;
After going through some references indicated in the paper you are working on (ref. [8] and [20]):
The lexicographic sorting is the equivalent of the alphabetical one, for numbers i.e., [1 1 1 1] < [1 1 2 1] < [2 3 4 5] < [2 4 4 5]
So, in your case, you case use the function sortrows() in the following way:
A = [1 1 1 1;1 1 1 2;1 1 1 4;1 2 2 2; 1 2 2 1; 1 4 6 3; 2 3 4 5; 2 3 6 6]; % sample matrix
[B,idx] = sortrows(A,[1 2 3 4]); % Explicit notation but it is the Matlab default setting so equivalent to sortrows(A)
It means: Sort the rows of A by first looking at the first column and, in case of equality, looking at the second one, and so on.
If your are looking for a reverse order, you specify '-' before the number of the column.
So in the end, your code is good and if the results are not as expected it has to come from another step of the implementation...
Edit: the parameter idx records the original index of the sorted rows.

How to write this matrix in matlab,

I want to write this matrix in matlab,
s=[0 ..... 0
B 0 .... 0
AB B .... 0
. . .
. . .
. . . 0 ....
A^(n-1)*B ... AB B ]
I have tried this below code but giving error,
N = 50;
A=[2 3;4 1];
B=[3 ;2];
[nx,ny] = size(A);
s(nx,ny,N) = 0;
for n=1:1:N
s(:,:,n)=A.^n;
end
s_x=cat(3, eye(size(A)) ,s);
for ii=1:1:N-1
su(:,:,ii)=(A.^ii).*B ;
end
z= zeros(1,60,1);
su1 = [z;su] ;
s_u=repmat(su1,N);
seems like the concatenation of matrix is not being done.
I am a beginner so having serious troubles,please help.
Use cell arrays and the answer to your previous question
A = [2 3; 4 1];
B = [3 ;2 ];
N = 60;
[cs{1:(N+1),1:N}] = deal( zeros(size(B)) ); %// allocate space, setting top triangle to zero
%// work on diagonals
x = B;
for ii=2:(N+1)
[cs{ii:(N+2):((N+1)*(N+2-ii))}] = deal(x); %//deal to diagonal
x = A*x;
end
s = cell2mat(cs); %// convert cells to a single matrix
For more information you can read about deal and cell2mat.
Important note about the difference between matrix operations and element-wise operations
In your question (and in your previous one) you confuse between matrix power: A^2 and element-wise operation A.^2:
matrix power A^2 = [16 9;12 13] is the matrix product of A*A
element-wise power A.^2 takes each element separately and computes its square: A.^2 = [4 9; 16 1]
In yor question you ask about matrix product A*b, but the code you write is A.*b which is an element-by-element product. This gives you an error since the size of A and the size of b are not the same.
I often find that Matlab gives itself to a coding approach of "write what it says in the equation". That also leads to code that is easy to read...
A = [2 3; 4 1];
B = [3; 2];
Q = 4;
%// don't need to...
s = [];
%// ...but better to pre-allocate s for performance
s = zeros((Q+1)*2, Q);
X = B;
for m = 2:Q+1
for n = m:Q+1
s(n*2+(-1:0), n-m+1) = X;
end
X = A * X;
end

how to select specific index in 3rd matrix from third dimention in matlab

I know this is a simple question but difficult to formulate in one sentence to google the answer.So, I have a 3d matrix with size 2x2x3 like this
A(:,:,1) =[1 1; 1 1];
A(:,:,2) =[2 2; 2 2];
A(:,:,3) =[4 4; 4 4];
and matrix B with size 2x2
B = [ 1 2; 2 3];
What i need is to chose from each third dimension in A just one number using matrix B:
for i=1:2,
for j=1:2,
C(i,j) = A(i,j,B(i,j));
end
end
How to that in one line without a loop?
Not really a single line, but without a loop:
[I J] = ind2sub (size(B), 1:numel(B));
linInd = sub2ind (size (A), I, J, B(:)');
C = reshape (A(linInd), size(B));
Here is another variation:
[r,c,~] = size(A);
[J,I] = meshgrid(1:size(B,1), 1:size(B,2));
idx = reshape(I(:) + r*(J(:)-1) + r*c*(B(:)-1), size(B));
C = A(idx)