3

I want to unwrape a pillar (truncated cone shaped) which has cone shape. How can I do it.

Lower radius=1.8506 m (red in pic) Upper radius=1.6849 m (green in pic)

The coordinates of my pillar

center: Bottom circle : xyz: 0,0,0 Top circle : xyz: 0,0,24.6 Please see attached figure.

Cone apex: 0,0,275 (I just calculated) angle (half)enter image description here:0.38 projection radius=1.84 ( WHAT should I give)enter image description here

The coordinates of cylinder, I can get

r=sqrt(x^2+y^2)
theta=atan(y,x)
z=z

How can I project them on plane.

Shahgee
  • 3,303
  • 8
  • 49
  • 81
  • 1
    @mbschenkel: Think you intended to link this one: http://stackoverflow.com/questions/28526099/unrectified-image-from-unwrapping-a-truncated-cone – Daniel Feb 16 '15 at 20:48
  • Could you point out the difference to your [second question](http://stackoverflow.com/questions/28526099/unrectified-image-from-unwrapping-a-truncated-cone)? - Thanks for the correction @Daniel – mbschenkel Feb 16 '15 at 21:35

2 Answers2

4

There's probably many codes around on fileexchange or highly optimized solutions on the web (for texture projection for instance), anyway here is my solution:

I assume pillar data is a matrix of size [tcount x zcount] where tcount is the number of scan positions along angular axis and zcount is the number of scan positions along height axis.

So here is the code:

%
% PURPOSE:
%
%   Project cone data to plane data
%
% INPUT:
%
%   thetaValues: Angular-scan values (in radians !!)
%   zValues: z-scan values (whathever unit)
%   coneData: Scanned data of size thetaCount-by-zCount
%   zminRadius: Radius at zmin position (same unit as zValues)
%   zmaxRadius: Radius at zmax position (same unit as zValues)
%   xvalues: Values to have along x-axis (by default biggestRadius * thetaValues centered around theta = 0)
%
% OUTPUT:
%
%   xvalues: Positions along x-axis (same unit as zValues)
%   zvalues: Positions along z-axis (same values/unit as input)
%   planeData: Plane data of size xcount-by-zcount 
%
function [xvalues, zValues, planeData] = Cone2Plane(thetaValues, zValues, coneData, zminRadius, zmaxRadius, xvalues)
%[
    % Default arguments
    if (nargin < 6), xvalues = []; end

    % Init
    zmin = min(zValues);
    zmax = max(zValues);    
    smallestRadius = min(zminRadius, zmaxRadius);
    biggestRadius = max(zminRadius, zmaxRadius);

    % Ensure thetaValues range in -pi;+pi;
    thetaValues = mod(thetaValues + pi, 2*pi) - pi;
    [thetaValues, si] = sort(thetaValues);
    coneData = coneData(si, :);

    % Intercept theorem (Thales)
    %
    %      A-------+-------\
    %     /|       |        \
    %    / |       |         \
    %   D--E-------+----------\
    %  /   |       |           \
    % B----C-------+------------\
    BC = biggestRadius - smallestRadius; 
    AE = zmax - zValues(:);
    AC = (zmax - zmin);
    DE = (BC * AE) / AC;
    radiuses = smallestRadius + DE;

    % Projection
    if (isempty(xvalues)), xvalues = biggestRadius * thetaValues; end
    xcount = length(xvalues);
    zcount = length(zValues);
    planeData = zeros(xcount, zcount);        
    for zi = 1:zcount,
        localX = radiuses(zi) * thetaValues;
        localValues = coneData(:, zi);
        planeData(:, zi) = interp1(localX, localValues, xvalues, 'linear', 0);
    end
%]
end
  • I will not enter into details of Thales theorem to compute radiuses for each z-position.

  • I reorder angular positions to be in [-180°;+180°] so as to have symmetric x-positions (i.e. xLocal = radiusLocal * angularPos).

  • The tricky part is to re-interpolate xLocal to some xGlobal positions (Which I assume to be xLocal = biggestRadius * angularPos, but you can of course provide your own values as an argument to Cone2Plane routine).

Here some test case:

function [] = TestCone2Plane()
%[
    % Scanning info
    zminRadius = 1.8506;
    zmaxRadius = 1.6849;
    zValues = linspace(0.0, 24.6, 100); 
    thetaValues = linspace(0, 359, 360) * pi / 180;

    % Build dummy cone data
    tcount = length(thetaValues);
    zcount = length(zValues);    
    coneData = rand(tcount, zcount);

    % Convert to plane data
    xvalues = []; % Means automatic x-positions
    [xvalues, zValues, planeData] = Cone2Plane(thetaValues, zValues, coneData, zminRadius, zmaxRadius, xvalues);

    % Display
    [X, Z] = ndgrid(xvalues, zValues);
    pcolor(X, Z, planeData);  
    shading flat;
%]
end

Edit

It is unclear what exact input data you have, but if pillar is a set of (x,y,z, intensity) points, you may reduce data set to coneData as follow:

thetas = atan2(y(:), x(:));
thetaValues = unique(thetas); tcount = length(thetaValues);
zValues = unique(z); zcount = length(zValues);    
coneData = zeros(tcount, zcount);
for ti = 1:tcount,
  logict = (thetas == thetaValues(ti));
  for zi = 1:zcount,
     logicz = (z == zValues(zi));
     coneData(ti, zi) = mean(intensity(logict & logicz));
  end
end

NB In practice, you may want to use some unique with tolerance (+ logic = abs(val-pos) < tol) to further reduce data while accounting for noise in scan positions.

Community
  • 1
  • 1
CitizenInsane
  • 4,755
  • 1
  • 25
  • 56
  • How can I get coneData from my theta and height. I have miilion of points. coneData = ndgrid(theta,height) would not work there. It is due to size of matrix. – Shahgee Feb 13 '15 at 12:08
  • @ vCitizenInsane. My data is Data=[X,Y,Z,Intensity]. How can I map my points with their original intensity, – Shahgee Feb 13 '15 at 12:47
  • @Shah It is unclear what exact input data you have; see my edits in the answer to see if it may suit your needs. – CitizenInsane Feb 13 '15 at 13:26
2
  1. so you want get (x,y,z)=f(u,v) ?

    • u=<0.0,1.0> ... angle coordinate
    • v=<0.0,1.0> ... height coordinate let v=0.0 be bottom
    • you got 24 periods of |sin| waves along the perimeter
    • with amplitudes: a0 at bottom and a1 at the top
    • pillar has radius r0 at bottom and r1 at the top
    • pillar has height h
    • pillar
  2. first basic cylinder

    x=r*cos(2.0*M_PI*u)
    y=r*sin(2.0*M_PI*u)
    z=h*v
    
  3. now cone

    r=r0+(r1-r0)*v
    x=r*cos(2.0*M_PI*u)
    y=r*sin(2.0*M_PI*u)
    z=h*v
    
    • just linear interpolation of radius is added
  4. now the |sin| waves

    r=r0+(r1-r0)*v
    a=a0+(a1-a0)*v
    r-=a*fabs(sin(2.0*M_PI*12.0*u))
    x=r*cos(2.0*M_PI*u)
    y=r*sin(2.0*M_PI*u)
    z=h*v
    
    • just linear interpolation of amplitude of |sin| wave is added
    • and then the |sin| wave is applied to radius

Now the u,v coordinates are the coordinates inside your plane (texture for example)

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • @ Spektre Thanx. What is M_PI. – Shahgee Feb 13 '15 at 11:50
  • @Shah `M_PI = 3.1415926535897932384626433832795` it is constant from C++ math.h ... – Spektre Feb 13 '15 at 11:52
  • @Shah the waves could be anything I assumed |sin| but to make sure you should compare its shape to your pillar and use appropriate correction or function instead for example |sin^2(alpha)| ...or use alpha only on some range not the full circle ...if nothing is precise enough you can add bezier ... – Spektre Feb 13 '15 at 11:56