Clear Filters
Clear Filters

Extract shapes from photos as graphs using MATLAB and express them as functions

6 views (last 30 days)
I would like to extract a function by graphing the outline of the Hindenburg airship.
Here, I would like to define a function that matches the actual size of the Hindenburg.
For example, the length of the Hindenburg airship is 245.3 meters. The length of both endpoints of the function will be 245.3
I even put dots on a picture and expressed it as a graph, but I can't define the function according to the actual scale.
I used this code
data=imread('project_final.png');
imshow(data);
b=drawpolygon('Color','red');
bx=b.Position(:,1);
by=b.Position(:,2);
f=fit(bx,by,'poly4')
  3 Comments
Walter Roberson
Walter Roberson on 4 Dec 2023
Those look to me to likely be catenary and so would need to be fit with hyperbolic functions.
Unfortunately it is mathematically impossible to measure a finite number of points to a finite precision and then through mechanical processing determine what the curve definitely "is". You need to fit against mathematical models of what is reasonable given the physics of the situation.
Kilsu Kim
Kilsu Kim on 4 Dec 2023
Additionally, the shape likely took inspiration from an airfoil. Therefore, finding or designing a similar airfoil shape using a tool like XFOILl or Airfoil Tools could be a practical solution(If you're interested!:))

Sign in to comment.

Accepted Answer

DGM
DGM on 4 Dec 2023
Edited: DGM on 4 Dec 2023
This isn't an answer to the curve fitting problem, but first things first. Fix the image so you're not trying to fit a curve to a distorted image.
% read the image
A = imread('blimp.png');
A = rgb2gray(A);
% these coordinates are a quadrilateral
% defined by the endpoints of the two projections
boxm = [9 119; 16 334; 715 343; 714 120]; % [x y]
% assert that this is where they're supposed to be
boxf = [9 120; 9 334; 714 334; 714 120]; % [x y]
% adjust the image
TF = fitgeotrans(boxm,boxf,'projective');
outview = imref2d(size(A));
B = imwarp(A,TF,'fillvalues',255,'outputview',outview);
imshow(B,'border','tight')
% these are a polyline describing the vertical shear defect
boxm = [9 120; 529 119; 540 120; 713 120]; % [x y]
boxm = [boxm; boxm+[0 100]]; % control points can't be colinear, so make a cage
% assert that this is where they're supposed to be
boxf = [9 120; 529 120; 540 120; 713 120]; % [x y]
boxf = [boxf; boxf+[0 100]];
% adjust the image again
TF = fitgeotrans(boxm,boxf,'pwl');
B = imwarp(B,TF,'fillvalues',255,'outputview',outview);
imshow(B,'border','tight')
% save the image and transcribe it with something else
imwrite(B,'b_corrected.png')
It's not perfect, but it's a lot better than before.
Normally, I do this sort of transcription via Inkscape
This is only slightly different due to the absence of axes.
  1 Comment
DGM
DGM on 4 Dec 2023
Edited: DGM on 4 Dec 2023
FWIW, this is what I did.
I transcribed two curves, one for the profile view and one for the plan view. Using the attached SVG:
% using the following FEX tools:
% https://www.mathworks.com/matlabcentral/fileexchange/72225-load-svg-into-your-matlab-code
% filename of manually-fit svg file
fname = 'blimp.svg';
% data range from original image axis labels
% this is where the rectangle is drawn in the SVG
xrange = [0 245.3];
yrange = xrange; % the box is square to preserve data aspect ratio
% spline discretization parameter [0 1]
coarseness = 0.01;
% get plot box geometry
str = fileread(fname);
str = regexp(str,'((?<=<rect)(.*?)(?=\/>))','match');
pbx = regexp(str,'((?<=x=")(.*?)(?="))','match');
pby = regexp(str,'((?<=y=")(.*?)(?="))','match');
pbw = regexp(str,'((?<=width=")(.*?)(?="))','match');
pbh = regexp(str,'((?<=height=")(.*?)(?="))','match');
pbrect = [str2double(pbx{1}{1}) str2double(pby{1}{1}) ...
str2double(pbw{1}{1}) str2double(pbh{1}{1})];
% get coordinates representing the curve
S = loadsvg(fname,coarseness,false);
for k = 1:numel(S) % there are multiple curves
x = S{k}(:,1);
y = S{k}(:,2);
% rescale to fit data range
x = xrange(1) + diff(xrange)*(x-pbrect(1))/pbrect(3);
y = yrange(1) + diff(yrange)*(pbrect(4) - (y-pbrect(2)))/pbrect(4);
% correct for offsets
x = rescale(x,xrange(1),xrange(2)); % assume each curve represents the same length
y = y - min(y); % remove y-offset
% get rid of nonunique points
% this may or may not be needed depending on the shape
% of the curves and how they're to be processed
[x,idx,~] = unique(x,'stable');
y = y(idx);
% shove the prepared data back into S for later
S{k} = [x y];
end
% plot the two curves
for k = 1:numel(S)
x = S{k}(:,1);
y = S{k}(:,2);
plot(x,y); hold on
end
grid on;
xlim(xrange)
%axis equal % if you want to display it with 1:1 data aspect
% let's say that taking the average of the curves is appropriate
xf = linspace(0,245.3,100);
y1 = interp1(S{1}(:,1),S{1}(:,2),xf,'linear','extrap');
y2 = interp1(S{2}(:,1),S{2}(:,2),xf,'linear','extrap');
yf = max((y1 + y2)/2,0); % the average curve
plot(xf,yf)
legend({'sample 1','sample 2','average'})
I have no idea whether the two curves are supposed to differ, or whether the sections are exactly circular. Likewise, I have no idea what an appropriate fit model would be.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!