I have a problem with fsurf command:
When I use
fsurf(#(x,y) ackleyfcn([x,y]),[-32 32 -32 32])
I got this warning:
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly vectorize your function to return an output with the same size and shape as the input arguments.
And this picture (after a long time, about 20 sec):
fsurf plot
When I use
ezsurf(#(x,y) ackleyfcn([x,y]),[-32 32 -32 32])
I got no warning and the correct (and fast) picture:
ezsurf plot
Where:
function z = ackleyfcn(xx)
% Ackley's function
% Search domain: [-32,32]
% Global minimum: f(x) = 0 | x = (0,...,0)
d = size(xx, 2);
xx = max(-32,min(32,xx));
z = -20*exp(-0.2*sqrt(1/d*sum(xx.^2,2))) - exp(1/d*sum(cos(2*pi*xx),2)) + 20 + exp(1);
end
I think this Ackley's function is correctly vectorized. Am I right?
What is the error with fsurf and why the image generated by it is strange and takes longer to be generated?
Thanks in advance!
Ps.: I am using R2017b version.
From the documentation:
The function must accept two matrix input arguments and return a matrix output argument of the same size.
You assumed that the inputs are column vectors.
To fix this you could try
function z = ackleyfcn(x,y)
xx = [x(:),y(:)];
% ... your code here
z = reshape(z,size(x));
and
fsurf(#ackleyfcn,[-32 32 -32 32])
MathWorks' Support Response:
I have been able to reproduce the slow down that you were experiencing. The fsurf function tries to determine what density of points to use in order to give an accurate depiction of the function you pass it. Since the ackleyfcn has many small oscillations, fsurf decides to use a very dense mesh in order to display it. This feature is not available in ezsurf which is why the plots look so different.
The time fsurf takes is also much longer because if it displaying many more points. If you would like to use fsurf to produce the plot similar to ezplot, you can turn off the AdaptiveMeshDenstity feature by using the following line of code:
set(fsurf(#(x,y) ackleyfcn([x,y]),[-32 32 -32 32]),'AdaptiveMeshDensity',0,'MeshDensity',60)
Note that this will increase the speed of fsurf and will produce a plot similar to that of ezsurf. However, this new surface uses fewer points and so does not fully represent the ackleyfcn function.
Related
MATLAB code included for reference below.
The pixel value displayed is 153 199 215.
I can calculate the norm (330.5072) using the norm function in the MATLAB command line.
However, when I run the code below, upon reaching the norm function, MATLAB errors with "Undefined function 'norm' for input arguments of type 'uint8'".
for i = 1:length(centers)
center = round(centers(i,:));
disp(center);
pixel = rgb(center(1), center(2),:);
pixel = [pixel(1,1,1) pixel(1,1,2) pixel(1,1,3)];
disp(pixel);
n = norm(pixel);
MATLAB's 'norm' function does not take uint8 data as an argument.
Cast pixel to a double using
pixel = double(pixel);
before calling the norm function, and the code runs without error.
I am solving a delay differential equation using MATLAB dde23 function. I want to use the output generated by the first dde23 function in the second dde23 function. Here is the code
tspan=[0:1:1440]';
x0=1.7;
%1st function
% options = ddeset('OutputFcn',#odeplot,'OutputSel',1);
sol = dde23(#dd,70,x0,tspan,options);
y_obs=sol.y;
tspan_new=sol.x;
%{2nd function
x1=[x0 ; 0.1; 0.01; 0.01];
final_sol = dde23(#ddc,70,x1,tspan,[],y_obs);
y_fit=final_sol.y;
tdata=final_sol.x;
%}
The time series I generated as an input to the first function is of size 1441 but the size of tspan_new and y_obs is 212 (generated from the dde23 output). I am unable to understand why the size is changing.
Is it possible to output y_obs at each time point provided in the input i.e. is it possible to obtain y_obs of length 1441 in this case ?
Since the size of output is different I am unable to use y_obs vector in my second function. The size of y_fit and tdata is again entirely different from y_obs and tspan.
Unlike the ODE Suite that implements a dense output routine as part of its time march, dde23 requires an explicit post-deval to accomplish what you're after:
tspan=[0:1:1440]';
x0=1.7;
%1st function
sol = dde23(#dd,70,x0,tspan([1,end]),options);
y_obs = deval(sol,tspan);
This function uses local Hermite cubic interpolation on the mesh generated by its dynamic time-stepping routine to approximate the y value at the requested t values.
I have written the function below to perform image rectification. I am using just the standard MATLAB library functions (estimateUncalibratedRectification and estimateFundamentalMatrix) and my own wrapper function to MATLAB's matchFeatures to perform stereo rectification. Yet, with the same inputs I get different results every time. I know this is related to the use of RANSAC to estimate the fundamental matrix. However, the rectification is terrible sometimes and passable others. For example, over 10 different runs of my function with identical input, two results were okay, while 8 gave me variations on this error:
Warning: An epipole may be located inside of an image. The epipoles
are located at [285.8503,76.1656] in I1 and [265.5734,130.3931] in I2,
but the specified imageSize was [320,568]. Severe distortion may
result if T1 or T2 are used to transform these images. See
isEpipoleInImage for more information.
> In coder.internal.warning (line 7)
In cvalgEstimateUncalibratedRectification (line 114)
In estimateUncalibratedRectification (line 107)
In pairwiseTransformation (line 48)
I believe that this means that the rectification was unable to project the epipole to infinity.
What's going on here? It is worth noting that I have 279 putative matches and 32 inlierMatches between my images.
My function:
function [t1, t2] = pairwiseTransformation(img1, img2, features1, features2)
% Identify putative matches
[matches1, matches2] = matchFeaturePoints(rgb2gray(img1), features1, ...
rgb2gray(img2), features2);
% Estimate the fundamental matrix so that matches2' * F * matches1 = 0
% F transforms matches1 to a line that runs through the corresponding
% point in matches1. Therefore, any rotation and translation derived from F
% (and E) will apply to camera 2's relative position, holding camera 1 fixed.
[F, inliers] = estimateFundamentalMatrix(matches1, matches2, 'Method', 'RANSAC', ...
'NumTrials', 2000, 'DistanceThreshold', 1e-4);
% Use the RANSAC inliers to determine the relative position of img2 compared to img1
inlierMatches1 = matches1(inliers, :);
inlierMatches2 = matches2(inliers, :);
[t1, t2] = estimateUncalibratedRectification(F, inlierMatches1, inlierMatches2, ...
size(img1));
r1 = imwarp(img1, projective2d(t1), 'OutputView', imref2d(size(img1)));
r2 = imwarp(img2, projective2d(t2), 'OutputView', imref2d(size(img1)));
figure;
subplot(2,2,1),imshow(img1)
subplot(2,2,2),imshow(img2)
subplot(2,2,3),imshow(r1)
subplot(2,2,4),imshow(r2)
end
Here's a decent rectification (top row is original images, bottom is rectified):
And here's a totally botched effort that gave the epipole warning:
32 inlier matches seems too few... How do your putative matches look?
One thing to try is to tweak the parameters of estimateFundamentalMatrix. I would use MSAC instead of RANSAC, and increase the DistanceThreshold to something like .1 or even 1. At the same time you may want to increase the Confidence parameter, maybe to 99.99. That would force RANSAC to go through more trials, and increase your chances of finding the right solution.
The other thing to try is to get more and better putative matches from matchFeatures. You should try tweaking the parameters of your feature detector function to get more features, and then tweak the parameters of matchFeatures to make sure that the matches are still good. You can also try different detectors and descriptors.
I wrote a small program in MATLAB to compute the Shapley value
using the multi-linear extension of a TU game. However, I run
into trouble with the Symbolic Math Toolbox of MATLAB. In
the program I have to integrate a set of functions to get the
Shapley value. However, inside a MATLAB program I cannot use
the int() command
Error using sym/subsindex (line 663) Ivalid indexing or function definition. When defining a function, ensure that the body of the function is a SYM object. When indexing, the input must be numeric, logical or ':'.
Error in ShapleyValueML (line 65)shv(jj)=int(dfy,0,1)
as a consequence I have to use integral() instead. In this case, I
need to transcribe the set of expressions into MATLAB function handle
with matlabFunction(). However, on all Linux machines (MATLAB R2014a) on
which I have access this command does not work (see the discussion below).
As a workaround, the MATLAB program returns the set of functions
into the current workspace, there the Shapley value can be computed
using the int() command.
To make the discussion more concrete, let us consider this small
MATLAB program first.
function [shv,F,dfm]=ShapleyValueML(v)
N=length(v);
[~, n]=log2(N);
S=1:N;
int=0:-1:1-n;
mat=(rem(floor(S(:)*pow2(int)),2)==1);
cmat=(rem(floor(S(:)*pow2(int)),2)==0);
x=sym('x',[1 n]);
mx=1-x;
y = sym('y');
vy=ones(1,n)*y;
F=0;
shv=zeros(1,n);
dfm=cell(1,n);
for ss=1:N
pd1=x(mat(ss,:));
pd2=mx(cmat(ss,:));
pd=prod(pd1)*prod(pd2)*v(ss);
F=pd+F;
end
F=expand(F);
for jj=1:n
dF=diff(F,x(jj));
dfy=subs(dF,x,vy);
%% Does not work!! MATLAB bug???
% mf=matlabFunction(dfy);
% shv(jj)=integral(mf,0,1);
%%
%% The best would be to use:
%%
% shv(jj)=int(dfy,0,1)
%% but it cannot be used inside a program.
dfm{jj}=dfy;
end
end
The commented parts are the parts that do not work inside
the program, but are needed to compute the Shapley value
with that program, which is its purpose. I tested this program
up to 12 players, and I was able to successfully calculate the
Shapley value by a two step procedure. Hence, the above program
specifies correctly the considered problem. To get a better
understanding of this two step procedure and of the functionality
of the above program, let us focus on a three person game.
The values of the coalitions are given by the following data array
>> v = [0,0,90,0,100,120,220];
Notice that coalitions are ordered in accordance with their unique
integer representations. The game is defined, we can now evaluate
the multi-linear extension and the set of partial derivatives with
the above program, but not the Shapley value.
>> [shv,F,dfm]=ShapleyValueML(v);
Integration of the set of partial derivatives runs over the diagonal
of the unit-cube, but then we can set the variables from [x1,x2,x3]
to [y,y,y], and integration runs from 0 to 1.
>> for k=1:3, shv(k)=int(dfm{k},0,1);end;
The solution of the integration is the Shapley value given by:
>> shv
shv =
65 75 80
Checking that this is indeed the Shapley value can be accomplished
with a potential function approach implemented in
>> sh_v=ShapleyValue(v)
sh_v =
65 75 80
that ships with my MATLAB Game Theory Toolbox MatTuGames from
http://www.mathworks.com/matlabcentral/fileexchange/35933-mattugames
Instead of integrating with int() one can also use integral(),
but then the contents like
>> dfm{1}
ans =
- 90*y^2 + 190*y
must be rewritten with matlabFunction() into a function handle. As I
have mentioned above this does not work under Linux
(MATLAB R2013a,R2013b,R2014a). To see this let us try to reproduce
the example
>> syms x y
>> r = sqrt(x^2 + y^2);
from the documentation at the URL:
http://www.mathworks.de/de/help/symbolic/generate-matlab-functions.html?searchHighlight=matlabFunction
This should give
ht =
#(x,y)tanh(sqrt(x.^2+y.^2))
but I get
>> ht = matlabFunction(tanh(r))
Cell contents reference from a non-cell array object.
Error in vectorize (line 15)
c = cells{i};
Error in sym/matlabFunction>mup2mat (line 319)
res = vectorize(res(2:end-1)); % remove quotes
Error in sym/matlabFunction>mup2matcell (line 304)
r = mup2mat(c{1});
Error in sym/matlabFunction (line 123)
body = mup2matcell(funs);
Here comes now my question: Exists there an alternative procedure to
get from
>> dfm{1}
ans =
- 90*y^2 + 190*y
a function handle
>> df=#(y) (- 90.*y.^2 + 190.*y)
df =
#(y)(-90.*y.^2+190.*y)
to integrate it by
>> integral(df,0,1)
ans =
65
Or to put it differently. Is there an alternative method available to
change multiplication * to element-wise multiplication .*, and the
power operation ^ to element-wise power.^?
Of course, any suggestions of improvement for the above MATLAB program
are highly appreciated.
I think I know what the problem is; Towards the beginning of ShapleyValueML function, you have a variable named int which shadows the builtin integration function:
...
int=0:-1:1-n; %# <-- problem!
...
shv(jj)=int(dfy,0,1)
...
That explains the error coming from sym/subsindex, you were using a symbolic object as an index into the numeric array int.
Change the variable name to something else, and the commented code runs fine (the symbolic integration)! Simple as that :)
I must to use angle = atan2(norm(cross(a,b)),dot(a,b)), for calculating the angle between two vectors a,b and these are double type and norm is undefined for this type. How do I resolve this problem? I need to calculate the angle between two vectors this way.
In your comments, you have shown us how you are actually writing out the angle calculation and it is not the same as how you have put it in your post.
atan2(norm(cross(I(i,j,:),I_avg)),dot(I(i,j,:),I_avg));
I is an image you are loading in. I'm assuming it's colour because of the way you are subsetting I. Because I is a 3D matrix, doing I(i,j,:) will give you a 1 x 1 x 3 vector when in fact this has to be a 1D vector. norm does not recognize this structure which is why you're getting this error. Therefore, you need to use squeeze to remove the singleton dimensions so that this will become a 3 x 1 vector, rather than a 1 x 1 x 3 vector. As such, you need to rewrite your code so that you're doing this instead. Bear in mind that in your comments, angle is always overwritten inside the for loop, so you probably want to save the results of each pixel. With this, you probably want to create a 2D array of angles that will store these results. In other words:
I=imread('thesis.jpg');
I = double(I);
angles = zeros(m,n);
I_avg = squeeze(I_avg); %// Just in case
for i=1:m
for j=1:n
pixels = squeeze(I(i,j,:)); %// Add this statement and squeeze
angles(i,j) = atan2(norm(pixels,I_avg)),dot(pixels,I_avg)); %// Change
end
end
Minor note
MATLAB has a built-in function called angle that determines the angle from the origin to a complex number in the complex plane. It is not recommended you call your variable angle as this will unintentionally shadow over the angle function, and any other code that you create from this point onwards may rely on that actual angle function, and you will get unintended results.
Another minor note
Using i and j as loop variables is not recommended. These letters are reserved for the complex number, and this can produce unintentional results. Take a look at this question and post by Shai here - Using i and j as variables in Matlab. As such, it is suggested you use other variable names instead.
As #rayryeng has successfully answered this question, I would like to turn my post into a more general one by sharing my experience in debugging in Matlab. I hope anyone who somehow managed to find this post get more or less thinking about the habits a good programmer should have.
The question goes like: "How would I do if I get errors?"
Here's an excellent article by Eric in which he lists the rule-of-thumbs when you encounter a bug and wish to get rid of it. It's originally been cited by Stackoverflow, and that's the reason I read it.
If you still get no clue / idea how you can play with your code, see how this person does:
Pin-point the buggy line
(The number should start with 0) Make sure before running a script, you clear out any previously stored variables, including the notorious i and j's (you should never see them in any workspace). If any one is needed for the buggy code to run, save('buggy.mat','importantvar') before clear and load('buggy.mat') after clear.
By doing so, you can isolate your buggy code from anything else, which could have bad influences. For example, in a previously called script, there is a line
double = [2,4,6]; % you should never name a variable `double`
and in the next script, you have
>> e = str2num('uint8(200)')
e =
200
>> double(e)
Index exceeds matrix dimensions.
>>
>> f = single(2.36)
f =
2.3600
>> double(f)
Subscript indices must either be real positive integers or
logicals.
>>
The reason is double is no longer an inbuild function, but a user-defined variable. Too bad to pick up a name carelessly!
....anyway, let's clear the workspace and get rid of double.
>> clear
Read the error message, thoroughly.
Now let's begin with OP's problem. The original code (trimmed) goes like this -
img = imread('peppers.png');
a = img(300,200,:);
b = img(200,300,:);
d = norm(cross(a,b));
.... hence the error
Undefined function 'norm' for input arguments of type 'uint8'.
Error in untitled (line 6)
d = norm(cross(a,b));
Most beginners are only interested in the first line of the error message, which by it alone usually doesn't provide any useful help, or only in the red color, which leads to the famous question "my code does not work!"
But think twice. You still have another 2 lines unread! Error in untitled (line 6) says I'm running a script named untitled and the (first) error lies in line 6, and the code in that line is d = norm(cross(a,b));.
Now, at least you know a little more about your code - "My code d = norm(cross(a,b)); doesn't work!"
Although most likely we may also vote this kind of question to get closed, it's still much much better than a simply "It does not work!".
Now we can pin-point the buggy line
try
% this line will raise an error
d = norm(cross(a,b));
catch err
disp(err.message)
end
Look into the functions
First, make sure the inner function cross works as expected -
>> cross(a,b)
ans(:,:,1) =
0
ans(:,:,2) =
255
ans(:,:,3) =
0
>>
Good. So now we can even narrow down the error to the outer norm.
One more thing to mention. You can always find Mathworks' documentation for any in-build function, by typing "matlab function", such as "matlab norm" in Google (or any other search engine) and clicking on the first result. If you prefer, you can also type in Matlab command window doc _function_ such as doc norm and read the doc in Matlab. It's of course a pleasure of us on Stackoverflow to give you the reference by doing the same thing, but it takes a longer time because a human is, in this aspect, always slower than a search engine.
The error reads Undefined function 'norm' for input arguments of type 'uint8'.. So the input for norm should not be uint8, unsigned 8-bit integer. But what should it be?
% why `norm` "does not work"?
% this line runs perfectly well
norm(cross([1,2,3], [4,5,6]))
% so what is working?
class([1,2,3]) % so `norm` works for `double`
One thing we can do now is convert a and b to double precision. Let's try it now.
% try fixing 'uint8' error
a2 = double(a);
b2 = double(b);
whos a b % now they are double, which `norm` should work for
try
% this line will raise an error
d = norm(cross(a2,b2));
catch err
disp(err.message)
end
Now the error becomes Input must be 2-D.. What's wrong with the input?
% what is "must be 2-D" error?
size(a2) % a2 is 3-D
disp(b2) % b2 is also 3-D
This gives output in command window
ans =
1 1 3
(:,:,1) =
255
(:,:,2) =
150
(:,:,3) =
0
In OP's problem, he/she is trying to calculate something about color difference (to the best of my knowledge) which involves the angle between two color vectors in RGB space. So the vectors are needed. With imread, each pixel of the image is stored as 3 elements in the matrix, first 2 dimension being its physical position, the 3 dimension being RGB channel components. Hence pixel(200,300) with color rgb[255,150,0] is stored by us in variable b wihch is a 3-D vector.
By understanding what we need and what Matlab can do, we can combine these two points into one. We need the norm of the cross product of a and b, while the useful information (the 3 component values) is stored in the 3rd dimension. Matlab can calculate the norm of the cross product of a vector with all its information in the 1st dimension. (Here, "dimension" refers to that of the Matlab variable; a vector with 3 elements in its 1st dimension is physically a 3-D vector).
After thinking twice, we are now able to debug our code - just put all 3 elements into the 1st dimension.
% so we want the 3 elements in the 3rd dimension become in the 1st dim
a3 = squeeze(a2);
b3 = reshape(b2,numel(b2),[]);
try
d = norm(cross(a3,b3));
catch err
disp(err.message)
end
d
Bonus: If by default Matlab treats a 3-D vector as a "1-D array", then most probably the cross function has not been working correctly. Let's make a check -
>> clear
>> a = [1,2,3]
a =
1 2 3
>> b=[4,5,6]
b =
4 5 6
>> cross(a,b)
ans =
-3 6 -3
>>
The result should be the same as the one we can get by calculating by hand.
Now if we put the components into the 3rd dimension of the variable -
>> clear
>> a(1,1,:)=[1,2,3]
a(:,:,1) =
1
a(:,:,2) =
2
a(:,:,3) =
3
>> b(1,1,:)=[4,5,6]
b(:,:,1) =
4
b(:,:,2) =
5
b(:,:,3) =
6
>> cross(a,b)
ans(:,:,1) =
-3
ans(:,:,2) =
6
ans(:,:,3) =
-3
>>
.... seems OK. cross also puts the result in the 3rd dimension. In fact, Mathworks' documentation says
If A and B are vectors, then they must have a length of 3.
If A and B are matrices or multidimensional arrays, then they must
have the same size. In this case, the cross function treats A and B as
collections of three-element vectors. The function calculates the
cross product of corresponding vectors along the first array dimension
whose size equals 3.
At last, one thing is always correct to anyone who wants to do something with programming - be cautious and prudent when writing your code.