Distance between broken line and experimental values - matlab

I need to evaluate a set of broken lines (red line), returned by a forward model, and select the one best fitting a set of experimental values (green dots); example in the image below. Do you have any suggestion on how to calculate the distance of the points from the broken line?

A decent (I think) approach would be to compute the sum of square distances from the fit to the points.
Assuming that you describe the links between the red dots as straight lines, then you can do it by
Computing the equation of each line between red points.
Compute distances between green points and red points. Assign the line from (1.) between closest 2 red points to each green dot.
Compute distance between each green dot and corresponding (2.) line.
score=sum(sqrt(distances))
If you want interpolate between your red points with something other than linear you may need to find a bit fancier maths, but the process should be the same.

Related

Improving scatter plot in Matlab

I have to do the scatter plot of a 2-dimensional region in Matlab.
The collection of the points (x,y) that should be included in the scatter is obtained by running a computationally intense code. As a result, this is the scatter that I get
I don't like the picture because in principle there should be no white dots (i.e., spaces among the scatter dots) inside the blue region. The white dots are there because, given that the points to be included in the scatter are obtained by running a computationally intense code, as a result I get a very coarse grid of points to plot.
I tried to cheat by increasing the size of the scatter dots but the result is even worse as the region looks more and more waving on the borders.
Is there anything I could do to "manually" fill the white spaces inside the blue area? Other ideas?
If you want the whole region to be filled, a patch object might be better suited to your needs. Not knowing how you're generating the points, that might be easier said than done. If you are systematically searching the whole area or something like that, it shouldn't be too hard to identify the edges, or define small patches for each square space on the plot.

Curve fit with three points with a given slope

This might be of math problem than Matlab. Nonetheless, here is my problem.
so, I have a data set represented by the green curve. It's usually linear, but sometimes it can have a slight curvature. Then, I have two additional points: the red and the blue. The red is far out in the negative. Its amplitude is 30~100 bigger than the X value of the green circle and it's always on the X-axis. The blue circle is always on the Y-axis.
I need a curve that fits the red, the blue, and the green circles, but there are two more constraints:
Blue curve can't be negative
where the blue curve meets the green curve, I want the slopes of them to be the same (smooth transition)
The red point doesn't have to be on the Y-axis, but asymptotic to zero and very close to zero at the red circle.
I have tried different inverse functions such as exponential, polynomial, 1/something, etc., but without a slope constraint, the end-result tends to have a cusp at the green point and it causes a problem for an overall analysis in which this curve-fitting function is used.
Can this be done?
If you just need to roughly match the slope and you have access to the data points of the green curve (not just the green dot), you can use multiple points of the green curve in the fitting function together with the blue and red point. That should produce a curve that passes through all the points and pretty much match the slope in the green point.
Clearly, if you need to match the slope with mathematical precision, you need to set up another constraint equation as it was suggested by duffymo.
I'm taking an answer from
https://math.stackexchange.com/questions/2523269/three-point-curve-fit-with-a-specificed-slope-at-one-point][1]
This uses the fact that it passes three points and at one point, its slope is known. With the four equations and a generic irrational/exponential function, I was able to create a reasonable curve-fit.

How to find the corners in a skeleton image using Matlab?

I have prepossessed and created skeleton image from an input image. But i couldn't figure out perfect solution for finding corners. I've tried using hough transform to find the lines and then calculate intersection. but it doesn't work well with given image as the lines are not perfect straight lines.
Any suggestions please
Some simple solution:
You can check each point of the graph for corner candidate:
1. Gather all points that are pretty close to this (in some neighborhood of the tested point)
2. Find center of mass for these points
3. Check the distance from the tested point to the center of mass - if distance is big, the point is candidate for corner
For each connected group of candidates select one and it will be the corner.
If the shape of your skeleton is not very complex, you'll get your corners.
If you need more precise result, you can approximate each neighborhood of points with a line using polyfit function and then calculate maximum deviation of points from this line. If deviation is big - it's a corner.

How to make a heat map on top of worldmap using hist3 in MATLAB?

