access sub-matrix of a multidimensional Mat in OpenCV - matlab

according to this
post and from OpenCV documentation, I can initialize and access each element of a multidimensional Mat.
Actually, I firstly coded in MATLAB and now need to convert to OpenCV. MATLAB matrix supports sub-matrix access like: a(:,:,3) or b(:,:,3:5)
Can this be done in OpenCV? as far as I know, this can be done with 2D Mat. How about more that 2D??
Edit01:
moreover, with multidimensional Mat, the properties cols and rows are not enough to characterize 3 sizes of the matrix. There are cases with dimension larger than 3. How to store these properties?
Edit02:
// create a 100x100x100 8-bit array
int sz[] = {100, 100, 100};
Mat bigCube(3, sz, CV_8U, Scalar::all(0));
I give up the idea of sub-matrix access with OpenCV Mat. Perhaps, it's not supported in OpenCV. But from this sample code, the constructor receives the 3rd dimension from 'sz'. Which property of Mat this 3rd dimension is passed to? probably in this case, rows = 100, cols = 100, the other ?? = 100
I'm lost with OPenCV documentation
Edit03: tracking Mat class from OpenCV source
I've found the definition of the constructor in Edit02 from mat.hpp:
inline Mat::Mat(int _dims, const int* _sz, int _type, const Scalar& _s)
: flags(0), dims(0), rows(0), cols(0), data(0), refcount(0),
datastart(0), dataend(0), datalimit(0), allocator(0), size(&rows)
{
create(_dims, _sz, _type);
*this = _s;
}
the next question is where and how "create" function here is defined?
=> tracing this Mat definition in OpenCV probably helps me to modify/customize my own features in Mat matrix
PS: excuse me if my post is written too messy!! I'm a novic programmer, trying to solve my programming problem. Plz feel free to correct me if my approach is not good or right enough. Thank you!!

You can easily access sub-matrix of 2D cv::Mat using functions rowRange, colRange or even
cv::Mat subMat = originalMat(cv::Rect(x,y,width,height));
Also, the number of channels in a matrix, that you can define in the matrix constructor, can be used as the third dimension (but it is limited to 256 or 512 i think).
There is also the templated cv::Mat_ class that you can adapt to fit your purpose
[edit]
I have checked the constructor for >2 dimensional matrices. When you run it the rows and cols field of Mat are set to -1. The actual matrix size is store in Mat::size as an array of int.
For matrix of dimensions >2 you cannot use the submatrices constructors using a cv::Rect or rowRange/colRange.
I'm afraid you have to do a bit of work to extract submatrices for dim>2, working directly with the row data. But you can use the information stored in Mat::step which tells you the layout of the array. This is explained in the official documentation.

you can create sub-matrix by:
cv::Mat subMat(100,100,CV_8U, bigCube.ptr(0));
subMat is a 2-D matrix so you can do what you want.

Related

Matlab function reshape doesnt´t calculate the last dimension while trying to create a 3D image from .raw binary image file

I created binarized images by using the Otsu methode in Matlab and cut out parts of the resulting image using a function. Now i want to take a look at these images with the VolumeViewer command. I know the x,y and z dimensions of the resulting imgages. I currently run this code doing it(excluding the volumeViewerwhich happens after the loop):
files= {'C3\C3_000mal_550_539_527.raw';...
};
for i=1:numel(files)
Image = fopen(files{i},'r');
ImageData{i} = fread(Image,Inf,'uint16=>uint16');
ImageData{i} = reshape(ImageData{i},550,539,[]);
fclose(openedCrystalImage);
end
Using this code runs into the following error using reshape:
Error using reshape
Product of known dimensions, 296450, not divisible into total number of elements, 78114575.
I did the maths and 550*539=296450 and 296450 * 527=156229150: If we divide the last number by the number of elements it equals 2 and thus is divisible into the total number of elements. In my opinion the reshape function is not able to find the size of the last dimension or defines it as 1.
Defining the size of z also results in an error suggesting using the brackets [], so the function can find it.
Error using reshape
Number of elements must not change. Use [] as one of the size inputs to automatically calculate the appropriate size
for that dimension.
Now to the weird part. This code works for another set of images, with diffrent sizes of the x,y and z ranges. So don´t know where the issue lies to be frank. So i would really appreciate and Answer to my question
I figured it out. The error lies here:
ImageData{i} = fread(Image,Inf,'uint16=>uint16');
Apparently by saving them as .raw before it converts the image to an 8 bit file rather than 16 bits it had before. Therefore, my dimension is double the size of the number of elements. With this alteration it works:
ImageData{i} = fread(Image,Inf,'uint8=>uint8');
The reason i was able to look at the other pictures was that the z range was divisble by 2.
So the reshape function was not the problem but size of the integer data while creating the array for the variable ImageData.
P.S. I just started out programming so the accuracy in the answer should be taken with a grain of salt

