Using bwdist (Distance transform) with a specific window size - matlab

I am using bwdist in MATLAB, but I want to use a specific window size. I think MATLAB uses its default window size. Is there any other function which let me to use my own window size?

Euclidean Distance transform measures the exact distance between pixels. Since exact distance involves calculation of sqrt() it becomes computational heavy.
In order to solve that issue, a Chamfer mask of 3x3 can be used to approximate the distance up to error of 8% with only liner calculations (without sqrt()).
Mask of size 5x5 approximated up to ~3% error.
If you want a distance transform with non-quclidian distance (for example Manhattan distance) than Chamfer is completely irrelevant.
In conclusion: there is no window size in Matlab. It uses exact calculation when you ask for Euclidian distance transform. In order to approximate it one can uses quasi-euclidian distance. For other distances (chessboard/Manhattan) the calculation is precise and fast.
You cannot simulate Chamfer masks with distance transform.
In openCV - distance transform uses Chamfer mask and you can set the size of the mask. Typically 5x5 mask is used because bigger masks will yiled almost the same results (unnoticeable difference for the human eye)

Related

How to find median trajectory of a spiral movement?

Lets some objects make complex spiral moving in 3D and we have get their trajectories projected on a plane.
How to find a median trajectory of such movements and estimate the amplitudes of spirals?
I assume that this requires averaging the coordinates of the trajectories, then somehow finding the distances from the extreme points of the trajectories to the midline. But I don't know a concrete algorithm for this. Can someone suggest this algorithm?
By median trajectory I mean a line that ges between path waves, something like linew on a picture below.
This is a case for a Kalman filter, but this method is a little complicated.
A simpler one is a moving average, with a number of samples that covers as closes as possible to a full period (which you can estimate visually).
Regarding the distances, you can compute the shortest Euclidean distance of every point to the midline (using a line-to-segment function). This will yield an alternating plot, which you can smoothen with a moving maximum (rather than average) over a period.

How to find distance mid point of bezier curve?

I am making game in Unity engine, where car is moving along the bezier curve by percentage of bezier curve legth.
On this image you can see curve with 8 stop points (yellow spheres). Between each stop point is 20% gap of total distance.
On the image above everything is working correctly, but when I move handles, that the handles have different length problem occurs.
As you can see on image above, distances between stop points are not equal. It is because of my algorithm, because I am finding point of segment by multiplying segment length by interpolation (t). In short problem is that: if t=0.5 it is not in the 50% percent of the segment. As you can see on first image, stop points are in half of segment, but in the second image it is not in half of segment. This problem will be fixed, if there is some mathematical formula, how to find distance middle point.
As you can see on the image above, there are two mid points. T param mid point can be found by setting t to 0.5 (it is what i am doing now), but it is not half of the distance.
How can I find distance mid point (for cubic bezier curve, that have handles in different distance)?
You have correctly observed that the parameter value t=0.5 is generally not the point in the middle of the length. That is a good start but the difficulty lies in the mathematics beneath.
Denoting the components of your parametric curve by x(t) and y(t), the length of the curve
between t=0 (the beginning) and a chosen parameter value t = u is equal to
What you are trying to do is to find u such that l(u) is one half of l(1). This is sometimes possible but often difficult or impossible. So what can you do?
One possibility is to approximate the point you want. A straightforward way is to approximate your Bezier curve by a piecewise linear curve (simply by choosing many parameter values 0 = t_0 < t_1 < ... < t_n = 1 and connecting the values in these parameters by line segments). Now it is easy to compute the entire length (Pythagoras Theorem is your friend) as well as the middle point (walk along the piecewise linear curve the prescribed length). The more points you sample, the more precise you will be and the more time your computation will take, so there is a trade-off. Of course, you can use a more complicated numerical scheme for the approximation but that is beyond the scope of the answer.
The second possibility is to restrict yourself to a subclass of Bezier curves that will let you do what you want. These are called Pythagorean-Hodograph (shortly PH) curves. They have the extremely useful property that there exists a polynomial sigma(t) such that
This means that you can compute the integral above and search for the correct value of u. However, everything comes at a price and the price here is that you will have less freedom, where to put the control points (for me as a mathematician, a cubic Bézier curve has four control points; computer graphics people often speak of "handles" so you might have to translate into your terminology). For the cubic case you can find the conditions on slide 15 of this seminar talk by Vito Vitrih.
Denote:
the control points,
;
then the Bézier curve is a PH curve if and only if
.
It is up to you to figure out, if you can enforce this condition in your situation or if it is too restrictive for your application.

