Iam facing problem in understanding and converting a matlab code into opencv. I want to know is there any equivalent function of sub2ind as in matlab in opencv. Or how to implement in opencv this particular function.
link for sub2ind function is
http://www.mathworks.in/help/techdoc/ref/sub2ind.html
A quick example to illustrate. Consider:
>> v = (1:4*3)
v =
1 2 3 4 5 6 7 8 9 10 11 12
>> M = reshape(v,[4 3])
M =
1 5 9
2 6 10
3 7 11
4 8 12
Now all the following are equivalent:
sz = size(M);
i = 3; j = 2;
M(i,j)
v( sub2ind(sz,i,j) )
v( sz(1)*(j-1)+i )
Just keep in mind that MATLAB uses a column-major order, while C is row-major order
Related
Unfortunately my programming skills are not that advanced and I really need to vectorize some loops to finish my thesis.
I tried to make things really clear and simple and I have the following two questions in matlab:
1.
If we have a 5x5 matrix A and we want to set the diagonal elements of this matrix to the diagonal of a matrix B, apart from diag(A)=diag(B) we could use :
for i=1:5
B(i,i)=A(i,i)
end
Now if I want to vectorize this I can not use:
i=1:5
B(i,i)=A(i,i)
In that way we assign each combination from 1:5. So, in the end we asign each element of A equal to B and not the diagonal.
Is there some way that we could assign each identical pair of (i,i)?
I tried :
i=1:5
j=1:5
B(i,find(j==i))=A(i,find(j==i))
But still does not work. I repeat I know the diag property but Im only interested on the particular problem.
2.
A similar problem is the fillowing.
b=[ones(2,2) ones(2,2)*2 ones(2,2)*3 ones(2,2)*4] ;
a = zeros(8,12);
for i=1:4
a((i-1)*2+1:(i)*2,(i-1)*3+1:(i)*3) = [8*ones(2,1) b(:,[2*(i-1)+1 2*i])];
end
Thank you for your time and for your help.
Let's bring some mask magic, shall we!
Problem #1
mask = eye(size(A))==1
A(mask) = B(mask)
For creating the mask, you can also use bsxfun -
N = size(A,1)
bsxfun(#eq,[1:N]',1:N)
Or finally, you can use linear indexing -
N = size(A,1)
A(1:N+1:N^2) = B(1:N+1:N^2)
Sample run -
>> A
A =
5 2 9 6 5
9 1 6 2 2
9 7 5 3 9
4 5 8 8 7
7 5 8 1 8
>> B
B =
5 5 2 8 2
1 1 6 5 2
7 8 5 4 4
1 8 9 8 8
1 7 6 1 8
>> mask = eye(size(A))==1;
>> A(mask) = B(mask)
A =
5 2 9 6 5
9 1 6 2 2
9 7 5 3 9
4 5 8 8 7
7 5 8 1 8
Problem #2
%// Append 8's at the start of every (2,2) block in b
b1 = reshape([8*ones(2,4) ; reshape(b,4,[])],2,[])
%// Mask where b1 values are to be put in an otherwise zeros filled array
mask = kron(eye(4,4),ones(2,3))==1
%// Initialize output arraya and set values from b1 into masked places
out = zeros(size(mask))
out(mask) = b1
For your first problem. Use logical indexing:
index = diag(ones(1,size(B,1))
B(index) = A(index)
let us consider following matrix
A=[1 2 3 4;2 4 6 7;3 1 9 8]
A =
1 2 3 4
2 4 6 7
3 1 9 8
size of which can easily be calculated using
n,m]=size(A)
n =
3
m =
4
let us consider that we want to get following vector v
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2)/2;
v(3)=(A(3,1)+A(2,2)+A(1,3))/3;
v(4)=(A(3,2)+A(2,3)+A(1,4))/3;
v(5)=(A(3,3)+A(2,4))/2;
v(6)=A(3,4);
definitely we need vector with size
v=zeros(n+m-1,1);
i have calculated first two element which seems trivial
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2))/2;
but all others i need to implement using cycles,please pay attention that i need it for general matrix using same principle,not exact for such matrix
my starting code is following
function [v]=dehankel(A);
%convert matrix A to vector using diagonal averaging
[n,m]=size(A);
v=zeros(n+m-1,1);
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2))/2;
for i=2:3
for j=2:3
please help me how to continue
A =
1 2 3 4
2 4 6 7
3 1 9 8
[n,m]=size(A);
v=zeros(n+m-1,1);
i = 1;
for d = -(n-1):(m-1)
v(i) = mean(diag(flipud(A),d));
i = i+1;
end
It can be done without loops (not the most readable code, I admit):
B = zeros(size(A,1)+size(A,2)-1, size(A,2));
B(bsxfun(#plus, (1:size(A,1)).', (0:size(A,2)-1)*(size(A,1)+size(A,1)+1))) = A;
v = sum(B.')./[1:size(A,1) size(A,1):-1:1];
I have matrix A in Matlab of dimension hxk and a matrix B of dimension yxk. I want to construct a vector C of dimension yx1 listing in each row j how many times B(j,:) appears in A.
If you are looking for perfect matches, one solution with bsxfun -
C = squeeze(sum(all(bsxfun(#eq,A,permute(B,[3 2 1])),2),1))
You can also use pdist2 (from the Statistics Toolbox):
C = sum(pdist2(A, B)==0);
Another solution using ismember and accumarray
A=[1 2 3; 4 5 6; 7 8 9; 1 2 3; 4 5 6; 10 11 12; 7 8 9];
B=[1 2 3; 10 11 12; 3 4 5; 7 8 9];
[uB,aB,cB]=unique(B,'rows');
[~,LocB] = ismember(A,uB,'rows');
C = accumarray(nonzeros(LocB),1,[size(B,1),1]);
C=C(cB);
which returns
C =
2 1 0 2
or some crazy coding which seems to be faster for most instances:
[u,v,w]=unique([B;A],'rows');
wB=w(1:size(B,1));
wA=w(size(B,1)+1:end);
C=accumarray(wA,1,[numel(v),1]);
C=C(wB);
This is the input matrix
7 9 6
8 7 9
7 6 7
Based on the frequency their appearance in the matrix (Note. these values are for explanation purpose. I didn't pre-calculate them in advance. That why I ask this question)
number frequency
6 2
7 4
8 1
9 2
and the output I expect is
4 2 2
1 4 2
4 2 4
Is there a simple way to do this?
Here's a three-line solution. First prepare the input:
X = [7 9 6;8 7 9;7 6 7];
Now do:
[a m n] = unique(X);
b = hist(X(:),a);
c = reshape(b(n),size(X));
Which gives this value for c:
4 2 2
1 4 2
4 2 4
If you also wanted the frequency matrix, you can get it with this code:
[a b']
Here is a code with for-loop (a is input matrix, freq - frequency matrix with 2 columns):
weight = zeros(size(a));
for k = 1:size(freq,1)
weight(a==freq(k,1)) = freq(k,2);
end
Maybe it can be solved without loops, but my code looks like:
M = [7 9 6 ;
8 7 9 ;
7 6 7 ;];
number = unique(M(:));
frequency = hist(M(:), number)';
map = containers.Map(number, frequency);
[height width] = size(M);
result = zeros(height, width); %allocate place
for i=1:height
for j=1:width
result(i,j) = map(M(i,j));
end
end
I don't have the package for nlfilter and I didn't quite follow this example.
I have a really simple function fun and I want to apply it to a moving window of an array. The array is Nx1, and I want to look at length k intervals, say. So for N=10 and k=3 and fun = #(x) min(x); I would get
A = [13 14 2 14 10 3 5 9 15 8];
filter(A,k,fun) = [2 2 2 3 3 3 5 8];
Here I only want to look at indices 1,2,3 then 2,3,4 then ... then 8,9,10, so the final sequence is length 7. I can do this easy with a for loop, but I have no idea how to vectorize it for Matlab. Help, please. Thanks.
Here is one very simple and fast way to do it:
>> min([A(1:(end-2)); A(2:(end-1)); A(3:end)], [], 1)
ans =
2 2 2 3 3 3 5 8
EDIT: Since you want a full function...
function running_min = running_min(x, k)
xrep = repmat(x, 1, k);
xrep = reshape([xrep zeros(1, k)], length(x)+1, k);
running_min = min(xrep, [], 2)';
running_min = running_min(1:end-k);
The post you mentioned gave a general solution for building sliding windows (you could control: overlapping vs. distinct, slide step, overlap amount, windows size)
In your case, it is much simpler and can be easily performed with the HANKEL function:
x = [13 14 2 14 10 3 5 9 15 8];
idx = hankel(1:3, 3:length(x))
min( x(idx) )
If you want to build a reusable solution:
function y = myFilter(x,k,fcn)
idx = hankel(1:k, k:length(x));
y = cellfun(fcn, num2cell(x(idx),1));
end
which we use as:
x = [13 14 2 14 10 3 5 9 15 8];
y = myFilter(x, 3, #(x)min(x))
Note I am using CELLFUN in case fcn cannot operate across dimensions in a vectorized manner...