I'm looking for an algorithm in Matlab that can preserve the shape of my data while allowing me to clamp the ends. I'm trying to generate the camber line from the chord line, the leading edge angle, trailing edge angle, and the position of the max camber. See Airfoil terminology for definitions. Using that information, I want to generate any number of points between the leading edge and the trailing edge, evenly spaced on the chord.
Here are the algorithms I've evaluated so far:
'pchip' doesn't seem to allow clamping, unless I mistyped repeatedly when searching, but does offer proper shape preservation.
'spline' doesn't preserve shape. Using 3 points of data, the middle data point being the max camber and both ends clamped, a spline can't guarantee the middle data to be the highest point on the generated curve. See this answer for an example of that behavior.
'csape' provides adequate end conditions, but I cannot be sure it is adequately shape preserving.
If your data will only ever have those three points, you can do it in two stages, one for the first half, and the next for the second half. You can use the fact that at the point furthest from the chord line (the middle point), the gradient of the line will be zero.
Generate each line as a spline between two points, with each end at the designated angle.
X = [0 5 10];
Y = [0 3 2];
start_slope = 0;
end_slope = -0.7;
xx1 = linspace(X(1), X(2), 100);
xx2 = linspace(X(2), X(3), 100);
yy1 = spline(X(1:2), [start_slope, Y(1:2), 0], xx1);
yy2 = spline(X(2:3), [0, Y(2:3), end_slope], xx2);
plot([xx1, xx2], [yy1, yy2]);
hold on
scatter(X, Y, 'filled')
I've posted my question on the mathematics stack exchange and got the following answer. Essentially, I can use the Fritsch-Carlson scheme to calculate/set slopes at my data points. If I want to set the slope to my middle point, I will separate my interval in two parts, like Bill Cheatham suggests.
I can also wrap my data and use pchip or a spline for the points that apply instead of reimplementing the whole method.
Related
Suppose there is a binary image of a black background and white lines "plotted" on it, i.e., they aren't burnt onto the image. For example:
I need to retain only the lines that are parallel to atleast one of the other lines in the picture. If not perfectly parallel, at least close enough to be parallel(perhaps a variable that can control the degree of parallelism would help with that). In other words, if I choose a particular line and it has one or more lines that are parallel to it, I retain it, else I discard it. I need to do that for all lines in the image.
I came across Hough transform but I'm having trouble understanding how to use the bins to check the orientations and determine parallel lines. Or is there a better way to go about this?
Also, since the lines aren't a part of the image and are just plotted on it, I don't have an image to feed into the Hough Transform function. Can I use the output of the plot function as input directly? This is the code I wrote to plot the white lines:
Location1 is a m-by-2 matrix that contains the coordinates to draw the lines.
figure; imshow(blackImage);
hold on ;
for i=1:size(Location1,1)-1
h = plot([Location1(i,1) Location1(i+1,1)], [Location1(i,2) Location1(i+1,2)]) ;
set(h,'linewidth', .1, 'color', 'b') ;
end
Any help would be appreciated.
Given that
for i=1:size(Location1,1)-1
% one line = Location1(i,:) to Location1(i+1,:)
end
then
theta = atan2(diff(Location1(:,2)),diff(Location1(:,1)));
But since lines are parallel even if their theta is in the opposite direction, you want to map all angles to half a circle:
theta = mod(theta,pi/2);
Now theta is in the range [-π/2,π/2].
To find similar angles:
[s,i] = sort(theta);
k = find(diff(s)<0.01); % diff(s) is always positive because s is sorted
i = i([k,k+1]);
theta(i) % <-- sets of similar angles
% Location1(i,:),Location1(i+1,:) <- corresponding lines
The task is to connect the centroids that I have got using regionprops horizontally in rows and then predict missing objects.
Here is the image that I have:
This is what I want to achieve :
All centroids within a certain y-coordinate range should be connected. After that I want to predict the missing objects. For example, there should be more objects/centroids present on the green line in the image above.
My code so far :
BW = rgb2gray(imread('noise_removal_single_25_cropped.png'));
props = regionprops(im2bw(BW), 'Centroid');
centroids = cat(1, props.Centroid);
[B,L] = bwboundaries(BW,'noholes');
imshow(label2rgb(L, #jet, [.5 .5 .5]))
hold on
for k = 1:length(B)
boundary = B{k};
plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2)
end
plot(centroids(:,1),centroids(:,2), 'b*')
plot(centroids(:,1),centroids(:,2), 'k-')
The code connects all centroids vertically and I have no idea how to detect missing objects/centroids (maybe based on length of line)?
Let us assume that the rows are perfectly horizontal. It seems that you can easily cluster the points by ordinate, either knowing row separators in advance, or by analysis of the point density.
Take the median ordinate of every cluster and discard the outliers (those farther than a defined tolerance from the median).
Sort the inliers by abscissa. The gap lengths (or point count in a sliding window) will tell you about missing points.
If the rows aren't perfectly horizontal, it remains likely that you can cluster by ordinates and obtain good horizontal separators. In every cluster, use a robust line fitting algorithm that will perform outlier detection, and sort horizontally as before. You can also deskew (using the line equation), but given the small slope, this will make little difference.
Final remark: if all lines are parallel, you can perform skew detection collectively by finding the gravity centers (or medioids) of the clusters and translating the clusters to a common center, giving a single thick line.
I would like to draw height lines of a function (represented by matrices, of course), using MATLAB.
I'm familiar with contour, but contour draws lines at even-spaced heights, while I would like to see lines (with height labels), in constant distance from one another when plotted.
This means that if a function grows rapidly in one area, I won't get a plot with dense height lines, but only a few lines, at evenly spaced distances.
I tried to find such an option in the contour help page, but couldn't see anything. Is there a built in function which does it?
There is no built-in function to do this (to my knowledge). You have to realize that in the general case you can't have lines that both represent iso-values and that are spaced with a fixed distance. This is only possible with plots that have special scaling properties, and again, this is not the general case.
This being said, you can imagine to approach your desired plot by using the syntax in which you specify the levels to plots:
...
contour(Z,v) draws a contour plot of matrix Z with contour lines at the data values specified in the monotonically increasing vector v.
...
So all you need is the good vector v of height values. For this we can take the classical Matlab exemple:
[X,Y,Z] = peaks;
contour(X,Y,Z,10);
axis equal
colorbar
and transform it in:
[X,Y,Z] = peaks;
[~, I] = sort(Z(:));
v = Z(I(round(linspace(1, numel(Z),10))));
contour(X,Y,Z,v);
axis equal
colorbar
The result may not be as nice as what you expected, but this is the best I can think of given that what you ask is, again, not possible.
Best,
One thing you could do is, instead of plotting the contours at equally spaces levels (this is what happens when you pass an integer to contour), to plot the contours at fixed percentiles of your data (this requires passing a vector of levels to contour):
Z = peaks(100); % generate some pretty data
nlevel = 30;
subplot(121)
contour(Z, nlevel) % spaced equally between min(Z(:)) and max(Z(:))
title('Contours at fixed height')
subplot(122)
levels = prctile(Z(:), linspace(0, 100, nlevel));
contour(Z, levels); % at given levels
title('Contours at fixed percentiles')
Result:
For the right figure, the lines have somewhat equal spacing for most of the image. Note that the spacing is only approximately equal, and it is impossible to get the equal spacing over the complete image, except in some trivial cases.
I have a set of data whose points I have plotted and fitted using a power of 2 fit in MATLAB. I'm trying to draw 3 lines to that curve as tangential lines. Each of these lines start from the co-ordinates of say, (x,y): (2,0) (4,0) (9,0).
Is it possible for MATLAB to draw lines from the curve to the first known point until the line has only one solution (tangent to the curve) with the curve?
I feel that this requires some sort of specified interval which tells MATLAB to step the co-ordinates until it finds the closest point. Does anyone know if this has been done or can be done at all?
From a point not lying on the curve, you want to draw a line that is tangent to it. In case of a convex function like y=2^x this is only possible from a point under the curve (not over it).
Since you already have the point (call it (a,b)), you need the slope of such a line. The slope is determined by the values (y-b)/(x-a) where (x,y) runs over the curve. Specifically, the "forward-looking" tangent has the slope equal to the minimum of (y-b)/(x-a) over all x>a. And the "backward-looking " tangent has the slope equal to the maximum of (y-b)/(x-a) over all x
Here is a very straightforward implementation of the above: I used find to restrict the search to either x>a or x<a and took min and max to find the slopes.
x = 0:0.01:4;
y = 2.^x;
a = 2;
b = 3;
k = min((y(find(x>a))-b)./(x(find(x>a))-a));
plot(x,y)
hold on
plot(x,k*(x-a)+b,'r')
k = max((y(find(x<a))-b)./(x(find(x<a))-a));
plot(x,k*(x-a)+b,'g')
I found an implementation of the Hough transform in MATLAB at Rosetta Code, but I'm having trouble understanding it. Also I would like to modify it to show the original image and the reconstructed lines (de-Houghing).
Any help in understanding it and de-Houghing is appreciated. Thanks
Why is the image flipped?
theImage = flipud(theImage);
I can't wrap my head around the norm function. What is its purpose, and can it be avoided?
EDIT: norm is just a synonym for euclidean distance: sqrt(width^2 + height^2)
rhoLimit = norm([width height]);
Can someone provide an explanation of how/why rho, theta, and houghSpace is calculated?
rho = (-rhoLimit:1:rhoLimit);
theta = (0:thetaSampleFrequency:pi);
numThetas = numel(theta);
houghSpace = zeros(numel(rho),numThetas);
How would I de-Hough the Hough space to recreate the lines?
Calling the function using a 10x10 image of a diagonal line created using the identity (eye) function
theImage = eye(10)
thetaSampleFrequency = 0.1
[rho,theta,houghSpace] = houghTransform(theImage,thetaSampleFrequency)
The actual function
function [rho,theta,houghSpace] = houghTransform(theImage,thetaSampleFrequency)
%Define the hough space
theImage = flipud(theImage);
[width,height] = size(theImage);
rhoLimit = norm([width height]);
rho = (-rhoLimit:1:rhoLimit);
theta = (0:thetaSampleFrequency:pi);
numThetas = numel(theta);
houghSpace = zeros(numel(rho),numThetas);
%Find the "edge" pixels
[xIndicies,yIndicies] = find(theImage);
%Preallocate space for the accumulator array
numEdgePixels = numel(xIndicies);
accumulator = zeros(numEdgePixels,numThetas);
%Preallocate cosine and sine calculations to increase speed. In
%addition to precallculating sine and cosine we are also multiplying
%them by the proper pixel weights such that the rows will be indexed by
%the pixel number and the columns will be indexed by the thetas.
%Example: cosine(3,:) is 2*cosine(0 to pi)
% cosine(:,1) is (0 to width of image)*cosine(0)
cosine = (0:width-1)'*cos(theta); %Matrix Outerproduct
sine = (0:height-1)'*sin(theta); %Matrix Outerproduct
accumulator((1:numEdgePixels),:) = cosine(xIndicies,:) + sine(yIndicies,:);
%Scan over the thetas and bin the rhos
for i = (1:numThetas)
houghSpace(:,i) = hist(accumulator(:,i),rho);
end
pcolor(theta,rho,houghSpace);
shading flat;
title('Hough Transform');
xlabel('Theta (radians)');
ylabel('Rho (pixels)');
colormap('gray');
end
The Hough Transform is a "voting" approach where each image point casts a vote on the existence of a certain line (not a line segment) in an image. The voting is carried out in the parameter space for a line: the polar coordinate representation of normal vectors.
We discretize the parameter space and allow each image point to suggest parameters which would be compatible with a line through the point. Each of your questions can be addressed in terms of how the parameter space is treated in code. Wikipedia has a good article with worked examples that might clarify things (if you are having any conceptual troubles).
For your specific questions:
The image is flipped so the origin is the bottom right corner. As far as I can tell this step is not technically necessary. It does change the outcome somewhat due to discretization issues. The other implementations on Rosetta Code do not flip the image.
rhoLimit holds the maximum radius of an image point in polar coordinates (recall the norm of a vector is its magnitude).
rho and theta are discretizations of the polar coordinate plane according to a sampling rate. houghSpace creates a matrix with an element for each possible combination of the discrete rho/theta values.
The Hough Transform does not specify the lengths of putative lines; the peaks in the voting space just specify the polar coordinates of the normal vector of the line. You can "de-Hough" by selecting the peaks and drawing the corresponding lines, or perhaps by drawing every possible line and using the number of votes as a grayscale weight. It is not possible to re-create the original image from the Hough Transform, just the lines identified by the transform (and your thresholding scheme on the votes).
Following the example from the question produces the following graph. The placement of grid lines and the datatips cursor can be a bit misleading (though the variable values in the 'tip are correct). Since this is an image of the parameter space and not the image space the sampling rate we chose is determining the number of bins in each variable. At this sampling rate, the image points are compatible with more than one possible line; in other words our lines have subpixel resolution, in the sense that they cannot be drawn without overlap in a 10x10 image.
Once we have chosen a peak, such as that corresponding to the line with normal (rho,theta) = (6.858,0.9), we can draw that line in an image however we choose. Automated peak picking, that is thresholding to find the highly up-voted lines, is its own problem - you could ask a another question about the topic in DSP or about a particular algorithm here.
For example methods see the code and documentation of MATLAB's houghpeaks and houghlines functions.