Error message when storing output from loop in matrix

I have this program which calculates the realized covariance for each day in my sample but I have some troubles with storing the output in a matrix.
the program is as follows:
for i=1:66:(2071*66)
vec = realized_covariance(datapa(i:i+65),data(i:i+65),datapo(i:i+65),data(i:i+65),'wall','Fixed',fixedInterval,5)
mat(2,4142) = vec
end
Output:
vec =
1.0e-03 *
0.1353 -0.0283
-0.0283 0.0185
Subscripted assignment dimension mismatch.
I have tried various way to store the output in a matrix like defining a matrix on zeroes to store the output in or let the row dimension of the storing matrix be undefined, but nothing seems to do the job.
I would really appreciate an advice on how to tackle this challenge.
I have used a solution which does the job.
I defined a matrix and then filled in all my output one at the time using the following:
A = zeros(0,0) %before loop, only serve to define the storing matrix
A = [A; vec]%after the calculating function, inside the loop.
Actually mat(2,4142) is a single location in a matrix, you can't assign there four values.
You need to define the exact location inside mat every time you want to assign values into it. Try doing it like that:
mat=zeros(2,2142);
for k=1:66:(2071*66)
vec=realized_covariance(datapa(i:i+65),data(i:i+65),datapo(i:i+65),data(i:i+65),'wall','Fixed',fixedInterval,5)
mat(:,[(((k-1)/66)*2)+1 (((k-1)/66)*2)+2])=vec;
end
You're trying to store a 2 x 2 matrix into a single element. I.e. 4 elements on the right hand side, one on the left. That won't fit. See it like this: you have a garage besides your house where 1 car fits. You've got three friends coming over and they also want to park their car inside. That's a problem though, as you've got only space for one. So you have to buy a bigger garage: assign 4 elements on the left (e.g. mat(ii:ii+1,jj:jj+1) = [1 2;3 4]), or use a cell/structure array.
As Steve suggests in a comment below, you can use a 3D matrix quite easily:
counters = 1:66:(2071*66);
mat = zeros(2,2,numel(counters)); %// initialise output matrix
for ii=1:numel(counters)
vec = realized_covariance(datapa(counters(ii):counters(ii+65)),...
data(counters(ii):counters(ii+65)),datapo(counters(ii):counters(ii+65)),...
data(counters(ii):counters(ii+65)),'wall','Fixed',fixedInterval,5)
mat(:,:,ii) = vec; %// store in a 3D matrix
end
Now mat is 3D, with the first two coordinates being your regular output, i.e.e vec, and the last index is the iteration number. So to access the output of iteration 1032 you'd do mat(:,:,1032), possibly with a squeeze around that to make it 2D instead of 3D.

Conversion from Matlab CSC to CSR format