My x-axis is latitudes, y-axis is longitudes, and z-axis is the hist3 of the two. It is given by: z=hist3(location(:,1:2),[180,360]), where location(:,1) is the latitude column, and location(:,2) is the longitude column.
What I now want is, instead of plotting on a self-created XY plane, I want to plot the same on a worldmap. And instead of representing the frequency of each latitude-longitude pair with the height of the bars of hist3, I want to represent the frequency of each location by a heat map on top of the world map, corresponding to each latitude-longitude pair's frequency on the dataset. I have been searching a lot for this, but have not found much help. How to do this? I could only plot the skeleton of the worldmap like this:
worldmap world
load geoid
geoshow(geoid, geoidrefvec, 'DisplayType', 'texturemap');
load coast
geoshow(lat, long)
I don't know what the colour is being produced based on.
Additionally, if possible, I would also like to know how to plot the hist3 on a 3D map of the world (or globe), where each bar of the hist3 would correspond to the frequency of each location (i.e., each latitude-longitude pair). Thank you.
The hist3 documentation, which you can find here hist3, says:
Color the bars based on the frequency of the observations, i.e. according to the height of the bars. set(get(gca,'child'),'FaceColor','interp','CDataMode','auto');
If that's not what you need, you might wanna try it with colormap. More info about it here colormap. I haven't tried using colormap on histograms directly, so If colormap doesn't help, then you can try creating a new matrix manually which will have values in colors instead of the Z values the histogram originally had.
To do that, you need to first calculate the maximum Z value with:
maxZ=max(Z);
Then, you need to calculate how much of the colors should overlap. For example, if you use RGB system and you assign Blue for the lowest values of the histogram, then Green for the middle and Red for the High, and the green starts after the Blue with no overlap, than it will look artificial. So, if you decide that you will have, for example overlapping of 10 values, than, having in mind that every R, G and B component of the RGB color images have 255 values (8 bits) and 10 of each overlap with the former, that means that you will have 255 values (from the Blue) + 245 values (From the Green, which is 255 - 10 since 10 of the Green overlap with those of the Blue) + 245 (From the Red, with the same comment as for the Green), which is total amount of 745 values that you can assign to the new colored Histogram.
If 745 > maxZ there is no logic for you to map the new Z with more than maxZ values. Then you can calculate the number of overlaping values in this manner:
if 745 > maxZ
overlap=floor(255- (maxZ-255)/2)
end
At this point you have 10 overlapping values (or more if you still think that it doesn't looks good) if the maximum value of the Z is bigger than the total amount of values you are trying to assign to the new Z, or overlap overlapping values, if the maximum of Z is smaller.
When you have this two numbers (i.e. 745 and maxZ), you can write the following code so you can create the newZ.
First you need to specify that newZ is of the same size as Z. You can achieve that by creating a zero matrix with the same size as Z, but having in mind that in order to be in color, it has to have an additional dimension, which will specify the three color components (if you are working with RGB).
This can be achieved in the following manner:
newZ=zeros(size(Z),3)
The number 3 is here, as I said, so you would be able to give color to the new histogram.
Now you need to calculate the step (this is needed only if maxZ > The number of colors you wish to assign). The step can be calculated as:
stepZ=maxZ/Total_Number_of_Colors
If maxZ is, for example 2000 and Total_Number_of_Colors is (With 10 overlaping colours) 745, then stepZ=2.6845637583892617449664429530201. You will also need a counter so you would know what color you would assign to the new matrix. You can initialize it here:
count=0;
Now, finally the assignment is as follows:
For i=1:stepZ:maxZ
count=count+1;
If count>245
NewZ(Z==stepz,3)=count;
elseif count>245 && count<256
NewZ(Z==stepz,3)=count;
NewZ(Z==stepz,2)=count-245;
elseif count>255
NewZ(Z==stepz,2)=count-245;
elseif count>500 && count<511
NewZ(Z==stepz,2)=count-245;
NewZ(Z==stepz,1)=count-500;
else
NewZ(Z==stepz,1)=count-500;
end
end
At this point you have colored your histogram. Note that you can manually color it in different colors than red, green and blue (even if you are working in RGB), but it would be a bit harder, so if you don't like the colors you can experiment with the last bit of code (the one with the for loops), or check the internet of some other automatic way to color your newZ matrix.
Now, how do you think to superimpose this matrix (histogram) over your map? Do you want only the black lines to be shown over the colored histogram? If that's the case, than it can be achieved by resampling the NewZ matrix (the colored histogram) with the same precision as the map. For example, if the map is of size MxN, then the histogram needs to be adjusted to that size. If, on the other hand, their sizes are the same, then you can directly continue to the next part.
Your job is to find all pixels that have black in the map. Since the map is not binary (blacks and whites), it will be a bit more harder, but still achievable. You need to find a satisfactory threshold for the three components. All the lines under this threshold should be the black lines that are shown on the map. You can test these values with imshow(worldmap) and checking the values of the black lines you wish to preserve (borders and land edges, for example) by pointing the cross tool on the top of the figure, in the tools bar on every pixel which is of interest.
You don't need to test all black lines that you wish to preserve. You just need to have some basic info about what values the threshold should have. Then you continue with the rest of the code and if you don't like the result so much, you just adjust the threshold in some trial and error manner. When you have figured that this threshold is, for example, (40, 30, 60) for all of the RGB values of the map that you wish to preserve (have in mind that only values that are between (0,0,0) and (40,30,60) will be kept this way, all others will be erased), then you can add the black lines with the following few commands:
for i = 1:size(worldmap,1)
for j = 1:size(worldmap,2)
if worldmap(i,j,1)<40 && worldmap(i,j,2)<30 && worldmap(i,j,3)<60
newZ(i,j,:)=worldmap(i,j,:)
end
end
I want to note that I haven't tested this code, since I don't have Matlab near me atm, so It can have few errors, but those should be easily debugable.
Hopes this is what you need,
Cheers!

Separate the connected lines and shapes

I want an approach and method to separate the connected lines. Here is my image
and here is the result I would like
How do I solve that problem? Thank you in advance!
Sincerely
The watershed would be a problem as you have shown it produces multiple segmentations of the original line. Originally the watershed works for grains due to their convex shapes, while here in the case of lines there is no global convex shape to cause a good fragmentation, it would be good to use the watershed with some constraints.
It would be good to try solving a simpler version of the problem. Imagine that there are only horizontal and vertical lines possible. So in this case it would mean separating the horizontal long lines by cutting the short vertical lines (length measured by projecting on the x-y gradient). The basic hint is to use the gradient/slope of these lines to help decide where to cut - orthogonal line. In the more general case the problem requires a measure of local curvature or geodesic distance.
A simpler solution(in edit) is just removing the junction points in the skeleton you have.
This would cause some of your lines which are connected horizontally to be segmented but i guess this can be fixed with some end point filtering. A simple try here:
J = imread('input.png');
B = bwmorph(J,'branchpoints');
L = bwlabel((J>0).*(~B),8); %removing the branch points from the skeleton
Label = label2rgb(bwlabel((J>0).*(~B),8),'jet',[0 0 0]);
Final labeled line components. This requires further end point prefiltering, direction based filtering.
The parts of the contour that should be separated are basically the sections that are not in the same direction as most of the rest of the contour.
I can only give you a basic way to do this without specific code or functions and I doubt it is the most efficient, but since there are not too many answers here...also this is using the knowledge of the problem and the solution...
Find the connected contour with all its branches as a set of pixel coordinates (which represent the line as a single pixel wide contour)
Convert the contour list to a set of angles between each adjacent pixel coordinate
Optional: Filter out the high frequency components with an averaging filter
Histogram the angles to find the angle most of the contour lines lay on (call it the common angle)
Search the contour looking for sections that go from +/-common angle (tolerance of +/-30 degrees) to the negative of that (-/+ common angle with similar tolerance).
For each section delete the pixels associated with angles between the two thresholds above (i.e. common angle + 30 deg to -common angle - 30 degrees.
Repeat for each connected contour
Hope this helps some