I'm trying to convert my image processing code on MATLAB into C by using MATLAB coder. using imread needs a coder.entrinsic declaration. However, this means that the output to imread will be an mxArray. This is a problem as I cannot use this with the step function. The error report from code generation is shown below:
Does anyone know a way around this?
When using coder.extrinsic, functions declared as extrinsic will return mxArray types. If you pass these to other Matlab functions, Coder will resolve everything well, but if you use them with your own functions or in any way try to manipulate them, you need to help Coder resolve them into a known type. You do this by pre-defining a variable and copying the mxArray into it, which will allow Coder to correctly convert to a standard data type. If you know the exact size beforehand, you can preallocate the variable before the call and skip the copy, but in this case it may be a bit trickier.
In the case of your function, I assume you have a call somewhere that looks like:
I = imread([some paramaters]);
We need to get the mxArray type from the call to imread, then determine its dimensions so that another variable can be allocated in a native type. The determination of the mxArray dimensions using the size function itself needs to have a preallocated variable so that size does not return a mxArray also. Here are the steps:
coder.extrinsic('imread');
Itemp = imread([some paramaters]);
idims = zeros(1,3); %Need to preallocate idims so it does not become an mxArray
idims = size(Itemp)
I = coder.nullcopy(zeros(idims, 'uint8')); % Allocate but do not initialize an array of uint8 values of the same size as Itemp
I = Itemp; % Copy the data from the mxArray into the final variable.
If you know the exact size of the image before the call to imread, you can skip the copy and the second variable and simply preallocate the variable I to the correct size, but this is not typically the case for an image read.
You can see a little more information on how to do this in the following help document from Mathworks:
http://www.mathworks.com/help/simulink/ug/calling-matlab-functions.html#bq1h2z9-47
Related
How can I create a constant variable in MATLAB (and its results the generated C code), so I can use it later in my code to specify the size of variables.
I want to have an array that its size is not hardcoded via number all over the code.
I want to specify the size at the beginning of the code like how we do in C code using one of the followings:
const int arraySize=5
#define arraysize 5
Later: int array[arraySize];
When I write the following in MATLAB, Coder just replaces arraySize with the actual number which is 5:
arraySize=int8(5);
array=zeros(1,arraySize); % zeros is just used for specifying size
Generated code:
void coder(double A[5])
{
memset(&A[0], 0, sizeof(double) << 16);
}
I tried using the following but it does not allow me to use arraySize in MATLAB calculations:
arraySize=coder.opaque('const int16','5');
A=zeros(1,arraySize);
This may be related to constant folding which I can not disable!
This array size may be repeated throughout the different functions and code many times, so global probably may be related to this
Having a constant variable appear by name (rather than the value) in the sizes of other variables is unfortunately not supported in MATLAB Coder as of MATLAB R2019a. We've made an internal note of your request so we can look at lifting that limitation in the future.
Well, I am trying to implement an algorithm on Matlab. It requires the usage of a slice of an high dimensional array inside a for loop. When I try to use the logical indexing, Matlab creates an additional copy of that slice and since my array is huge, it takes a lot of time.
slice = x(startInd:endInd);
What I am trying to do is to use that slice without copying it. I just need the slice data to input a linear operator. I won't update that part during the iterations.
To do so, I tried to write a Mex file whose output is a double
type array and whose size is equal to the intended slice data size.
plhs[0] = mxCreateUninitNumericMatrix(0, 0, mxDOUBLE_CLASS,mxREAL); % initialize but do not allocate any additional memory
ptr1 = mxGetPr(prhs[0]); % get the pointer of the input data
Then set the pointer of the output to the starting index of the input data.
mxSetPr(plhs[0], ptr1+startInd);
mxSetM(plhs[0], 1);
mxSetN(plhs[0], (endInd-startInd)); % Update the dimensions as intended
When I set the starting index to be zero, it just works fine. When I try to give
other values than 0, Mex file compiles with no error but Matlab crashes when the Mex function is called.
slice = mex_slicer(x, startInd, endInd);
What might be the problem here?
The way you assign the data pointer to the array, it means that MATLAB will attempt to free that memory when the array is deleted or has something else assigned to it. Attempting to call free using a pointer that was not obtained by malloc will cause a crash.
Unfortunately, MATLAB does not support "views", arrays that point at parts of a different array. So there is no way to do what you want to do.
An alternative solution would be to:
store your data differently, so that it doesn't take as much time to index (e.g. in smaller arrays)?
perform all your computations in C or C++ inside a MEX-file, where you can very simply point at sub-ranges of a larger data block.
See this FEX submission on creating MATLAB variables that "point" to the interior data of an existing variable. You can either do it as a shared data copy which is designed to be safe (but incurs some additional overhead), or as an unprotected direct reference (faster but risks crashing MATLAB if you don't clear it properly).
https://www.mathworks.com/matlabcentral/fileexchange/65842-sharedchild-creates-a-shared-data-copy-of-a-contiguous-subsection-of-an-existing-variable
I want to generate a c++ code for DCT function using Matlab coder. I wrote this simple function and tried to convert it to c++.
function output_signal = my_dct(input_signal)
output_signal = dct(input_signal);
end
When I use a fixed size type for the input argument (such as double 1x64), there is no problem; however, a variable-sized type (such as double 1x:64) for the input argument results in these errors:
The preceding error is caused by: Non-constant expression..
The input to coder.const cannot be reduced to a constant.
Can anyone please help me?
Thanks in advance.
The documentation is a bit vague for DCT in Coder, but it implies that the input size must be a constant power of 2 along the dimension of the transform. From DCT help:
C/C++ Code Generation
Generate C and C++ code using MATLAB® Coder™.
Usage notes and limitations:
C and C++ code generation for dct requires DSP System Toolbox™ software.
The length of the transform dimension must be a power of two. If specified, the pad or truncation value must be constant. Expressions or variables are allowed if their values do not change.
It doesn't directly say that the length of the variable (at least along the dimension being transformed) going into the dct function must be a constant, but given how coder works, it really probably has to be. Since that's the error it's returning, it appears that's a limitation.
You could always modify your calling function to zero pad to a known maximum length, thus making the length constant.
For instance, something like this might work:
function output_signal = my_dct(input_signal)
maxlength = 64;
tinput = zeros(1,maxlength);
tinput(1:min(end, numel(input_signal))) = input_signal(1:min(end, maxlength));
output_signal = dct(tinput);
end
That code will cause tinput to always have a size of 1 by 64 elements. Of course, the output will also always be 64 elements long also, which means it'll be scaled and may have a difference frequency scale than you're expecting.
This is my matlab function:
function [mask] = computeMask (I, threshold, win_var, borderx, bordery)
coder.extrinsic('imfilter');
%-- compute Variances of the RGB and IR patches
mean_I = imfilter(I,ones(win_var)/win_var/win_var,'same','symmetric','conv');
mean2_I = imfilter(I.^2,ones(win_var)/win_var/win_var,'same','symmetric','conv');
std_I= real(sqrt(mean2_I-mean_I.^2)+1e-5);
mask= std_I>threshold;
% add the border of the image to the mask
% (filters are not complete at the border)
mask(1:((bordery-1)/2),:)=0;
mask((end-(bordery-1)/2):end,:)=0;
mask(:,1:((borderx-1)/2))=0;
mask(:,(end-(borderx-1)/2):end)=0;
% add the area where the vignetting is too strong
Cy=floor(size(mask,1)/2);
Cx=floor(size(mask,2)/2);
[x,y]=meshgrid(1:size(mask,2),1:size(mask,1));
mask(((x-Cx).^2+(y-Cy).^2)>8e4)=0;
%mask(((x-Cx).^2+(y-Cy).^2)>1.3e4)=0;
return
When trying to build Build "Instrumented MEX Function" I get these errors: ??* ? Expected either a logical, char, int, fi, single, or double. Found an mxArray. MxArrays are returned from calls to the MATLAB interpreter and are not supported inside expressions. They may only be used on the right-hand side of assignments and as arguments to extrinsic functions.*
Error in ==> computeMask Line: 21 Column: 18: std_I= real(sqrt(mean2_I-mean_I.^2)+1e-5);
How to fix these problems? please help me !!! Thank you very much
Since you declared imfilter as extrinsic, the generated code will call into MATLAB to run this function. This will result in an mXArray type. To help coder convert mxArray type to a native type you should initialize the outputs of imfilter before calling imfilter. For example, if the output of imfilter is of same type and size as its input I, then use
mean_I = I;
mean_I = imfilter(I,ones(win_var)/win_var/win_var,'same','symmetric','conv');
Note that imfilter still does not generate any code. imfilter is still called in MATLAB.
You can see documentation for this at http://www.mathworks.com/help/fixedpoint/ug/calling-matlab-functions.html in section "Converting mxArrays to Known Types".
I'm having a problem sending a value from a GUI to an Embedded MATLAB Function (EMF) in a Simulink model. I get this value from a slider in my GUI and send it to an EMF block in my model. I can confirm that the value is being transferred correctly from my GUI to my Simulink block, since I can display the value with a display block in my model and see the value change when I change the slider position in my GUI. However I keep getting this error when I run my model:
Could not determine the size of this expression.
Function 'Kastl' (#18.282.283), line 14, column 1:
"f"
This is part of my EMF block code:
function y = input_par(u,fstart)
...
f_end = 1000;
f = fstart:f_end;
...
I believe MikeT is correct: you can't redefine the size of a variable in an embedded function. If you look at this Embedded MATLAB Function documentation page under the subsection Defining Local Variables, it says:
Once you define a variable, you cannot
redefine it to any other type or size
in the function body.
You will have to rework your embedded function such that the variables you declare are not changing size. Since I don't know what you are subsequently doing with the variable f, there's not much more specific help I can give you.
In general, if you absolutely need to use data that changes size, one solution is to pad the data with "garbage" values in order to maintain a constant size. For example:
MAX_ELEMS = 1000; % Define the maximum number of elements in the vector
f = [fstart:MAX_ELEMS nan(1,fstart-1)]; % Create vector and pad with NaNs
In the above example, the variable f will always have 1000 elements (assuming the value of fstart is an integer value less than or equal to 1000). The value NaN is used to pad the vector to the appropriate constant size. Any subsequent code would have to be able to recognize that a value of NaN should be ignored. Depending on what calculations are subsequently done in the embedded function, different pad values might be needed in place of NaN (such as 0, negative values, etc.).
I believe the issue you are running into is that you can't change a parameter during simulation that will cause the dimension of a signal to change. In your example, the code,
f = fstart:f_end;
changes size whenever fstart changes. I think this is what EMF block is complaining about. I don't have any easy workaround for this particular issue, but maybe there's an equivalent way of doing what you want that avoids this issue.