Finding Sub-Pixel Accurate Maxima in a 3D Image

I am using a 3D cross correlation technqiue to track a particle in 3D. It is very robust but my z dimension is 4x times lower resolution than my x and y. The cross correlation produces a 3D image with a single maximum. I would like to localise this point with sub-pixel accuracy using interpolation of some sort I expect.
Any help welcome!
Craig
You could use bicubic (tricubic in 3D?) or similar interpolation around the peak, as used for image scaling, to better localize the peak. This is commonly done in image processing, for example when localizing peaks in difference-of-gaussian stacks for blob detection, by performing a cubic approximation in each dimension, with the respective neighbouring pixels.

Measure circularity or ellipticality

I have some binary images that want to classify them base on shape of them in MATLAB. If they have circular or elliptical shape they belong to class one,if they have elliptical shape with dent in their boundary they belong to class two. I dont know how can I use this feature. Can any body help me with this?
You can use the eccentricity property in regionprops. From MATLAB documentation of eccentricity:
The eccentricity is the ratio of the distance between the foci of the ellipse and its major axis length. The value is between 0 and 1. (0 and 1 are degenerate cases. An ellipse whose eccentricity is 0 is actually a circle, while an ellipse whose eccentricity is 1 is a line segment.)
So as the value of eccentricity increases , the ellipse starts becoming flatter. Hence, at its maximum value = 1, it is a line segment.
To check if there is a dent in the ellipse, you can use check for convexity. Whenever there is a dent in an ellipse, it will be non-convex. In other words, if you try to fit a convex polygon, it won't be able to approximate the shape well enough. You can use convexArea property to check the same. From MATLAB documentation of convexArea:
Returns a p-by-2 matrix that specifies the smallest convex polygon that can contain the region. Each row of the matrix contains the x- and y-coordinates of one vertex of the polygon. Only supported for 2-D label matrices.
So you use bwlabel to create a 2-D label matrix from your binary image and then check the difference between the area of your binary image and the area of the fitted convex polygon. Measuring area could be as simple as counting pixels. You already know that the number pixels of your fitted convex polygon = p. Just take the absolute difference between p and the number of pixels in your original binary image. You should be able to easily set a threshold to classify into one of the two classes.
I think you can write the code for this. Hope this helps.

How to make "well" a ridge-shape from a given 2d line? (gaussian, matlab)

My goal is to make a ridge(mountain)-like shape from the given line. For that purpose, I applied the gaussian filter to the given line. In this example below, one line is vertical and one has some slope. (here, background values are 0, line pixel values are 1.)
Given line:
Ridge shape:
When I applied gaussian filter, the peak heights are different. I guess this results from the rasterization problem. The image matrix itself is discrete integer space. The gaussian filter is actually not exactly circular (s by s matrix). Two lines also suffer from rasterization.
How can I get two same-peak-height nice-looking ridges(mountains)?
Is there more appropriate way to apply the filter?
Should I make a larger canvas(image matrix) and then reduce the canvas by interpolation? Is it a good way?
Moreover, I appreciate if you can suggest a way to make ridges with a certain peak height. When using gaussian filter, what we can do is deciding the size and sigma of the filter. Based on those parameters, the peak height varies.
For information, image matrix size is 250x250 here.
You can give a try to distance transform. Your image is a binary image (having only two type of values, 0 and 1). Therefore, you can generate similar effects with distance transform.
%Create an image similar to yours
img=false(250,250);
img(sub2ind(size(img),180:220,linspace(20,100,41)))=1;
img(1:200,150)=1;
%Distance transform
distImg=bwdist(img);
distImg(distImg>5)=0; %5 is set manually to achieve similar results to yours
distImg=5-distImg; %Get high values for the pixels inside the tube as shown
%in your figure
distImg(distImg==5)=0; %Making background pixels zero
%Plotting
surf(1:size(img,2),1:size(img,1),double(distImg));
To get images with certain peak height, you can change the threshold of 5 to a different value. If you set it to 10, you can get peaks with height equal to the next largest value present in the distance transform matrix. In case of 5 and 10, I found it to be around 3.5 and 8.
Again, if you want to be exact 5 and 10, then you may multiply the distance transform matrix with the normalization factor as follows.
normalizationFactor=(newValue-minValue)/(maxValue-minValue) %self-explanatory
Only disadvantage I see is, I don't get a smooth graph as you have. I tried with Gaussian filter too, but did not get a smooth graph.
My result: