├── .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 |
10 |
11 |
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 |
9 |
10 |
11 |
12 |
13 |
14 |
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 |
74 |
75 |
76 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
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 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 | 1506262057121
296 |
297 |
298 | 1506262057121
299 |
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 |
328 |
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)
--------------------------------------------------------------------------------