


create boundary data structure from raw data
Syntax: bnd = obtainBnd(dataMatrix)
A structure is created that contains the measurement data in dataMatrix
(one data point each column) including some basic measures. The
structure contains the fields cartX, cartY, polarAngle (radian),
polarDistance that represent the input data. Additionally, the
following fields are returned:
polarBinSize: range of angle (radian) that is covered by each
distance in polarDistance
centerPointOriginal: coordinate origin as for the input points
centerPointMean: coordinate origin as centered to the mean
polarBoundaryArea: shape area estimated from circle sections
convexHullArea: area of convex hull
vrepHull: convex hull in V-rep
hrepHull: convex hull in H-rep
meanWidthHull: mean width of the convex hull
convexity: convexity ratio as [shape area]/[hull area]
largestAngleGap: largest gap in polarAngle vector
sphericity1: 1 - (maxPolar - minPolar)/meanPolar
sphericity2: 1 - stdPolar / meanPolar
sphericity3: pi*[diameter area eq. circle] / [circumfence of hull]
brightFraction: fraction of bright pixels (only with provided image)
obtainBnd(.., type) sets the input data type. For type='cart', cartesian
coordinates are exprected. For type='polar', the input data is
interpreted as polar coordinates with the distance in the first row and
the angle (radian) in the second row.
obtainBnd(.., type, image, sizeFraction, threshold) Allows to provide the
corresponding image data to evaluate a brightness fraction of some
area. The area is a circle with a radius of 0.5*sizeFraction*[minimum
polar distance] that is centered in the bounding box. Bright pixels are
any pixels above the threshold. This measure is used to filter for air
bubbles.
See also: fitShapeBnd, viewBoundary

