├── ExtractPowerLine ├── L037_Sens1_600x250_cloud_10.mat ├── L037_Sens1_600x250_cloud_8.mat ├── L037_Sens1_600x250_cloud_9.mat ├── catenary.m ├── demo_extract_powerline.m ├── eigenDV.m ├── extractPLs.m ├── findMerge.m ├── getDist.m ├── getPCA.m ├── insert.m ├── insert3.m ├── insert_3D.m ├── isFit.m ├── isMerge.m ├── merge.m ├── polyfitn.m ├── re_f1_nonGroundPoints.png ├── re_f2_candidate powerline points.png ├── re_f3_candidate powerline points clusters.png ├── re_f4_powerline points clusters.png ├── re_f5_colorization clusters.png ├── re_f6_powerLines clusters.png ├── re_f7_Power line model.png ├── rotate.m ├── show_segs.m └── showbreaks.m ├── LICENSE └── README.md /ExtractPowerLine/L037_Sens1_600x250_cloud_10.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwshi-pku/3DLiDAR/953d4c4ced1c7a1dbd7ecdf6271f6f470057bbb8/ExtractPowerLine/L037_Sens1_600x250_cloud_10.mat -------------------------------------------------------------------------------- /ExtractPowerLine/L037_Sens1_600x250_cloud_8.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwshi-pku/3DLiDAR/953d4c4ced1c7a1dbd7ecdf6271f6f470057bbb8/ExtractPowerLine/L037_Sens1_600x250_cloud_8.mat -------------------------------------------------------------------------------- /ExtractPowerLine/L037_Sens1_600x250_cloud_9.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwshi-pku/3DLiDAR/953d4c4ced1c7a1dbd7ecdf6271f6f470057bbb8/ExtractPowerLine/L037_Sens1_600x250_cloud_9.mat -------------------------------------------------------------------------------- /ExtractPowerLine/catenary.m: -------------------------------------------------------------------------------- 1 | %% Catenary: y=a+ccosh((x-b)/c) 2 | function cfun = catenary(xs,ys) 3 | syms x; 4 | f = fittype('a+c*cosh((x-b)/c)','independent','x','coefficients',{'a','c','b'}); 5 | cfun = fit(xs,ys,f,'StartPoint', [-780.6,780.4,-1.184]) 6 | end -------------------------------------------------------------------------------- /ExtractPowerLine/demo_extract_powerline.m: -------------------------------------------------------------------------------- 1 | % /**************************************************************************** 2 | % * Please cite the following paper, If you use this code in your work. 3 | % * 4 | % * Zhenwei Shi, Yi Lin, and Hui Li. "Extraction of urban power lines and 5 | % * potential hazard analysis from mobile laser scanning point clouds." 6 | % * International Journal of Remote Sensing 41, no. 9 (2020): 3411-3428. 7 | % * 8 | % * The paper can be downloaded from 9 | % * https://www.tandfonline.com/doi/full/10.1080/01431161.2019.1701726 10 | % * Copyright 11 | % * Institute of Remote Sensing & GIS, 12 | % * School of Earth and Space Sciences, Peking University (www.pku.edu.cn) 13 | % * Zhenwei Shi; Yi Lin; Hui Li 14 | % * contact us: zwshi@pku.edu.cn; lihui@pku.edu.cn 15 | % *****************************************************************************/ 16 | 17 | % Extracting powerline from mobile lidar point cloud 18 | % function: [isPLIndex] = extractPLs(pointcloud,radius,angleThr,LThr) 19 | % pointcloud: mobile lidar point cloud [x y z] 20 | % radius: Neighborhood point search radius 21 | % angleThr: Threshold value of the angle between normal vector and (0 0 1) 22 | % LThr: linear feature L satisfy the conditions L≥LThr for power line 23 | % point. 24 | 25 | % Example 26 | % radius = 0.5; 27 | % angleThr = 10; 28 | % LThr = 0.98; 29 | % [isPLIndex] = extractPLs(pointcloud,radius,angleThr,LThr); 30 | 31 | %% step1 Mobile LiDAR filtering 32 | clc; clear; close all; 33 | tic 34 | nonGroundPoints = []; 35 | for i=8:10 36 | filename = ['L037_Sens1_600x250_cloud_' num2str(i)]; 37 | load([filename '.mat']) 38 | 39 | [counts,centers] = hist(ptCloudA.data(:,3),50); 40 | [~,I] = max(counts); 41 | nonGroundIndex = ptCloudA.data(:,3)>centers(I+3); 42 | nonGroundPoints = [nonGroundPoints; ptCloudA.data(nonGroundIndex,1:3)]; 43 | end 44 | toc 45 | figure 46 | pcshow(nonGroundPoints) 47 | title('Non ground points') 48 | view(60,25) 49 | print(gcf,'-dpng','-r300', 'f1_nonGroundPoints.png') 50 | 51 | %% step1 Extract powerline point points 52 | radius = 0.5; 53 | angleThr = 10; 54 | LThr = 0.98; 55 | tic 56 | isPLIndex = extractPLs(nonGroundPoints,radius,angleThr,LThr); 57 | toc 58 | isPLIndex = logical(isPLIndex); 59 | 60 | figure 61 | pcshow(nonGroundPoints(isPLIndex,:)) 62 | title('Candidate power line points') 63 | view(60,25) 64 | print(gcf,'-dpng','-r300', 'f2_candidate powerline points.png') 65 | 66 | %% step2 Euclidean clustering 67 | ptCloud = pointCloud(nonGroundPoints(isPLIndex,:)); 68 | minDistance = 2.0; 69 | [labels,numClusters] = pcsegdist(ptCloud,minDistance); 70 | 71 | figure 72 | pcshow(ptCloud.Location,labels) 73 | title('Candidate power line clusters') 74 | view(60,25) 75 | print(gcf,'-dpng','-r300', 'f3_candidate powerline points clusters.png') 76 | 77 | index = ones(size(labels,1),1); 78 | power_lines = []; 79 | for i=1:numClusters 80 | cluster = index*i == labels; 81 | if(sum(cluster)<15) 82 | continue; 83 | end 84 | xyzs = ptCloud.Location(cluster,:); 85 | power_lines = [power_lines; xyzs]; 86 | end 87 | PLs = pointCloud(power_lines); 88 | figure 89 | pcshow(PLs); 90 | title('Power line clusters') 91 | view(60,25) 92 | print(gcf,'-dpng','-r300', 'f4_powerline points clusters.png') 93 | 94 | %% step3 Power line modeling 95 | ptCloud = PLs; 96 | minDistance = 0.3; 97 | [labels,numClusters] = pcsegdist(ptCloud,minDistance); 98 | figure 99 | show_segs(ptCloud.Location,labels,1); 100 | title('Different clusters are given different colors') 101 | view(60,25) 102 | print(gcf,'-dpng','-r300', 'f5_colorization clusters.png') 103 | 104 | counts = []; 105 | index = ones(size(labels,1),1); 106 | 107 | % Constructing structure based on Clustering 108 | for i=1:numClusters 109 | cluster_index = index*i == labels; 110 | cluster_raw = ptCloud.Location(cluster_index,:); 111 | xyzs_new = cluster_raw; 112 | powerLines(i).Location = xyzs_new; 113 | powerLines(i).Label = 0; 114 | powerLines(i).Count = size(xyzs_new,1); 115 | powerLines(i).Ids = []; 116 | counts = [counts; powerLines(i).Count]; 117 | end 118 | 119 | % Get the sorting ID of cluster points 120 | [counts_new, ind] = sort(counts,'descend'); 121 | [powerLines_pro ind]= merge(powerLines, ind); 122 | [powerLines_pro ind]= merge(powerLines_pro, ind); 123 | [powerLines_pro ind]= merge(powerLines_pro, ind); 124 | 125 | powerLines_new = []; 126 | colors = []; 127 | for i = 1:size(powerLines_pro,2) 128 | powerLines_new = [powerLines_new; powerLines_pro(i).Location]; 129 | colors = [colors; repmat(rand(1,3),size(powerLines_pro(i).Location,1),1)]; 130 | end 131 | % ptpl = pointCloud(powerLines_new,'Color',colors) 132 | figure 133 | % pcshow(ptpl) 134 | pcshow(powerLines_new,colors) 135 | title('Power line clusters') 136 | view(60,25) 137 | print(gcf,'-dpng','-r300', 'f6_powerLines clusters.png') 138 | 139 | % Calculate the power line length and delete the power line less than the length threshold 140 | i = 1; 141 | while i <= size(powerLines_pro,2) 142 | dist = getDist(powerLines_pro(i).Location); 143 | if dist < 1.5 144 | powerLines_pro(i) = []; 145 | else 146 | i = i + 1; 147 | end 148 | end 149 | 150 | % Calculate the length of the power line 151 | i = 1; 152 | sumdist = 0; 153 | while i <= size(powerLines_pro,2) 154 | dist = getDist(powerLines_pro(i).Location); 155 | i = i + 1; 156 | sumdist = sumdist + dist; 157 | end 158 | sumdist 159 | 160 | % Insert points to sparse power lines 161 | for i = 1:size(powerLines_pro,2) 162 | powerLines_pro_new(i).Location = insert_3D(powerLines_pro(i).Location, 0.1); 163 | end 164 | % save('C:\Users\Lily\Desktop\PLM','powerLines_pro_new') 165 | 166 | % powerLines_pro_new = powerLines_pro; 167 | % visualization 168 | powerLines_new = []; 169 | colors = []; 170 | for i = 1:size(powerLines_pro_new,2) 171 | powerLines_new = [powerLines_new; powerLines_pro_new(i).Location]; 172 | temp = repmat(rand(1,3),size(powerLines_pro_new(i).Location,1),1); 173 | colors = [colors; temp]; 174 | PLMs(i).Location = powerLines_pro_new(i).Location; 175 | PLMs(i).Color = temp; 176 | end 177 | % ptplm = pointCloud(powerLines_new,'Color',colors) 178 | figure 179 | % pcshow(ptplm.Location(1:1:end,:),ptplm.Color(1:1:end,:)) 180 | pcshow(powerLines_new,colors) 181 | title('Power line modeling') 182 | view(60,25) 183 | print(gcf,'-dpng','-r300', 'f7_Power line model.png') 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /ExtractPowerLine/eigenDV.m: -------------------------------------------------------------------------------- 1 | %% Get the maximum eigenvalue and its corresponding eigenvector, and return the included angle with the X axis 2 | function [eValue,eVector,angle] = eigenDV(xyzs) 3 | covm = cov(xyzs); 4 | [V,D] = eig(covm); 5 | [D_sort,index] = sort(diag(D),'descend'); 6 | V_sort = V(:,index); 7 | 8 | eVector = V_sort(:,1)'; 9 | eValue = D_sort(1); 10 | X = [1 0 0]; 11 | Y = [0 1 0]; 12 | Z = [0 0 1]; 13 | N = X; 14 | cross_vector = cross(N,eVector); % The Z component is regular in the positive Z direction 15 | if(cross_vector(3)<0) 16 | eVector = -eVector; 17 | end 18 | angle = acos(sum(N.*eVector)/sqrt(sum(N.^2))*sqrt(sum(eVector.^2)))*180.0/pi; 19 | end -------------------------------------------------------------------------------- /ExtractPowerLine/extractPLs.m: -------------------------------------------------------------------------------- 1 | function isPLIndex = extractPLs(nonGroundPoints,radius,angleThr,LThr) 2 | [normals, Ls] = getPCA(nonGroundPoints,radius); 3 | angle = acosd(normals(:,3)./sqrt(sum(normals.^2,2))); 4 | isPLIndex = abs(angle - 90) < angleThr & Ls>LThr; 5 | 6 | % normals = pcnormals(pointCloud(nonGroundPoints),30); 7 | % figure 8 | % pcshow(nonGroundPoints) 9 | % title('Adjusted Normals of Point Cloud') 10 | % hold on 11 | % quiver3(nonGroundPoints(:,1),nonGroundPoints(:,2),nonGroundPoints(:,3), normals(:,1), normals(:,1), normals(:,1)); 12 | % hold off 13 | end -------------------------------------------------------------------------------- /ExtractPowerLine/findMerge.m: -------------------------------------------------------------------------------- 1 | %% Merge over split powerline points 2 | function ids = findMerge(powerLines, index, begin) 3 | ids = []; 4 | A = powerLines(index(begin)).Location; 5 | if size(A,1)<10 6 | return; 7 | end 8 | meanAz = mean(A(:,3)); 9 | % 10 | A_shift = A-mean(A); 11 | [eValue,eVector,angle] = eigenDV(A_shift); 12 | 13 | % Rotate clockwise around the Z axis for a certain number of degrees, and the data B is in the x-z rectangular coordinates 14 | ARotated = rotate(A_shift, -angle*pi/180.0); 15 | A_shift_x = ARotated(:,1); 16 | A_shift_z = ARotated(:,3); 17 | p = polyfit(A_shift_x,A_shift_z,2); 18 | % p = catenary(A_shift_x,A_shift_z); 19 | pl = polyfit(A(:,1),A(:,2),1); 20 | 21 | for i = begin+1:size(index,1) 22 | if powerLines(index(i)).Label == 1 23 | continue; 24 | end 25 | 26 | B = powerLines(index(i)).Location; 27 | meanBz = mean(B(:,3)); 28 | PLB_shift = B-mean(A); 29 | BRotated = rotate(PLB_shift, -angle*pi/180.0); 30 | B_shift_x = BRotated(:,1); 31 | B_shift_y = BRotated(:,2); 32 | B_shift_z = BRotated(:,3); 33 | % meanBy = abs(mean(B_shift_y)) 34 | 35 | if isa(p,'cfit') 36 | B_Pz = p(B_shift_x); 37 | else 38 | B_Pz = polyval(p,B_shift_x); 39 | end 40 | B_Py = polyval(pl,B(:,1)); 41 | deltaBy = abs(mean(B_Py - B(:,2))); 42 | 43 | % meanBd = abs(mean(B_Pz - B_shift_z)); 44 | deltaBz = abs(meanAz-meanBz); 45 | meanBd = max(abs(B_Pz - B_shift_z)); 46 | if deltaBy < 0.5 & meanBd < 0.2 & deltaBz < 4 47 | result = 1; 48 | else 49 | result = 0; 50 | end 51 | if 0 52 | figure(3) 53 | pcshow(ARotated) 54 | hold on 55 | pcshow(BRotated) 56 | close 3; 57 | end 58 | clc 59 | 60 | if result == 1 61 | ids = [ids; index(i)]; 62 | A_shift_x = [A_shift_x; B_shift_x]; 63 | A_shift_z = [A_shift_z;B_shift_z]; 64 | p = polyfit(A_shift_x,A_shift_z,2); 65 | end 66 | end 67 | end -------------------------------------------------------------------------------- /ExtractPowerLine/getDist.m: -------------------------------------------------------------------------------- 1 | %% Calculate power line length 2 | function dist = getDist(powerLines) 3 | if size(powerLines,1)<3 4 | dist = 0; 5 | return; 6 | end 7 | shift = powerLines-mean(powerLines); 8 | [eValue,eVector,angle] = eigenDV(shift); 9 | 10 | % Rotate clockwise around the Z axis for a certain number of degrees, and the data B is in the x-z rectangular coordinates 11 | rotated = rotate(shift, -angle*pi/180.0); 12 | shift_x = rotated(:,1); 13 | dist = max(shift_x)-min(shift_x); 14 | end -------------------------------------------------------------------------------- /ExtractPowerLine/getPCA.m: -------------------------------------------------------------------------------- 1 | function [normals, Ls] = getPCA(xyz,r) 2 | idxNN = rangesearch(xyz, xyz, r); 3 | normals = nan(size(xyz,1),3); 4 | Ls = nan(size(xyz,1),1); 5 | 6 | for i=1:size(xyz,1) 7 | if numel(idxNN{i})<3 8 | continue; 9 | end 10 | XNN = xyz(idxNN{i},:); 11 | 12 | covm = cov(XNN); 13 | [V, lambda] = pcacov(covm); 14 | normals(i,:) = V(:,1)'; 15 | lmbda1 = lambda(1); 16 | lmbda2 = lambda(2); 17 | lmbda3 = lambda(3); 18 | 19 | % [V,D] = eig(covm); 20 | % [D_S,index] = sort(diag(D),'descend'); 21 | % V_S = V(:,index); 22 | % 23 | % lmbda1 = D_S(1); 24 | % lmbda2 = D_S(2); 25 | % lmbda3 = D_S(3); 26 | 27 | L = (lmbda1-lmbda2)/lmbda1; 28 | P = (lmbda2-lmbda3)/lmbda1; 29 | S = lmbda3/lmbda1; 30 | Ls(i,1) = L; 31 | end 32 | end -------------------------------------------------------------------------------- /ExtractPowerLine/insert.m: -------------------------------------------------------------------------------- 1 | %% Add data point 2 | function [points, insert_pnts]= insert(xys, p, resolution) 3 | insert_pnts = []; 4 | minValue = min(xys(:,1)); 5 | maxValue = max(xys(:,1)); 6 | xs_gap = linspace(maxValue, minValue, floor(abs(maxValue-minValue)/resolution)); 7 | if isa(p,'cfit') 8 | ys_gap = p(xs_gap); 9 | points = [xs_gap' ys_gap]; 10 | else 11 | ys_gap = polyval(p,xs_gap); 12 | points = [xs_gap' ys_gap']; 13 | end 14 | 15 | insert_pnts = points; 16 | return; 17 | 18 | % insert_pnts = []; 19 | % i = 1; 20 | % num = size(xys,1)-1; 21 | % while i<=num 22 | % dist = sqrt(sum((xys(i,:)-xys(i+1,:)).^2)); 23 | % n = floor((dist/resolution)); 24 | % if n>0 25 | % xs = linspace(xys(i,1),xys(i+1,1),n + 2); 26 | % xs(end) = []; 27 | % xs(1) = []; 28 | % ys = polyval(p,xs); 29 | % xys = [xys(1:i,:);[xs' ys'];xys(i+1:end,:)]; 30 | % insert_pnts = [insert_pnts; [xs' ys']]; 31 | % end 32 | % i = i + 1; 33 | % end 34 | % points = xys; 35 | end -------------------------------------------------------------------------------- /ExtractPowerLine/insert3.m: -------------------------------------------------------------------------------- 1 | %% Add data point 2 | function [points, insert_pnts]= insert3(xyzs, p, resolution) 3 | insert_pnts = []; 4 | i = 1; 5 | num = size(xyzs,1)-1; 6 | while i<=num 7 | dist = sqrt(sum((xyzs(i,:)-xyzs(i+1,:)).^2)); 8 | n = floor((dist/resolution)); 9 | if n>0 10 | xs = linspace(xyzs(i,1),xyzs(i+1,1),n + 2); 11 | xs(end) = []; 12 | xs(1) = []; 13 | zs = polyval(p,xs); 14 | inserted = [xs' zeros(size(xs,2),1) zs']; 15 | xyzs = [xyzs(1:i,:);inserted;xyzs(i+1:end,:)]; 16 | insert_pnts = [insert_pnts; inserted]; 17 | end 18 | i = i + 1; 19 | end 20 | points = xyzs; 21 | end 22 | -------------------------------------------------------------------------------- /ExtractPowerLine/insert_3D.m: -------------------------------------------------------------------------------- 1 | %% Fit wires, and insert points at sparse parts with fixed resolution to form new wire data points. 2 | function xyzs_new = insert_3D(cluster_raw, resolution) 3 | cluster_shift = cluster_raw-mean(cluster_raw); 4 | if size(cluster_shift,1)<3 5 | xyzs_new = cluster_raw; 6 | return; 7 | end 8 | 9 | [eValue,eVector,angle] = eigenDV(cluster_shift); 10 | 11 | % Rotate clockwise around the Z axis for a certain number of degrees, and the data B is in the x-z rectangular coordinates 12 | rotated = rotate(cluster_shift, -angle*pi/180.0); 13 | x = rotated(:,1); 14 | y = rotated(:,2); 15 | z = rotated(:,3); 16 | p = polyfit(x,z,2); 17 | % p = catenary(x,z); 18 | [xzs_new xzs_inserted] = insert([x z], p, resolution); 19 | if isempty(xzs_inserted) 20 | xyzs_new = cluster_raw; 21 | return; 22 | end 23 | % xyzs_new = [x y z; xzs_inserted(:,1) zeros(size(xzs_inserted,1),1) xzs_inserted(:,2)]; 24 | xyzs_new = [xzs_inserted(:,1) zeros(size(xzs_inserted,1),1) xzs_inserted(:,2)]; 25 | 26 | % [x_new,ind] = sort(xyzs_new(:,1),'descend'); 27 | % xyzs_new = xyzs_new(ind,:); 28 | xyzs_new = rotate(xyzs_new, angle*pi/180.0)+mean(cluster_raw); 29 | end -------------------------------------------------------------------------------- /ExtractPowerLine/isFit.m: -------------------------------------------------------------------------------- 1 | % Judge whether clustering can fit the catenary model 2 | % result = 0 reject,result = 1 accept 3 | function mse = isFit(A) 4 | mse = 10; 5 | if size(A,1)<10 6 | return; 7 | end 8 | 9 | A_shift = A-mean(A); 10 | [eValue,eVector,angle] = eigenDV(A_shift); 11 | 12 | % Rotate clockwise around the Z axis for a certain number of degrees, and the data B is in the x-z rectangular coordinates 13 | ARotated = rotate(A_shift, -angle*pi/180.0); 14 | A_shift_x = ARotated(:,1); 15 | A_shift_z = ARotated(:,3); 16 | p = polyfit(A_shift_x,A_shift_z,2); 17 | % p = catenary(A_shift_x,A_shift_z); 18 | A_new_z = polyval(p,A_shift_x); 19 | mse = rmse(A_shift_z,A_new_z); 20 | end -------------------------------------------------------------------------------- /ExtractPowerLine/isMerge.m: -------------------------------------------------------------------------------- 1 | function result = isMerge(PLA, PLB) 2 | PLA_shift = PLA-mean(PLA); 3 | if size(PLA_shift,1)<3 4 | result = 0; 5 | return; 6 | end 7 | 8 | [eValue,eVector,angle] = eigenDV(PLA_shift); 9 | 10 | % Rotate clockwise around the Z axis for a certain number of degrees, and the data B is in the x-z rectangular coordinates 11 | rotated = rotate(PLA_shift, -angle*pi/180.0); 12 | PLA_shift_x = rotated(:,1); 13 | PLA_shift_y = rotated(:,2); 14 | PLA_shift_z = rotated(:,3); 15 | meanPLAy = mean(PLA_shift_y); 16 | 17 | PLB_shift = PLB-mean(PLA); 18 | rotated = rotate(PLB_shift, -angle*pi/180.0); 19 | PLB_shift_x = rotated(:,1); 20 | PLB_shift_y = rotated(:,2); 21 | PLB_shift_z = rotated(:,3); 22 | meanPLBy = mean(PLB_shift_y); 23 | 24 | % p = polyfit(PLA_shift_x,PLA_shift_z,2); 25 | % PLB_Pz = polyval(p,PLB_shift_x); 26 | p = catenary(PLA_shift_x,PLA_shift_z); 27 | PLB_Pz = p(PLB_shift_x); 28 | mean_dist = abs(mean(PLB_Pz - PLB_shift_z)); 29 | 30 | if abs(meanPLBy) < 0.1 & mean_dist < 0.1 31 | result = 1; 32 | else 33 | result = 0; 34 | end 35 | end -------------------------------------------------------------------------------- /ExtractPowerLine/merge.m: -------------------------------------------------------------------------------- 1 | %% Fusion power line 2 | function [powerLines_pro, index]= merge(powerLines, ind) 3 | for i=1:size(ind,1) 4 | if powerLines(ind(i)).Label == 1 5 | continue; 6 | end 7 | ids = findMerge(powerLines, ind, i); 8 | powerLines(ind(i)).Ids = ids; 9 | for j=1:size(ids,1) 10 | powerLines(ids(j)).Label = 1; 11 | end 12 | end 13 | 14 | % Delete marked data 15 | powerLines_pro = powerLines; 16 | i = 1; 17 | while i <= size(powerLines_pro,2) 18 | if powerLines_pro(i).Label 19 | powerLines_pro(i) = []; 20 | else 21 | i = i + 1; 22 | end 23 | end 24 | 25 | for i = 1:size(powerLines_pro,2) 26 | for j =1:size(powerLines_pro(i).Ids,1) 27 | powerLines_pro(i).Location = [powerLines_pro(i).Location; powerLines(powerLines_pro(i).Ids(j)).Location]; 28 | end 29 | end 30 | 31 | counts = []; 32 | for i = 1:size(powerLines_pro,2) 33 | powerLines_pro(i).Label = 0; 34 | powerLines_pro(i).Count = size(powerLines_pro(i).Location,1); 35 | powerLines_pro(i).Ids = []; 36 | counts = [counts; powerLines(i).Count]; 37 | end 38 | [counts_new, index] = sort(counts,'descend'); 39 | 40 | end -------------------------------------------------------------------------------- /ExtractPowerLine/polyfitn.m: -------------------------------------------------------------------------------- 1 | %% The function order is obtained by automatic fitting:[p,s,m,n] = polyfitn(x,y,10,0.01) 2 | function [p,n] = polyfitn(x,y,top_n,thr_precise) 3 | % for i=1:top_n 4 | % p = polyfit(x,y,i); 5 | % f = polyval(p,x); %Calculate the value of the fitting function at X. 6 | % if sum((f-y).^2)centers(I+3); 33 | nonGroundPoints = [nonGroundPoints; ptCloudA.data(nonGroundIndex,1:3)]; 34 | end 35 | toc 36 | figure 37 | pcshow(nonGroundPoints) 38 | title('Non ground points') 39 | view(60,25) 40 | print(gcf,'-dpng','-r300', 'f1_nonGroundPoints.png') 41 | 42 | %% step1 Extract powerline point points 43 | radius = 0.5; 44 | angleThr = 10; 45 | LThr = 0.98; 46 | tic 47 | isPLIndex = extractPLs(nonGroundPoints,radius,angleThr,LThr); 48 | toc 49 | isPLIndex = logical(isPLIndex); 50 | 51 | figure 52 | pcshow(nonGroundPoints(isPLIndex,:)) 53 | title('Candidate power line points') 54 | view(60,25) 55 | print(gcf,'-dpng','-r300', 'f2_candidate powerline points.png') 56 | ``` 57 | 58 | Results 59 | -------------- 60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 | 70 | 71 | Our Publications 72 | -------------- 73 | 74 | Please consider citing our papers if you find these codes help your research. 75 | 76 | **Zhenwei Shi**, Yi Lin, and Hui Li. **Extraction of urban power lines and potential hazard analysis from mobile laser scanning point clouds.** International Journal of Remote Sensing 41, no. 9 (2020): 3411-3428. 77 | 78 | **Zhenwei Shi**, Zhizhong Kang, Yi Lin, Yu Liu, and Wei Chen. **Automatic recognition of pole-like objects from mobile laser scanning point clouds.** Remote Sensing 10, no. 12 (2018): 1891. 79 | 80 | 81 | 82 | --------------------------------------------------------------------------------