Indexing issue in MATLAB (image processing) - matlab

I'm dealing with a predictive block-matching motion estimation algorithm. This means, the values of motion vectors are found using the previously found values and I am stuck with a really trivial thing.
I'm dealing with images divided into blocks, so I should have a motion vector for each block. I created a 2xN matrix motion_vectors, where N is the number of all blocks (blocks_in_the_first_row*blocks_in_the_first_column). The first row is the x coordinate and second row the y coordinate of the motion vector.
I have 2 predictors to help to estimate the motion vector of the current block.
If my current block is at position (i,j) then the positions of the predictors are (i, j-1) (the block "on top)" and (i-1, j) (the block on the left).
My problem is, that I can't figure out a way how to adress the predictor blocks (in for loops) in motion_vectors since the dimensions are different (one is a 2xN matrix, the other blocks_in_row x blocks_in_column). I also wouldn't like to change the dimensions of motion_vectors, since then I would need a two-"layer" array. One for the x coordinates and one for y, but that doesn't fit to the further design.
I hope I made myself understandable, if not, please let me know.
Thanks for any clues!

If you're accessing an element of motion_vectors, you're getting data about a corresponding block. That means that there's a system of translating between an index 1 through N, where N is blocks_in_row*blocks_in_column, and a specific block. If index 1 is the top-left block, index 2 is the block to its right, and you increment as reading a book (left-to-right and wrap to the next row), then you would translate as follows:
row_of_block = floor((index_in_motion_vector-1)/number_of_columns) + 1
col_of_block = mod((index_in_motion_vector-1), number_of_columns) + 1
(This is called row-major ordering.)
If instead index 1 is the top-left block and index 2 is the block below it, and you wrap to the top of the next column when done with one, then the conversion would be
row_of_block = mod((index_in_motion_vector-1), number_of_rows) + 1
col_of_block = floor((index_in_motion_vector-1)/number_of_rows) + 1
(This is called column-major ordering, and is what MATLAB uses by default.)
So, if you're iterating 1 to N, you can just use those conversions. If you'd like to iterate 1 through number_of_rows, and 1 through number_of_columns you would do the opposite.
If you're using the book-like indexing of blocks (row-major ordering), the conversion to index of the motion vector would be
col_in_motion_vector = (row_of_block-1)*number_of_columns + column_of_block
If you're using the second, top-to-bottom-and-wrap method of indexing blocks (column-major ordering), the conversion would instead be
col_in_motion_vector = (column_of_block-1)*number_of_rows + row_of_block

Related

Modifying matrix values ± a specific index value - MATLAB

I am attempting to create a model whereby there is a line - represented as a 1D matrix populated with 1's - and points on the line are generated at random. Every time a point is chosen (A), it creates a 'zone of exclusion' (based on an exponential function) such that choosing another point nearby has a much lower probability of occurring.
Two main questions:
(1) What is the best way to generate an exponential such that I can multiply the numbers surrounding the chosen point to create the zone of exclusion? I know of exppdf however i'm not sure if this allows me to create an exponential which terminates at 1, as I need the zone of exclusion to end and the probability to return to 1 eventually.
(2) How can I modify matrix values plus/minus a specific index (including that index)? I got as far as:
x(1:100) = 1; % Creates a 1D-matrix populated with 1's
p = randi([1 100],1,1);
x(p) =
But am not sure how to go about using the randomly generated number to alter values in the matrix.
Any help would be much appreciated,
Anna
Don't worry about exppdf, pick the width you want (how far away from the selected point does the probability return to 1?) and define some simple function that makes a small vector with zero in the middle and 1 at the edges. So here I'm just modifying a section of length 11 centred on p and doing nothing to the rest of x:
x(1:100)=1;
p = randi([1 100],1,1);
% following just scaled
somedist = (abs(-5:5).^2)/25;
% note - this will fail if p is at edges of data, but see below
x(p-5:p+5)=x(p-5:p+5).*somedist;
Then, instead of using randi to pick points you can use datasample which allows for giving weights. In this case your "data" is just the numbers 1:100. However, to make edges easier I'd suggest initialising with a "weight" vector which has zero padding - these sections of x will not be sampled from but stop you from having to make edge checks.
x = zeros([1 110]);
x(6:105)=1;
somedist = (abs(-5:5).^2)/25;
nsamples = 10;
for n = 1:nsamples
p = datasample(1:110,1,'Weights',x);
% if required store chosen p somewhere
x(p-5:p+5)=x(p-5:p+5).*somedist;
end
For an exponential exclusion zone you could do something like:
somedist = exp(abs(-5:5))/exp(5)-exp(0)/exp(5);
It doesn't quite return to 1 but fairly close. Here's the central region of x (ignoring the padding) after two separate runs:

Beginner Matrix Access in MATLAB

Now first off, I am not even sure this is called a matrix, and I am new to MATLAB. But let's say I have a "matrix" that looks like this:
for n=1:10
...
someImage = mat(:,:,n) %The "matrix"
...
end
where n could be the frames in a video, for example, and the first 2 ':' are the row and column data for the 2D image (the frame).
If I only wanted the first ':' of data (the row? column? element?), how would I access only that?
Intuitively, I think something like:
row1 = mat(:,0,0)
row2 = mat(0,:,0)
row3 = mat(0,0,:)
but that doesn't seem to be working.
P.S. I know that these aren't really rows, the terminology for all this would also be greatly appreciated
Also, it may not have anything to do with this, but I am using a MATLAB GUI as well, and the "matrix" is stored like this:
handles.mat(:,:,n)
I don't think it has anything to do with my actual question, but it might so I will put it here
-Thanks!
One point I would like to make before starting: MATLAB starts indexing at 1, and not 0. This is a common mistake that most people who have a C/Java/Python programming background make going into MATLAB.
Also, by doing:
row1 = mat(:,1,1);
This accesses all of the rows for the first column and the first frame of your video. Be aware that this will produce a M x 1 vector, where M denotes the number of rows for a frame in your video.
Also:
row2 = mat(1,:,1);
This accesses all of the columns in the first row of the first frame. Be aware that this will produce a 1 x N vector, where N denotes the number of columns for a frame in your video.
Also:
row3 = mat(1,1,:);
This accesses all of the pixels in the entire video sequence at row 1 and column 1. You can think of this as a temporal slice at the top left corner of your video sequence. Be aware that this will produce a 1 x 1 x T vector, where T is the number of frames in your video. If you access just a single pixel location in your video, the first two dimensions are superfluous, and so you can use the squeeze command to shrink all of the singleton dimensions so that it simplifies to a T x 1 vector. In other words, do this:
row3 = squeeze(mat(1,1,:));
FWIW, you do have the right terminology. Rows and columns are used in image / video processing all the time. As for the "matrix", you can call this a temporal sequence or a frame sequence in terms of video processing. It certainly is a 3D matrix, but people in this domain denote it as either one of the two as it is really a sequence of images / frames stacked on top of each other.

Matlab - Dilation function alternative

I'm looking through various online sources trying to learn some new stuff with matlab.
I can across a dilation function, shown below:
function rtn = dilation(in)
h =size(in,1);
l =size(in,2);
rtn = zeros(h,l,3);
rtn(:,:,1)=[in(2:h,:); in(h,:)];
rtn(:,:,2)=in;
rtn(:,:,3)=[in(1,:); in(1:h-1,:)];
rtn_two = max(rtn,[],3);
rtn(:,:,1)=[rtn_two(:,2:l), rtn_two(:,l)];
rtn(:,:,2)=rtn_two;
rtn(:,:,3)=[rtn_two(:,1), rtn_two(:,1:l-1)];
rtn = max(rtn,[],3);
The parameter it takes is: max(img,[],3) %where img is an image
I was wondering if anyone could shed some light on what this function appears to do and if there's a better (or less confusing way) to do it? Apart from a small wiki entry, I can't seem to find any documentation, hence asking for your help.
Could this be achieved with the imdilate function maybe?
What this is doing is creating two copies of the image shifted by one pixel up/down (with the last/first row duplicated to preserve size), then taking the max value of the 3 images at each point to create a vertically dilated image. Since the shifted copies and the original are layered in a 3-d matrix, max(img,[],3) 'flattens' the 3 layers along the 3rd dimension. It then repeats this column-wise for the horizontal part of the dilation.
For a trivial image:
00100
20000
00030
Step 1:
(:,:,1) (:,:,2) (:,:,3) max
20000 00100 00100 20100
00030 20000 00100 20130
00030 00030 20000 20030
Step 2:
(:,:,1) (:,:,2) (:,:,3) max
01000 20100 22010 22110
01300 20130 22013 22333
00300 20030 22003 22333
You're absolutely correct this would be simpler with the Image Processing Toolbox:
rtn = imdilate(in, ones(3));
With the original code, dilating by more than one pixel would require multiple iterations, and because it operates one dimension at a time it's limited to square (or possibly rectangular, with a bit of modification) structuring elements.
Your function replaces each element with the maximum value among the corresponding 3*3 kernel. By creating a 3D matrix, the function align each element with two of its shift, thus equivalently achieves the 3*3 kernel. Such alignment was done twice to find the maximum value along each column and row respectively.
You can generate a simple matrix to compare the result with imdilate:
a=magic(8)
rtn = dilation(a)
b=imdilate(a,ones(3))
Besides imdilate, you can also use
c=ordfilt2(a,9,ones(3))
to get the same result ( implements a 3-by-3 maximum filter. )
EDIT
You may have a try on 3D image with imdilate as well:
a(:,:,1)=magic(8);
a(:,:,2)=magic(8);
a(:,:,3)=magic(8);
mask = true(3,3,3);
mask(2,2,2) = false;
d = imdilate(a,mask);

how to find mean of columns in nested structure in MATLAB

I've organized some data into a nested structure that includes several subjects, 4-5 trials per subject, then identifying data like height, joint torque over a gait cycle, etc. So, for example:
subject(2).trial(4).torque
gives a matrix of joint torques for the 4th trial of subject 2, where the torque matrix columns represent degrees of freedom (hip, knee, etc.) and the rows represent time increments from 0 through 100% of a stride. What I want to do is take the mean of 5 trials for each degree of freedom and use that to represent the subject (for that degree of freedom). When I try to do it like this for the 1st degree of freedom:
for i = 2:24
numTrialsThisSubject = size(subject(i).trial, 2);
subject(i).torque = mean(subject(i).trial(1:numTrialsThisSubject).torque(:,1), 2);
end
I get this error:
??? Scalar index required for this type of multi-level indexing.
I know I can use a nested for loop to loop through the trials, store them in a temp matrix, then take the mean of the temp columns, but I'd like to avoid creating another variable for the temp matrix if I can. Is this possible?
You can use a combination of deal() and cell2mat().
Try this (use the built-in debugger to run through the code to see how it works):
for subject_k = 2:24
% create temporary cell array for holding the matrices:
temp_torques = cell(length(subject(subject_k).trial), 1);
% deal the matrices from all the trials (copy to temp_torques):
[temp_torques{:}] = deal(subject(subject_k).trial.torque);
% convert to a matrix and concatenate all matrices over rows:
temp_torques = cell2mat(temp_torques);
% calculate mean of degree of freedom number 1 for all trials:
subject(subject_k).torque = mean(temp_torques(:,1));
end
Notice that I use subject_k for the subject counter variable. Be careful with using i and j in MATLAB as names of variables, as they are already defined as 0 + 1.000i (complex number).
As mentioned above in my comment, adding another loop and temp variable turned out to be the simplest execution.

For loop inside another for loop to make new set of vectors

I would like to use a for loop within a for loop (I think) to produce a number of vectors which I can use separately to use polyfit with.
I have a 768x768 matrix and I have split this into 768 separate cell vectors. However I want to split each 1x768 matrix into sections of 16 points - i.e. 48 new vectors which are 16 values in length. I want then to do some curve fitting with this information.
I want to name each of the 48 vectors something different however I want to do this for each of the 768 columns. I can easily do this for either separately but I was hoping that there was a way to combine them. I tried to do this as a for statement within a for statement however it doesn't work, I wondered if anyone could give me some hints on how to produce what I want. I have attached the code.
Qne is my 768*768 matrix with all the points.
N1=768;
x=cell(N,1);
for ii=1:N1;
x{ii}=Qnew(1:N1,ii);
end
for iii = 1:768;
x2{iii}=x{iii};
for iv = 1:39
N2=20;
x3{iii}=x2{iii}(1,(1+N2*iv:N2+N2*iv));
%Gx{iv}=(x3{iv});
end
end
Use a normal 2D matrix for your inner split. Why? It's easy to reshape, and many of the fitting operations you'll likely use will operate on columns of a matrix already.
for ii=1:N1
x{ii} = reshape(Qnew(:, ii), 16, 48);
end
Now x{ii} is a 2D matrix, size 16x48. If you want to address the jj'th split window separately, you can say x{ii}(:, jj). But often you won't have to. If, for example, you want the mean of each window, you can just say mean(x{ii}), which will take the mean of each column, and give you a 48-element row vector back out.
Extra reference for the unasked question: If you ever want overlapping windows of a vector instead of abutting, see buffer in the signal processing toolbox.
Editing my answer:
Going one step further, a 3D matrix is probably the best representation for equal-sized vectors. Remembering that reshape() reads out columnwise, and fills the new matrix columnwise, this can be done with a single reshape:
x = reshape(Qnew, 16, 48, N1);
x is now a 16x48x768 3D array, and the jj'th window of the ii'th vector is now x(:, jj, ii).