Meshgrid / Surface clipping - matlab

I am working with some antarctic DEM data in Matlab. So, far I have been able to generate a nice looking mesh, with the following basic code:
load (Data.xyz)
X = Data(:,1);
Y = Data(:,2);
Z = Data(:,3);
xr = unique(X);
yr = unique(Y);
gz = zeros(length(yr),length(xr));
gz = griddata(X,Y,Z,xr,yr');
figure
mesh(xr,yr,gz);
hold on
contour3(xr,yr,gz,'k-');
hold off
Now I have a few questions, which I have not been able to answer despite being at it since past couple of days and looking at all forums and googling day and night. I hope you all experts might be able to suggest me something. My questions are:
The above code takes a lot of time. Agreed that the DEM for antarctica is large sized and slow response time for a code does not necessarily mean that its incorrect. However, I am totally unable to run this code on my laptop (2.5 GHz/4GB) - its so slow. I am wondering if there are other ways to generate mesh which are faster and more efficient.
The second issue is that the above "Data.xyz" contains DEM data from all antarctica. After generating a mesh, I want to clip it based on locations. Say, for e.g., I want to extract mesh data for area bound by x1,y1, x2,y2, x3, y3, and x4,y4. How do I go about doing that? I could not find a suitable function or tool or any user script anywhere which will allow me to do so. Is it possible to cut a mesh in matlab?
I am running Matlab 2012a, and I do not have access to mapping toolbox. Any suggestions???

1.I'd just like to clarify what it is you want your code to do. For the data X,Y,Z, I would assume these are points (X,Y) (not sampled on a grid) each associated with some elevation Z.
When you call
gz = griddata(X,Y,Z,xr,yr');
You are saying that every possible pair (xr(i),yr(j)) are the locations on your grid where you want to sample the surface to create your mesh. I could be wrong but I don't think this is what you want?
I think you would rather sample at equally spaced points, instead using something like...
xr = min(X):spacing:max(X);
yr = min(Y):spacing:max(Y);
gz = griddata(X,Y,Z,xr,yr'); % ' is for the transpose
mesh(xr,yr,gz);
Where spacing a reasonable number for the scale of your data. The way your code is now, you could be taking far more samples than you want, which could be why your code takes so long.
For 2. I think you could get a for loop to just add the points insde the region of interest to three new lists of X,Y,Z values. If your region is rectangular bounded by x_left,x_right and y_left,y_right ...
Xnew = []; Ynew = []; Znew = [];
for i = 1:length(X)
if ( x_left<X(i) )&&( X(i)<x_right )&&( y_left<Y(i) )&&( Y(i)<y_right )
Xew = [Xnew, X(i)];
Ynew = [Ynew, Y(i)];
Znew = [Znew, Z(i)];
end
end

Related

Why is the resultant of my improfile function returning with a mirrored graph in MATLAB?

I am currently running improfile on MATLAB with a line going through the center of the picture below:
After doing so, I'm plotting the resultant using the code below:
xi = [1 size(d_Img,2) size(d_Img,2) 1];
yi = [ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2 ),ceil(size(d_Img,1)/2)];
c_d = improfile(d_Img,xi,yi);
c_c = improfile(c_Img,xi,yi);
c_d = c_d';
c_c = c_c';
size_c = size(c_d);
n = 1:size_c(2);
plot(n,c_d);
And here is the plot:
Why are the curves mirroring each other? I am asking to gain a better understanding of what exactly improfile seems to be achieving in MATLAB.
improfile computes something like a "path integral", it gives you the image intensity values around a user specified path. For example, if you use:
improfile(img,[1 1],[1 size(img,2)]);
It gives the same as img(:,1). This is because the path you are using in improfile is from (1,1) to (1,size(img,2)) , meaning the first row. However you could definitely add more complicated paths.
In your case you are going trow a path defined by 4 points. The points are, if I substitute your equation by the resultant numbers:
(1,79)->(134,79)->(134,79)->(1,79). Thus, looking at this, it is obvious that your result should be mirrored, because you are integrating over a line the way there, and back!
Sidenote:
you can do plot(c_d); and forget about that n

Exporting data in zoomed in region of MATLAB plot to workspace

I have 4-5 subplots of timeseries data and scatter plots in a MATLAB figure whose x axes are linked. The data is quite long and I've zoomed into a small portion of the figure.Now I want to export just the data contained in this zoomed in portion to work-space as variables. Is it possible?
For example, the following is the plot for the full dataset.
The following is the zoomed in portion,
Now I want to export all the variables or time-section of the variables corresponding to the above zoomed in portion to workspace.
Building off of Ratbert's comment, let's set up a sample plot to play around with.
x = 1:10;
h.myfig = figure();
h.myaxes = axes('Parent', h.myfig);
h.myplot = plot(x);
I'm going to assume you have MATLAB R2014b or newer, which is where MATLAB switched graphics handles to objects. If you have an older version you can swap all of my dot notations with get and set calls, where appropriate.
Now with this initial plot, if we enter h.myaxes.XLim or get(h.myaxes, 'XLim'), we return:
ans =
1 10
Now if we zoom in arbitrarily and make the same call, we get something different. In my case:
ans =
3.7892 7.0657
Now it's up to you how you want to use this information to window your data. A very basic method would be to use find to get the indices of the closest data points to these limits.
For example:
newlimits = h.myaxes.XLim;
newminidx = find(x >= floor(newlimits(1)), 1);
newmaxidx = find(x >= ceil(newlimits(2)), 1);
newmin = x(newminidx);
newmax = x(newmaxidx);
Returns [newmin, newmax] of:
ans =
3 8
I used floor and ceil here because I know my data is integers, your criteria may be different but the process is the same. Hopefully this is enough to get you started.

Matlab figures - remove filling from gaussian distributions

I am emulating a NAND Flash mlc and I am using hist() to display the results which are 4 gaussian distributions.
The problem is that I am trying to display 8 distributions at once one the same figure and they overlap. So, I want to find a way to remove the filling inside the gaussian distributions and only keep the outline. Is there a way to do this? I have found that maybe "basic fitting" option in Matlab can do this but it is "grey" and I cannot select it on this figure.
--
Well I tried adding a simple a picture which can explain everything but I could not due to my reputation.
I am working in FPGA(ZedBoard) in order to create the emulation but that has nothing to do with the question I am asking.
So, I get an input file with single-precision values out of ZedBoard, which then I insert in Matlab and get the figure I am talking about.
I would not think that my code in Matlab could help in any way that is why I did not put it.
Although, I should have mentioned that the eight distributions have almost the exact same characteristics so they appear almost on the same place. This is why I am looking a way to display them properly.
These "hists" below have to appear on the same figure without overlapping on each other. Normally, when Matlab is displaying gaussian distributions with "hist" uses a blue filling which I want to remove and only leave the outlining of the distribution if possible. I hope I have given a better view of my problem with this added.
fid1 = fopen('soft_without.txt');
A = textscan(fid1,'%s');
B = char(A{1});
fclose (fid1);
output = typecast(uint32(hex2dec(B)),'single');
hist(output,1000);
fid2 = fopen('soft_with.txt');
A = textscan(fid2,'%s');
B = char(A{1});
fclose (fid2);
output1 = typecast(uint32(hex2dec(B)),'single');
hist(output1,1000);
Let's first put all the data into one dataset, rather than having a bunch of different variables:
filenames = ls('*.txt'); % or whatever you do to make up your list of files
data = zeros(1000, 8); %preallocate
% going to use first file to set location of bins so they're all the same
fid = fopen(filenames(1,:))
A = textscan(fid,'%s');
B = char(A{1});
fclose(fid);
output = typecast(uint32(hex2dec(B)),'single');
[x, bins] = hist(output,1000);
data(:,1) = x;
% set rest to same bins
for n = 2:8
fid = fopen(filenames(n,:))
A = textscan(fid,'%s');
B = char(A{1});
fclose(fid);
output = typecast(uint32(hex2dec(B)),'single');
x = hist(output,bins);
data(:,n) = x;
end
bar(bins,data);
This will plot your eight sets as eight different (side by side) bars. Another route would be to plot the over the top of each other but set different edge colors and no face color (possibly also experiment with changing width).
colors = jet(8); % eight colors from the jet colormap
figure; hold on;
for n = 1:8
bar(bins,data(:,n),'facecolor','none','edgecolor', colors(n,:));
end

Interactive curve fitting with MATLAB using custom GUI?

I find examples the best way to demonstrate my question. I generate some data, add some random noise, and fit it to get back my chosen "generator" value...
x = linspace(0.01,1,50);
value = 3.82;
y = exp(-value.*x);
y = awgn(y,30);
options = optimset('MaxFunEvals',1000,'MaxIter',1000,'TolFun',1e-10,'Display','off');
model = #(p,x) exp(-p(1).*x);
startingVals = [5];
lb = [1];
ub = [10];
[fittedValue] = lsqcurvefit(model,startingVals,x,y,lb,ub,options)
fittedGraph = exp(-fittedValue.*x);
plot(x,y,'o');
hold on
plot(x,fittedGraph,'r-');
In this new example, I have generated the same data but this time added much more noise to the first 15 points. Because it is random sometimes it works out okay, but after a few runs I get a good example that illustrates my problem. Same code, except for these lines added under value = 3.82
y = exp(-value.*x);
y(1:15) = awgn(y(1:15),5);
y(15:end) = awgn(y(15:end),30);
As you can see, it has clearly not given a good fit to where the data seems reliable, because it is fitting from points 1-50. What I want to do is say, okay MATLAB, I can see we have some noisy data but it seems decent over a range, only fit your exponential from points 15 to the end. I could go back to my code and update it to do this, but I will be batch fitting graphs like this where each one will have different ranges of 'good' data.
So what I am after is a GUI callback mechanisms that allows me to click on two circles from the data and have them change color or something, which indicates the lsqcurvefit will only fit over that range. Internally all it has to change is inside the lsqcurvefit call e.g.
x(16:end),y(16:end)
But the range should update depending on the starting and ending circles I have clicked.
I hope my question is clear. Thanks.
You could use ginput to select the two points for your min and max in the plot.
[x,y]=ginput(2);
%this returns you the x and y coordinates of two points clicked after each other
%the min point is assumed to be clicked first
min=[x(1) y(1)];
max=[x(2) y(2)];
then you could fit your curve with the coordinates for min and max I guess.
You could also switch between a rightclick for the min and a leftclick for the max etc.
Hope this helps you.

Is it possible in Matlab to plot not matching SURFPoints?

I am trying to find the difference between two images, using Matlab. The classic built in function that Matlab provides for this is because the two images don't have the same dimensions (The objects in the images are the same, but in the second image other objects are introduced).
And i thought i could use SURF Features to accomplish this.
Here's the code:
source = imread('source.png');
target = imread('target.png');
source = rgb2gray(source);
target = rgb2gray(target);
sourcePoints=detectSURFFeatures(source,'MetricThreshold',100.0,'NumOctaves',1,'NumScaleLevels',6);
targetPoints=detectSURFFeatures(target,'MetricThreshold',100.0,'NumOctaves',1,'NumScaleLevels',6);
%figure; imshow(source);
%hold on;
%plot(sourcePoints.selectStrongest(10000));
[sourceFeatures, sourcePoints]=extractFeatures(source,sourcePoints,'SURFSize',64);
[targetFeatures,targetPoints]=extractFeatures(target,targetPoints,'SURFSize',64);
boxPairs = matchFeatures(sourceFeatures, targetFeatures);
matchedSourcePoints = sourcePoints(boxPairs(:, 1), :);
matchedTargetPoints = targetPoints(boxPairs(:, 2), :);
figure;
showMatchedFeatures(source, target, matchedSourcePoints, matchedTargetPoints, 'montage');
display(matchedSourcePoints);
display(matchedTargetPoints);
The problem is that from what i know you have functions that only display matched SURF Points, and i would need to plot on the target image only the points that didn't match with the points in the source image.
The resulting "matchedTargetPoints" and the "targetPoints" variables are arrays of SURFPoints objects, so the find function doesn't work, subtracting or making array operations on them don't work.
I also tried to loop through "targetPoints" and check for every one if the point exists, but the script takes forever, so this also doesn't work.
Does anyone have any idea how this might be accomplished?
Any response is appreciated.
Thank you.
You can get the (x,y) locations of the points stored in an M-by-2 matrix by using the Location property of the SURFPoints object. Then you can get the unmatched points using logical indexing:
targetPointsLoc = targetPoints.Location;
unmatchedIdx = true(size(targetPoitnsLoc, 1), 1);
unmatchedIdx(boxPairs(:, 2)) = false;
unmatchedTargetPoints = targetPointsLoc(unmatchedIdx, :);
Now you can use plot to display the unmatched points.
Out of curiosity, why do you care about the unmatched points?