I am using mex bridge to perform some operations on Sparse matrices from Matlab.
For that I need to convert input matrix into CSR (compressed row storage) format, since Matlab stores the sparse matrices in CSC (compressed column storage).
I was able to get value array and column_indices array. However, I am struggling to get row_pointer array for CSR format.Is there any C library that can help in conversion from CSC to CSR ?
Further, while writing a CUDA kernel, will it be efficient to use CSR format for sparse operations or should I just use following arrays :- row indices, column indices and values?
Which on would give me more control over the data, minimizing the number for-loops in the custom kernel?
Compressed row storage is similar to compressed column storage, just transposed. So the simplest thing is to use MATLAB to transpose the matrix before you pass it to your MEX file. Then, use the functions
Ap = mxGetJc(spA);
Ai = mxGetIr(spA);
Ax = mxGetPr(spA);
to get the internal pointers and treat them as row storage. Ap is row pointer, Ai is column indices of the non-zero entries, Ax are the non-zero values. Note that for symmetric matrices you do not have to do anything at all! CSC and CSR are the same.
Which format to use heavily depends on what you want to do with the matrix later. For example, have a look at matrix formats for Sparse matrix vector multiplication. That is one of the classic papers, research has moved since then so you can look around further.
I ended up converting CSC format from Matlab to CSR using CUSP library as follows.
After getting the matrix A from matlab and I got its row,col and values vectors and I copied them in respective thrust::host_vector created for each of them.
After that I created two cusp::array1d of type Indices and Values as follows.
typedef typename cusp::array1d<int,cusp::host_memory>Indices;
typedef typename cusp::array1d<float,cusp::host_memory>Values;
Indices row_indices(rows.begin(),rows.end());
Indices col_indices(cols.begin(),cols.end());
Values Vals(Val.begin(),Val.end());
where rows, cols and Val are thrust::host_vector that I got from Matlab.
After that I created a cusp::coo_matrix_view as given below.
typedef cusp::coo_matrix_view<Indices,Indices,Values>HostView;
HostView Ah(m,n,NNZa,row_indices,col_indices,Vals);
where m,n and NNZa are the parameters that I get from mex functions of sparse matrices.
I copied this view matrix to cusp::csr_matrixin device memory with proper dimensions set as given below.
cusp::csr_matrix<int,float,cusp::device_memory>CSR(m,n,NNZa);
CSR = Ah;
After that I just copied the three individual content arrays of this CSR matrix back to the host using thrust::raw_pointer_cast where arrays with proper dimension are already mxCalloced as given below.
cudaMemcpy(Acol,thrust::raw_pointer_cast(&CSR.column_indices[0]),sizeof(int)*(NNZa),cudaMemcpyDeviceToHost);
cudaMemcpy(Aptr,thrust::raw_pointer_cast(&CSR.row_offsets[0]),sizeof(int)*(n+1),cudaMemcpyDeviceToHost);
cudaMemcpy(Aval,thrust::raw_pointer_cast(&CSR.values[0]),sizeof(float)*(NNZa),cudaMemcpyDeviceToHost);
Hope this is useful to anyone who is using CUSP with Matlab
you can do something like this:
n = size(M,1);
nz_num = nnz(M);
[col,rowi,vals] = find(M');
row = zeros(n+1,1);
ll = 1; row(1) = 1;
for l = 2:n
if rowi(l)~=rowi(l-1)
ll = ll + 1;
row(ll) = l;
end
end
row(n+1) = nz_num+1;`
It works for me, hope it can help somebody else!

Forcing a specific size when using spconvert in Matlab

I am loading a sparse matrix in MATLAB using the command:
A = spconvert(load('mymatrix.txt'));
I know that the dimension of my matrix is 1222 x 1222, but the matrix is loaded as 1220 x 1221. I know that it is impossible for MATLAB to infer the real size of my matrix, when it is saved sparse.
A possible solution for making A the right size, is to include a line in mymatrix.txt with the contents "1222 1222 0". But I have hundreds of matrices, and I do not want to do this in all of them.
How can I make MATLAB change the size of the matrix to a 1222 x 1222?
I found the following solution to the problem, which is simple and short, but not as elegant as I hoped:
A = spconvert(load('mymatrix.txt'));
if size(A,1) ~= pSize || size(A,2) ~= pSize
A(pSize,pSize) = 0;
end
where pSize is the preferred size of the matrix. So I load the matrix, and if the dimensions are not as I wanted, I insert a 0-element in the lower right corner.
Sorry, this post is more a pair of clarifying questions than it is an answer.
First, is the issue with the 'load' command or with 'spconvert'? As in, if you do
B = load('mymatrix.txt')
is B the size you expect? If not, then you can use 'textread' or 'fread' to write a function that creates the matrix of the right size before inputting into 'spconvert'.
Second, you say that you are loading several matrices. Is the issue consistent among all the matrices you are loading. As in, does the matrix always end up being two rows less and one column less than you expect?
I had the same problem, and this is the solution I came across:
nRows = 1222;
nCols = 1222;
A = spconvert(load('mymatrix.txt'));
[i,j,s] = find(A);
A = sparse(i,j,s,nRows,nCols);
It's an adaptation of one of the examples here.

MATLAB: Using interpolation to replace missing values (NaN)

I have cell array each containing a sequence of values as a row vector. The sequences contain some missing values represented by NaN.
I would like to replace all NaNs using some sort of interpolation method, how can I can do this in MATLAB? I am also open to other suggestions on how to deal with these missing values.
Consider this sample data to illustrate the problem:
seq = {randn(1,10); randn(1,7); randn(1,8)};
for i=1:numel(seq)
%# simulate some missing values
ind = rand( size(seq{i}) ) < 0.2;
seq{i}(ind) = nan;
end
The resulting sequences:
seq{1}
ans =
-0.50782 -0.32058 NaN -3.0292 -0.45701 1.2424 NaN 0.93373 NaN -0.029006
seq{2}
ans =
0.18245 -1.5651 -0.084539 1.6039 0.098348 0.041374 -0.73417
seq{3}
ans =
NaN NaN 0.42639 -0.37281 -0.23645 2.0237 -2.2584 2.2294
Edit:
Based on the responses, I think there's been a confusion: obviously I'm not working with random data, the code shown above is simply an example of how the data is structured.
The actual data is some form of processed signals. The problem is that during the analysis, my solution would fail if the sequences contain missing values, hence the need for filtering/interpolation (I already considered using the mean of each sequence to fill the blanks, but I am hoping for something more powerful)
Well, if you're working with time-series data then you can use Matlab's built in interpolation function.
Something like this should work for your situation, but you'll need to tailor it a little ... ie. if you don't have equal spaced sampling you'll need to modify the times line.
nseq = cell(size(seq))
for i = 1:numel(seq)
times = 1:length(seq{i});
mask = ~isnan(seq{i});
nseq{i} = seq{i};
nseq{i}(~mask) = interp1(times(mask), seq{i}(mask), times(~mask));
end
You'll need to play around with the options of interp1 to figure out which ones work best for your situation.
I would use inpaint_nans, a tool designed to replace nan elements in 1-d or 2-d matrices by interpolation.
seq{1} = [-0.50782 -0.32058 NaN -3.0292 -0.45701 1.2424 NaN 0.93373 NaN -0.029006];
seq{2} = [0.18245 -1.5651 -0.084539 1.6039 0.098348 0.041374 -0.73417];
seq{3} = [NaN NaN 0.42639 -0.37281 -0.23645 2.0237];
for i = 1:3
seq{i} = inpaint_nans(seq{i});
end
seq{:}
ans =
-0.50782 -0.32058 -2.0724 -3.0292 -0.45701 1.2424 1.4528 0.93373 0.44482 -0.029006
ans =
0.18245 -1.5651 -0.084539 1.6039 0.098348 0.041374 -0.73417
ans =
2.0248 1.2256 0.42639 -0.37281 -0.23645 2.0237
If you have access to the System Identification Toolbox, you can use the MISDATA function to estimate missing values. According to the documentation:
This command linearly interpolates
missing values to estimate the first
model. Then, it uses this model to
estimate the missing data as
parameters by minimizing the output
prediction errors obtained from the
reconstructed data.
Basically the algorithm alternates between estimating missing data and estimating models, in a way similar to the Expectation Maximization (EM) algorithm.
The model estimated can be any of the linear models idmodel (AR/ARX/..), or if non given, uses a default-order state-space model.
Here's how to apply it to your data:
for i=1:numel(seq)
dat = misdata( iddata(seq{i}(:)) );
seq{i} = dat.OutputData;
end
Use griddedInterpolant
There also some other functions like interp1. For curved plots spline is the the best method to find missing data.
As JudoWill says, you need to assume some sort of relationship between your data.
One trivial option would be to compute the mean of your total series, and use those for missing data. Another trivial option would be to take the mean of the n previous and n next values.
But be very careful with this: if you're missing data, you're generally better to deal with those missing data, than to make up some fake data that could screw up your analysis.
Consider the following example
X=some Nx1 array
Y=F(X) with some NaNs in it
then use
X1=X(find(~isnan(Y)));
Y1=Y(find(~isnan(Y)));
Now interpolate over X1 and Y1 to compute all values at all X.