0001 function bnd = obtainBnd(dataMatrix, dataType, image, ... 0002 sizeFraction, threshold, restoreFlag, resampleFlag) 0003 % create boundary data structure from raw data 0004 % 0005 % Syntax: bnd = obtainBnd(dataMatrix) 0006 % 0007 % A structure is created that contains the measurement data in dataMatrix 0008 % (one data point each column) including some basic measures. The 0009 % structure contains the fields cartX, cartY, polarAngle (radian), 0010 % polarDistance that represent the input data. Additionally, the 0011 % following fields are returned: 0012 % polarBinSize: range of angle (radian) that is covered by each 0013 % distance in polarDistance 0014 % centerPointOriginal: coordinate origin as for the input points 0015 % centerPointMean: coordinate origin as centered to the mean 0016 % polarBoundaryArea: shape area estimated from circle sections 0017 % convexHullArea: area of convex hull 0018 % vrepHull: convex hull in V-rep 0019 % hrepHull: convex hull in H-rep 0020 % meanWidthHull: mean width of the convex hull 0021 % convexity: convexity ratio as [shape area]/[hull area] 0022 % largestAngleGap: largest gap in polarAngle vector 0023 % sphericity1: 1 - (maxPolar - minPolar)/meanPolar 0024 % sphericity2: 1 - stdPolar / meanPolar 0025 % sphericity3: pi*[diameter area eq. circle] / [circumfence of hull] 0026 % brightFraction: fraction of bright pixels (only with provided image) 0027 % 0028 % obtainBnd(.., type) sets the input data type. For type='cart', cartesian 0029 % coordinates are exprected. For type='polar', the input data is 0030 % interpreted as polar coordinates with the distance in the first row and 0031 % the angle (radian) in the second row. 0032 % 0033 % obtainBnd(.., type, image, sizeFraction, threshold) Allows to provide the 0034 % corresponding image data to evaluate a brightness fraction of some 0035 % area. The area is a circle with a radius of 0.5*sizeFraction*[minimum 0036 % polar distance] that is centered in the bounding box. Bright pixels are 0037 % any pixels above the threshold. This measure is used to filter for air 0038 % bubbles. 0039 % 0040 % See also: fitShapeBnd, viewBoundary 0041 0042 % The elk-library: convex geometry applied to crystallization modeling. 0043 % Copyright (C) 2014 Alexander Reinhold 0044 % 0045 % This program is free software: you can redistribute it and/or modify it 0046 % under the terms of the GNU General Public License as published by the 0047 % Free Software Foundation, either version 3 of the License, or (at your 0048 % option) any later version. 0049 % 0050 % This program is distributed in the hope that it will be useful, but 0051 % WITHOUT ANY WARRANTY; without even the implied warranty of 0052 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0053 % General Public License for more details. 0054 % 0055 % You should have received a copy of the GNU General Public License along 0056 % with this program. If not, see <http://www.gnu.org/licenses/> 0057 0058 if ~exist('dataType', 'var') 0059 dataType = 'cart'; 0060 end 0061 0062 %% input matrix check 0063 % dimensions of data matrix 0064 if size(dataMatrix, 1) == 2 0065 % everything OK 0066 elseif size(dataMatrix, 2) == 2 0067 dataMatrix = dataMatrix'; 0068 else 0069 error('elk:boundaryCurve:wrongInput', ... 0070 'input data matrix must contains two rows, one data point in each column'); 0071 end 0072 0073 %% restore points 0074 if exist('restoreFlag', 'var') && ~isempty(restoreFlag) && ... 0075 restoreFlag == 1 && strcmpi(dataType, 'cart') 0076 dataMatrix = restoreBoundary(dataMatrix); 0077 end 0078 0079 %% evaluate brightness 0080 if ~exist('sizeFraction', 'var'),sizeFraction = 0.5;end 0081 if ~exist('threshold', 'var'),threshold=90;end 0082 % if image is provided 0083 if exist('image', 'var') && ~isempty(image) && strcmpi(dataType, 'cart') 0084 brightFraction = computeBrightFraction(image, ... 0085 dataMatrix(1,:), dataMatrix(2,:), ... 0086 sizeFraction, threshold); 0087 end 0088 0089 %% build struct 0090 % extract cartesian and polar data 0091 if strcmpi(dataType, 'cart') 0092 % get data 0093 bnd.cartX = dataMatrix(1,:); 0094 bnd.cartY = dataMatrix(2,:); 0095 % center data 0096 [bnd.cartX, bnd.cartY bnd.centerPointOriginal] = ... 0097 centerCart(bnd.cartX, bnd.cartY); 0098 % create polar data 0099 [bnd.polarAngle bnd.polarDistance] = ... 0100 convertCartToPolar(bnd.cartX, bnd.cartY); 0101 % sort data 0102 [bnd.polarAngle bnd.polarDistance, permutationVector] = ... 0103 standardizePolar(bnd.polarAngle, bnd.polarDistance); 0104 bnd.cartX = bnd.cartX(permutationVector); 0105 bnd.cartY = bnd.cartY(permutationVector); 0106 0107 elseif strcmpi(dataType, 'polar') 0108 % get data 0109 bnd.polarAngle = dataMatrix(1,:); 0110 bnd.polarDistance = dataMatrix(2,:); 0111 % check origin in interior 0112 if min(bnd.polarDistance) < 0 0113 error('elk:boundary:wrongInput', ['The polar input data must have ' ... 0114 'positive distances only']); 0115 end 0116 % sort data 0117 [bnd.polarAngle bnd.polarDistance, ~] = ... 0118 standardizePolar(bnd.polarAngle, bnd.polarDistance); 0119 % create cart data 0120 [bnd.cartX bnd.cartY] = convertPolarToCart(bnd.polarAngle, ... 0121 bnd.polarDistance); 0122 bnd.centerPointOriginal = [0; 0]; 0123 else 0124 error('elk:boundaryCurve:wrongInput', ... 0125 'the specified data type must be ''cart'' or ''polar'''); 0126 end 0127 0128 if exist('resampleFlag', 'var') && resampleFlag > 0 0129 % resample data to an accuracy of resampleFlag 0130 angleVector = 0:resampleFlag:2*pi; 0131 distanceVector = 0*angleVector; 0132 for iAngle = 1:length(angleVector) 0133 thisFilter = (bnd.polarAngle >= (angleVector(iAngle) - resampleFlag/2)) | ... 0134 (bnd.polarAngle >= (angleVector(iAngle) - resampleFlag/2 + 2*pi)); 0135 thisFilter = thisFilter & ... 0136 (bnd.polarAngle <= (angleVector(iAngle) + resampleFlag/2)) | ... 0137 (bnd.polarAngle <= (angleVector(iAngle) + resampleFlag/2 - 2*pi)); 0138 distanceVector(iAngle) = mean(bnd.polarDistance(thisFilter)); 0139 end 0140 angleVector(isnan(distanceVector)) = []; 0141 distanceVector(isnan(distanceVector)) = []; 0142 bnd.polarAngle = angleVector; 0143 bnd.polarDistance = distanceVector; 0144 [bnd.cartX bnd.cartY] = convertPolarToCart(bnd.polarAngle, ... 0145 bnd.polarDistance); 0146 end 0147 0148 0149 %% add angle bin sizes 0150 leftPolarAngle = 0.5*[bnd.polarAngle(end)-2*pi bnd.polarAngle(1:(end-1))] + ... 0151 0.5*bnd.polarAngle; 0152 rightPolarAngle = 0.5*[bnd.polarAngle(2:end) bnd.polarAngle(1)+2*pi] + ... 0153 0.5*bnd.polarAngle; 0154 bnd.polarBinSize = rightPolarAngle - leftPolarAngle; 0155 0156 %% correct bnd 0157 bnd = moveBndToCenterOfMass(bnd); 0158 0159 %% add convexity information 0160 bnd.polarBoundaryArea = sum(bnd.polarDistance.^2.*bnd.polarBinSize)/2; 0161 [K bnd.convexHullArea] = convhull(bnd.cartX, bnd.cartY); 0162 bnd.vrepHull.V = [bnd.cartX(K)' bnd.cartY(K)']; 0163 bnd.hrepHull = convertVrepToHrep(bnd.vrepHull); 0164 bnd.meanWidthHull = sum(computeEdgeLengthHrep(bnd.hrepHull, ... 0165 bnd.hrepHull.A))/pi; 0166 bnd.convexity = bnd.polarBoundaryArea/bnd.convexHullArea; 0167 bnd.largestAngleGap = max(diff([bnd.polarAngle bnd.polarAngle(1)+2*pi])); 0168 bnd.sphericity = 1 - (max(bnd.polarDistance) - min(bnd.polarDistance)) ... 0169 / mean(bnd.polarDistance); 0170 bnd.sphericity2 = 1 - std(bnd.polarDistance) ... 0171 / mean(bnd.polarDistance); 0172 bnd.sphericity3 = 2*sqrt(bnd.convexHullArea/pi)/bnd.meanWidthHull; 0173 if exist('brightFraction', 'var') 0174 bnd.brightFraction = brightFraction; 0175 end 0176 0177 %% add circle fit 0178 bnd.lambda = 0.5*max(bnd.polarDistance) + 0.5*min(bnd.polarDistance); 0179 0180 end