├── .idea ├── UAV-and-TrueOrtho.iml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── Building Roof Contour ├── BD_edge.py └── RDP.py ├── Dsm to UAV_BD Roof Contour └── DSM_GEN_BD.py ├── Edge Color ├── DSCF2098_1471837627895.JPG ├── coloredges.m └── test.jpg ├── Elimate PC Error └── PointCloud_Error.py ├── Image mosiac ├── Color_balance.py └── TrueOrtho_mosiac_rough.py ├── PC to DSM └── DEMInterp.py ├── PC2Ortho └── PC2ortho.py ├── README.md ├── T_ortho_py ├── True_Ortho.py ├── ntu_pix4d_0212_calibrated_external_camera_parameters.txt └── ntu_pix4d_0212_dsm.tfw ├── True Ortho ├── True_ortho_test.m ├── dsm_angle.m ├── ntu_pix4d_0212_calibrated_external_camera_parameters.txt ├── sort_array.m └── trueortho_generation.m └── UAV2TrueOrtho layer └── RDP_UAV2TrueOrho.py /.idea/UAV-and-TrueOrtho.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 75 | 76 | 83 | 84 | 85 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 113 | 114 | 117 | 118 | 119 | 120 | 123 | 124 | 127 | 128 | 131 | 132 | 133 | 134 | 137 | 138 | 141 | 142 | 145 | 146 | 147 | 148 | 151 | 152 | 155 | 156 | 159 | 160 | 161 | 162 | 165 | 166 | 169 | 170 | 173 | 174 | 175 | 176 | 179 | 180 | 183 | 184 | 187 | 188 | 189 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 221 | 222 | 223 | 224 | 241 | 242 | 253 | 254 | 272 | 273 | 288 | 289 | 290 | 292 | 293 | 294 | 295 | 1506262057121 296 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | -------------------------------------------------------------------------------- /Building Roof Contour/BD_edge.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon May 8 15:00:07 2017 4 | 5 | @author: Leon 6 | """ 7 | from osgeo import gdal 8 | import matplotlib.pyplot as plt 9 | import numpy as np 10 | import pandas as pd 11 | from scipy import spatial 12 | import cv2 13 | from math import * 14 | from scipy import ndimage 15 | 16 | def PC2UAV(PC_data,h_max,h_min,h,w,*EX_par): #EX_par = [XL,YL,ZL,omega,phi,kappa,f,x0,y0] 17 | point_cloud = pd.read_csv(PC_data,names=['X', 'Y', 'Z', 'R','G','B'],delim_whitespace=True) 18 | 19 | X = point_cloud.X.copy().values 20 | Y = point_cloud.Y.copy().values # Inverse the Y-axis 21 | Z = point_cloud.Z.copy().values 22 | 23 | del point_cloud 24 | 25 | loc = np.where((Zh_min)) 26 | #EX_par 27 | XL = EX_par[0]; 28 | YL = EX_par[1]; 29 | ZL = EX_par[2]; 30 | omega = np.deg2rad(EX_par[3]); 31 | phi = np.deg2rad(EX_par[4]); 32 | kappa = np.deg2rad(EX_par[5]); 33 | f = EX_par[6]; 34 | x0 = EX_par[7]; 35 | y0 = EX_par[8]; 36 | # Colinear Equation 37 | m11 = cos(phi)*cos(kappa); 38 | m12 = sin(omega)*sin(phi)*cos(kappa)+cos(omega)*sin(kappa); 39 | m13 = -cos(omega)*sin(phi)*cos(kappa)+sin(omega)*sin(kappa); 40 | m21 = -cos(phi)*sin(kappa); 41 | m22 = -sin(omega)*sin(phi)*sin(kappa)+cos(omega)*cos(kappa); 42 | m23 = cos(omega)*sin(phi)*sin(kappa)+sin(omega)*cos(kappa); 43 | m31 = sin(phi); 44 | m32 = -sin(omega)*cos(phi); 45 | m33 = cos(omega)*cos(phi); 46 | 47 | XA = X[loc] 48 | YA = Y[loc] 49 | ZA = Z[loc] 50 | 51 | xa = x0 - f*((m11*(XA-XL)+m12*(YA-YL)+m13*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 52 | ya = y0 + f*((m21*(XA-XL)+m22*(YA-YL)+m23*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 53 | 54 | xa = np.around(xa) 55 | ya = np.around(ya) 56 | loc = np.where((xa0)&(ya0)) 57 | 58 | xa = xa[loc] 59 | ya = ya[loc] 60 | xa = xa.astype(int) 61 | ya = ya.astype(int) 62 | PC_image = np.zeros((h,w)) 63 | 64 | PC_image[ya,xa] = int(255) 65 | PC_image = np.uint8(PC_image) 66 | return PC_image 67 | 68 | def PC_p_edge(edge_image,PC_image): 69 | # edge_image = cv2.imread(edge_image) 70 | # edge_image = cv2.cvtColor(edge_image, cv2.COLOR_BGR2GRAY) 71 | loc = np.where((edge_image>127)&(PC_image>130)) 72 | print(len(loc[0])) 73 | contour_img = np.zeros(edge_image.shape, np.uint8) 74 | contour_img[loc] = 255 75 | #edge_image[loc] = 0 76 | return contour_img 77 | #return edge_image 78 | 79 | def show_image(img): 80 | plt.imshow(img,cmap = 'gray') 81 | 82 | def img_gaussian(img,mask): 83 | img = ndimage.filters.gaussian_filter(img,mask, mode='nearest') 84 | 85 | return img 86 | 87 | def dilation(img,kernel_size,i): 88 | kernel = np.ones((kernel_size,kernel_size),np.uint8) 89 | dilation_img = cv2.dilate(img,kernel,iterations = i) 90 | return dilation_img 91 | 92 | def erosion(img,kernel_size,i): 93 | kernel = np.ones((kernel_size,kernel_size),np.uint8) 94 | erosion_img = cv2.erode(img,kernel,iterations = i) 95 | return erosion_img 96 | 97 | def closing(img,kernel_size): 98 | kernel = np.ones((kernel_size,kernel_size),np.uint8) 99 | closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) 100 | return closing 101 | 102 | def opening(img,kernel_size): 103 | kernel = np.ones((kernel_size,kernel_size),np.uint8) 104 | opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) 105 | return opening 106 | 107 | def img_fill(im_in,n): # n = binary image threshold 108 | th, im_th = cv2.threshold(im_in, n, 255, cv2.THRESH_BINARY); 109 | 110 | # Copy the thresholded image. 111 | im_floodfill = im_th.copy() 112 | 113 | # Mask used to flood filling. 114 | # Notice the size needs to be 2 pixels than the image. 115 | h, w = im_th.shape[:2] 116 | mask = np.zeros((h+2, w+2), np.uint8) 117 | 118 | # Floodfill from point (0, 0) 119 | cv2.floodFill(im_floodfill, mask, (0,0), 255); 120 | 121 | # Invert floodfilled image 122 | im_floodfill_inv = cv2.bitwise_not(im_floodfill) 123 | 124 | # Combine the two images to get the foreground. 125 | fill_image = im_th | im_floodfill_inv 126 | 127 | return fill_image 128 | 129 | def canny(img_name): 130 | img = cv2.imread(img_name,0) 131 | img = cv2.GaussianBlur(img, (5, 5), 0) 132 | canny = cv2.Canny(img, 1, 3) 133 | dst = cv2.bitwise_and(img, img, mask=canny) 134 | cv2.imwrite('canny.jpg',dst) 135 | return dst 136 | 137 | if __name__=="__main__": 138 | #I.O. 139 | f = 3803.28260713083182054106; 140 | x0 = 2471.84341749838540636119; 141 | y0 = 1653.25150608682383790438; 142 | 143 | df = pd.read_csv('ntu_pix4d_0212_calibrated_external_camera_parameters.txt', sep=' ') 144 | img_name = df['imageName'].values 145 | EX = np.array([df['X'].values, df['Y'].values, df['Z'].values, 146 | df['Omega'].values, df['Phi'].values, df['Kappa'].values]).T 147 | 148 | img = 'DSCF2098_1471837627895.JPG' 149 | 150 | index_image = np.where(img_name==img) #get the index of the image 151 | 152 | EX_par = np.squeeze(EX[index_image]) #which photos EX 153 | EX_par = np.append(EX_par,[f,x0,y0]) 154 | print(EX_par) 155 | PC_image = PC2UAV('ntu_pix4d_0212_group1_densified_point_cloud.xyz',-227,-233,3264,4896,*EX_par) 156 | #Gaussian blur 157 | PC = img_gaussian(PC_image,3) 158 | 159 | loc = np.where(PC>15) 160 | PC_image[loc] = 255 161 | PC_image = opening(PC_image,8) 162 | cv2.imwrite('PC.jpg',PC_image) 163 | #Canny 164 | edge_img = canny(img) 165 | contour_image = PC_p_edge(edge_img,PC_image) 166 | cv2.imwrite('contour.jpg',contour_image) 167 | 168 | contour_image = closing(contour_image,10) 169 | contour_image = dilation(contour_image,5,5) 170 | cv2.imwrite('dilation.jpg',contour_image) 171 | fill_img = img_fill(contour_image,127) 172 | fill_img = erosion(fill_img,5,3) 173 | #show_image(contour_image) 174 | cv2.imwrite('fill.jpg',fill_img) -------------------------------------------------------------------------------- /Building Roof Contour/RDP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Feb 18 01:16:56 2017 4 | 5 | @author: Leon 6 | """ 7 | from osgeo import gdal 8 | import matplotlib.pyplot as plt 9 | import numpy as np 10 | import pandas as pd 11 | from scipy import spatial 12 | import cv2 13 | 14 | im = cv2.imread('fill.jpg') 15 | ntu = cv2.imread('DSCF2098_1471837627895.jpg') 16 | imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) 17 | ret,thresh = cv2.threshold(imgray,127,255,0) 18 | __,contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) 19 | print("there are " + str(len(contours)) + " contours") 20 | 21 | #size 22 | [h,w,_] = im.shape 23 | im_final = np.zeros((h,w)) 24 | 25 | 26 | cnt = contours[0] 27 | print("there are " + str(len(cnt)) + " points in contours[0]") 28 | approx = cv2.approxPolyDP(cnt,30,True) 29 | print("after approx, there are " + str(len(approx)) + " points") 30 | print(approx) 31 | cv2.drawContours(im,[approx],0,(255,0,0),-1) 32 | 33 | contours.sort(key=len,reverse = True) 34 | cnt = contours[0] 35 | print("there are " + str(len(cnt)) + " points in contours[1]") 36 | approx = cv2.approxPolyDP(cnt,50,True) 37 | print("after approx, there are " + str(len(approx)) + " points") 38 | print(approx) 39 | cv2.drawContours(im,[approx],0,(0,255,0),-1) 40 | cv2.drawContours(ntu,[approx],-1,(255,0,0),3) 41 | cv2.drawContours(im_final,[approx],-1,(255,255,255),-1) 42 | 43 | cv2.imwrite('contour.jpg',im) 44 | cv2.imwrite('contour_ntu.jpg',ntu) 45 | cv2.imwrite('final_building.jpg',im_final) 46 | 47 | -------------------------------------------------------------------------------- /Dsm to UAV_BD Roof Contour/DSM_GEN_BD.py: -------------------------------------------------------------------------------- 1 | from osgeo import gdal 2 | import cv2 3 | import numpy as np 4 | import pandas as pd 5 | from math import * 6 | from scipy import ndimage 7 | #convert dsm point to UAV 8 | 9 | def Dsm_pt2_UAV(dsm_name,affine_name,h_max,h_min,h,w,*EX_par): 10 | # load Dsm 11 | ds = gdal.Open(dsm_name) 12 | band = ds.GetRasterBand(1) 13 | dsm_arr = band.ReadAsArray() 14 | affine_par = np.loadtxt(affine_name) 15 | [A,D,B,E,C,F] = affine_par 16 | 17 | #EX_par 18 | XL = EX_par[0]; 19 | YL = EX_par[1]; 20 | ZL = EX_par[2]; 21 | omega = np.deg2rad(EX_par[3]); 22 | phi = np.deg2rad(EX_par[4]); 23 | kappa = np.deg2rad(EX_par[5]); 24 | f = EX_par[6]; 25 | x0 = EX_par[7]; 26 | y0 = EX_par[8]; 27 | 28 | loc = np.where((dsm_arr>h_min)&(dsm_arr 0) & (ya < h) & (ya > 0)) 52 | 53 | xa = xa[loc] 54 | ya = ya[loc] 55 | xa = xa.astype(int) 56 | ya = ya.astype(int) 57 | PC_image = np.zeros((h, w)) 58 | 59 | PC_image[ya, xa] = int(255) 60 | PC_image = np.uint8(PC_image) 61 | return PC_image 62 | 63 | 64 | def PC_p_edge(edge_image, PC_image): 65 | # edge_image = cv2.imread(edge_image) 66 | # edge_image = cv2.cvtColor(edge_image, cv2.COLOR_BGR2GRAY) 67 | loc = np.where((edge_image > 127) & (PC_image > 130)) 68 | print(len(loc[0])) 69 | contour_img = np.zeros(edge_image.shape, np.uint8) 70 | contour_img[loc] = 255 71 | # edge_image[loc] = 0 72 | return contour_img 73 | # return edge_image 74 | 75 | 76 | def show_image(img): 77 | plt.imshow(img, cmap='gray') 78 | 79 | 80 | def img_gaussian(img, mask): 81 | img = ndimage.filters.gaussian_filter(img, mask, mode='nearest') 82 | 83 | return img 84 | 85 | 86 | def dilation(img, kernel_size, i): 87 | kernel = np.ones((kernel_size, kernel_size), np.uint8) 88 | dilation_img = cv2.dilate(img, kernel, iterations=i) 89 | return dilation_img 90 | 91 | 92 | def erosion(img, kernel_size, i): 93 | kernel = np.ones((kernel_size, kernel_size), np.uint8) 94 | erosion_img = cv2.erode(img, kernel, iterations=i) 95 | return erosion_img 96 | 97 | 98 | def closing(img, kernel_size): 99 | kernel = np.ones((kernel_size, kernel_size), np.uint8) 100 | closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) 101 | return closing 102 | 103 | 104 | def opening(img, kernel_size): 105 | kernel = np.ones((kernel_size, kernel_size), np.uint8) 106 | opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) 107 | return opening 108 | 109 | 110 | def img_fill(im_in, n): # n = binary image threshold 111 | th, im_th = cv2.threshold(im_in, n, 255, cv2.THRESH_BINARY); 112 | 113 | # Copy the thresholded image. 114 | im_floodfill = im_th.copy() 115 | 116 | # Mask used to flood filling. 117 | # Notice the size needs to be 2 pixels than the image. 118 | h, w = im_th.shape[:2] 119 | mask = np.zeros((h + 2, w + 2), np.uint8) 120 | 121 | # Floodfill from point (0, 0) 122 | cv2.floodFill(im_floodfill, mask, (0, 0), 255); 123 | 124 | # Invert floodfilled image 125 | im_floodfill_inv = cv2.bitwise_not(im_floodfill) 126 | 127 | # Combine the two images to get the foreground. 128 | fill_image = im_th | im_floodfill_inv 129 | 130 | return fill_image 131 | 132 | 133 | def canny(img_name): 134 | img = cv2.imread(img_name, 0) 135 | img = cv2.GaussianBlur(img, (9, 9), 1) 136 | canny = cv2.Canny(img, 1, 3) 137 | dst = cv2.bitwise_and(img, img, mask=canny) 138 | cv2.imwrite('canny.jpg', dst) 139 | return dst 140 | 141 | 142 | def bilatera(Dsm_arr, mask, n): 143 | Dsm_arr = cv2.bilateralFilter(Dsm_arr, mask, n, n) 144 | 145 | return Dsm_arr 146 | 147 | 148 | def main(): 149 | #I.O. 150 | f = 3803.28260713083182054106; 151 | x0 = 2471.84341749838540636119; 152 | y0 = 1653.25150608682383790438; 153 | 154 | df = pd.read_csv('ntu_pix4d_0212_calibrated_external_camera_parameters.txt', sep=' ') 155 | img_name = df['imageName'].values 156 | EX = np.array([df['X'].values, df['Y'].values, df['Z'].values, 157 | df['Omega'].values, df['Phi'].values, df['Kappa'].values]).T 158 | 159 | img = 'DSCF2114_1471837627895.JPG' 160 | 161 | index_image = np.where(img_name==img) #get the index of the image 162 | 163 | EX_par = np.squeeze(EX[index_image]) #which photos EX 164 | EX_par = np.append(EX_par,[f,x0,y0]) 165 | print('EX parameter',EX_par) 166 | # Dsm pixel to UAV photo pixel 167 | PC_image = Dsm_pt2_UAV('selfmade_dsm.tif','ntu_pix4d_0212_dsm.tfw',-227,-233,3264,4896,*EX_par) 168 | cv2.imwrite('Org_PC.jpg',PC_image) 169 | 170 | # Gaussian blur 171 | # PC = img_gaussian(PC_image, 3) 172 | # loc = np.where(PC > 15) 173 | # PC_image[loc] = 255 174 | # PC_image = opening(PC_image,8) 175 | # cv2.imwrite('PC_image.jpg', PC_image) 176 | 177 | # Canny 178 | edge_img = canny(img) 179 | contour_image = PC_p_edge(edge_img, PC_image) 180 | cv2.imwrite('contour.jpg', contour_image) 181 | 182 | contour_image = closing(contour_image,10) 183 | contour_image = dilation(contour_image,5,5) 184 | cv2.imwrite('dilation.jpg',contour_image) 185 | fill_img = img_fill(contour_image,127) 186 | fill_img = erosion(fill_img,5,3) 187 | #show_image(contour_image) 188 | cv2.imwrite('fill.jpg',fill_img) 189 | 190 | if __name__=="__main__": 191 | main() -------------------------------------------------------------------------------- /Edge Color/DSCF2098_1471837627895.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeonChen66/UAV-and-TrueOrtho/a9ab6b24547dbaab869d30f18bd01bd57a29a92b/Edge Color/DSCF2098_1471837627895.JPG -------------------------------------------------------------------------------- /Edge Color/coloredges.m: -------------------------------------------------------------------------------- 1 | function [edge_magnitude, edge_orientation] = coloredges(im) 2 | %COLOREDGES Edges of a color image by the max gradient method. 3 | % [MAGNITUDE, ORIENTATION] = COLOREDGES(IMAGE) 4 | % Extracts the edges of a color image without converting it to grayscale. 5 | % 6 | % Changes in color are detected even when the grayscale color of two 7 | % pixels are the same. The edge strength is typically greater or equal to 8 | % the magnitude obtained by simply filtering a grayscale image. 9 | % 10 | % Optionally, the edge orientation can also be returned. 11 | % 12 | % Example 13 | % ------- 14 | % The image generated by the example code shows two edge types: 15 | % White - edges found by both methods. 16 | % Red - edges found only by the color method. 17 | % 18 | % This clearly shows that a significant amount of information is lost by 19 | % the standard method, but it is recovered with the gradient method. 20 | % 21 | % figure, im = imread('peppers.png'); imshow(im) 22 | % 23 | % %get color edges and normalize magnitude 24 | % C = coloredges(im); 25 | % C = C / max(C(:)); 26 | % 27 | % %get grayscale edges and normalize magnitude 28 | % G_image = single(rgb2gray(im)) / 255; 29 | % G = sqrt(imfilter(G_image, fspecial('sobel')').^2 + imfilter(G_image, fspecial('sobel')).^2); 30 | % G = G / max(G(:)); 31 | % 32 | % %show comparison 33 | % figure, imshow(uint8(255 * cat(3, C, G, G))) 34 | % 35 | % Algorithm 36 | % --------- 37 | % The RGB color of each pixel is treated as a 3D vector, and the strength 38 | % of the edge is the magnitude of the maximum gradient. This also works 39 | % if the image is in any other (3-dimensional) color space. Direct 40 | % formulas for the jacobian eigenvalues were used, so this function is 41 | % vectorized and yields good results without sacrificing performance. 42 | % 43 | % Author: Joo F. Henriques 44 | % 45 | 46 | %J is the jacobian, its elements are the partial derivatives of r/g/b 47 | %with respect to x/y. the edge strength is the greatest eigenvalue of: 48 | % J'*J 49 | % = 50 | % [ rx, gx, bx ] * [ rx, ry ] 51 | % [ ry, gy, by ] [ gx, gy ] 52 | % [ bx, by ] 53 | % = 54 | % [ rx^2 + gx^2 + bx^2, rx*ry + gx*gy + bx*by ] 55 | % [ rx*ry + gx*gy + bx*by, ry^2 + gy^2 + by^2 ] 56 | % = 57 | % [ Jx, Jxy ] 58 | % [ Jxy, Jy ] 59 | 60 | %smoothed partial derivatives using sobel filter (could use any other) 61 | im = single(im) / 255; 62 | yfilter = fspecial('sobel'); 63 | xfilter = yfilter'; 64 | 65 | rx = imfilter(im(:,:,1), xfilter); 66 | gx = imfilter(im(:,:,2), xfilter); 67 | bx = imfilter(im(:,:,3), xfilter); 68 | 69 | ry = imfilter(im(:,:,1), yfilter); 70 | gy = imfilter(im(:,:,2), yfilter); 71 | by = imfilter(im(:,:,3), yfilter); 72 | 73 | Jx = rx.^2 + gx.^2 + bx.^2; 74 | Jy = ry.^2 + gy.^2 + by.^2; 75 | Jxy = rx.*ry + gx.*gy + bx.*by; 76 | 77 | %compute first (greatest) eigenvalue of 2x2 matrix J'*J. 78 | %note that the abs() is only needed because some values may be slightly 79 | %negative due to round-off error. 80 | D = sqrt(abs(Jx.^2 - 2*Jx.*Jy + Jy.^2 + 4*Jxy.^2)); 81 | e1 = (Jx + Jy + D) / 2; 82 | %the 2nd eigenvalue would be: e2 = (Jx + Jy - D) / 2; 83 | 84 | edge_magnitude = sqrt(e1); 85 | 86 | if nargout > 1, 87 | %compute edge orientation (from eigenvector tangent) 88 | edge_orientation = atan2(-Jxy, e1 - Jy); 89 | end 90 | 91 | end 92 | -------------------------------------------------------------------------------- /Edge Color/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeonChen66/UAV-and-TrueOrtho/a9ab6b24547dbaab869d30f18bd01bd57a29a92b/Edge Color/test.jpg -------------------------------------------------------------------------------- /Elimate PC Error/PointCloud_Error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Apr 11 23:33:54 2017 4 | 5 | @author: Leon 6 | """ 7 | 8 | import numpy as np 9 | import pandas as pd 10 | import cv2 11 | from math import * 12 | 13 | def PC_error_Eli(Dsm_name,img_name,height_max,height_min,*EX_par): 14 | point_cloud = pd.read_csv(Dsm_name,names=['X', 'Y', 'Z', 'R','G','B'], 15 | delim_whitespace=True) 16 | #img_ortho = cv2.imread('final_building_ortho.jpg',0) 17 | img = cv2.imread(img_name,0) 18 | [h,w] = img.shape 19 | 20 | #building height 21 | #Point Cloud 22 | XA = point_cloud.X.copy() 23 | YA = point_cloud.Y.copy() 24 | ZA = point_cloud.Z.copy() 25 | R = point_cloud.R.copy() 26 | G = point_cloud.G.copy() 27 | B = point_cloud.B.copy() 28 | #colinear equation 29 | XL = EX_par[0]; 30 | YL = EX_par[1]; 31 | ZL = EX_par[2]; 32 | omega = np.deg2rad(EX_par[3]); 33 | phi = np.deg2rad(EX_par[4]); 34 | kappa = np.deg2rad(EX_par[5]); 35 | f = EX_par[6]; 36 | x0 = EX_par[7]; 37 | y0 = EX_par[8]; 38 | 39 | m11 = cos(phi)*cos(kappa); 40 | m12 = sin(omega)*sin(phi)*cos(kappa)+cos(omega)*sin(kappa); 41 | m13 = -cos(omega)*sin(phi)*cos(kappa)+sin(omega)*sin(kappa); 42 | m21 = -cos(phi)*sin(kappa); 43 | m22 = -sin(omega)*sin(phi)*sin(kappa)+cos(omega)*cos(kappa); 44 | m23 = cos(omega)*sin(phi)*sin(kappa)+sin(omega)*cos(kappa); 45 | m31 = sin(phi); 46 | m32 = -sin(omega)*cos(phi); 47 | m33 = cos(omega)*cos(phi); 48 | #Criteria 49 | Z = ZA.values 50 | xa = x0 - f*((m11*(XA-XL)+m12*(YA-YL)+m13*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 51 | ya = y0 + f*((m21*(XA-XL)+m22*(YA-YL)+m23*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 52 | xa = np.around(xa).values.astype(int) 53 | ya = np.around(ya).values.astype(int) 54 | pts = np.squeeze(np.dstack((xa,ya))) 55 | #first time sort if in UAV image 56 | loc_1 = np.where((pts[:,1]>0) & (pts[:,1]0) &(pts[:,0]height_min)&(Z0) & (pts[:,1]0) &(pts[:,0]height_min)&(Z0) & (pts[:,1]0) &(pts[:,0]height_min)&(Zheight_min)&(Z0) & (pts[:,1]0) &(pts[:,0]height_min)&(Zheight_min)) 296 | PC_building = PC_data[loc] 297 | 298 | return PC_building 299 | 300 | def PC_2xyz(PC_data,xyz_name): 301 | np.savetxt(xyz_name,PC_data,delimiter=' ', 302 | fmt='%.2f %.2f %.2f %u %u %u') 303 | 304 | if __name__ == "__main__": 305 | height_max = -222 306 | height_min = -234 307 | ground_height = -294 308 | # I.O. 309 | f = 3803.28260713083182054106; 310 | x0 = 2471.84341749838540636119; 311 | y0 = 1653.25150608682383790438; 312 | # E.O. 313 | df = pd.read_csv('ntu_pix4d_0212_calibrated_external_camera_parameters.txt', sep=' ') 314 | img_name = df['imageName'].values 315 | EX = np.array([df['X'].values, df['Y'].values, df['Z'].values, 316 | df['Omega'].values, df['Phi'].values, df['Kappa'].values]).T 317 | 318 | img = 'DSCF2114_1471837627895.JPG' 319 | 320 | index_image = np.where(img_name==img) #get the index of the image 321 | 322 | EX_par = np.squeeze(EX[index_image]) #which photos EX 323 | EX_par = np.append(EX_par,[f,x0,y0]) 324 | 325 | """ 326 | PC_data = PC_error_Eli('ntu_pix4d_0212_group1_densified_point_cloud.xyz' 327 | ,'final_building.jpg',height_max,height_min,*EX_par) 328 | PC_2xyz(PC_data,'test_2.xyz') 329 | #PC_building = Sep_building(PC_data,height_max,height_min) 330 | PC_building = PC_Er_building('ntu_pix4d_0212_group1_densified_point_cloud.xyz' 331 | ,'final_building.jpg',height_max,height_min,*EX_par) 332 | PC_2xyz(PC_building,'PC_building.xyz') 333 | PC_ground = PC_Er_ground('ntu_pix4d_0212_group1_densified_point_cloud.xyz' 334 | ,'final_building.jpg',height_max,height_min,*EX_par) 335 | PC_2xyz(PC_ground,'PC_ground.xyz') 336 | """ 337 | PC_data = PC_error_mod2ground('ntu_pix4d_0212_group1_densified_point_cloud.xyz' 338 | ,'final_building.jpg',height_max,height_min,ground_height,*EX_par) 339 | 340 | PC_2xyz(PC_data,'Error_modification_PC.xyz') -------------------------------------------------------------------------------- /Image mosiac/Color_balance.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue May 02 09:42:35 2017 4 | 5 | @author: User 6 | """ 7 | 8 | import cv2 9 | import math 10 | import numpy as np 11 | import sys 12 | 13 | def apply_mask(matrix, mask, fill_value): 14 | masked = np.ma.array(matrix, mask=mask, fill_value=fill_value) 15 | return masked.filled() 16 | 17 | def apply_threshold(matrix, low_value, high_value): 18 | low_mask = matrix < low_value 19 | matrix = apply_mask(matrix, low_mask, low_value) 20 | 21 | high_mask = matrix > high_value 22 | matrix = apply_mask(matrix, high_mask, high_value) 23 | 24 | return matrix 25 | 26 | def simplest_cb(img, percent): 27 | assert img.shape[2] == 3 28 | assert percent > 0 and percent < 100 29 | 30 | half_percent = percent / 200.0 31 | 32 | channels = cv2.split(img) 33 | 34 | out_channels = [] 35 | for channel in channels: 36 | assert len(channel.shape) == 2 37 | # find the low and high precentile values (based on the input percentile) 38 | height, width = channel.shape 39 | vec_size = width * height 40 | flat = channel.reshape(vec_size) 41 | 42 | assert len(flat.shape) == 1 43 | 44 | flat = np.sort(flat) 45 | 46 | n_cols = flat.shape[0] 47 | 48 | low_val = flat[math.floor(n_cols * half_percent)] 49 | high_val = flat[math.ceil( n_cols * (1.0 - half_percent))] 50 | 51 | print "Lowval: ", low_val 52 | print "Highval: ", high_val 53 | 54 | # saturate below the low percentile and above the high percentile 55 | thresholded = apply_threshold(channel, low_val, high_val) 56 | # scale the channel 57 | normalized = cv2.normalize(thresholded, thresholded.copy(), 0, 255, cv2.NORM_MINMAX) 58 | out_channels.append(normalized) 59 | 60 | return cv2.merge(out_channels) 61 | 62 | 63 | if __name__ == '__main__': 64 | img = cv2.imread('T_Ortho.tif') 65 | out = simplest_cb(img, 1) 66 | cv2.imwrite('balance.jpg',out) 67 | cv2.imshow("before", img) 68 | cv2.imshow("after", out) 69 | cv2.waitKey(0) -------------------------------------------------------------------------------- /Image mosiac/TrueOrtho_mosiac_rough.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Spyder Editor 4 | 5 | Moasic of TrueOrtho 6 | """ 7 | 8 | import cv2 9 | import numpy as np 10 | import os 11 | import matplotlib.pyplot as plt 12 | import glob 13 | tt = glob.glob(' *.JPG ') 14 | 15 | 16 | img_name_all = os.listdir(".") 17 | 18 | img_list = [] 19 | 20 | img_list = [s for s in img_name_all if ".JPG" in s] 21 | 22 | T_Ortho = cv2.imread(img_list[4]) 23 | 24 | for img_name in img_list: 25 | img = cv2.imread(img_name) 26 | gray_image = cv2.cvtColor(T_Ortho, cv2.COLOR_BGR2GRAY) 27 | # loc = np.where((T_Ortho[:,:,0]<10)&(T_Ortho[:,:,1]<10)&(T_Ortho[:,:,2]<10)) 28 | loc = np.where(gray_image<15) 29 | T_Ortho[loc] = img[loc] 30 | 31 | T_Ortho = cv2.medianBlur(T_Ortho,3) 32 | cv2.imwrite('T_Ortho.tif',T_Ortho) -------------------------------------------------------------------------------- /PC to DSM/DEMInterp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from osgeo import gdal 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | import pandas as pd 8 | from scipy import spatial 9 | import cv2 10 | from scipy import ndimage 11 | 12 | def genDSM(PC_data,h,w,n,ground_height,affine_par,upper_bd_par): 13 | [A,D,B,E,C,F] = np.loadtxt(affine_par) 14 | 15 | point_cloud = pd.read_csv(PC_data,names=['X', 'Y', 'Z', 'R','G','B'],delim_whitespace=True) 16 | 17 | X = point_cloud.X.copy() 18 | Y = point_cloud.Y.copy() # Inverse the Y-axis 19 | Z = point_cloud.Z.copy() 20 | 21 | del point_cloud 22 | #Dsm_arr = np.zeros((h, w)) 23 | # cKDtree 24 | tree = spatial.cKDTree(list(zip(Y, X))) 25 | #Affine Trans 26 | xv, yv = np.meshgrid(np.linspace(1,w,w),np.linspace(1,h,h)) 27 | XA = A*xv+B*yv+C 28 | YA = D*xv+E*yv+F 29 | pts = np.dstack((YA,XA)) 30 | 31 | dis, loc = tree.query(pts, k=n ,distance_upper_bound=upper_bd_par) 32 | #mask = np.where(np.sum(np.isinf(dis),axis=2)!=n) 33 | del xv,yv 34 | 35 | #Dsm_arr = Z[loc[:,:,0].ravel()].reshape(h,w) 36 | #Dsm array operation 37 | Dsm_arr = Z[loc[:,:,:].ravel()].values.reshape(-1, n).max(axis=1).reshape(h,w) 38 | Dsm_arr[np.isnan(Dsm_arr)] = ground_height #ground height 39 | Dsm_arr=np.float32(Dsm_arr) 40 | 41 | return Dsm_arr 42 | 43 | def genDSM_building(BD_footprint,PC_data,h,w,n,ground_height,affine_par,upper_bd_par): 44 | 45 | [A,D,B,E,C,F] = np.loadtxt(affine_par) 46 | BD_footprint = cv2.imread(BD_footprint,0) 47 | point_cloud = pd.read_csv(PC_data,names=['X', 'Y', 'Z', 'R','G','B'],delim_whitespace=True) 48 | 49 | X = point_cloud.X.copy() 50 | Y = point_cloud.Y.copy() # Inverse the Y-axis 51 | Z = point_cloud.Z.copy() 52 | 53 | del point_cloud 54 | Dsm_arr = np.zeros((h, w)) 55 | # cKDtree 56 | tree = spatial.cKDTree(list(zip(Y, X))) 57 | #Affine Trans 58 | yv, xv = np.where(BD_footprint>127) 59 | XA = A*xv+B*yv+C 60 | YA = D*xv+E*yv+F 61 | pts = np.dstack((YA,XA)) 62 | dis, loc = tree.query(pts, k=n ,distance_upper_bound=upper_bd_par) 63 | #building use max 64 | Dsm_arr[yv,xv] = Z[loc[:,:,:].ravel()].values.reshape(-1, n).max(axis=1) 65 | Dsm_arr=np.float32(Dsm_arr) 66 | 67 | return Dsm_arr 68 | 69 | def genDSM_ground(BD_footprint,PC_data,h,w,n,ground_height,affine_par,upper_bd_par): 70 | 71 | [A,D,B,E,C,F] = np.loadtxt(affine_par) 72 | BD_footprint = cv2.imread(BD_footprint,0) 73 | point_cloud = pd.read_csv(PC_data,names=['X', 'Y', 'Z', 'R','G','B'],delim_whitespace=True) 74 | 75 | X = point_cloud.X.copy() 76 | Y = point_cloud.Y.copy() # Inverse the Y-axis 77 | Z = point_cloud.Z.copy() 78 | 79 | del point_cloud 80 | Dsm_arr = np.zeros((h, w)) 81 | # cKDtree 82 | tree = spatial.cKDTree(list(zip(Y, X))) 83 | #Affine Trans 84 | #yv, xv = np.where(BD_footprint==0) 85 | yv, xv = np.where(BD_footprint<=127) 86 | XA = A*xv+B*yv+C 87 | YA = D*xv+E*yv+F 88 | pts = np.dstack((YA,XA)) 89 | 90 | dis, loc = tree.query(pts, k=n ,distance_upper_bound=upper_bd_par) 91 | #ground use min or max 92 | Dsm_arr[yv,xv] = Z[loc[:,:,:].ravel()].values.reshape(-1, n).max(axis=1) 93 | Dsm_arr=np.float32(Dsm_arr) 94 | 95 | return Dsm_arr 96 | 97 | def Dsm_median(Dsm_arr,mask): 98 | Dsm_arr = ndimage.filters.median_filter(Dsm_arr,mask) 99 | 100 | return Dsm_arr 101 | 102 | def Dsm_gaussian(Dsm_arr,mask): 103 | Dsm_arr = ndimage.filters.gaussian_filter(Dsm_arr,mask, mode='nearest') 104 | 105 | return Dsm_arr 106 | 107 | def Dsm_bilatera(Dsm_arr,mask,n): 108 | Dsm_arr = cv2.bilateralFilter(Dsm_arr,mask,n,n) 109 | 110 | return Dsm_arr 111 | 112 | #show Dsm 113 | 114 | def Dsm_show(DSM_arr): 115 | plt.imshow(DSM_arr,cmap = 'gray') 116 | """ds = gdal.Open( "ntu_pix4d_0212_dsm.tif" ) 117 | pix4d_dsm = np.array(ds.GetRasterBand(1).ReadAsArray()) 118 | pix4d_dsm[np.where(pix4d_dsm==-10000)] = ground_height""" 119 | 120 | 121 | def fill_empty(Dsm_arr,n): #Dsm_arr & set up Empty cell' height 122 | loc = np.isnan(Dsm_arr) 123 | Dsm_arr[loc] = n 124 | return Dsm_arr 125 | #save to Geotiff 126 | def arr2Raster(data_name,Dsm_arr): 127 | [h,w] = Dsm_arr.shape 128 | driver = gdal.GetDriverByName('GTiff') 129 | dataset = driver.Create( 130 | data_name, w, h, 1, gdal.GDT_Float32) 131 | dataset.GetRasterBand(1).WriteArray(Dsm_arr[:, :]) 132 | dataset.FlushCache() 133 | 134 | def combine_layer(Dsm_building,Dsm_ground): 135 | loc = np.where(Dsm_building == 0) 136 | Dsm_building[loc] = Dsm_ground[loc] 137 | return Dsm_building 138 | 139 | def main(): 140 | """ 141 | Dsm_arr = genDSM('test.xyz',7118,4186, 142 | 3,-300,'ntu_pix4d_0212_dsm.tfw',1) 143 | Dsm_arr = Dsm_median(Dsm_arr,13) 144 | #Dsm_arr = Dsm_gaussian(Dsm_arr,3) 145 | Dsm_arr = Dsm_bilatera(Dsm_arr,19,400) 146 | DSM_show(Dsm_arr) 147 | arr2Raster('selfmade_dsm.tif',Dsm_arr) 148 | """ 149 | Dsm_building = genDSM_building('final_building_ortho.jpg','PC_building.xyz',7118,4186, 150 | 3,-300,'ntu_pix4d_0212_dsm.tfw',3) 151 | Dsm_building = Dsm_median(Dsm_building,3) 152 | #Dsm_building = Dsm_bilatera(Dsm_building,13,250) 153 | #Dsm_show(Dsm_building) 154 | Dsm_ground = genDSM_ground('final_building_ortho.jpg','PC_ground.xyz',7118,4186, 155 | 3,-300,'ntu_pix4d_0212_dsm.tfw',3) 156 | # 157 | Dsm_ground = Dsm_median(Dsm_ground,3) 158 | #Dsm_ground = Dsm_bilatera(Dsm_ground,13,400) 159 | #Dsm_show(Dsm_ground) 160 | 161 | 162 | final_Dsm = combine_layer(Dsm_building,Dsm_ground) 163 | final_Dsm = fill_empty(final_Dsm,-300) 164 | final_Dsm = Dsm_bilatera(final_Dsm,13,200) 165 | Dsm_show(final_Dsm) 166 | 167 | #arr2Raster('distortion_correct_dsm.tif',final_Dsm) 168 | 169 | if __name__ == "__main__": 170 | main() -------------------------------------------------------------------------------- /PC2Ortho/PC2ortho.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # from osgeo import gdal 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | import pandas as pd 7 | from scipy import spatial 8 | import cv2 9 | from osgeo import gdal 10 | 11 | def get_space(data): 12 | 13 | tree = spatial.cKDTree(data[['X', 'Y', 'Z']]) 14 | 15 | # The first column is the current point itself 16 | # and the second one is the nearest point 17 | dis, loc = tree.query(data[['X', 'Y', 'Z']], k=2) 18 | 19 | return np.mean(dis[:, 1]) 20 | 21 | 22 | def GEM_Dsm(data,h,w,n,upper_bd_par,affine_par): 23 | # Read basic point cloud data 24 | X = data.X.copy() 25 | Y = data.Y.copy() 26 | Z = data.Z.copy() 27 | C_R = data.C_R.copy() 28 | C_G = data.C_G.copy() 29 | C_B = data.C_B.copy() 30 | 31 | # Affine Par 32 | [A, D, B, E, C, F] = affine_par 33 | xv, yv = np.meshgrid(np.linspace(1, w, w), np.linspace(1, h, h)) 34 | XA = A * xv + B * yv + C 35 | YA = D * xv + E * yv + F 36 | pts = np.dstack((YA, XA)) 37 | 38 | # cKDtree 39 | tree = spatial.cKDTree(list(zip(Y, X))) 40 | dis, loc = tree.query(pts, k=n, distance_upper_bound=upper_bd_par) 41 | # Get the max Z 42 | idx = (Z[loc[:, :, :].ravel()].values.reshape(-1, n)).argmax(axis=1) 43 | num = np.arange(h*w) 44 | final_idx = tuple((num,idx)) 45 | # Trans max Z index to color 46 | loc2 = loc.reshape(h*w, n)[final_idx] 47 | # Ortho 48 | Ortho = np.zeros((h, w, 3)) 49 | # Ortho[:,:,2] = C_R[loc[:, :, 0].ravel()].values.reshape(h, w) 50 | # Ortho[:, :, 1] = C_G[loc[:, :, 0].ravel()].values.reshape(h, w) 51 | # Ortho[:, :, 0] = C_B[loc[:, :, 0].ravel()].values.reshape(h, w) 52 | Ortho[:,:,2] = C_R[loc2.ravel()].values.reshape(h, w) 53 | Ortho[:, :, 1] = C_G[loc2.ravel()].values.reshape(h, w) 54 | Ortho[:, :, 0] = C_B[loc2.ravel()].values.reshape(h, w) 55 | return Ortho 56 | 57 | 58 | def array2Raster(result_arr,affine_par,dstFilename): 59 | # save arr to geotiff 60 | driver = gdal.GetDriverByName('GTiff') 61 | 62 | [A, D, B, E, C, F] = affine_par 63 | 64 | if result_arr.ndim == 2: 65 | [height,width] = result_arr.shape 66 | dataset = driver.Create(dstFilename, width, height, numBand, gdal.GDT_Float32) 67 | dataset.SetGeoTransform((C, A, B, F, D, E)) 68 | dataset.GetRasterBand(1).WriteArray(array[:, :]) 69 | #dataset.GetRasterBand(1).SetNoDataValue(0) 70 | 71 | elif result_arr.ndim == 3: 72 | [height,width,numBand] = result_arr.shape 73 | dataset = driver.Create(dstFilename, width, height, numBand, gdal.GDT_Float32) 74 | dataset.SetGeoTransform((C, A, B, F, D, E)) 75 | for i in range(numBand): 76 | dataset.GetRasterBand(i + 1).WriteArray(result_arr[:, :, i]) 77 | #dataset.GetRasterBand(i + 1).SetNoDataValue(-999.0) 78 | 79 | dataset.FlushCache() # Write to disk 80 | 81 | 82 | 83 | def main(): 84 | data = pd.read_csv( 85 | 'Leon_group1_densified_point_cloud.xyz', 86 | names=['X', 'Y', 'Z', 'C_R','C_G','C_B'], 87 | delim_whitespace=True) 88 | # Calculate Geotiff information 89 | Auto = True 90 | 91 | # If it is auto 92 | if Auto == True: 93 | # spacing could be changed 94 | spacing = 1.6*get_space(data) 95 | 96 | w = int((data.X.max() - data.X.min()) / spacing) 97 | h = int((data.Y.max() - data.Y.min()) / spacing) 98 | affine_par = [spacing,0,0,-spacing,data.X.min(),data.Y.max()] 99 | 100 | else: 101 | affine_name = '' 102 | affine_par = np.loadtxt(affine_name) # input the affine name 103 | h = 1792 104 | w = 1053 105 | 106 | print(affine_par) 107 | print(h,w) 108 | # Generate DEM 109 | ortho = GEM_Dsm(data, h, w, 3, 0.15,affine_par) 110 | # save to tif 111 | ortho = ortho.astype(np.uint8) 112 | # ortho = cv2.medianBlur(ortho, 3) 113 | cv2.imwrite('ortho.tif',ortho) 114 | 115 | array2Raster(ortho,affine_par,'test.tif') 116 | 117 | if __name__=="__main__": 118 | main() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UAV-and-TrueOrtho 2 | Master's Thesis 3 | 4 | * Application of UAV photos generates True Ortho Image 5 | 6 | * Modify the distortion of DSM result in distortion of builing edge in True Ortho image 7 | 8 | 9 | 1. Building Roof Contour 10 | 11 | -- Recognize building roof contour and building roof by something like DSM but not so dense. With limited and appropriate upper bound. 12 | 13 | 2. Dsm to UAV_BD Roof Contour 14 | 15 | -- Recognize building roof contour and building roof by point cloud. 16 | 17 | 3. Edge Color 18 | 19 | -- Balance the color of Ortho photo. 20 | 21 | 4. Elimate PC Error 22 | 23 | -- By the building roof layer, modify the error point cloud to ground height. 24 | 25 | 5. PC to DSM 26 | 27 | -- Point cloud interpolates to DSM. 1) Original 2)divide into building and ground then interpolate with constrains. 28 | 29 | 6. T_ortho_py 30 | 31 | -- Generate True ortho photos in Python 32 | 33 | 7. True Ortho 34 | 35 | -- Generate True ortho photos in Matlab 36 | 37 | 8. UAV2TrueOrtho layer 38 | 39 | -- Transform the building roof layer on the UAV photos to the True Ortho (Dsm) layer to constrain the interpolation. 40 | -------------------------------------------------------------------------------- /T_ortho_py/True_Ortho.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun May 14 08:13:34 2017 4 | 5 | @author: Leon 6 | """ 7 | 8 | import numpy as np 9 | import cv2 10 | import pandas as pd 11 | from osgeo import gdal 12 | from math import * 13 | 14 | def dsm_angle(dsm_name,affine_par,EX_par): 15 | # load Dsm 16 | ds = gdal.Open(dsm_name) 17 | band = ds.GetRasterBand(1) 18 | dsm_arr = band.ReadAsArray() 19 | 20 | [h,w] = dsm_arr.shape 21 | 22 | [A,D,B,E,C,F] = affine_par 23 | [XL,YL,ZL,omega,phi,kappa] = EX_par 24 | #calculate nadir 25 | nadir_matrix = np.array(np.matrix([[A,B],[D,E]]).I*np.matrix([[XL-C],[YL-F]])) 26 | nadir_col = nadir_matrix[0] 27 | nadir_row = nadir_matrix[1] 28 | print(nadir_col,nadir_row) 29 | X_nadir = np.around(nadir_col)*A+np.around(nadir_row)*B+C; 30 | Y_nadir = np.around(nadir_col)*D+np.around(nadir_row)*E+F; 31 | Z_nadir = dsm_arr[np.around(nadir_row).astype(int),np.around(nadir_col).astype(int)]; 32 | """ 33 | X_nadir = X_nadir - XL 34 | Y_nadir = Y_nadir - YL 35 | Z_nadir = Z_nadir - ZL 36 | """ 37 | X_nadir = 0 38 | Y_nadir = 0 39 | Z_nadir = -1 40 | 41 | # Calculate each cell's Angle 42 | [y,x] = np.mgrid[0:h,0:w] 43 | XA = (A*x)+(B*y)+C; 44 | YA = (D*x)+(E*y)+F; 45 | ZA = dsm_arr; 46 | vector_X = XA-XL; 47 | vector_Y = YA-YL; 48 | vector_Z = ZA-ZL; 49 | del x,y,XA,YA,ZA 50 | #vector_A = np.squeeze(np.dstack((vector_X,vector_Y,vector_Z))) 51 | 52 | 53 | vector_dot = (vector_X*X_nadir+vector_Y*Y_nadir+vector_Z*Z_nadir) \ 54 | /(np.sqrt((vector_X)**2+(vector_Y)**2+(vector_Z)**2) \ 55 | *np.sqrt((X_nadir)**2+(Y_nadir)**2+(Z_nadir)**2)) 56 | dsm_angle = np.arccos(vector_dot) 57 | dsm_angle = np.rad2deg(dsm_angle) 58 | 59 | return dsm_angle,int(nadir_row[0]),int(nadir_col[0]) 60 | 61 | def sort_list(z_list): 62 | temp = -10000 #temp = current max value 63 | for i in range(len(z_list)): 64 | if temp= abs(nadir_row-j): 79 | x = np.linspace(nadir_col,i,abs(i-nadir_col)+1).astype(int) 80 | y = np.linspace(nadir_row,j,abs(i-nadir_col)+1).astype(int) 81 | z = dsm_angle[y,x] 82 | z = sort_list(z) 83 | dsm_angle[y,x] = z 84 | else: 85 | x = np.linspace(nadir_col,i,abs(j-nadir_row)+1).astype(int) 86 | y = np.linspace(nadir_row,j,abs(j-nadir_row)+1).astype(int) 87 | z = dsm_angle[y,x] 88 | z = sort_list(z) 89 | dsm_angle[y,x] = z 90 | 91 | j = h-1 92 | for i in range(w): 93 | if abs(nadir_col-i) >= abs(nadir_row-j): 94 | x = np.linspace(nadir_col,i,abs(i-nadir_col)+1).astype(int) 95 | y = np.linspace(nadir_row,j,abs(i-nadir_col)+1).astype(int) 96 | z = dsm_angle[y,x] 97 | z = sort_list(z) 98 | dsm_angle[y,x] = z 99 | else: 100 | x = np.linspace(nadir_col,i,abs(j-nadir_row)+1).astype(int) 101 | y = np.linspace(nadir_row,j,abs(j-nadir_row)+1).astype(int) 102 | z = dsm_angle[y,x] 103 | z = sort_list(z) 104 | dsm_angle[y,x] = z 105 | 106 | j = w-1 107 | for i in range(h): 108 | if abs(nadir_col-j) <= abs(nadir_row-i): 109 | x = np.linspace(nadir_col,j,abs(i-nadir_row)+1).astype(int) 110 | y = np.linspace(nadir_row,i,abs(i-nadir_row)+1).astype(int) 111 | z = dsm_angle[y,x] 112 | z = sort_list(z) 113 | dsm_angle[y,x] = z 114 | else: 115 | x = np.linspace(nadir_col,j,abs(j-nadir_col)+1).astype(int) 116 | y = np.linspace(nadir_row,i,abs(j-nadir_col)+1).astype(int) 117 | z = dsm_angle[y,x] 118 | z = sort_list(z) 119 | dsm_angle[y,x] = z 120 | 121 | j = 0 122 | for i in range(h): 123 | if abs(nadir_col-j) <= abs(nadir_row-i): 124 | x = np.linspace(nadir_col,j,abs(i-nadir_row)+1).astype(int) 125 | y = np.linspace(nadir_row,i,abs(i-nadir_row)+1).astype(int) 126 | z = dsm_angle[y,x] 127 | z = sort_list(z) 128 | dsm_angle[y,x] = z 129 | else: 130 | x = np.linspace(nadir_col,j,abs(j-nadir_col)+1).astype(int) 131 | y = np.linspace(nadir_row,i,abs(j-nadir_col)+1).astype(int) 132 | z = dsm_angle[y,x] 133 | z = sort_list(z) 134 | dsm_angle[y,x] = z 135 | 136 | loc = np.where(dsm_angle == -10000) 137 | dsm_arr[loc] = -10000 138 | return dsm_arr 139 | 140 | 141 | def ortho_gen(img_name,dsm_arr_occlude,f,x0,y0,affine_par,EX_par): 142 | # load Dsm and image 143 | dsm_arr = dsm_arr_occlude 144 | img = cv2.imread(img_name) 145 | #shape of Dsm and image 146 | [h,w] = dsm_arr.shape 147 | [img_h,img_w,_] = img.shape 148 | [A,D,B,E,C,F] = affine_par 149 | [XL,YL,ZL,omega,phi,kappa] = EX_par 150 | omega = np.deg2rad(omega) 151 | phi = np.deg2rad(phi) 152 | kappa = np.deg2rad(kappa) 153 | #colinear equation 154 | m11 = cos(phi)*cos(kappa); 155 | m12 = sin(omega)*sin(phi)*cos(kappa)+cos(omega)*sin(kappa); 156 | m13 = -cos(omega)*sin(phi)*cos(kappa)+sin(omega)*sin(kappa); 157 | m21 = -cos(phi)*sin(kappa); 158 | m22 = -sin(omega)*sin(phi)*sin(kappa)+cos(omega)*cos(kappa); 159 | m23 = cos(omega)*sin(phi)*sin(kappa)+sin(omega)*cos(kappa); 160 | m31 = sin(phi); 161 | m32 = -sin(omega)*cos(phi); 162 | m33 = cos(omega)*cos(phi); 163 | [y,x] = np.mgrid[0:h,0:w] 164 | XA = (A*x)+(B*y)+C; 165 | YA = (D*x)+(E*y)+F; 166 | ZA = dsm_arr 167 | xa = x0 - f*((m11*(XA-XL)+m12*(YA-YL)+m13*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 168 | ya = y0 + f*((m21*(XA-XL)+m22*(YA-YL)+m23*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 169 | xa = np.around(xa).astype(int) 170 | ya = np.around(ya).astype(int) 171 | print(xa.shape) 172 | #True Ortho Generation 173 | loc = np.where((xa<0)|(xa>=img_w)|(ya<0)|(ya>=img_h)|(dsm_arr==-10000)) 174 | xa[loc] = 0 175 | ya[loc] = 0 176 | true_ortho = np.zeros((h,w,3)) 177 | true_ortho[:,:,0] = img[ya,xa,0] 178 | true_ortho[:,:,1] = img[ya,xa,1] 179 | true_ortho[:,:,2] = img[ya,xa,2] 180 | 181 | true_ortho[loc[0],loc[1],0] = 0 182 | true_ortho[loc[0],loc[1],1] = 0 183 | true_ortho[loc[0],loc[1],2] = 0 184 | return true_ortho 185 | 186 | def write_trueortho(true_ortho,img_name): 187 | path = 'True_ortho/'+ 'TrueOrtho_'+ img_name 188 | cv2.imwrite(path,true_ortho) 189 | 190 | """ 191 | Read Pix4d calibrated EX camera parameters 192 | imageName X Y Z Omega Phi Kappa 193 | X_sigma Y_sigma Z_sigma Omega_sigma Phi_sigma Kappa_sigma 194 | """ 195 | 196 | #interio 197 | if __name__ == "__main__": 198 | #I.O. 199 | f = 3803.28260713083182054106; 200 | x0 = 2471.84341749838540636119; 201 | y0 = 1653.25150608682383790438; 202 | 203 | df = pd.read_csv('ntu_pix4d_0212_calibrated_external_camera_parameters.txt',sep=' ') 204 | img_name = df['imageName'].values 205 | EX = np.array([df['X'].values,df['Y'].values,df['Z'].values, 206 | df['Omega'].values,df['Phi'].values,df['Kappa'].values]).T 207 | 208 | affine_par = np.loadtxt('ntu_pix4d_0212_dsm.tfw') 209 | 210 | for i in range(len(img_name)): 211 | EX_par = EX[i] 212 | img_N = img_name[i] 213 | angle_matrix,nadir_row,nadir_col = dsm_angle('distortion_correct_dsm.tif',affine_par,EX_par) 214 | 215 | dsm_arr_occlude = occluded('distortion_correct_dsm.tif',angle_matrix,nadir_row,nadir_col) 216 | 217 | true_ortho = ortho_gen(img_N,dsm_arr_occlude,f,x0,y0,affine_par,EX_par) 218 | 219 | write_trueortho(true_ortho,img_N) -------------------------------------------------------------------------------- /T_ortho_py/ntu_pix4d_0212_calibrated_external_camera_parameters.txt: -------------------------------------------------------------------------------- 1 | imageName X Y Z Omega Phi Kappa X_sigma Y_sigma Z_sigma Omega_sigma Phi_sigma Kappa_sigma 2 | DSCF2095_1471837627895.JPG -47.589898 -112.967840 14.563259 0.372899 5.563224 -87.087730 0.064740 0.066129 0.022104 0.023724 0.021497 0.012215 3 | DSCF2096_1471837627895.JPG -47.266448 -69.705102 13.656372 0.584250 2.427601 -86.335806 0.048643 0.053995 0.017705 0.018928 0.018332 0.011242 4 | DSCF2097_1471837627895.JPG -45.762437 -28.239167 14.304658 -0.179759 0.019750 -88.817709 0.046390 0.047824 0.017492 0.017488 0.016987 0.011191 5 | DSCF2098_1471837627895.JPG -44.565271 17.775985 14.067157 -0.985902 0.030544 -85.832167 0.045069 0.042397 0.017105 0.017424 0.016644 0.011173 6 | DSCF2099_1471837627895.JPG -45.987830 61.560791 16.416270 -2.628044 4.364595 -84.790066 0.042412 0.037379 0.015416 0.018774 0.016856 0.011379 7 | DSCF2100_1471837627895.JPG -48.051967 107.859106 18.775050 -4.793824 -0.358415 -82.781685 0.045271 0.037774 0.017287 0.021018 0.016298 0.011418 8 | DSCF2101_1471837627895.JPG -50.237360 151.784161 17.689699 -4.746575 3.780450 -88.120440 0.047622 0.045551 0.026400 0.024379 0.018192 0.011836 9 | DSCF2113_1471837627895.JPG 90.701859 111.442276 14.204265 8.772210 18.921334 55.743559 0.066053 0.055801 0.030837 0.018514 0.020010 0.017091 10 | DSCF2114_1471837627895.JPG 69.854204 52.270523 14.745816 -0.766717 18.474911 83.124288 0.048880 0.047465 0.024456 0.017218 0.014578 0.014033 11 | DSCF2115_1471837627895.JPG 65.120354 -13.741446 15.477564 -3.740045 11.246366 96.090933 0.053059 0.060285 0.027457 0.018836 0.015279 0.012590 12 | DSCF2116_1471837627895.JPG 71.385659 -82.633509 16.241369 -2.480558 2.302424 100.442207 0.065653 0.073899 0.025283 0.023242 0.018903 0.012385 13 | DSCF2166_1471837627895.JPG 31.548220 100.017777 18.225632 9.226626 7.632804 67.138191 0.059338 0.053104 0.022604 0.020934 0.019426 0.013338 14 | DSCF2167_1471837627895.JPG 11.525764 32.646476 19.283961 6.745241 16.764800 82.824701 0.046870 0.043291 0.022514 0.017012 0.017007 0.013988 15 | DSCF2168_1471837627895.JPG 3.373504 -39.804152 19.293842 3.032475 13.208878 96.132557 0.047903 0.047987 0.021650 0.016803 0.016582 0.012963 16 | DSCF2169_1471837627895.JPG 6.984648 -114.515819 18.932130 2.839176 6.491926 99.203731 0.045069 0.050574 0.019259 0.020060 0.017264 0.012353 17 | DSCF2170_1471837627895.JPG 16.477577 -189.145473 18.614493 3.132403 -3.990582 99.780051 0.062750 0.072044 0.038178 0.028650 0.021799 0.014045 18 | -------------------------------------------------------------------------------- /T_ortho_py/ntu_pix4d_0212_dsm.tfw: -------------------------------------------------------------------------------- 1 | 0.081460000000 2 | 0 3 | 0 4 | -0.081460000000 5 | -225.449960000000 6 | 303.807240000000 7 | -------------------------------------------------------------------------------- /True Ortho/True_ortho_test.m: -------------------------------------------------------------------------------- 1 | function [] = True_ortho_test(Dsm_array,img_name,XL,YL,ZL,omega,phi,kappa,A,B,C,D,E,F,f,x0,y0) 2 | 3 | %[X,map] = imread(pixel_Angle{1}); 4 | img = imread(img_name{1}); 5 | %Dsm_array = pixel_Angle; 6 | %dsm to geotiff 7 | %{ 8 | A = 0.08146; 9 | B = 0; 10 | D = 0; 11 | E = -0.08146; 12 | C = -225.44996; 13 | F = 303.80724; 14 | %} 15 | %Exterios 16 | 17 | %XL = -44.565271; 18 | %YL = 17.775985; 19 | %ZL = 14.067157; 20 | %omega = deg2rad(omega); 21 | %phi = deg2rad(phi); 22 | %kappa = deg2rad(kappa); 23 | %f = 3803.28260713083182054106; 24 | %x0 = 2471.84341749838540636119; 25 | %y0 = 1653.25150608682383790438; 26 | 27 | m11 = cos(phi)*cos(kappa); 28 | m12 = sin(omega)*sin(phi)*cos(kappa)+cos(omega)*sin(kappa); 29 | m13 = -cos(omega)*sin(phi)*cos(kappa)+sin(omega)*sin(kappa); 30 | m21 = -cos(phi)*sin(kappa); 31 | m22 = -sin(omega)*sin(phi)*sin(kappa)+cos(omega)*cos(kappa); 32 | m23 = cos(omega)*sin(phi)*sin(kappa)+sin(omega)*cos(kappa); 33 | m31 = sin(phi); 34 | m32 = -sin(omega)*cos(phi); 35 | m33 = cos(omega)*cos(phi); 36 | 37 | [h,w] = size(Dsm_array); 38 | true_ortho = zeros(h,w,3); 39 | [img_h,img_w,rgb] = size(img); 40 | 41 | [x,y] = meshgrid(1:w,1:h); 42 | %True Ortho Generation 43 | XA = (A*x)+(B*y)+C; 44 | YA = (D*x)+(E*y)+F; 45 | ZA = Dsm_array; 46 | xa = x0 - f.*((m11.*(XA-XL)+m12.*(YA-YL)+m13.*(ZA-ZL))./(m31.*(XA-XL)+m32.*(YA-YL)+m33.*(ZA-ZL))); 47 | ya = y0 + f.*((m21.*(XA-XL)+m22.*(YA-YL)+m23.*(ZA-ZL))./(m31.*(XA-XL)+m32.*(YA-YL)+m33.*(ZA-ZL))); 48 | %ya = x0 -f*((m21*(XA-XL)+m22*(YA-YL)+m23*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 49 | %xa = y0 -f*((m11*(XA-XL)+m12*(YA-YL)+m13*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 50 | %xa = -(xa-3264/2); 51 | %ya = ya + 4896/2; 52 | %ya = -ya; 53 | xa = round(xa); 54 | ya = round(ya); 55 | num = find(xa>0 & xa<=img_w & ya>0 & ya<=img_h & Dsm_array~=-10000); 56 | 57 | true_ortho_R = zeros(h,w); 58 | true_ortho_G = zeros(h,w); 59 | true_ortho_B = zeros(h,w); 60 | 61 | R = img(1:img_h,1:img_w,1); 62 | G = img(1:img_h,1:img_w,2); 63 | B = img(1:img_h,1:img_w,3); 64 | 65 | true_ortho_R(num) = R(sub2ind(size(img),ya(num),xa(num))); 66 | true_ortho_G(num) = G(sub2ind(size(img),ya(num),xa(num))); 67 | true_ortho_B(num) = B(sub2ind(size(img),ya(num),xa(num))); 68 | 69 | true_ortho(1:h,1:w,1) = true_ortho_R; 70 | true_ortho(1:h,1:w,2) = true_ortho_G; 71 | true_ortho(1:h,1:w,3) = true_ortho_B; 72 | 73 | 74 | %name1 = 'True_ortho_test/'; 75 | 76 | name_last = sprintf('True_ortho_test/ortho_test_%s',img_name{1}); 77 | 78 | true_ortho = uint8(true_ortho); 79 | imwrite(true_ortho,name_last); 80 | 81 | end -------------------------------------------------------------------------------- /True Ortho/dsm_angle.m: -------------------------------------------------------------------------------- 1 | function Dsm_array = dsm_angle(dsm_name,img_name,XL,YL,ZL,omega,phi,kappa,A,B,C,D,E,F,f,x0,y0) 2 | % Read DSM 3 | [X,map] = imread(dsm_name); 4 | img = imread(img_name{1}); 5 | Dsm_array = X; 6 | 7 | %dsm to geotiff 8 | %{ 9 | A = 0.08146; 10 | B = 0; 11 | D = 0; 12 | E = -0.08146; 13 | C = -225.44996; 14 | F = 303.80724; 15 | %} 16 | %Exterios 17 | 18 | %XL = -44.565271; 19 | %YL = 17.775985; 20 | %ZL = 14.067157; 21 | %omega = deg2rad(omega); 22 | %phi = deg2rad(phi); 23 | %kappa = deg2rad(kappa); 24 | %f = 3803.28260713083182054106; 25 | %x0 = 2471.84341749838540636119; 26 | %y0 = 1653.25150608682383790438; 27 | 28 | [h,w] = size(Dsm_array); 29 | [img_h,img_w] = size(img); 30 | 31 | m11 = cos(phi)*cos(kappa); 32 | m12 = sin(omega)*sin(phi)*cos(kappa)+cos(omega)*sin(kappa); 33 | m13 = -cos(omega)*sin(phi)*cos(kappa)+sin(omega)*sin(kappa); 34 | m21 = -cos(phi)*sin(kappa); 35 | m22 = -sin(omega)*sin(phi)*sin(kappa)+cos(omega)*cos(kappa); 36 | m23 = cos(omega)*sin(phi)*sin(kappa)+sin(omega)*cos(kappa); 37 | m31 = sin(phi); 38 | m32 = -sin(omega)*cos(phi); 39 | m33 = cos(omega)*cos(phi); 40 | 41 | %dsm coordinate to photo coordinate in order to find nidir 42 | dsm2photo_ya = zeros(h,w); 43 | dsm2photo_xa = zeros(h,w); 44 | dsm2photonadir = zeros(h,w); 45 | %{ 46 | for i = 1:h 47 | for j = 1:w 48 | XA = A*j+B*i+C; 49 | YA = D*j+E*i+F; 50 | ZA = Dsm_array(i,j); 51 | xa = x0 - f*((m11*(XA-XL)+m12*(YA-YL)+m13*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 52 | ya = y0 + f*((m21*(XA-XL)+m22*(YA-YL)+m23*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 53 | if xa>0 && xa<=img_w && ya>0 && ya<=img_h 54 | dsm2photonadir(i,j) = (ya-y0)^2+(xa-x0)^2; 55 | else 56 | dsm2photonadir(i,j) = 10000000; 57 | end 58 | end 59 | end 60 | %} 61 | nadir = inv([A B;D E])*[XL-C;YL-F] 62 | %minMatrix = min(dsm2photonadir(:)); 63 | %[nadir_row,nadir_col] = find(dsm2photonadir==minMatrix); 64 | nadir_row = round(nadir(2)); 65 | nadir_col = round(nadir(1)); 66 | 67 | %True Ortho Angle 68 | 69 | pixel_Angle = zeros(h,w); 70 | X_nadir = round(nadir_col)*A+round(nadir_row)*B+C; 71 | Y_nadir = round(nadir_col)*D+round(nadir_row)*E+F; 72 | Z_nadir = Dsm_array(round(nadir_row),round(nadir_col)); 73 | vector_B = [X_nadir-XL Y_nadir-YL Z_nadir-ZL]'; 74 | 75 | %Calculate each cell's Angle 76 | [x,y] = meshgrid(1:w,1:h); 77 | XA = (A*x)+(B*y)+C; 78 | YA = (D*x)+(E*y)+F; 79 | ZA = Dsm_array; 80 | vector_X = XA-XL; 81 | vector_Y = YA-YL; 82 | vector_Z = ZA-ZL; 83 | %vector_A = cat(3,vector_X,vector_Y,vector_Z); 84 | 85 | vector_dot = (vector_X*vector_B(1)+vector_Y*vector_B(2)+vector_Z*vector_B(3))./(sqrt((vector_X).^2+(vector_Y).^2+(vector_Z).^2)*norm(vector_B)); 86 | pixel_Angle = acosd(vector_dot); 87 | 88 | pixel_Angle(Dsm_array==-10000) = -10000; %Check if pixel_Angle on DSM is -10000 89 | pixel_Angle = real(pixel_Angle); 90 | 91 | % occluded detection 92 | 93 | global occlude_area 94 | occlude_area = zeros(h,w); 95 | theta = linspace(0,2*pi,28000); 96 | r = sqrt((h)^2+(w)^2); 97 | x = r*cos(theta)+nadir_col; 98 | x(x>w) = w; 99 | x(x<1) = 1; 100 | y = r*sin(theta)+nadir_row; 101 | y(y>h)=h; 102 | y(y<1)=1; 103 | %{ 104 | for i = 1:28000 105 | if x(i) == w 106 | test_x = linspace(nadir_col,x(i),x(i)-nadir_col+1); 107 | test_y = linspace(nadir_row,y(i),x(i)-nadir_col+1); 108 | test_zip = [round(test_y'),round(test_x')]; 109 | sort_array(test_zip,pixel_Angle,test_x,test_y); 110 | elseif x(i)==1 111 | test_x = linspace(nadir_col,x(i),abs(x(i)-nadir_col)+1); 112 | test_y = linspace(nadir_row,y(i),abs(x(i)-nadir_col)+1); 113 | test_zip = [round(test_y'),round(test_x')]; 114 | sort_array(test_zip,pixel_Angle,test_x,test_y); 115 | elseif y(i)==1 116 | test_x = linspace(nadir_col,x(i),abs(y(i)-nadir_row)+1); 117 | test_y = linspace(nadir_row,y(i),abs(y(i)-nadir_row)+1); 118 | test_zip = [round(test_y'),round(test_x')]; 119 | sort_array(test_zip,pixel_Angle,test_x,test_y); 120 | elseif y(i)==h 121 | test_x = linspace(nadir_col,x(i),y(i)-nadir_row+1); 122 | test_y = linspace(nadir_row,y(i),y(i)-nadir_row+1); 123 | test_zip = [round(test_y'),round(test_x')]; 124 | sort_array(test_zip,pixel_Angle,test_x,test_y); 125 | end 126 | end 127 | %} 128 | j = 1; 129 | for i = 1:w 130 | if abs(nadir_col-i) >= abs(nadir_row-j) 131 | test_x = linspace(nadir_col,i,abs(i-nadir_col)+1); 132 | test_y = linspace(nadir_row,j,abs(i-nadir_col)+1); 133 | test_zip = [round(test_y'),round(test_x')]; 134 | sort_array(test_zip,pixel_Angle,test_x,test_y); 135 | else 136 | test_x = linspace(nadir_col,i,abs(j-nadir_row)+1); 137 | test_y = linspace(nadir_row,j,abs(j-nadir_row)+1); 138 | test_zip = [round(test_y'),round(test_x')]; 139 | sort_array(test_zip,pixel_Angle,test_x,test_y); 140 | end 141 | end 142 | 143 | j = h; 144 | for i = 1:w 145 | if abs(nadir_col-i) >= abs(nadir_row-j) 146 | test_x = linspace(nadir_col,i,abs(i-nadir_col)+1); 147 | test_y = linspace(nadir_row,j,abs(i-nadir_col)+1); 148 | test_zip = [round(test_y'),round(test_x')]; 149 | sort_array(test_zip,pixel_Angle,test_x,test_y); 150 | else 151 | test_x = linspace(nadir_col,i,abs(j-nadir_row)+1); 152 | test_y = linspace(nadir_row,j,abs(j-nadir_row)+1); 153 | test_zip = [round(test_y'),round(test_x')]; 154 | sort_array(test_zip,pixel_Angle,test_x,test_y); 155 | end 156 | end 157 | 158 | j = w; 159 | for i = 1:h 160 | if abs(nadir_col-j) <= abs(nadir_row-i) 161 | test_x = linspace(nadir_col,j,abs(i-nadir_row)+1); 162 | test_y = linspace(nadir_row,i,abs(i-nadir_row)+1); 163 | test_zip = [round(test_y'),round(test_x')]; 164 | sort_array(test_zip,pixel_Angle,test_x,test_y); 165 | else 166 | test_x = linspace(nadir_col,j,abs(j-nadir_col)+1); 167 | test_y = linspace(nadir_row,i,abs(j-nadir_col)+1); 168 | test_zip = [round(test_y'),round(test_x')]; 169 | sort_array(test_zip,pixel_Angle,test_x,test_y); 170 | end 171 | end 172 | 173 | j = 1; 174 | for i = 1:h 175 | if abs(nadir_col-j) <= abs(nadir_row-i) 176 | test_x = linspace(nadir_col,j,abs(i-nadir_row)+1); 177 | test_y = linspace(nadir_row,i,abs(i-nadir_row)+1); 178 | test_zip = [round(test_y'),round(test_x')]; 179 | sort_array(test_zip,pixel_Angle,test_x,test_y); 180 | else 181 | test_x = linspace(nadir_col,j,abs(j-nadir_col)+1); 182 | test_y = linspace(nadir_row,i,abs(j-nadir_col)+1); 183 | test_zip = [round(test_y'),round(test_x')]; 184 | sort_array(test_zip,pixel_Angle,test_x,test_y); 185 | end 186 | end 187 | 188 | Dsm_array(occlude_area==-10000)=-10000; 189 | -------------------------------------------------------------------------------- /True Ortho/ntu_pix4d_0212_calibrated_external_camera_parameters.txt: -------------------------------------------------------------------------------- 1 | imageName X Y Z Omega Phi Kappa X_sigma Y_sigma Z_sigma Omega_sigma Phi_sigma Kappa_sigma 2 | DSCF2095_1471837627895.JPG -47.589898 -112.967840 14.563259 0.372899 5.563224 -87.087730 0.064740 0.066129 0.022104 0.023724 0.021497 0.012215 3 | DSCF2096_1471837627895.JPG -47.266448 -69.705102 13.656372 0.584250 2.427601 -86.335806 0.048643 0.053995 0.017705 0.018928 0.018332 0.011242 4 | DSCF2097_1471837627895.JPG -45.762437 -28.239167 14.304658 -0.179759 0.019750 -88.817709 0.046390 0.047824 0.017492 0.017488 0.016987 0.011191 5 | DSCF2098_1471837627895.JPG -44.565271 17.775985 14.067157 -0.985902 0.030544 -85.832167 0.045069 0.042397 0.017105 0.017424 0.016644 0.011173 6 | DSCF2099_1471837627895.JPG -45.987830 61.560791 16.416270 -2.628044 4.364595 -84.790066 0.042412 0.037379 0.015416 0.018774 0.016856 0.011379 7 | DSCF2100_1471837627895.JPG -48.051967 107.859106 18.775050 -4.793824 -0.358415 -82.781685 0.045271 0.037774 0.017287 0.021018 0.016298 0.011418 8 | DSCF2101_1471837627895.JPG -50.237360 151.784161 17.689699 -4.746575 3.780450 -88.120440 0.047622 0.045551 0.026400 0.024379 0.018192 0.011836 9 | DSCF2113_1471837627895.JPG 90.701859 111.442276 14.204265 8.772210 18.921334 55.743559 0.066053 0.055801 0.030837 0.018514 0.020010 0.017091 10 | DSCF2114_1471837627895.JPG 69.854204 52.270523 14.745816 -0.766717 18.474911 83.124288 0.048880 0.047465 0.024456 0.017218 0.014578 0.014033 11 | DSCF2115_1471837627895.JPG 65.120354 -13.741446 15.477564 -3.740045 11.246366 96.090933 0.053059 0.060285 0.027457 0.018836 0.015279 0.012590 12 | DSCF2116_1471837627895.JPG 71.385659 -82.633509 16.241369 -2.480558 2.302424 100.442207 0.065653 0.073899 0.025283 0.023242 0.018903 0.012385 13 | DSCF2166_1471837627895.JPG 31.548220 100.017777 18.225632 9.226626 7.632804 67.138191 0.059338 0.053104 0.022604 0.020934 0.019426 0.013338 14 | DSCF2167_1471837627895.JPG 11.525764 32.646476 19.283961 6.745241 16.764800 82.824701 0.046870 0.043291 0.022514 0.017012 0.017007 0.013988 15 | DSCF2168_1471837627895.JPG 3.373504 -39.804152 19.293842 3.032475 13.208878 96.132557 0.047903 0.047987 0.021650 0.016803 0.016582 0.012963 16 | DSCF2169_1471837627895.JPG 6.984648 -114.515819 18.932130 2.839176 6.491926 99.203731 0.045069 0.050574 0.019259 0.020060 0.017264 0.012353 17 | DSCF2170_1471837627895.JPG 16.477577 -189.145473 18.614493 3.132403 -3.990582 99.780051 0.062750 0.072044 0.038178 0.028650 0.021799 0.014045 18 | -------------------------------------------------------------------------------- /True Ortho/sort_array.m: -------------------------------------------------------------------------------- 1 | function test_sort = sort_array(test_zip,pixel_Angle,test_x,test_y) %function 2 | global occlude_area; 3 | for i = 1:length(test_zip); 4 | test_z(i,1) = pixel_Angle(test_zip(i,1),test_zip(i,2)); 5 | end 6 | test_array = [round(test_x') round(test_y') test_z]; 7 | for i = 1:length(test_array) 8 | if test_array(i,3)h_min)) 63 | #EX_par 64 | XL = EX_par[0]; 65 | YL = EX_par[1]; 66 | ZL = EX_par[2]; 67 | omega = np.deg2rad(EX_par[3]); 68 | phi = np.deg2rad(EX_par[4]); 69 | kappa = np.deg2rad(EX_par[5]); 70 | f = EX_par[6]; 71 | x0 = EX_par[7]; 72 | y0 = EX_par[8]; 73 | # Colinear Equation 74 | m11 = cos(phi)*cos(kappa); 75 | m12 = sin(omega)*sin(phi)*cos(kappa)+cos(omega)*sin(kappa); 76 | m13 = -cos(omega)*sin(phi)*cos(kappa)+sin(omega)*sin(kappa); 77 | m21 = -cos(phi)*sin(kappa); 78 | m22 = -sin(omega)*sin(phi)*sin(kappa)+cos(omega)*cos(kappa); 79 | m23 = cos(omega)*sin(phi)*sin(kappa)+sin(omega)*cos(kappa); 80 | m31 = sin(phi); 81 | m32 = -sin(omega)*cos(phi); 82 | m33 = cos(omega)*cos(phi); 83 | 84 | XA = X[loc] 85 | YA = Y[loc] 86 | ZA = Z[loc] 87 | 88 | xa = x0 - f*((m11*(XA-XL)+m12*(YA-YL)+m13*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 89 | ya = y0 + f*((m21*(XA-XL)+m22*(YA-YL)+m23*(ZA-ZL))/(m31*(XA-XL)+m32*(YA-YL)+m33*(ZA-ZL))); 90 | 91 | # cKDtree 92 | tree = spatial.cKDTree(list(zip(xa, ya))) 93 | pts = np.squeeze(approx) 94 | print(pts) 95 | dis, loc = tree.query(pts, k=1) 96 | print(dis) 97 | x = XA[loc] 98 | y = YA[loc] 99 | ortho_edgeP = np.matrix([[A,B],[D,E]]).I*np.squeeze(np.dstack((x-C,y-F))).T 100 | return ortho_edgeP 101 | 102 | def draw_Point(ortho_edgeP,h,w): 103 | ortho = np.zeros((h,w)) 104 | ortho_edgeP = ortho_edgeP.T.astype(int) 105 | print(ortho_edgeP) 106 | cv2.drawContours(ortho,[ortho_edgeP],-1,(255,255,255),-1) 107 | cv2.imwrite('ortho_building_footprint.jpg',ortho) 108 | img = cv2.imread('ntu_pix4d_0212_transparent_mosaic_group1.tif') 109 | cv2.drawContours(img,[ortho_edgeP],-1,(0,0,255),3) 110 | cv2.imwrite('test.jpg',img) 111 | 112 | if __name__=="__main__": 113 | # I.O. 114 | f = 3803.28260713083182054106; 115 | x0 = 2471.84341749838540636119; 116 | y0 = 1653.25150608682383790438; 117 | # E.O. 118 | df = pd.read_csv('ntu_pix4d_0212_calibrated_external_camera_parameters.txt', sep=' ') 119 | img_name = df['imageName'].values 120 | EX = np.array([df['X'].values, df['Y'].values, df['Z'].values, 121 | df['Omega'].values, df['Phi'].values, df['Kappa'].values]).T 122 | #image name 123 | img = 'DSCF2114_1471837627895.JPG' 124 | 125 | index_image = np.where(img_name==img) #get the index of the image 126 | 127 | EX_par = np.squeeze(EX[index_image]) #which photos EX 128 | EX_par = np.append(EX_par,[f,x0,y0]) 129 | ortho_edgeP = UAV2ortho('ntu_pix4d_0212_group1_densified_point_cloud.xyz',approx 130 | ,'ntu_pix4d_0212_dsm.tfw',-220,-240,*EX_par) 131 | 132 | draw_Point(ortho_edgeP,7118,4186) --------------------------------------------------------------------------------