I have two vectors
K=[1 1 1 2 1 2 1 4 2 10 4 5 1]
and
L=[2 0 1 2 1 2 1 3 2 0 1 2 1]
I want to compare the value of the 7th element in each vector with the neighbours of this value, where the neighbours are 5 elements next to this element in each side. So for K, the 7th element is 1 and the neighbours are 1 1 1 2 1 2 (left neighbours) and 4 2 10 4 5 1 (right neighbours).
For L, the 7th element is 1 and the neighbours are 2 0 1 2 1 2 (left neighbours) and 3 2 0 1 2 1 (right neighbours). If the difference between the 7th value and each of its neighbours is above a certain threshold then I'll do something e.g X=1, if not then I'll do another thing e.g X=2.
So in my example I'll set the threshold to 3, so for K the 7th element value is 1 and the difference between it and two of its neighbours 10,5 are more than the threshold value 3 so X will be 1. For L the 5th element value is 1 and the difference between it and all of its neighbours is less than the threshold value 3 so X will be 2. So I'm wondering if anyone could assist me to do this condition, I'm not sure if this can be done without loops to save time.
You can check this condition using any and or:
N = 5; % reference index
T = 3; % threshold
V = L; % used to pass the vector L to the if-statement
% V = K;
% formulate if-statement to check for values
% below/above index N and check if any difference
% exceeds the threshold
% the or-statement (because it does not matter if the
% threshold is exceeded above index N or below)
% is expressed as |
if any((V(1:N-1)-V(N))>T) | any((V(N+1:end)-V(N))>T)
X = 1;
else
X = 2;
end
Note
Depending on your Matlab version V(1:N-1)-V(N) will not work, because the matrix dimensions do not agree. In this case use: V(1:N-1)-ones(size(V(1:N-1))).*V(N)
Related
I have the following code:
x = VarName3;
y = VarName4;
x = (x/6000)/60;
plot(x, y)
Where VarName3 and VarName4 are 3000x1. I would like to apply a median filter to this in MATLAB. However, the problem I am having is that, if I use medfilt1, then I can only enter a single array of variables as the first argument. And for medfilt2, I can only enter a matrix as the first argument. But the data looks very obscured if I convert x and y into a matrix.
The x is time and y is a list of integers. I'd like to be able to filter out spikes and dips. How do I go about doing this? I was thinking of just eliminating the erroneous data points by direct manipulation of the data file. But then, I don't really get the effect of a median filter.
I found a solution using sort.
Median is the center element, so you can sort three elements, and take the middle element as median.
sort function also returns the index of the previous syntaxes.
I used the index information for restoring the matching value of X.
Here is my code sample:
%X - simulates time.
X = [1 2 3 4 5 6 7 8 9 10];
%Y - simulates data
Y = [0 1 2 0 100 1 1 1 2 3];
%Create three vectors:
Y0 = [0, Y(1:end-1)]; %Left elements [0 0 1 2 0 2 1 1 1 2]
Y1 = Y; %Center elements [0 1 2 0 2 1 1 1 2 3]
Y2 = [Y(2:end), 0]; %Right elements [1 2 0 2 1 1 1 2 3 0]
%Concatenate Y0, Y1 and Y2.
YYY = [Y0; Y1; Y2];
%Sort YYY:
%sortedYYY(2, :) equals medfilt1(Y)
%I(2, :) equals the index: value 1 for Y0, 2 for Y1 and 3 for Y2.
[sortedYYY, I] = sort(YYY);
%Median is the center of sorted 3 elements.
medY = sortedYYY(2, :);
%Corrected X index of medY
medX = X + I(2, :) - 2;
%Protect X from exceeding original boundries.
medX = min(max(medX, min(X)), max(X));
Result:
medX =
1 2 2 3 6 7 7 8 9 9
>> medY
medY =
0 1 1 2 1 1 1 1 2 2
Use a sliding window on the data vector centred at a given time. The value of your filtered output at that time is the median value of the data in the sliding window. The size of the sliding window is an odd value, not necessarily fixed to 3.
Say X is the given vector:
X=[1
2
4
2
3
1
4
5
2
4
5];
And Y is the given subset of elements from X:
Y=[3
4
5];
The required output is the number of times the elements in Y occur in X:
out=[1
3
2];
My solution to do this would be to use for loop:
for i=1:size(X,1)
temp = X(X(:,1)==Y(i,1),:);
out(i,1) = size(temp,1);
end
But when X and Y are large, this is inefficient. So, how to do it faster making use of vectorization? I know about hist and histc, but I can't think of how to use them in this case to get the desired output.
A Fast Option
You could use bsxfun combined with sum to compute this
sum(bsxfun(#eq, Y, X.'), 2)
Explanation
In this example, bsxfun performs a given operation on every combination of elements in X and Y. The operation we're gonig to use is eq (a check for equality). The result is a matrix that has a row for each element in Y and a column for each element in X. It will have a 1 value if the element in X equals the element in Y that corresponds to a given row.
bsxfun(#eq, Y, X.')
% 0 0 0 0 1 0 0 0 0 0 0
% 0 0 1 0 0 0 1 0 0 1 0
% 0 0 0 0 0 0 0 1 0 0 1
We can then sum across the columns to count the number of elements in X that were equal to a given value in Y.
sum(bsxfun(#eq, Y, X.'), 2)
% 1
% 3
% 2
On newer versions of MATLAB (since R2016b), you can omit the bsxfun since the equality operation will automatically broadcast.
sum(Y - X.', 2)
A Memory-Efficient Option
The first option isn't the most efficient since it requires creating a matrix that is [numel(Y), numel(X)] elements large. Another way which may be more memory efficient may be to use the second output of ismember combined with accumarray
[tf, ind] = ismember(X, Y);
counts = accumarray(ind(tf), ones(sum(tf), 1), [numel(Y), 1], #numel);
Explanation
ismember is used to determine if the values in one array are in another. The first input tells us if each element of the first input is in the second input and the second output tells you where in the second input each element of the first input was found.
[tf, ind] = ismember(X, Y);
% 0 0 1 0 1 0 1 1 0 1 1
% 0 0 2 0 1 0 2 3 0 2 3
We can use the second input to "group" the same values together. The accumarray function does exactly this, it uses the ind variable above to determine groups and then applies a given operation to each group. In our case, we want to simply determine the number of element within each group. So to do that we can pass a second input the size of the ind input (minus the ones that didn't match) of ones, and then use numel as the operation (counts the number in each group)
counts = accumarray(ind(tf), ones(sum(tf), 1), [numel(Y), 1], #numel);
% 1
% 3
% 2
I have 2 matrices; Matrix A and Matrix B.
Matrix A = [1 3 6 2 7;
2 1 5 3 4;
8 3 7 2 1]
Matrix B = [0 0 1 0 0;
0 0 0 0 1;
0 1 0 0 0]
and I want to check if the '1' in matrix B is placed in a place in matrix A where it is greater than or equal to 6 then leave it as it is. But if it is smaller than 6, then go to the place of the number that is less than this number in matrix A and put a '1' in this place in matrix B and add the 2 numbers and recheck if the sum is equal to or greater than 6 and so on.
As you can see in matrix B row 2 the 1 is put in the place of 4 in matrix A. Since the 4 is less than 6 then I will go to the second smaller number than the 4 which in this case is 3 and add 3 and 4 together. This will give us 7 which is greater than 6 so we will stop. So here for example the output matrix will be:
Matrix output = [0 0 1 0 0;
0 0 0 1 1;
0 1 0 1 1]
The steps:
Go to the number that is just smaller than it. In this case go to 3 as it is the one that is just smaller than the 4. I can explain more:
check the place of the 1 in Matrix B and see its value in Matrix A.
If the number in Matrix A is greater than 6, leave it as it is and leave the 1 in Matrix B as it is and go to another row.
If the number in Matrix A is smaller than 6, then what we want is that we want add this number to another number and make it equal to or greater than 6.
This number is the one that is just smaller than it. For example if the row has [2 5 6 1 3] and the 1 is placed in the place of the 5 and 5 is less than the constraint. So we have to go to the 3 as it is the one that is just smaller than the 5 and add them together.
After adding them put 1's in the places of both numbers and check the constraints again. If it satisfies the constraint leave them and go to another row. If not go the one that is just smaller than the number again and do the same.
Thank you so much.
This code is working when matrix B is empty and it puts the 1 in the place of the highest number and it checks the constraint. If it is less than the number it will go to the second highest number and add and recheck and so on.. But what I want now is to solve it with predefined 0s and 1s
B=zeros(size(A));
for k=1:size(A,1)
a=A(k,:)
[b,ia]=sort(a,'descend')
c=cumsum(b)
jj=find(c>=6,1)
idx=ia(1:jj)
B(k,idx)=1
end
This one took a while, but I think I got it in the end...
Doing most of the process without loop except the final stage, plugging in the index row by row to change B which can be done by a arrayfun. I think there might be a few redundant steps, but I think it is pretty fast.
C = A';
D = B' > 0 ;
E = repmat(max(C(D),1),[1 size(A,2)]);
F = A-E<=0;
G = A.*F;
[H ind] = sort (G,2,'descend');
I = (cumsum(H,2) >=6)*-1 +1;
Indent = ones(size(A,1),1);
J = [Indent I];
K = J(:,1:size(A,2)).*ind;
for t= 1:size(A,1)
B(t,K(t,K(t,:)~=0)) = 1;
end
>> B =
0 0 1 0 0
0 0 0 1 1
0 1 0 1 1
Suppose I have matrix, where each cell of this matrix describes a location (e.g. a bin of a histogram) in a two dimensional space. Lets say, some of these cells contain a '1' and some a '2', indicating where object number 1 and 2 are located, respectively.
I now want to find those cells that describe the "touching points" between the two objects. How do I do that efficiently?
Here is a naive solution:
X = locations of object number 1 (x,y)
Y = locations of object number 2 (x,y)
distances = pdist2(X,Y,'cityblock');
Locations (x,y) and (u,v) touch, iff the respective entry in distances is 1. I believe that should work, however does not seem very clever and efficient.
Does anyone have a better solution? :)
Thank you!
Use morphological operations.
Let M be your matrix with zeros (no object) ones and twos indicating the locations of different objects.
M1 = M == 1; % create a logical mask of the first object
M2 = M == 2; % logical mask of second object
dM1 = imdilate( M1, [0 1 0; 1 1 1; 0 1 0] ); % "expand" the mask to the neighboring pixels
[touchesY touchesX] =...
find( dM1 & M2 ); % locations where the expansion of first object overlap with second one
Code
%%// Label matrix
L = [
0 0 2 0 0;
2 2 2 1 1;
2 2 1 1 0
0 1 1 1 1]
[X_row,X_col] = find(L==1);
[Y_row,Y_col] = find(L==2);
X = [X_row X_col];
Y = [Y_row Y_col];
%%// You code works till this point to get X and Y
%%// Peform subtractions so that later on could be used to detect
%%// where Y has any index that touches X
%%// Subtract all Y from all X. This can be done by getting one
%%//of them and in this case Y into the third dimension and then subtracting
%%// from all X using bsxfun. The output would be used to index into Y.
Y_touch = abs(bsxfun(#minus,X,permute(Y,[3 2 1])));
%%// Perform similar subtractions, but this time subtracting all X from Y
%%// by putting X into the third dimension. The idea this time is to index
%%// into X.
X_touch = abs(bsxfun(#minus,Y,permute(X,[3 2 1]))); %%// for X too
%%// Find all touching indices for X, which would be [1 1] from X_touch.
%%// Thus, their row-sum would be 2, which can then detected and using `all`
%%// command. The output from that can be "squeezed" into a 2D matrix using
%%// `squeeze` command and then the touching indices would be any `ones`
%%// columnwise.
ind_X = any(squeeze(all(X_touch==1,2)),1)
%%// Similarly for Y
ind_Y = any(squeeze(all(Y_touch==1,2)),1)
%%// Get the touching locations for X and Y
touching_loc = [X(ind_X,:) ; Y(ind_Y,:)]
%%// To verify, let us make the touching indices 10
L(sub2ind(size(L),touching_loc(:,1),touching_loc(:,2)))=10
Output
L =
0 0 2 0 0
2 2 2 1 1
2 2 1 1 0
0 1 1 1 1
L =
0 0 10 0 0
2 10 10 10 1
10 10 10 10 0
0 10 10 1 1
K=[1 1 1 2 1 2 10 4 2 10 0 5 1] is a vector, I want to compare the value of the 7th element in K with the neighbours of this value, where the neighbours are 6 elements next to this element in each side. So for K, the 7th element is 10 and the neighbours are 1 1 1 2 1 2 (left neighbours) and 4 2 10 4 5 1 (right neighbours).If the difference between the 7th value and each of its neighbours is above a certain threshold then I'll do something e.g X=1, if not then I'll do another thing e.g X=2.
So in my example below I set the threshold to 3, so for K the 7th element value is 10 and the difference between it and two of its neighbours 10,5 are more than the threshold value 3 so X will be 1. I'm comparing the X=1 because there are couple of elements with diff. more than T inc the 11th element0, but if K=[8 7 8 9 7 7 10 7 7 8 0 9 8] then X=2 although the diff. between it and the 11th element is >T but this is because the 11th element is zero0.
I'm using the below script related to my other question found here link
N = 6; % reference index
T = 3; % threshold
V = K;
% formulate if-statement to check for values
% below/above index N and check if any difference
% exceeds the threshold
% the or-statement (because it does not matter if the
% threshold is exceeded above index N or below)
% is expressed as |
if any((V(1:N-1)-V(N))>T) | any((V(N+1:end)-V(N))>T)
X = 1;
else
X = 2;
end
Hey I think you should check diff in-build function of matlab it solves my problem.