Identify items in each grid using MATLAB - matlab

I have data set in refxy size 500 x 3 where each row represents one location such that 1st, 2nd and 3rd columns have x coordinate, y coordinate and the weight v1 of the location. Using following code, I divide this area into 14 x 18 grid and I find how many points in each grid which gives in output blockNums_v1.
function gridcounttest
load refxy
x = refxy(:,1);
y = refxy(:,2);
v1 = refxy(:,3);
nBinsX = 14 ;
nBinsY = 18 ;
xg = linspace( 0, 700, nBinsX+1 ) ;
yg = linspace( 0, 900, nBinsY+1 ) ;
nCells = nBinsX * nBinsY ;
xId = sum( bsxfun( #ge, x, xg(1:end-1) ), 2 ) ;
yId = sum( bsxfun( #ge, y, yg(1:end-1) ), 2 ) ;
cellId = nBinsY * (xId - 1) + yId ;
blockNums_v1 = accumarray( cellId, 1, [nCells, 1] )
blockSum_v1 = accumarray( cellId, v1, [nCells, 1] )
blockMean_v2 = accumarray( cellId, v1, [nCells, 1], #mean )
Can someone please help me to identify which points, probably the row numbers, are included in each grid? e.g., if grid number 10 has 3 points which are in row 23, 51 and 432. This code gives output 3 but NOT 23, 51, 432 which I need to get now :)
Thanks !!!

You can find the rows of points which are in a grid element by
rowsOfValuesInGridpoint10 = find(cellId == 10);
The problem is that the output is not uniform, when you want to find the points of several grid elements.
You could store the rows in Matlab-cells, e.g.
for i=1:nCells
rowsInThisElement{i} = find(cellId == i);
end
rowsInThisElement{10}

Related

Multidimensional data storage and interpolation

I have a function (so to speak, i actually have data with this characteristic) with one variable x and several parameters a, b and c, so y = f(x, a, b, c).
Now i want to interpolate within families of parameters (for example for variations of a).
I'm currently doing this for data with one parameter (here, y is the data matrix)
% generate variable and data
x = linspace(0, 1, 100);
a = [0, 1]; % parameter
for i = 1:length(a)
y(:, i) = x.^2 + a(i);
end
% interpolate:
yi = interp1(a, y.', 0.5);
This works fine, but how do i expand this to more dimensions?
My current data format is like this: Each column of my data matrix represents one specific set of parameters, so for example:
0 0 0 0
1 1 1 1
2 2 2 2
3 3 3 3
where the first column denotes a = 0, b = 0, the second a = 1, b = 0, the third a = 0, b = 1 and the last a = 1, b = 1 (values are just for clarification, this is not on purpose binary. Also, the data columns are obviously not the same).
This data format is just the consequence of my data aquisition scheme, but i'm happy to change this into something more useful. Whatever works.
Works well for me:
% generate variable and data
x = linspace(0, 1, 100);
a = [0, 1, 2]; % parameter
b = [3, 4, 5]; % parameter
c = [6, 7, 8]; % parameter
% Create grid
[X,A,B,C]=ndgrid(x,a,b,c);
% define function
foo = #(x,p1,p2,p3) p1.*x.^2 + p2.*x + p3;
% evaluate function
Y = foo(X,A,B,C);
% interpolate:
yi = interpn(X,A,B,C,Y,x,1,4,6);
#zlon's answer works fine for the interpolation part, here i want to show how to convert the data from the format i provided to the needed format for the interpolation.
The two-dimensional matrix must be transformed into a N-dimensional one. Since the columns are not necessarily in order, we need to find the right ones. This is what i did:
First, we need to know the parameter set of each column:
a = [ 2, 2, 1, 0, 0, 1 ];
b = [ 1, 0, 0, 1, 0, 1 ];
These vectors length match the number of columns in the data matrix. The first column for example now contains the data for a = 2 and b = 1.
Now we can generate the new table:
A = -Inf;
i = 1;
while true
A = min(a(a > A)); % find next a
if isempty(A)
break
end
idxa = find(a == A); % store possible indices
B = -Inf;
j = 1;
while true
B = min(b(b > B))); % find next b
if isempty(B)
break
end
idxb = find(b == B); % store possible indices
% combine both indices
idx = intersect(idxa, idxb);
% save column in new data table
data(:, i, j) = olddata(:, idx);
% advance
j = j + 1;
end
i = i + 1;
end

How can I hot one encode in Matlab? [duplicate]

This question already has answers here:
Create a zero-filled 2D array with ones at positions indexed by a vector
(4 answers)
Closed 5 years ago.
Often you are given a vector of integer values representing your labels (aka classes), for example
[2; 1; 3; 3; 2]
and you would like to hot one encode this vector, such that each value is represented by a 1 in the column indicated by the value in each row of the labels vector, for example
[0 1 0;
1 0 0;
0 0 1;
0 0 1;
0 1 0]
For speed and memory savings, you can use bsxfun combined with eq to accomplish the same thing. While your eye solution may work, your memory usage grows quadratically with the number of unique values in X.
Y = bsxfun(#eq, X(:), 1:max(X));
Or as an anonymous function if you prefer:
hotone = #(X)bsxfun(#eq, X(:), 1:max(X));
Or if you're on Octave (or MATLAB version R2016b and later) , you can take advantage of automatic broadcasting and simply do the following as suggested by #Tasos.
Y = X == 1:max(X);
Benchmark
Here is a quick benchmark showing the performance of the various answers with varying number of elements on X and varying number of unique values in X.
function benchit()
nUnique = round(linspace(10, 1000, 10));
nElements = round(linspace(10, 1000, 12));
times1 = zeros(numel(nUnique), numel(nElements));
times2 = zeros(numel(nUnique), numel(nElements));
times3 = zeros(numel(nUnique), numel(nElements));
times4 = zeros(numel(nUnique), numel(nElements));
times5 = zeros(numel(nUnique), numel(nElements));
for m = 1:numel(nUnique)
for n = 1:numel(nElements)
X = randi(nUnique(m), nElements(n), 1);
times1(m,n) = timeit(#()bsxfunApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times2(m,n) = timeit(#()eyeApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times3(m,n) = timeit(#()sub2indApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times4(m,n) = timeit(#()sparseApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times5(m,n) = timeit(#()sparseFullApproach(X));
end
end
colors = get(0, 'defaultaxescolororder');
figure;
surf(nElements, nUnique, times1 * 1000, 'FaceColor', colors(1,:), 'FaceAlpha', 0.5);
hold on
surf(nElements, nUnique, times2 * 1000, 'FaceColor', colors(2,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times3 * 1000, 'FaceColor', colors(3,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times4 * 1000, 'FaceColor', colors(4,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times5 * 1000, 'FaceColor', colors(5,:), 'FaceAlpha', 0.5);
view([46.1000 34.8000])
grid on
xlabel('Elements')
ylabel('Unique Values')
zlabel('Execution Time (ms)')
legend({'bsxfun', 'eye', 'sub2ind', 'sparse', 'full(sparse)'}, 'Location', 'Northwest')
end
function Y = bsxfunApproach(X)
Y = bsxfun(#eq, X(:), 1:max(X));
end
function Y = eyeApproach(X)
tmp = eye(max(X));
Y = tmp(X, :);
end
function Y = sub2indApproach(X)
LinearIndices = sub2ind([length(X),max(X)], [1:length(X)]', X);
Y = zeros(length(X), max(X));
Y(LinearIndices) = 1;
end
function Y = sparseApproach(X)
Y = sparse(1:numel(X), X,1);
end
function Y = sparseFullApproach(X)
Y = full(sparse(1:numel(X), X,1));
end
Results
If you need a non-sparse output bsxfun performs the best, but if you can use a sparse matrix (without conversion to a full matrix), then that is the fastest and most memory efficient option.
You can use the identity matrix and index into it using the input/labels vector, for example if the labels vector X is some random integer vector
X = randi(3,5,1)
ans =
2
1
2
3
3
then, the following will hot one encode X
eye(max(X))(X,:)
which can be conveniently defined as a function using
hotone = #(v) eye(max(v))(v,:)
EDIT:
Although the solution above works in Octave, you have you modify it for Matlab as follows
I = eye(max(X));
I(X,:)
I think this is fast specially when matrix dimension grows:
Y = sparse(1:numel(X), X,1);
or
Y = full(sparse(1:numel(X), X,1));
Just posting the sub2ind solution too to satisfy your curiosity :)
But I like your solution better :p
>> X = [2,1,2,3,3]'
>> LinearIndices = sub2ind([length(X),3], [1:length(X)]', X);
>> tmp = zeros(length(X), 3);
>> tmp(LinearIndices) = 1
tmp =
0 1 0
1 0 0
0 1 0
0 0 1
0 0 1
Just in case someone is looking for the 2D case (as I was):
X = [2 1; ...
3 3; ...
2 4]
Y = zeros(3,2,4)
for i = 1:4
Y(:,:,i) = ind2sub(X,X==i)
end
gives a one-hot encoded matrix along the 3rd dimension.

Subtract background from image

I am trying to to subtract the background from a picture of an object to leave only the foreground object. I have found the RGB values of the background as 218 220 219 using imshow(). How can I use the RGB values with imsubtract()?
y = [218 220 219];
z = imsubtract(img,y);
Error using imsubtract (line 55)
X and Y must have the same size and class, or Y must be a scalar double.
You can use bsxfun to do that
z = bsxfun( #minus, img, permute( [218 220 219], [1 3 2] ) );
You need to pay attention to data type and range. If img is of type uint8 pixel values will be in range 0..255 but it will be difficult to subtract values as you'll see results underflowing at 0: uint8(4) - uint8(10) is 0...
Thus, you might want to convert img to double using im2double having pixel values in range 0..1. In that case you'll have to convert the "gray" vector [2218 220 219] to 0..1 range by dividing it by 255.
So, a more complete solution would be
z = bsxfun( #minus, im2double(img), permute( [218 220 219]/255, [1 3 2] ) );
The following ended up getting me closer to the answer I was looking for, although not without your guidance!
img = imread('IMG_0792.jpg');
img = im2double(img);
rows = numel(img(:,1,1));
columns = numel(img(1,:,1));
for i = 1:rows
for j = 1:columns
if ( ( img(i,j,1) > 0.75) && ( img(i,j,2) > 0.7) && ( img(i,j,3) > 0.7) )
img(i,j,1) = 1;
img(i,j,2) = 1;
img(i,j,3) = 1;
end
end
end
imshow(img);

matlab convert subwindow into vector

% obtain small windows of the image (say 16x16 windows and possibly using the crop function)
[rows columns] = size(B);
blockSizeR = 25; % Rows in block.
blockSizeC = 25; % Columns in block.
wholeBlockRows = floor(rows / blockSizeR);
wholeBlockCols = floor(columns / blockSizeC);
image3d = zeros(wholeBlockRows, wholeBlockCols);
sliceNumber = 1;
dataStruct = [];
for row = 1 : blockSizeR : rows
for col = 1 : blockSizeC : columns
row1 = row;
row2 = row1 + blockSizeR - 1;
col1 = col;
col2 = col1 + blockSizeC - 1;
oneBlock = B(row1:row2, col1:col2);
subplot(4, 4, sliceNumber);
imshow(oneBlock);
caption = sprintf('Block #%d of 16', sliceNumber);
title(caption);
drawnow;
dataStruct = [dataStruct, oneBlock(:)];
sliceNumber = sliceNumber + 1;
end
end
I am trying to extract 16 25x25 subwindows from a 100x100 pixel image, then convert each subwindow into a 125 column vector, but my data structure for appending all these vectors seem to be 625 x 16 instead of 125 x 16.
The subwindows seem to be displayed fine in the figure. Any clues as to where i went wrong would be much appreciated.
You can use mat2cell and cellfun:
dataStruct = mat2cell( B, blockSizeR * ones( 1, wholeBlockRows ), ...
blockSizeC * ones( 1, wholeBlockCols ) );
dataStruct = cellfun( #(x) x(:), dataStruct, 'uni', 0 );
dataStruct = [dataStruct{:}];

Is there a way to use the column before and after a center column to do analysis?

I'm trying to do analysis on datasets that have a varying number of columns, but I need to use 3 columns per use of my equation. I want to use all columns in my dataset (with the exception of the first and last as they will not work) But I need to select a center column, the column before, and the column after. I need to implement these equations:
lower_actual = lower_original - dark;
lower_avg = sum(lower_actual)/length(lower_actual);
lower_gain = lower_avg./lower_actual;
upper_actual = upper_original - dark;
upper_avg = sum(upper_actual)/length(upper_actual);
upper_gain = upper_avg./upper_actual;
middle_actual = middle_original - dark;
x1 = lower_actual;
x2 = middle_actual;
x3 = upper_actual;
y1 = lower_gain;
y3 = upper_gain;
y2 = (((x2-x1).*(y3-y1))./(x3-x1))+y1;
interpolate = y2.*middle_actual;
In these equations the variables correlate to:
lower = column before
middle = center column
upper = column after
dark = first column in data set
You could use HANKEL function to generate all possible indices of all three consecutive columns (with the exception of the first and last ones):
Example:
>> X = rand(10,7);
>> idx = hankel((1:3)+1, 3+1:size(M,2)-1)
idx =
2 3 4
3 4 5
4 5 6
Each column gives you the indices of before/middle/after of one combination of columns of X in that order:
interpolate = zeros(size(X,1), size(idx,2));
for i=1:size(idx,2)
ind = idx(:,i);
xLower = X(:,ind(1));
xMiddle = X(:,ind(2));
xUpper = X(:,ind(3));
%# perform calculations
interpolate(:,i) = ...;
end
Suppose you work on a matrix M, e.g.
M = randn(10, 7);
Just loop over the columns skipping the first one and the last one.
interpolate = zeros(size(M, 1), size(M, 2) - 2);
dark = M(:, 1);
% Loop over the columns. Do not use the first and the last column as
% center columns.
for idx = 2 : size(M, 2) - 2
lower_original = M(:, idx);
middle_original = M(:, idx + 1);
upper_original = M(:, idx + 2);
% Your computations.
lower_actual = lower_original - dark;
lower_avg = mean(lower_actual);
lower_gain = lower_avg./lower_actual;
upper_actual = upper_original - dark;
upper_avg = mean(upper_actual);
upper_gain = upper_avg./upper_actual;
middle_actual = middle_original - dark;
x1 = lower_actual;
x2 = middle_actual;
x3 = upper_actual;
y1 = lower_gain;
y3 = upper_gain;
y2 = (((x2-x1).*(y3-y1))./(x3-x1))+y1;
interpolate(:, idx - 1) = y2.*middle_actual;
end
The maximum column index which is fetched is size(M, 2) - 3 + 2 == size(M, 2) - 1, i.e. the last column will be skipped.