├── Python Scripts
├── farm_generation.py
├── height.py
├── segment.py
└── voting.py
├── README.md
├── pics
├── figure_5.PNG
├── kent_filtered.png
└── youtube_screenshot.png
└── point_cloud_processing
├── CMakeLists.txt
├── launch
├── hardware_transform.launch
└── sim_transform.launch
├── package.xml
└── src
├── bounding_box.cpp
├── box_filter.cpp
├── bt.cpp
├── cloud_size.cpp
├── cluster_extraction.cpp
├── cluster_height_estimate.cpp
├── concatenate_cloud.cpp
├── crop_clusters.cpp
├── dji_tf_broadcast.cpp
├── fill_clusters.cpp
├── icp.cpp
├── known_ground_plane_max_height_estimate.cpp
├── map_height.cpp
├── max_height_estimate.cpp
├── nnsearch.cpp
├── non_dji_tf_listener.cpp
├── perimeter_heights.cpp
├── plane_height_estimate.cpp
├── plot_heights.cpp
├── recenter_cloud.cpp
├── save_cloud.cpp
├── simulation_tf_listener.cpp
├── single_box_filter.cpp
├── single_crop_box_filter.cpp
├── single_save_cloud.cpp
├── tf_listener.cpp
├── transform_and_plane_extraction.cpp
├── transform_cloud_and_save.cpp
├── transform_sim_and_save.cpp
├── turfgrass_heights.cpp
├── velodyne_tf_broadcast.cpp
├── view_colored_plot.cpp
├── view_grid.cpp
├── view_oriented_grid.cpp
├── view_single_cloud.cpp
├── voting_scheme.cpp
├── voxel_filter.cpp
└── zed_cloud_view.cpp
/Python Scripts/farm_generation.py:
--------------------------------------------------------------------------------
1 | from scipy.spatial import Delaunay
2 | import numpy as np
3 | import matplotlib.pyplot as plt
4 | from sympy import Plane, Point3D
5 | import math
6 | from collada import *
7 | from random import seed
8 | from random import random
9 | from random import randint
10 | from math import pi
11 | import xml.etree.ElementTree as ET
12 |
13 | seed(1)
14 |
15 |
16 | def sign(x1, y1, x2, y2, x3, y3):
17 | return (x1 - x3) * (y2 - y3) - (x2 - x3) * (y1 - y3)
18 |
19 |
20 | def isInside(x1, y1, x2, y2, x3, y3, x, y):
21 |
22 | d1 = sign(x, y, x1, y1, x2, y2)
23 | d2 = sign(x, y, x2, y2, x3, y3)
24 | d3 = sign(x, y, x3, y3, x1, y1)
25 |
26 | has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
27 | has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)
28 |
29 | return not(has_neg and has_pos)
30 |
31 |
32 | height_variation = 0
33 | grid_size = 0
34 | num_of_vertices = 0
35 |
36 | ground_param_file = open('ground_params.txt', 'r')
37 | lines = ground_param_file.readlines()
38 |
39 | count = 0
40 | for line in lines:
41 | if count == 0:
42 | grid_size = int(line)
43 | elif count == 1:
44 | num_of_vertices = int(line)
45 | elif count == 2:
46 | height_variation = float(line)
47 | count = count + 1
48 |
49 | print('Generating 2D Delaunay triangulation')
50 | points = np.random.random([num_of_vertices, 2])
51 | end_vertices = np.array([[-0.5 * grid_size, -0.5 * grid_size], [-0.5 * grid_size, 0.5 * grid_size], [0.5 * grid_size, -0.5 * grid_size], [0.5 * grid_size, 0.5 * grid_size]])
52 | points = points * grid_size
53 | points = points - (grid_size / 2)
54 | points = np.append(points, end_vertices, axis=0)
55 | tri = Delaunay(points)
56 |
57 | indices = np.asarray(tri.simplices)
58 |
59 | #plt.triplot(points[:,0], points[:,1], tri.simplices)
60 | #plt.plot(points[:,0], points[:,1], 'o')
61 | #plt.show()
62 |
63 | print('Randomizing Z values')
64 | points_3d = np.random.random((points.shape[0], 3))
65 | points_3d = (-1 * height_variation / 2) + (points_3d * height_variation)
66 |
67 | points_3d[:,0] = points[:,0]
68 | points_3d[:,1] = points[:,1]
69 |
70 | all_normals = np.zeros((1,3))
71 |
72 | count = 0
73 |
74 | print('Computing Normal vectors')
75 | for item in tri.simplices:
76 | point1 = points_3d[item[0]]
77 | point2 = points_3d[item[1]]
78 | point3 = points_3d[item[2]]
79 | triangle = Plane(Point3D(point1[0], point1[1], point1[2]), Point3D(point2[0], point2[1], point2[2]), Point3D(point3[0], point3[1], point3[2]))
80 | normal = np.zeros((1,3))
81 | normal[0][0] = float(triangle.normal_vector[0])
82 | normal[0][1] = float(triangle.normal_vector[1])
83 | normal[0][2] = float(triangle.normal_vector[2])
84 |
85 | mag = (normal[0][0] * normal[0][0]) + (normal[0][1] * normal[0][1]) + (normal[0][2] * normal[0][2])
86 | mag = math.sqrt(mag)
87 | normal[0][0] = normal[0][0] / mag
88 | normal[0][1] = normal[0][1] / mag
89 | normal[0][2] = normal[0][2] / mag
90 |
91 | if count == 0:
92 | count = count + 1
93 | all_normals[0,:] = normal
94 | else:
95 | all_normals = np.append(all_normals, normal, axis=0)
96 |
97 | reformed_ind = np.zeros((all_normals.shape[0], 3, 2))
98 |
99 | for i in range(0, all_normals.shape[0]):
100 | reformed_ind[i][0][0] = indices[i][0]
101 | reformed_ind[i][1][0] = indices[i][1]
102 | reformed_ind[i][2][0] = indices[i][2]
103 | reformed_ind[i][0][1] = 4 * i
104 | reformed_ind[i][1][1] = (4 * i) + 1
105 | reformed_ind[i][2][1] = (4 * i) + 2
106 |
107 | normals_4 = np.zeros((all_normals.shape[0] * 4, all_normals.shape[1]))
108 | for i in range(0, all_normals.shape[0]):
109 | normals_4[4 * i] = all_normals[i]
110 | normals_4[(4*i) + 1] = all_normals[i]
111 | normals_4[(4*i) + 2] = all_normals[i]
112 | normals_4[(4*i) + 3] = all_normals[i]
113 |
114 | points_3d_ravel = np.ravel(points_3d, order='C')
115 | normals_4_ravel = np.ravel(normals_4, order='C')
116 | reformed_ind_ravel = np.ravel(reformed_ind, order='C')
117 | reformed_ind_ravel = reformed_ind_ravel.astype(int)
118 |
119 | print('Creating ground Collada/.dae model')
120 | mesh = Collada()
121 | effect = material.Effect("effect0", [], "phong", diffuse=(1,1,1), specular=(0,1,0))
122 | mat = material.Material("material0", "mymaterial", effect)
123 | mesh.effects.append(effect)
124 | mesh.materials.append(mat)
125 |
126 | vert_src = source.FloatSource("verts-array", np.array(points_3d_ravel), ('X', 'Y', 'Z'))
127 | normal_src = source.FloatSource("normals-array", np.array(normals_4_ravel), ('X', 'Y', 'Z'))
128 |
129 | geom = geometry.Geometry(mesh, "geometry0", "myground", [vert_src, normal_src])
130 |
131 | input_list = source.InputList()
132 | input_list.addInput(0, 'VERTEX', "#verts-array")
133 | input_list.addInput(1, 'NORMAL', "#normals-array")
134 |
135 | triset = geom.createTriangleSet(reformed_ind_ravel, input_list, "materialref")
136 |
137 | geom.primitives.append(triset)
138 | mesh.geometries.append(geom)
139 |
140 | matnode = scene.MaterialNode("materialref", mat, inputs=[])
141 | geomnode = scene.GeometryNode(geom, [matnode])
142 | node = scene.Node("node0", children=[geomnode])
143 |
144 | myscene = scene.Scene("myscene", [node])
145 | mesh.scenes.append(myscene)
146 | mesh.scene = myscene
147 |
148 | mesh.write('generated_ground.dae')
149 |
150 | print(mesh)
151 |
152 | indices = indices.astype(int)
153 | plot_width = 0
154 | plot_length = 0
155 | row_width = 0
156 | row_length = 0
157 | plants_per_plot = 0
158 | low_scale = 0
159 | high_scale = 0
160 | row_params = []
161 | model_locations = []
162 | model_heights = []
163 |
164 | param_file = open('params.txt', 'r')
165 | lines = param_file.readlines()
166 |
167 | count = 0
168 | for line in lines:
169 | if count == 0:
170 | items = line.split()
171 | count2 = 0
172 | for item in items:
173 | if count2 == 0:
174 | plot_width = float(item)
175 | elif count2 == 1:
176 | plot_length = float(item)
177 | count2 = count2 + 1
178 | elif count == 1:
179 | items = line.split()
180 | count2 = 0
181 | for item in items:
182 | if count2 == 0:
183 | row_width = float(item)
184 | elif count2 == 1:
185 | row_length = float(item)
186 | count2 = count2 + 1
187 | elif count == 2:
188 | plants_per_plot = int(line)
189 | elif count == 3:
190 | items = line.split()
191 | count2 = 0
192 | for item in items:
193 | if count2 == 0:
194 | low_scale = float(item)
195 | elif count2 == 1:
196 | high_scale = float(item)
197 | count2 = count2 + 1
198 | else:
199 | row_params.append(line)
200 | count = count + 1
201 |
202 | model_location_file = open('models.txt', 'r')
203 | lines = model_location_file.readlines()
204 | for line in lines:
205 | model_locations.append(line.rstrip('\n'))
206 |
207 | model_heights_file = open("3D_Models/height.txt", "r")
208 | lines = model_heights_file.readlines()
209 | for line in lines:
210 | model_heights.append(float(line))
211 |
212 | tree = ET.parse('empty.world')
213 | root = tree.getroot()
214 | model = ET.parse('soy.model')
215 | model_root = model.getroot()
216 |
217 | x_origin = 0
218 | y_origin = 0
219 |
220 | print('Generating soy models')
221 | sim_heights_file = open("simulated_heights.csv", "w")
222 | count = 1
223 | y_count = 1
224 | for item in row_params:
225 | params = item.split()
226 |
227 | num_of_plots = int(params[0])
228 | row_offset = float(params[1])
229 | x_origin = row_offset
230 | for i in range(0, num_of_plots):
231 | heights = ""
232 | for j in range(0, plants_per_plot):
233 | x_val = (random() * plot_width) + x_origin
234 | y_val = (random() * plot_length) + y_origin
235 | z_val = 0.0
236 | for k in range(0, indices.shape[0]):
237 | x1 = points_3d[indices[k][0]][0]
238 | y1 = points_3d[indices[k][0]][1]
239 | x2 = points_3d[indices[k][1]][0]
240 | y2 = points_3d[indices[k][1]][1]
241 | x3 = points_3d[indices[k][2]][0]
242 | y3 = points_3d[indices[k][2]][1]
243 | z1 = points_3d[indices[k][0]][2]
244 | z2 = points_3d[indices[k][1]][2]
245 | z3 = points_3d[indices[k][2]][2]
246 |
247 | if isInside(x1, y1, x2, y2, x3, y3, x_val, y_val):
248 | normal = all_normals[k]
249 | d = (normal[0] * x1) + (normal[1] * y1) + (normal[2] * z1)
250 | z_val = (d - (normal[0] * x_val) - (normal[1] * y_val)) / normal[2]
251 | #print(z_val > 0.0)
252 | #print(str(z1) + " " + str(z2) + " " + str(z3) + " " + str(z_val))
253 | break
254 |
255 | x_scale = low_scale + (random() * (high_scale - low_scale))
256 | y_scale = low_scale + (random() * (high_scale - low_scale))
257 | z_scale = low_scale + (random() * (high_scale - low_scale))
258 | yaw = random() * (2 * pi)
259 | model_num = randint(0, 4)
260 | model_file = model_locations[model_num]
261 | pose_val = str(x_val) + " " + str(y_val) + " " + str(z_val) + " 0 0 " + str(yaw)
262 | scale_val = str(x_scale) + " " + str(y_scale) + " " + str(z_scale)
263 | soy_name = "soybean_" + str(count)
264 | link_name = "soybean_" + str(count) + "_link"
265 | col_name = "soybean_" + str(count) + "_collision"
266 | heights = heights + str(model_heights[model_num] * z_scale) + ","
267 | for model_name in model_root.iter('model'):
268 | model_name.set('name', soy_name)
269 | for model_name in model_root.iter('link'):
270 | model_name.set('name', link_name)
271 | for pose in model_root.iter('pose'):
272 | pose.text = pose_val
273 | for model_name in model_root.iter('collision'):
274 | model_name.set('name', col_name)
275 | for model_name in model_root.iter('visual'):
276 | model_name.set('name', soy_name)
277 | for scale_name in model_root.iter('scale'):
278 | scale_name.text = scale_val
279 | for model_location in model_root.iter('uri'):
280 | model_location.text = model_file
281 | for world in root.findall('world'):
282 | world.append(model_root)
283 | #print(str(x_val) + " " + str(y_val))
284 | count = count + 1
285 | tree.write('soy_row.world')
286 | tree = ET.parse('soy_row.world')
287 | root = tree.getroot()
288 | x_origin = x_origin + plot_width + row_width
289 | heights = heights[:-1] + "\n"
290 | sim_heights_file.write(heights)
291 | x_origin = 0
292 | y_origin = y_origin - plot_length - row_length
293 | y_count = y_count + 1
294 |
295 | ground_param_file.close()
296 | param_file.close()
297 | model_location_file.close()
298 |
--------------------------------------------------------------------------------
/Python Scripts/height.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import open3d
3 | import os
4 | import math
5 |
6 | folder_path = "/home/user01/Data/CorrectCluster/"
7 |
8 | pc_gp = open3d.io.read_point_cloud('/home/user01/Data/PointCloud/ground_plane.pcd')
9 | ground_plane = np.asarray(pc_gp.points)
10 |
11 | centroid = np.mean(ground_plane, axis=0)
12 |
13 | r = ground_plane - centroid
14 |
15 | xx_a = np.multiply(r[:, 0], r[:, 0])
16 | xx = np.sum(xx_a)
17 | xy_a = np.multiply(r[:, 0], r[:, 1])
18 | xy = np.sum(xy_a)
19 | xz_a = np.multiply(r[:, 0], r[:, 2])
20 | xz = np.sum(xz_a)
21 | yy_a = np.multiply(r[:, 1], r[:, 1])
22 | yy = np.sum(yy_a)
23 | yz_a = np.multiply(r[:, 1], r[:, 2])
24 | yz = np.sum(yz_a)
25 | zz_a = np.multiply(r[:, 2], r[:, 2])
26 | zz = np.sum(zz_a)
27 |
28 | det_x = yy*zz - yz*yz
29 | det_y = xx*zz - xz*xz
30 | det_z = xx*yy - xy*xy
31 |
32 | max = det_x
33 | max_letter = 1
34 |
35 | if det_y > max:
36 | max = det_y
37 | max_letter = 2
38 | if det_z > max:
39 | max = det_z
40 | max_letter = 3
41 |
42 | dir = np.zeros(3)
43 | if max_letter == 1:
44 | dir[0] = det_x
45 | dir[1] = xz * yz - xy * zz
46 | dir[2] = xy * yz - xz * yy
47 | elif max_letter == 2:
48 | dir[0] = xz*yz - xy*zz
49 | dir[1] = det_y
50 | dir[2] = xy*xz - yz*xx
51 | elif max_letter == 3:
52 | dir[0] = xy * yz - xz * yy
53 | dir[1] = xy * xz - yz * xx
54 | dir[2] = det_z
55 |
56 | length = (dir[0] * dir[0]) + (dir[1] * dir[1]) + (dir[2] * dir[2])
57 | length = math.sqrt(length)
58 |
59 | dir = np.divide(dir, length)
60 |
61 | for filename in os.listdir(folder_path):
62 | file = folder_path + filename
63 | pc = open3d.io.read_point_cloud(file)
64 | cloud = np.asarray(pc.points)
65 | subtract_x = cloud[:, 0] - centroid[0]
66 | subtract_y = cloud[:, 1] - centroid[1]
67 | subtract_z = cloud[:, 2] - centroid[2]
68 | subtract_x = subtract_x * dir[0]
69 | subtract_y = subtract_y * dir[1]
70 | subtract_z = subtract_z * dir[2]
71 |
72 | temp_distance = np.add(subtract_x, subtract_y)
73 | temp_distance = np.add(temp_distance, subtract_z)
74 | temp_distance = np.absolute(temp_distance)
75 | max_height = np.amax(temp_distance)
76 | print("Max height: " + str(max_height) + " in meters.")
77 |
78 |
--------------------------------------------------------------------------------
/Python Scripts/segment.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import open3d
3 | from sklearn.cluster import KMeans
4 | from UliEngineering.Math.Coordinates import BoundingBox
5 | import cv2
6 |
7 | num_clusters = 112
8 | pc = open3d.io.read_point_cloud('/home/user01/Data/PointCloud/6-4-2019/recentered.pcd')
9 | cloud = np.asarray(pc.points)
10 |
11 | filtered_cloud = cloud.transpose()
12 | filtered_cloud = filtered_cloud[:, filtered_cloud[2] > 0.15]
13 | filtered_cloud = filtered_cloud.transpose()
14 |
15 | overall_filename = "/home/user01/Data/PointCloud/complete.pcd"
16 | pcd_total = open3d.geometry.PointCloud()
17 | pcd_total.points = open3d.utility.Vector3dVector(filtered_cloud)
18 | open3d.io.write_point_cloud(overall_filename, pcd_total)
19 |
20 | y = np.full(filtered_cloud.shape[0], 255)
21 | color = np.zeros(filtered_cloud.shape)
22 | color[:, 2] = y
23 |
24 | kmeans = KMeans(n_clusters=num_clusters, random_state=0, n_jobs=-1).fit(filtered_cloud)
25 |
26 | rectangle_list = []
27 | for i in range(0, num_clusters):
28 | cluster_cloud = filtered_cloud.transpose()
29 | cluster_cloud = cluster_cloud[:, kmeans.labels_ == i]
30 | cluster_cloud = cluster_cloud.transpose()
31 | filename = "/home/user01/Data/PointCloud/Clusters/cluster_" + str(i) + ".pcd"
32 | pcd_cluster = open3d.geometry.PointCloud()
33 | pcd_cluster.points = open3d.utility.Vector3dVector(cluster_cloud)
34 | open3d.io.write_point_cloud(filename, pcd_cluster)
35 | #average = np.mean(cluster_cloud, axis=0)
36 | #box_points = np.delete(cluster_cloud, 2, 1)
37 | #box_points = np.float32(box_points)
38 | #box = BoundingBox(box_points)
39 | #rect = cv2.minAreaRect(box_points)
40 | #points = [[box.center[0] - box.width/2, box.center[1] - box.height/2, average[2]], [box.center[0] - box.width/2, box.center[1] + box.height/2, average[2]],
41 | # [box.center[0] + box.width/2, box.center[1] - box.height/2, average[2]], [box.center[0] + box.width/2, box.center[1] + box.height/2, average[2]]]
42 | #lines = [[0, 1], [0, 2], [1, 3], [2, 3]]
43 | #colors = [[1, 0, 0] for i in range(len(lines))]
44 | #line_set = open3d.geometry.LineSet()
45 | #line_set.points = open3d.utility.Vector3dVector(points)
46 | #line_set.lines = open3d.utility.Vector2iVector(lines)
47 | #line_set.colors = open3d.utility.Vector3dVector(colors)
48 | #rectangle_list.append(line_set)
49 |
50 | # test_cloud = filtered_cloud[kmeans.labels_ == 100]
51 |
52 | centers = np.asarray(kmeans.cluster_centers_)
53 |
54 | cluster_colors = np.zeros(centers.shape)
55 | x = np.full(num_clusters, 255);
56 | cluster_colors[:, 0] = x
57 |
58 | filtered_cloud = np.concatenate((filtered_cloud, centers))
59 | color = np.concatenate((color, cluster_colors))
60 |
61 | pcd_filtered = open3d.geometry.PointCloud()
62 | pcd_filtered.points = open3d.utility.Vector3dVector(filtered_cloud)
63 | pcd_filtered.colors = open3d.utility.Vector3dVector(color)
64 |
65 |
66 |
67 | vis = open3d.visualization.Visualizer()
68 | vis.create_window()
69 | vis.add_geometry(pcd_filtered)
70 | #for i in range(0, num_clusters):
71 | # vis.add_geometry(rectangle_list[i])
72 | vis.run()
73 | vis.destroy_window()
74 |
--------------------------------------------------------------------------------
/Python Scripts/voting.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import numpy as np
3 | import open3d
4 |
5 | pc = open3d.io.read_point_cloud('/home/user01/Data/PointCloud/6-4-2019/recentered.pcd')
6 |
7 | with open("/home/user01/Data/clusters_data.csv", 'r') as dest_f:
8 | data_iter = csv.reader(dest_f,
9 | delimiter = ',',
10 | quotechar = '"')
11 | data = [data for data in data_iter]
12 |
13 | orientation_range = 0.3
14 | width_range = 0.3
15 | height_range = 0.5
16 |
17 | voting_scheme_orientation = dict()
18 | voting_scheme_width = dict()
19 | voting_scheme_height = dict()
20 |
21 | for line in data:
22 | orientation = float(line[1])
23 | count = 0
24 | while orientation > 0:
25 | orientation -= orientation_range
26 | count = count + 1
27 | key = count * orientation_range
28 | if key in voting_scheme_orientation:
29 | voting_scheme_orientation[key].append(float(line[1]))
30 | else:
31 | voting_scheme_orientation[key] = [float(line[1])]
32 |
33 | width = float(line[2])
34 | count = 0
35 | while width > 0:
36 | width -= width_range
37 | count = count + 1
38 | key = count * width_range
39 | if key in voting_scheme_width:
40 | voting_scheme_width[key].append(float(line[2]))
41 | else:
42 | voting_scheme_width[key] = [float(line[2])]
43 |
44 | height = float(line[3])
45 | count = 0
46 | while height > 0:
47 | height -= height_range
48 | count = count + 1
49 | key = count * height_range
50 | if key in voting_scheme_height:
51 | voting_scheme_height[key].append(float(line[3]))
52 | else:
53 | voting_scheme_height[key] = [float(line[3])]
54 |
55 | max_orientation_key = -100.0
56 | print("ORIENTATION")
57 | for key, value in voting_scheme_orientation.items():
58 | if max_orientation_key == -100.0:
59 | max_orientation_key = key
60 | else:
61 | if len(voting_scheme_orientation[key]) > len(voting_scheme_orientation[max_orientation_key]):
62 | max_orientation_key = key
63 | print(key, len(value))
64 |
65 | max_width_key = -100.0
66 | print("\nWIDTH")
67 | for key, value in voting_scheme_width.items():
68 | if max_width_key == -100.0:
69 | max_width_key = key
70 | else:
71 | if len(voting_scheme_width[key]) > len(voting_scheme_width[max_width_key]):
72 | max_width_key = key
73 | print(key, len(value))
74 |
75 | max_height_key = -100.0
76 | print("\nHEIGHT")
77 | for key, value in voting_scheme_height.items():
78 | if max_height_key == -100.0:
79 | max_height_key = key
80 | else:
81 | if len(voting_scheme_height[key]) > len(voting_scheme_height[max_height_key]):
82 | max_height_key = key
83 | print(key, len(value))
84 |
85 | print("\n")
86 | print(len(voting_scheme_orientation[max_orientation_key]))
87 | print("\n")
88 | print(len(voting_scheme_width[max_width_key]))
89 | print("\n")
90 | print(len(voting_scheme_height[max_height_key]))
91 |
92 | orientation_values = np.asarray(voting_scheme_orientation[max_orientation_key], dtype=np.float32)
93 | width_values = np.asarray(voting_scheme_width[max_width_key], dtype=np.float32)
94 | height_values = np.asarray(voting_scheme_height[max_height_key], dtype=np.float32)
95 |
96 | orientation_average = np.average(orientation_values)
97 | width_average = np.average(width_values)
98 | height_average = np.average(height_values)
99 |
100 | with open('/home/user01/Data/averages.csv', mode='w') as average_file:
101 | average_writer = csv.writer(average_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
102 | average_writer.writerow([orientation_average, width_average, height_average])
103 |
104 | # all_data = np.asarray(data)
105 | #
106 | # cloud = np.asarray(pc.points)
107 | #
108 | # filtered_cloud = cloud.transpose()
109 | # filtered_cloud = filtered_cloud[:, filtered_cloud[2] > 0.15]
110 | # filtered_cloud = filtered_cloud.transpose()
111 | #
112 | # pcd_filtered = open3d.geometry.PointCloud()
113 | # pcd_filtered.points = open3d.utility.Vector3dVector(filtered_cloud)
114 | # #pcd_filtered.colors = open3d.utility.Vector3dVector(color)
115 | #
116 | # vis = open3d.visualization.Visualizer()
117 | # vis.create_window()
118 | # vis.add_geometry(pcd_filtered)
119 | # #for i in range(0, num_clusters):
120 | # # vis.add_geometry(rectangle_list[i])
121 | # vis.run()
122 | # vis.destroy_window()
123 |
124 | print("\n")
125 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.youtube.com/watch?v=S3yJ5RLepR0)
2 |
3 | ## Citing this work
4 | PointCloudProcessing was developed for and used in the following paper
5 | [[DOI]](https://ieeexplore.ieee.org/document/9341343/citations?tabFilter=papers#citations) [[arXiv/PDF]](https://arxiv.org/abs/1910.14031):
6 |
7 | @INPROCEEDINGS{9341343,
8 | author={Dhami, Harnaik and Yu, Kevin and Xu, Tianshu and Zhu, Qian and Dhakal, Kshitiz and Friel, James and Li, Song and Tokekar, Pratap},
9 | booktitle={2020 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
10 | title={Crop Height and Plot Estimation for Phenotyping from Unmanned Aerial Vehicles using 3D LiDAR},
11 | year={2020},
12 | volume={},
13 | number={},
14 | pages={2643-2649},
15 | doi={10.1109/IROS45743.2020.9341343}
16 | }
17 |
18 | Please cite this paper when using PointCloudProcessing.
19 |
20 | 
21 |
22 | ROS Package is in the point_cloud_processing folder.
23 |
24 | Datasets:
25 |
26 | Kentland Wheat Farm
27 |
28 | https://drive.google.com/open?id=11Gq6jv23fsi0puPGos4_p8Nh1qeF4EdX
29 |
30 | Gazebo Soybean Farms
31 |
32 | https://drive.google.com/open?id=1cbuy1wDpMB792Pbp7qokSVROeLPORPQV
33 |
34 | This project is partly funded by SmartFarm Innovation Network and Virginia Tech iCAT institute.
35 |
36 | 
37 |
--------------------------------------------------------------------------------
/pics/figure_5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsd1121/PointCloudProcessing/b31a54c8dc0b29ecd9aa35df3a6624ef6106eca7/pics/figure_5.PNG
--------------------------------------------------------------------------------
/pics/kent_filtered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsd1121/PointCloudProcessing/b31a54c8dc0b29ecd9aa35df3a6624ef6106eca7/pics/kent_filtered.png
--------------------------------------------------------------------------------
/pics/youtube_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsd1121/PointCloudProcessing/b31a54c8dc0b29ecd9aa35df3a6624ef6106eca7/pics/youtube_screenshot.png
--------------------------------------------------------------------------------
/point_cloud_processing/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(point_cloud_processing)
3 |
4 | ## Compile as C++11, supported in ROS Kinetic and newer
5 | # add_compile_options(-std=c++11)
6 |
7 | ## Find catkin macros and libraries
8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
9 | ## is used, also find other catkin packages
10 | find_package(catkin REQUIRED COMPONENTS
11 | pcl_conversions
12 | pcl_ros
13 | octomap_ros
14 | roscpp
15 | sensor_msgs
16 | cmake_modules
17 | eigen_conversions
18 | tf_conversions
19 | )
20 | find_package(Eigen REQUIRED)
21 |
22 | ## System dependencies are found with CMake's conventions
23 | # find_package(Boost REQUIRED COMPONENTS system)
24 |
25 |
26 | ## Uncomment this if the package has a setup.py. This macro ensures
27 | ## modules and global scripts declared therein get installed
28 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
29 | # catkin_python_setup()
30 |
31 | ################################################
32 | ## Declare ROS messages, services and actions ##
33 | ################################################
34 |
35 | ## To declare and build messages, services or actions from within this
36 | ## package, follow these steps:
37 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in
38 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
39 | ## * In the file package.xml:
40 | ## * add a build_depend tag for "message_generation"
41 | ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
42 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
43 | ## but can be declared for certainty nonetheless:
44 | ## * add a exec_depend tag for "message_runtime"
45 | ## * In this file (CMakeLists.txt):
46 | ## * add "message_generation" and every package in MSG_DEP_SET to
47 | ## find_package(catkin REQUIRED COMPONENTS ...)
48 | ## * add "message_runtime" and every package in MSG_DEP_SET to
49 | ## catkin_package(CATKIN_DEPENDS ...)
50 | ## * uncomment the add_*_files sections below as needed
51 | ## and list every .msg/.srv/.action file to be processed
52 | ## * uncomment the generate_messages entry below
53 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
54 |
55 | ## Generate messages in the 'msg' folder
56 | # add_message_files(
57 | # FILES
58 | # Message1.msg
59 | # Message2.msg
60 | # )
61 |
62 | ## Generate services in the 'srv' folder
63 | # add_service_files(
64 | # FILES
65 | # Service1.srv
66 | # Service2.srv
67 | # )
68 |
69 | ## Generate actions in the 'action' folder
70 | # add_action_files(
71 | # FILES
72 | # Action1.action
73 | # Action2.action
74 | # )
75 |
76 | ## Generate added messages and services with any dependencies listed here
77 | # generate_messages(
78 | # DEPENDENCIES
79 | # sensor_msgs
80 | # )
81 |
82 | ################################################
83 | ## Declare ROS dynamic reconfigure parameters ##
84 | ################################################
85 |
86 | ## To declare and build dynamic reconfigure parameters within this
87 | ## package, follow these steps:
88 | ## * In the file package.xml:
89 | ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
90 | ## * In this file (CMakeLists.txt):
91 | ## * add "dynamic_reconfigure" to
92 | ## find_package(catkin REQUIRED COMPONENTS ...)
93 | ## * uncomment the "generate_dynamic_reconfigure_options" section below
94 | ## and list every .cfg file to be processed
95 |
96 | ## Generate dynamic reconfigure parameters in the 'cfg' folder
97 | # generate_dynamic_reconfigure_options(
98 | # cfg/DynReconf1.cfg
99 | # cfg/DynReconf2.cfg
100 | # )
101 |
102 | ###################################
103 | ## catkin specific configuration ##
104 | ###################################
105 | ## The catkin_package macro generates cmake config files for your package
106 | ## Declare things to be passed to dependent projects
107 | ## INCLUDE_DIRS: uncomment this if your package contains header files
108 | ## LIBRARIES: libraries you create in this project that dependent projects also need
109 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need
110 | ## DEPENDS: system dependencies of this project that dependent projects also need
111 | catkin_package(
112 | # INCLUDE_DIRS include
113 | # LIBRARIES point_cloud_processing
114 | # CATKIN_DEPENDS pcl_conversions pcl_ros roscpp sensor_msgs
115 | # DEPENDS system_lib
116 | DEPENDS Eigen
117 | )
118 |
119 | ###########
120 | ## Build ##
121 | ###########
122 |
123 | ## Specify additional locations of header files
124 | ## Your package locations should be listed before other locations
125 | include_directories(
126 | # include
127 | ${catkin_INCLUDE_DIRS}
128 | ${Eigen_INCLUDE_DIRS}
129 | )
130 |
131 | ## Declare a C++ library
132 | # add_library(${PROJECT_NAME}
133 | # src/${PROJECT_NAME}/point_cloud_processing.cpp
134 | # )
135 |
136 | ## Add cmake target dependencies of the library
137 | ## as an example, code may need to be generated before libraries
138 | ## either from message generation or dynamic reconfigure
139 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
140 |
141 | ## Declare a C++ executable
142 | ## With catkin_make all packages are built within a single CMake context
143 | ## The recommended prefix ensures that target names across packages don't collide
144 | # add_executable(${PROJECT_NAME}_node src/point_cloud_processing_node.cpp)
145 |
146 | add_executable(max_height_estimate src/max_height_estimate.cpp)
147 | add_executable(plane_height_estimate src/plane_height_estimate.cpp)
148 | add_executable(map_height src/map_height.cpp)
149 | add_executable(view_single_cloud src/view_single_cloud.cpp)
150 | add_executable(save_cloud src/save_cloud.cpp)
151 | add_executable(zed_cloud_view src/zed_cloud_view.cpp)
152 | add_executable(single_save_cloud src/single_save_cloud.cpp)
153 | add_executable(box_filter src/box_filter.cpp)
154 | add_executable(single_box_filter src/single_box_filter.cpp)
155 | add_executable(single_crop_box_filter src/single_crop_box_filter.cpp)
156 | add_executable(dji_tf_broadcast src/dji_tf_broadcast.cpp)
157 | add_executable(velodyne_tf_broadcast src/velodyne_tf_broadcast.cpp)
158 | add_executable(tf_listener src/tf_listener.cpp)
159 | add_executable(transform_cloud_and_save src/transform_cloud_and_save.cpp)
160 | add_executable(non_dji_tf_listener src/non_dji_tf_listener.cpp)
161 | add_executable(simulation_tf_listener src/simulation_tf_listener.cpp)
162 | add_executable(transform_sim_and_save src/transform_sim_and_save.cpp)
163 | add_executable(concatenate_cloud src/concatenate_cloud.cpp)
164 | add_executable(icp src/icp.cpp)
165 | add_executable(transform_and_plane_extraction src/transform_and_plane_extraction.cpp)
166 | add_executable(voxel_filter src/voxel_filter.cpp)
167 | add_executable(recenter_cloud src/recenter_cloud.cpp)
168 | add_executable(cluster_extraction src/cluster_extraction.cpp)
169 | add_executable(bounding_box src/bounding_box.cpp)
170 | add_executable(known_ground_plane_max_height_estimate src/known_ground_plane_max_height_estimate.cpp)
171 | add_executable(voting_scheme src/voting_scheme.cpp)
172 | add_executable(fill_clusters src/fill_clusters.cpp)
173 | add_executable(cluster_height_estimate src/cluster_height_estimate.cpp)
174 | add_executable(crop_clusters src/crop_clusters.cpp)
175 | add_executable(turfgrass_heights src/turfgrass_heights.cpp)
176 | add_executable(plot_heights src/plot_heights.cpp)
177 | add_executable(cloud_size src/cloud_size.cpp)
178 | add_executable(perimeter_heights src/perimeter_heights.cpp)
179 | add_executable(view_colored_plot src/view_colored_plot.cpp)
180 | add_executable(view_grid src/view_grid.cpp)
181 | add_executable(view_oriented_grid src/view_oriented_grid.cpp)
182 | add_executable(nnsearch src/nnsearch.cpp)
183 | add_executable(bt src/bt.cpp)
184 |
185 | ## Rename C++ executable without prefix
186 | ## The above recommended prefix causes long target names, the following renames the
187 | ## target back to the shorter version for ease of user use
188 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
189 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
190 |
191 | ## Add cmake target dependencies of the executable
192 | ## same as for the library above
193 | # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
194 |
195 | ## Specify libraries to link a library or executable target against
196 | # target_link_libraries(${PROJECT_NAME}_node
197 | # ${catkin_LIBRARIES}
198 | # )
199 |
200 | target_link_libraries(view_single_cloud ${catkin_LIBRARIES})
201 | target_link_libraries(view_single_cloud ${catkin_LIBRARIES})
202 | target_link_libraries(single_save_cloud ${catkin_LIBRARIES})
203 | target_link_libraries(save_cloud ${catkin_LIBRARIES})
204 | target_link_libraries(zed_cloud_view ${catkin_LIBRARIES})
205 | target_link_libraries(map_height ${catkin_LIBRARIES})
206 | target_link_libraries(max_height_estimate ${catkin_LIBRARIES})
207 | target_link_libraries(plane_height_estimate ${catkin_LIBRARIES})
208 | target_link_libraries(single_box_filter ${catkin_LIBRARIES})
209 | target_link_libraries(single_crop_box_filter ${catkin_LIBRARIES})
210 | target_link_libraries(box_filter ${catkin_LIBRARIES})
211 | target_link_libraries(dji_tf_broadcast ${catkin_LIBRARIES})
212 | target_link_libraries(velodyne_tf_broadcast ${catkin_LIBRARIES})
213 | target_link_libraries(tf_listener ${catkin_LIBRARIES})
214 | target_link_libraries(transform_cloud_and_save ${catkin_LIBRARIES})
215 | target_link_libraries(non_dji_tf_listener ${catkin_LIBRARIES})
216 | target_link_libraries(simulation_tf_listener ${catkin_LIBRARIES})
217 | target_link_libraries(transform_sim_and_save ${catkin_LIBRARIES})
218 | target_link_libraries(concatenate_cloud ${catkin_LIBRARIES})
219 | target_link_libraries(icp ${catkin_LIBRARIES})
220 | target_link_libraries(transform_and_plane_extraction ${catkin_LIBRARIES})
221 | target_link_libraries(voxel_filter ${catkin_LIBRARIES})
222 | target_link_libraries(recenter_cloud ${catkin_LIBRARIES})
223 | target_link_libraries(cluster_extraction ${catkin_LIBRARIES})
224 | target_link_libraries(bounding_box ${catkin_LIBRARIES})
225 | target_link_libraries(known_ground_plane_max_height_estimate ${catkin_LIBRARIES})
226 | target_link_libraries(voting_scheme ${catkin_LIBRARIES})
227 | target_link_libraries(fill_clusters ${catkin_LIBRARIES})
228 | target_link_libraries(cluster_height_estimate ${catkin_LIBRARIES})
229 | target_link_libraries(crop_clusters ${catkin_LIBRARIES})
230 | target_link_libraries(turfgrass_heights ${catkin_LIBRARIES})
231 | target_link_libraries(plot_heights ${catkin_LIBRARIES})
232 | target_link_libraries(cloud_size ${catkin_LIBRARIES})
233 | target_link_libraries(perimeter_heights ${catkin_LIBRARIES})
234 | target_link_libraries(view_colored_plot ${catkin_LIBRARIES})
235 | target_link_libraries(view_grid ${catkin_LIBRARIES})
236 | target_link_libraries(view_oriented_grid ${catkin_LIBRARIES})
237 | target_link_libraries(nnsearch ${catkin_LIBRARIES})
238 | target_link_libraries(bt ${catkin_LIBRARIES})
239 |
240 | #############
241 | ## Install ##
242 | #############
243 |
244 | # all install targets should use catkin DESTINATION variables
245 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
246 |
247 | ## Mark executable scripts (Python etc.) for installation
248 | ## in contrast to setup.py, you can choose the destination
249 | # install(PROGRAMS
250 | # scripts/my_python_script
251 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
252 | # )
253 |
254 | ## Mark executables and/or libraries for installation
255 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
256 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
257 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
258 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
259 | # )
260 |
261 | ## Mark cpp header files for installation
262 | # install(DIRECTORY include/${PROJECT_NAME}/
263 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
264 | # FILES_MATCHING PATTERN "*.h"
265 | # PATTERN ".svn" EXCLUDE
266 | # )
267 |
268 | ## Mark other files for installation (e.g. launch and bag files, etc.)
269 | # install(FILES
270 | # # myfile1
271 | # # myfile2
272 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
273 | # )
274 |
275 | #############
276 | ## Testing ##
277 | #############
278 |
279 | ## Add gtest based cpp test target and link libraries
280 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_point_cloud_processing.cpp)
281 | # if(TARGET ${PROJECT_NAME}-test)
282 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
283 | # endif()
284 |
285 | ## Add folders to be run by python nosetests
286 | # catkin_add_nosetests(test)
287 |
--------------------------------------------------------------------------------
/point_cloud_processing/launch/hardware_transform.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/point_cloud_processing/launch/sim_transform.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/point_cloud_processing/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | point_cloud_processing
4 | 0.0.0
5 | The point_cloud_processing package
6 |
7 |
8 |
9 |
10 | user
11 |
12 |
13 |
14 |
15 |
16 | TODO
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 | catkin
52 | pcl_conversions
53 | pcl_ros
54 | roscpp
55 | sensor_msgs
56 | libpcl-all-dev
57 | cmake_modules
58 | tf_conversions
59 | eigen_conversions
60 | pcl_conversions
61 | pcl_ros
62 | roscpp
63 | sensor_msgs
64 | tf_conversions
65 | eigen_conversions
66 | libpcl-all
67 | pcl_conversions
68 | pcl_ros
69 | roscpp
70 | sensor_msgs
71 | cmake_modules
72 | tf_conversions
73 | eigen_conversions
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/bounding_box.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | unsigned int microseconds = 10000;
16 |
17 | int main(int argc, char** argv)
18 | {
19 | std::list > cluster_list;
20 | if(argc != 3)
21 | {
22 | std::cerr << "Expecting input argument: folder #_of_.pcd_files " << std::endl;
23 | return -1;
24 | }
25 |
26 | std::ostringstream oss;
27 | oss << argv[1] << "cluster_";
28 |
29 | std::istringstream ss(argv[2]);
30 | int x;
31 | if(!(ss >> x)) {
32 | std::cerr << "Invalid number: " << argv[1] << '\n';
33 | }
34 | else if (!ss.eof()) {
35 | std::cerr << "Trailing characters after number: " << argv[1] << '\n';
36 | }
37 |
38 | pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
39 | viewer->setBackgroundColor (0, 0, 0);
40 | viewer->addCoordinateSystem (1.0);
41 | viewer->initCameraParameters ();
42 | viewer->setCameraPosition(0, 0, 43, 0, 0, 0, 0, 0, 0);
43 | for(int i = 0; i < x; i++) {
44 | std::cout << "Count: " << i << std::endl;
45 | std::ostringstream oss2;
46 | oss2 << oss.str() << i << ".pcd";
47 | pcl::PointCloud cloud;
48 | if(pcl::io::loadPCDFile (oss2.str(), cloud) == -1)
49 | {
50 | PCL_ERROR("Couldn't read file ");
51 | PCL_ERROR(oss.str().c_str());
52 | PCL_ERROR("\n");
53 | return (-1);
54 | }
55 | cluster_list.push_back(cloud);
56 | }
57 |
58 | int count = 0;
59 | std::list >::iterator it;
60 | for(it = cluster_list.begin(); it != cluster_list.end(); ++it) {
61 | pcl::PointCloud::Ptr cloud(new pcl::PointCloud);
62 | pcl::copyPointCloud(*it, *cloud);
63 |
64 | std::ostringstream cluster_number;
65 | cluster_number << "cluster " << count;
66 | std::ostringstream obb_number;
67 | obb_number << "obb " << count;
68 |
69 | double average = 0;
70 | for(size_t i = 0; i < cloud->points.size(); i++)
71 | {
72 | average += cloud->points[i].z;
73 | }
74 | average /= cloud->points.size();
75 |
76 | for(size_t i = 0; i < cloud->points.size(); i++)
77 | {
78 | cloud->points[i].z = average;
79 | }
80 |
81 | pcl::MomentOfInertiaEstimation feature_extractor;
82 | feature_extractor.setInputCloud (cloud);
83 | feature_extractor.compute ();
84 |
85 | std::vector moment_of_inertia;
86 | std::vector eccentricity;
87 | pcl::PointXYZ min_point_OBB;
88 | pcl::PointXYZ max_point_OBB;
89 | pcl::PointXYZ position_OBB;
90 | Eigen::Matrix3f rotational_matrix_OBB;
91 | float major_value, middle_value, minor_value;
92 | Eigen::Vector3f major_vector, middle_vector, minor_vector;
93 | Eigen::Vector3f mass_center;
94 |
95 | feature_extractor.getMomentOfInertia (moment_of_inertia);
96 | feature_extractor.getEccentricity (eccentricity);
97 | feature_extractor.getOBB (min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
98 | feature_extractor.getEigenValues (major_value, middle_value, minor_value);
99 | feature_extractor.getEigenVectors (major_vector, middle_vector, minor_vector);
100 | feature_extractor.getMassCenter (mass_center);
101 |
102 |
103 | viewer->addPointCloud (cloud, cluster_number.str());
104 |
105 | Eigen::Vector3f position (position_OBB.x, position_OBB.y, position_OBB.z);
106 | Eigen::Quaternionf quat (rotational_matrix_OBB);
107 | viewer->addCube (position, quat, max_point_OBB.x - min_point_OBB.x, max_point_OBB.y - min_point_OBB.y, max_point_OBB.z - min_point_OBB.z, obb_number.str());
108 |
109 | count++;
110 | }
111 |
112 | unsigned int microseconds = 100000;
113 | //viewer->spinOnce (100);
114 | //usleep(microseconds);
115 |
116 | count = 0;
117 | for(it = cluster_list.begin(); it != cluster_list.end(); ++it) {
118 | pcl::PointCloud::Ptr cloud(new pcl::PointCloud);
119 | //pcl::PointCloud::Ptr cloud_rgb(new pcl::PointCloud);
120 | pcl::copyPointCloud(*it, *cloud);
121 | std::ostringstream cluster_number;
122 | cluster_number << "cluster " << count;
123 | std::ostringstream obb_number;
124 | obb_number << "obb " << count;
125 | viewer->removePointCloud(cluster_number.str());
126 |
127 | for(int i = 0; i < cloud->points.size(); i++) {
128 | cloud->points[i].r = 255;
129 | cloud->points[i].r = 0;
130 | cloud->points[i].r = 0;
131 | }
132 | pcl::visualization::PointCloudColorHandlerCustom rgb(cloud, 255, 0, 0);
133 | viewer->addPointCloud (cloud, rgb, cluster_number.str());
134 | viewer->spinOnce (100);
135 |
136 |
137 | bool valid = false;
138 | while(!valid) {
139 | viewer->spinOnce (100);
140 | std::cout << "Is this cluster right? (y/n): ";
141 | char input;
142 | std::cin >> input;
143 | if(input == 'y') {
144 | valid = true;
145 | viewer->removePointCloud(cluster_number.str());
146 | viewer->removeShape(obb_number.str());
147 | pcl::visualization::PointCloudColorHandlerCustom rgb(cloud, 0, 0, 255);
148 | viewer->addPointCloud (cloud, rgb, cluster_number.str());
149 | std::ostringstream oss;
150 | oss << "/home/user01/Data/CorrectCluster/cluster_" << count << ".pcd";
151 | pcl::io::savePCDFileASCII(oss.str(), *cloud);
152 | }
153 | else if(input == 'n') {
154 | valid = true;
155 | viewer->removePointCloud(cluster_number.str());
156 | viewer->removeShape(obb_number.str());
157 | pcl::visualization::PointCloudColorHandlerCustom rgb(cloud, 255, 255, 255);
158 | viewer->addPointCloud (cloud, rgb, cluster_number.str());
159 | }
160 | else {
161 | valid = false;
162 | }
163 | }
164 |
165 | count++;
166 | //viewer->spinOnce(100);
167 | //usleep(microseconds * 3);
168 | }
169 | /*
170 | while(!viewer->wasStopped ())
171 | {
172 | viewer->spinOnce (100);
173 | usleep(microseconds);
174 | }
175 | */
176 | return (0);
177 | }
178 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/box_filter.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | int count = 0;
18 | std::ostringstream oss;
19 | std::ostringstream oss2;
20 |
21 | void cloud_cb(const sensor_msgs::PointCloud2ConstPtr& input)
22 | {
23 |
24 | count++;
25 | pcl::PCLPointCloud2 pcl_pc2;
26 | pcl_conversions::toPCL(*input, pcl_pc2);
27 | pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud);
28 | pcl::fromPCLPointCloud2(pcl_pc2, *temp_cloud);
29 | std::cerr << "Point cloud data: " << temp_cloud->points.size () << std::endl;
30 | std::cerr << "Count: " << count << std::endl;
31 |
32 | /* pcl::PointCloud::Ptr cloud_filtered_x(new pcl::PointCloud);
33 | pcl::PassThrough pass_x;
34 | pass_x.setInputCloud(temp_cloud);
35 | pass_x.setFilterFieldName("x");
36 | pass_x.setFilterLimits(-5.0, 5.0);
37 | pass_x.filter(*cloud_filtered_x);
38 | */
39 | pcl::PointCloud::Ptr cloud_filtered_y(new pcl::PointCloud);
40 | pcl::PassThrough pass_y;
41 | pass_y.setInputCloud(temp_cloud);
42 | pass_y.setFilterFieldName("y");
43 | pass_y.setFilterLimits(-5.0, 5.0);
44 | pass_y.filter(*cloud_filtered_y);
45 |
46 | std::ostringstream oss3;
47 | oss3 << oss2.str() << "/filtered_point_cloud_" << count << ".pcd";
48 | pcl::io::savePCDFileASCII(oss3.str(), *cloud_filtered_y);
49 |
50 | }
51 |
52 | int main(int argc, char** argv)
53 | {
54 |
55 | std::time_t t = std::time(0);
56 | std::tm* now = std::localtime(&t);
57 |
58 | oss << "/home/user01/Data/PointCloud/" << (now->tm_mon + 1) << "-"
59 | << (now->tm_mday) << "-" << (now->tm_year + 1900);
60 | mode_t nMode = 0733;
61 | int nError = 0;
62 | nError = mkdir(oss.str().c_str(), nMode);
63 |
64 | oss2 << "/home/user01/Data/PointCloud/" << (now->tm_mon + 1) << "-"
65 | << (now->tm_mday) << "-" << (now->tm_year + 1900) << "/filtered";
66 | nError = mkdir(oss2.str().c_str(), nMode);
67 |
68 | ros::init(argc, argv, "point_cloud_processing");
69 | ros::NodeHandle nh;
70 |
71 | ros::Subscriber sub = nh.subscribe("velodyne_points", 1, cloud_cb);
72 |
73 | ros::spin();
74 | }
75 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/bt.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | int count = 0;
9 |
10 | void octomap_cb(const octomap_msgs::Octomap& input)
11 | {
12 |
13 | count++;
14 | std::cout << count << std::endl;
15 | octomap::AbstractOcTree* tree = octomap_msgs::binaryMsgToMap(input);
16 | //tree->write("test.bt");
17 | octomap::OcTree* ocTree = new octomap::OcTree(0.1);
18 | ocTree = dynamic_cast(tree);
19 | ocTree->writeBinary("test.bt");
20 | }
21 |
22 | int main(int argc, char** argv)
23 | {
24 |
25 | ros::init(argc, argv, "point_cloud_processing");
26 | ros::NodeHandle nh;
27 |
28 | ros::Subscriber sub = nh.subscribe("octomap_binary", 1, octomap_cb);
29 |
30 | ros::spin();
31 | }
32 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/cloud_size.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | int main(int argc, char** argv)
9 | {
10 | if(argc != 2)
11 | {
12 | std::cerr << "Expecting input argument: file" << std::endl;
13 | return -1;
14 | }
15 |
16 | std::ostringstream oss;
17 | oss << argv[1];
18 |
19 | pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud);
20 | if(pcl::io::loadPCDFile (oss.str(), *temp_cloud) == -1)
21 | {
22 | PCL_ERROR("Couldn't read file ");
23 | PCL_ERROR(oss.str().c_str());
24 | PCL_ERROR("\n");
25 | return (-1);
26 | }
27 |
28 | std::cout << temp_cloud->size() << std::endl;
29 |
30 | return 0;
31 | }
32 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/cluster_extraction.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 |
17 | int
18 | main (int argc, char** argv)
19 | {
20 | if(argc != 2)
21 | {
22 | std::cerr << "Expecting input argument: file" << std::endl;
23 | return -1;
24 | }
25 |
26 | std::ostringstream oss;
27 | oss << argv[1];
28 |
29 | pcl::visualization::CloudViewer viewer ("Simple Cloud Viewer");
30 | unsigned int microseconds = 500000;
31 |
32 | // Read in the cloud data
33 | pcl::PCDReader reader;
34 | pcl::PointCloud::Ptr cloud (new pcl::PointCloud), cloud_f (new pcl::PointCloud);
35 | if(pcl::io::loadPCDFile (oss.str(), *cloud) == -1)
36 | {
37 | PCL_ERROR("Couldn't read file ");
38 | PCL_ERROR(oss.str().c_str());
39 | PCL_ERROR("\n");
40 | return (-1);
41 | }
42 | std::cout << "PointCloud before filtering has: " << cloud->points.size () << " data points." << std::endl; //*
43 |
44 | // Create the filtering object: downsample the dataset using a leaf size of 1cm
45 | /*
46 | pcl::VoxelGrid vg;
47 | pcl::PointCloud::Ptr cloud_filtered (new pcl::PointCloud);
48 | vg.setInputCloud (cloud);
49 | vg.setLeafSize (0.01f, 0.01f, 0.01f);
50 | vg.filter (*cloud_filtered);
51 | std::cout << "PointCloud after filtering has: " << cloud_filtered->points.size () << " data points." << std::endl; //*
52 | */
53 | pcl::PCDWriter writer;
54 |
55 | pcl::PointCloud::Ptr cloud_filtered (new pcl::PointCloud);
56 | cloud_filtered = cloud;
57 | // Create the segmentation object for the planar model and set all the parameters
58 | pcl::SACSegmentation seg;
59 | pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
60 | pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
61 | pcl::PointCloud::Ptr cloud_plane (new pcl::PointCloud ());
62 | seg.setOptimizeCoefficients (true);
63 | seg.setModelType (pcl::SACMODEL_PLANE);
64 | seg.setMethodType (pcl::SAC_RANSAC);
65 | seg.setMaxIterations (100);
66 | seg.setDistanceThreshold (0.2);
67 |
68 | int i=0, nr_points = (int) cloud_filtered->points.size ();
69 |
70 | // Segment the largest planar component from the remaining cloud
71 | seg.setInputCloud (cloud_filtered);
72 | seg.segment (*inliers, *coefficients);
73 | if (inliers->indices.size () == 0)
74 | {
75 | std::cout << "Could not estimate a planar model for the given dataset." << std::endl;
76 | return 0;
77 | }
78 |
79 | // Extract the planar inliers from the input cloud
80 | pcl::ExtractIndices extract;
81 | extract.setInputCloud (cloud_filtered);
82 | extract.setIndices (inliers);
83 | extract.setNegative (false);
84 |
85 | // Get the points associated with the planar surface
86 | extract.filter (*cloud_plane);
87 | std::cout << "PointCloud representing the planar component: " << cloud_plane->points.size () << " data points." << std::endl;
88 |
89 | // Remove the planar inliers, extract the rest
90 | extract.setNegative (true);
91 | extract.filter (*cloud_f);
92 | *cloud_filtered = *cloud_f;
93 |
94 |
95 | pcl::PointCloud::Ptr cloud_rgb(new pcl::PointCloud);
96 | cloud_rgb->points.resize(cloud_filtered->size());
97 |
98 | // Creating the KdTree object for the search method of the extraction
99 | pcl::search::KdTree::Ptr tree (new pcl::search::KdTree);
100 | tree->setInputCloud (cloud_filtered);
101 | std::vector cluster_indices;
102 | pcl::EuclideanClusterExtraction ec;
103 | ec.setClusterTolerance (0.1); // 2cm
104 | ec.setMinClusterSize (25);
105 | ec.setMaxClusterSize (25000);
106 | ec.setSearchMethod (tree);
107 | ec.setInputCloud (cloud_filtered);
108 |
109 | ec.extract (cluster_indices);
110 |
111 | int j = 0;
112 | for (std::vector::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
113 | {
114 | for(size_t i = 0; i < cloud_filtered->points.size(); i++)
115 | {
116 | cloud_rgb->points[i].x = cloud_filtered->points[i].x;
117 | cloud_rgb->points[i].y = cloud_filtered->points[i].y;
118 | cloud_rgb->points[i].z = cloud_filtered->points[i].z;
119 | cloud_rgb->points[i].r = 0;
120 | cloud_rgb->points[i].g = 0;
121 | cloud_rgb->points[i].b = 255;
122 | }
123 | pcl::PointCloud::Ptr cloud_cluster (new pcl::PointCloud);
124 | for (std::vector::const_iterator pit = it->indices.begin (); pit != it->indices.end (); ++pit) {
125 | cloud_cluster->points.push_back (cloud_filtered->points[*pit]);
126 | cloud_rgb->points[*pit].r = 255;
127 | cloud_rgb->points[*pit].g = 0;
128 | cloud_rgb->points[*pit].b = 0;
129 | }//*
130 | cloud_cluster->width = cloud_cluster->points.size ();
131 | cloud_cluster->height = 1;
132 | cloud_cluster->is_dense = true;
133 |
134 | std::cout << "PointCloud representing the Cluster: " << cloud_cluster->points.size () << " data points." << std::endl;
135 | std::stringstream ss;
136 | ss << "cloud_cluster_" << j << ".pcd";
137 | writer.write (ss.str (), *cloud_cluster, false); //*
138 | viewer.showCloud(cloud_rgb);
139 | usleep(microseconds);
140 | j++;
141 | }
142 |
143 | return (0);
144 | }
--------------------------------------------------------------------------------
/point_cloud_processing/src/cluster_height_estimate.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | //#include
14 | #include
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | struct Vector3
22 | {
23 | double x;
24 | double y;
25 | double z;
26 | };
27 |
28 | int main(int argc, char** argv)
29 | {
30 | if(argc != 4)
31 | {
32 | std::cerr << "param_file point_cloud_file clusters_file" << std::endl;
33 | return -1;
34 | }
35 |
36 | double distance_threshold = 0;
37 |
38 | std::ifstream infile(argv[1]);
39 |
40 | int count = 0;
41 | float param = 0;
42 | while(infile >> param) {
43 | switch(count) {
44 | case 0:
45 | distance_threshold = param;
46 | break;
47 | default:
48 | std::cout << "Shouldn't get to this. Param file setup incorrectly." << std::endl;
49 | break;
50 | }
51 | count++;
52 | }
53 |
54 | pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud);
55 | if(pcl::io::loadPCDFile (argv[2], *temp_cloud) == -1)
56 | {
57 | PCL_ERROR("Couldn't read file ");
58 | PCL_ERROR(argv[2]);
59 | PCL_ERROR("\n");
60 | return (-1);
61 | }
62 |
63 | pcl::PointCloud::Ptr bodyFiltered(new pcl::PointCloud);
64 |
65 | std::ofstream height_file;
66 | height_file.open("/home/naik/Data/PointCloud/heights.csv");
67 | height_file << "Cluster #,Height (meters)\n";
68 |
69 | std::ifstream infile2(argv[3]);
70 | std::string line;
71 | int linecount = 0;
72 | while(std::getline(infile2, line))
73 | {
74 | if(linecount == 0)
75 | {
76 | linecount++;
77 | continue;
78 | }
79 | std::istringstream s(line);
80 | std::string field;
81 | int fieldcount = 0;
82 | int clustercount = -1;
83 | double rotation = -1;
84 | double height = -1;
85 | double width = -1;
86 | double box_x = -1;
87 | double box_y = -1;
88 | while(getline(s, field, ','))
89 | {
90 | if(fieldcount == 0)
91 | clustercount = std::atoi(field.c_str());
92 | else if(fieldcount == 1)
93 | rotation = std::atof(field.c_str());
94 | else if(fieldcount == 2)
95 | width = std::atof(field.c_str());
96 | else if(fieldcount == 3)
97 | height = std::atof(field.c_str());
98 | else if(fieldcount == 4)
99 | box_x = std::atof(field.c_str());
100 | else if(fieldcount == 5)
101 | box_y = std::atof(field.c_str());
102 | /* std::cout << clustercount << std::endl;
103 | std::cout << rotation << std::endl;
104 | std::cout << width << std::endl;
105 | std::cout << height << std::endl;
106 | std::cout << box_x << std::endl;
107 | std::cout << box_y << std::endl;
108 | */
109 | fieldcount++;
110 | }
111 |
112 | height_file << clustercount << ",";
113 |
114 | //height += 4;
115 | pcl::CropBox boxFilter;
116 | boxFilter.setTranslation(Eigen::Vector3f(box_x, box_y, 0));
117 | boxFilter.setRotation(Eigen::Vector3f(0, 0, rotation));
118 | boxFilter.setMin(Eigen::Vector4f(0 - (height/2), 0 - (width/2), -100, 1.0));
119 | boxFilter.setMax(Eigen::Vector4f(0 + (height/2), 0 + (width/2), 100, 1.0));
120 | boxFilter.setInputCloud(temp_cloud);
121 | boxFilter.filter(*bodyFiltered);
122 |
123 |
124 |
125 |
126 | pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
127 | pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
128 | // Create segmentation object
129 | pcl::SACSegmentation seg;
130 | //Optional
131 | seg.setOptimizeCoefficients(true);
132 | seg.setAxis(Eigen::Vector3f(0,0,1));
133 | // Mandatory
134 | seg.setModelType(pcl::SACMODEL_PLANE);
135 | seg.setMethodType(pcl::SAC_RANSAC);
136 | seg.setDistanceThreshold(distance_threshold);
137 |
138 | seg.setInputCloud(bodyFiltered);
139 | seg.segment(*inliers, *coefficients);
140 |
141 | if(inliers->indices.size() == 0)
142 | {
143 | PCL_ERROR("Could not estimate a planar model for the given dataset.");
144 | return -1;
145 | }
146 |
147 | pcl::PointCloud::Ptr cloud_rgb(new pcl::PointCloud);
148 | cloud_rgb->points.resize(bodyFiltered->size() + 2);
149 | for(size_t i = 0; i < bodyFiltered->points.size(); i++)
150 | {
151 | cloud_rgb->points[i].x = bodyFiltered->points[i].x;
152 | cloud_rgb->points[i].y = bodyFiltered->points[i].y;
153 | cloud_rgb->points[i].z = bodyFiltered->points[i].z;
154 | cloud_rgb->points[i].r = 0;
155 | cloud_rgb->points[i].g = 0;
156 | cloud_rgb->points[i].b = 255;
157 | }
158 |
159 | for(size_t i = 0; i < inliers->indices.size(); ++i)
160 | {
161 | cloud_rgb->points[inliers->indices[i]].r = 255;
162 | cloud_rgb->points[inliers->indices[i]].g = 0;
163 | cloud_rgb->points[inliers->indices[i]].b = 0;
164 | }
165 |
166 | Vector3 sum;
167 | sum.x = 0;
168 | sum.y = 0;
169 | sum.z = 0;
170 | for(size_t i = 0; i < cloud_rgb->points.size(); i++)
171 | {
172 | if(cloud_rgb->points[i].r == 255)
173 | {
174 | sum.x += cloud_rgb->points[i].x;
175 | sum.y += cloud_rgb->points[i].y;
176 | sum.z += cloud_rgb->points[i].z;
177 | }
178 | }
179 |
180 | Vector3 centroid;
181 | centroid.x = sum.x / inliers->indices.size();
182 | centroid.y = sum.y / inliers->indices.size();
183 | centroid.z = sum.z / inliers->indices.size();
184 |
185 | double xx = 0.0;
186 | double xy = 0.0;
187 | double xz = 0.0;
188 | double yy = 0.0;
189 | double yz = 0.0;
190 | double zz = 0.0;
191 |
192 | for(size_t i = 0; i < cloud_rgb->points.size(); i++)
193 | {
194 | if(cloud_rgb->points[i].r == 255)
195 | {
196 | Vector3 r;
197 | r.x = cloud_rgb->points[i].x - centroid.x;
198 | r.y = cloud_rgb->points[i].y - centroid.y;
199 | r.z = cloud_rgb->points[i].z - centroid.z;
200 | xx += r.x * r.x;
201 | xy += r.x * r.y;
202 | xz += r.x * r.z;
203 | yy += r.y * r.y;
204 | yz += r.y * r.z;
205 | zz += r.z * r.z;
206 | }
207 | }
208 |
209 | double det_x = yy*zz - yz*yz;
210 | double det_y = xx*zz - xz*xz;
211 | double det_z = xx*yy - xy*xy;
212 |
213 | double max = det_x;
214 | int max_letter = 1;
215 | if(det_y > max)
216 | {
217 | max = det_y;
218 | max_letter = 2;
219 | }
220 | if(det_z > max)
221 | {
222 | max = det_z;
223 | max_letter = 3;
224 | }
225 |
226 | Vector3 dir;
227 | if(max_letter == 1)
228 | {
229 | dir.x = det_x;
230 | dir.y = xz*yz - xy*zz;
231 | dir.z = xy*yz - xz*yy;
232 | }
233 | else if(max_letter == 2)
234 | {
235 | dir.x = xz*yz - xy*zz;
236 | dir.y = det_y;
237 | dir.z = xy*xz - yz*xx;
238 | }
239 | else if(max_letter == 3)
240 | {
241 | dir.x = xy*yz - xz*yy;
242 | dir.y = xy*xz - yz*xx;
243 | dir.z = det_z;
244 | }
245 |
246 | double length = (dir.x * dir.x) + (dir.y * dir.y) + (dir.z * dir.z);
247 | length = sqrt(length);
248 |
249 | dir.x = dir.x / length;
250 | dir.y = dir.y / length;
251 | dir.z = dir.z / length;
252 |
253 | double distance = 0;
254 | Vector3 subtract;
255 | Vector3 point_max;
256 | int index = -1;
257 | for(size_t i = 0; i < cloud_rgb->points.size(); i++)
258 | {
259 | if(cloud_rgb->points[i].b == 255)
260 | {
261 | double temp_distance = 0;
262 | subtract.x = cloud_rgb->points[i].x - centroid.x;
263 | subtract.y = cloud_rgb->points[i].y - centroid.y;
264 | subtract.z = cloud_rgb->points[i].z - centroid.z;
265 | temp_distance = (dir.x * subtract.x) + (dir.y * subtract.y) + (dir.z * subtract.z);
266 |
267 | double mag_dist = std::abs(temp_distance);
268 |
269 | //height_file << mag_dist << ",";
270 |
271 | if(mag_dist > distance) {
272 | distance = mag_dist;
273 | point_max.x = cloud_rgb->points[i].x;
274 | point_max.y = cloud_rgb->points[i].y;
275 | point_max.z = cloud_rgb->points[i].z;
276 | index = i;
277 | }
278 | }
279 | }
280 |
281 | std::cerr << "Max distance in frame(meters): " << distance << " meters." << std::endl;
282 | //std::cerr << "Max distance in frame(inches): " << (distance * 39.3701) << " inches." << std::endl;
283 | height_file << distance << ",";
284 | height_file << std::endl;
285 |
286 | }
287 |
288 | /*
289 | int size = cloud_rgb->size();
290 | cloud_rgb->points[size - 1].x = centroid.x;
291 | cloud_rgb->points[size - 1].y = centroid.y;
292 | cloud_rgb->points[size - 1].z = centroid.z;
293 | cloud_rgb->points[size - 1].r = 255;
294 | cloud_rgb->points[size - 1].g = 255;
295 | cloud_rgb->points[size - 1].b = 255;
296 |
297 | cloud_rgb->points[size - 2].x = dir.x;
298 | cloud_rgb->points[size - 2].y = dir.y;
299 | cloud_rgb->points[size - 2].z = dir.z;
300 | cloud_rgb->points[size - 2].r = 255;
301 | cloud_rgb->points[size - 2].g = 165;
302 | cloud_rgb->points[size - 2].b = 0;
303 |
304 | cloud_rgb->points[index].r = 0;
305 | cloud_rgb->points[index].g = 255;
306 | cloud_rgb->points[index].b = 0;
307 |
308 | pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
309 | viewer->setBackgroundColor (0, 0, 0);
310 | viewer->addCoordinateSystem (1.0);
311 | viewer->initCameraParameters ();
312 | viewer->setCameraPosition(0, 0, 43, 0, 0, 0, 0, 0, 0);
313 | pcl::visualization::PointCloudColorHandlerCustom rgb (temp_cloud, 0, 0, 255);
314 | viewer->addPointCloud (temp_cloud, rgb, "full");
315 | //viewer->addPointCloud (cloud_rgb, rgb, "Cloud");
316 | viewer->addPointCloud (cloud_rgb, "test");
317 |
318 | unsigned int microseconds = 100000;
319 |
320 | while(!viewer->wasStopped ())
321 | {
322 | viewer->spinOnce (100);
323 | usleep(microseconds);
324 | }*/
325 | return 0;
326 | }
327 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/concatenate_cloud.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 |
11 | int main(int argc, char** argv)
12 | {
13 | if(argc != 3)
14 | {
15 | std::cerr << "Expecting input argument: folder #_of_.pcd_files " << std::endl;
16 | return -1;
17 | }
18 |
19 | pcl::PointCloud concatenated_cloud;
20 |
21 | std::ostringstream oss;
22 | oss << argv[1] << "point_cloud_";
23 |
24 | std::istringstream ss(argv[2]);
25 | int x;
26 | if(!(ss >> x)) {
27 | std::cerr << "Invalid number: " << argv[1] << '\n';
28 | }
29 | else if (!ss.eof()) {
30 | std::cerr << "Trailing characters after number: " << argv[1] << '\n';
31 | }
32 |
33 | for(int i = 1; i <= x; i++) {
34 | std::cout << "Count: " << i << std::endl;
35 | std::ostringstream oss2;
36 | oss2 << oss.str() << i << ".pcd";
37 | pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud);
38 | if(pcl::io::loadPCDFile (oss2.str(), *temp_cloud) == -1)
39 | {
40 | PCL_ERROR("Couldn't read file ");
41 | PCL_ERROR(oss.str().c_str());
42 | PCL_ERROR("\n");
43 | return (-1);
44 | }
45 |
46 | concatenated_cloud += *temp_cloud;
47 | }
48 |
49 | std::cout << "Done concatenating." << std::endl;
50 | std::cout << "SAVING FILE! DO NOT EXIT YET!" << std::endl;
51 |
52 | pcl::io::savePCDFileASCII("/home/naik/Data/PointCloud/concatenated_cloud.pcd", concatenated_cloud);
53 |
54 | std::cout << "Done saving file." << std::endl;
55 | return 0;
56 | }
57 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/crop_clusters.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | struct Vector3
20 | {
21 | double x;
22 | double y;
23 | double z;
24 | };
25 |
26 | int main(int argc, char** argv)
27 | {
28 | if(argc != 3)
29 | {
30 | std::cerr << "point_cloud_file clusters_file" << std::endl;
31 | return -1;
32 | }
33 |
34 | pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud);
35 | if(pcl::io::loadPCDFile (argv[1], *temp_cloud) == -1)
36 | {
37 | PCL_ERROR("Couldn't read file ");
38 | PCL_ERROR(argv[2]);
39 | PCL_ERROR("\n");
40 | return (-1);
41 | }
42 |
43 | pcl::PointCloud::Ptr bodyFiltered(new pcl::PointCloud);
44 |
45 | std::ifstream infile2(argv[2]);
46 | std::string line;
47 | int linecount = 0;
48 | while(std::getline(infile2, line))
49 | {
50 | if(linecount == 0)
51 | {
52 | linecount++;
53 | continue;
54 | }
55 | std::istringstream s(line);
56 | std::string field;
57 | int fieldcount = 0;
58 | int clustercount = -1;
59 | double rotation = -1;
60 | double height = -1;
61 | double width = -1;
62 | double box_x = -1;
63 | double box_y = -1;
64 | while(getline(s, field, ','))
65 | {
66 | if(fieldcount == 0)
67 | clustercount = std::atoi(field.c_str());
68 | else if(fieldcount == 1)
69 | rotation = std::atof(field.c_str());
70 | else if(fieldcount == 2)
71 | width = std::atof(field.c_str());
72 | else if(fieldcount == 3)
73 | height = std::atof(field.c_str());
74 | else if(fieldcount == 4)
75 | box_x = std::atof(field.c_str());
76 | else if(fieldcount == 5)
77 | box_y = std::atof(field.c_str());
78 | /* std::cout << clustercount << std::endl;
79 | std::cout << rotation << std::endl;
80 | std::cout << width << std::endl;
81 | std::cout << height << std::endl;
82 | std::cout << box_x << std::endl;
83 | std::cout << box_y << std::endl;
84 | */
85 | fieldcount++;
86 | }
87 |
88 | pcl::CropBox boxFilter;
89 | boxFilter.setTranslation(Eigen::Vector3f(box_x, box_y, 0));
90 | boxFilter.setRotation(Eigen::Vector3f(0, 0, rotation));
91 | boxFilter.setMin(Eigen::Vector4f(0 - (height/2), 0 - (width/2), -100, 1.0));
92 | boxFilter.setMax(Eigen::Vector4f(0 + (height/2), 0 + (width/2), 100, 1.0));
93 | boxFilter.setInputCloud(temp_cloud);
94 | boxFilter.filter(*bodyFiltered);
95 |
96 | std::ostringstream oss;
97 | oss << "/home/naik/Data/clusters/point_cloud_" << clustercount + 1 << ".pcd";
98 | pcl::io::savePCDFileASCII(oss.str(), *bodyFiltered);
99 |
100 |
101 | }
102 |
103 | return 0;
104 | }
105 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/dji_tf_broadcast.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 | #include
10 | void callback(const geometry_msgs::PointStampedConstPtr& position_data, const geometry_msgs::QuaternionStampedConstPtr& attitude_data) {
11 |
12 | std::cout << "Position Data: " << position_data->point.x << " " << position_data->point.y << " " << position_data->point.z << std::endl;
13 | std::cout << "Attitude Data: " << attitude_data->quaternion.x << " " << attitude_data->quaternion.y << " " << attitude_data->quaternion.z << " " << attitude_data->quaternion.w << std::endl;
14 | static tf::TransformBroadcaster br;
15 | tf::Transform transform;
16 | transform.setOrigin( tf::Vector3(position_data->point.x, position_data->point.y, position_data->point.z));
17 | tf::Quaternion q(attitude_data->quaternion.x, attitude_data->quaternion.y, attitude_data->quaternion.z, attitude_data->quaternion.w);
18 | transform.setRotation(q);
19 | br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", "dji"));
20 | }
21 |
22 | int main(int argc, char** argv){
23 | ros::init(argc, argv, "dji_tf_broadcaster");
24 |
25 | ros::NodeHandle nh;
26 |
27 | message_filters::Subscriber position_sub(nh, "/dji_sdk/local_position", 1);
28 | message_filters::Subscriber attitude_sub(nh, "/dji_sdk/attitude", 1);
29 |
30 | typedef message_filters::sync_policies::ApproximateTime MySyncPolicy;
31 | // ApproximateTime takes a queue size as its constructor argument, hence MySyncPolicy(10)
32 | message_filters::Synchronizer sync(MySyncPolicy(10), position_sub, attitude_sub);
33 | sync.registerCallback(boost::bind(&callback, _1, _2));
34 |
35 | ros::spin();
36 | return 0;
37 | };
--------------------------------------------------------------------------------
/point_cloud_processing/src/fill_clusters.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | unsigned int microseconds = 10000;
18 |
19 | int main(int argc, char** argv)
20 | {
21 | std::list > cluster_list;
22 | if(argc != 3)
23 | {
24 | std::cerr << "Expecting input argument: folder #_of_.pcd_files " << std::endl;
25 | return -1;
26 | }
27 |
28 | std::ostringstream oss;
29 | oss << argv[1] << "cluster_";
30 |
31 | std::istringstream ss(argv[2]);
32 | int x;
33 | if(!(ss >> x)) {
34 | std::cerr << "Invalid number: " << argv[1] << '\n';
35 | }
36 | else if (!ss.eof()) {
37 | std::cerr << "Trailing characters after number: " << argv[1] << '\n';
38 | }
39 |
40 | pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
41 | viewer->setBackgroundColor (0, 0, 0);
42 | viewer->addCoordinateSystem (1.0);
43 | viewer->initCameraParameters ();
44 | viewer->setCameraPosition(0, 0, 43, 0, 0, 0, 0, 0, 0);
45 | for(int i = 0; i < x; i++) {
46 | std::cout << "Count: " << i << std::endl;
47 | std::ostringstream oss2;
48 | oss2 << oss.str() << i << ".pcd";
49 | pcl::PointCloud cloud;
50 | if(pcl::io::loadPCDFile (oss2.str(), cloud) == -1)
51 | {
52 | PCL_ERROR("Couldn't read file ");
53 | PCL_ERROR(oss.str().c_str());
54 | PCL_ERROR("\n");
55 | return (-1);
56 | }
57 | cluster_list.push_back(cloud);
58 | }
59 |
60 | int count = 0;
61 | std::list >::iterator it;
62 | for(it = cluster_list.begin(); it != cluster_list.end(); ++it) {
63 | pcl::PointCloud::Ptr cloud(new pcl::PointCloud);
64 | pcl::copyPointCloud(*it, *cloud);
65 |
66 | std::ostringstream cluster_number;
67 | cluster_number << "cluster " << count;
68 | std::ostringstream obb_number;
69 | obb_number << "obb " << count;
70 |
71 | double average = 0;
72 | for(size_t i = 0; i < cloud->points.size(); i++)
73 | {
74 | average += cloud->points[i].z;
75 | }
76 | average /= cloud->points.size();
77 |
78 | for(size_t i = 0; i < cloud->points.size(); i++)
79 | {
80 | cloud->points[i].z = average;
81 | }
82 |
83 | pcl::MomentOfInertiaEstimation feature_extractor;
84 | feature_extractor.setInputCloud (cloud);
85 | feature_extractor.compute ();
86 |
87 | std::vector moment_of_inertia;
88 | std::vector eccentricity;
89 | pcl::PointXYZ min_point_OBB;
90 | pcl::PointXYZ max_point_OBB;
91 | pcl::PointXYZ position_OBB;
92 | Eigen::Matrix3f rotational_matrix_OBB;
93 | float major_value, middle_value, minor_value;
94 | Eigen::Vector3f major_vector, middle_vector, minor_vector;
95 | Eigen::Vector3f mass_center;
96 |
97 | feature_extractor.getMomentOfInertia (moment_of_inertia);
98 | feature_extractor.getEccentricity (eccentricity);
99 | feature_extractor.getOBB (min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
100 | feature_extractor.getEigenValues (major_value, middle_value, minor_value);
101 | feature_extractor.getEigenVectors (major_vector, middle_vector, minor_vector);
102 | feature_extractor.getMassCenter (mass_center);
103 |
104 |
105 | viewer->addPointCloud (cloud, cluster_number.str());
106 |
107 | Eigen::Vector3f position (position_OBB.x, position_OBB.y, position_OBB.z);
108 | Eigen::Quaternionf quat (rotational_matrix_OBB);
109 | //viewer->addCube (position, quat, max_point_OBB.x - min_point_OBB.x, max_point_OBB.y - min_point_OBB.y, max_point_OBB.z - min_point_OBB.z, obb_number.str());
110 |
111 | count++;
112 | }
113 |
114 | std::ifstream average_file ("/home/user01/Data/averages.csv");
115 | std::string value;
116 | int count2 = 0;
117 | double orientation_average = -1.0;
118 | double width_average = -1.0;
119 | double height_average = -1.0;
120 |
121 | while(average_file.good()) {
122 | getline(average_file, value, ',');
123 | std::cout << value << std::endl;
124 | if(count2 == 0) {
125 | orientation_average = std::atof(value.c_str());
126 | }
127 | else if(count2 == 1) {
128 | width_average = std::atof(value.c_str());
129 | }
130 | else if(count2 == 2) {
131 | height_average = std::atof(value.c_str());
132 | }
133 | count2++;
134 | }
135 |
136 | orientation_average += 0.03;
137 | height_average -= 0.4;
138 | float roll = 0, pitch = 0, yaw = orientation_average;
139 | Eigen::Quaternionf q;
140 | q = Eigen::AngleAxisf(roll, Eigen::Vector3f::UnitX())
141 | * Eigen::AngleAxisf(pitch, Eigen::Vector3f::UnitY())
142 | * Eigen::AngleAxisf(yaw, Eigen::Vector3f::UnitZ());
143 |
144 | std::ofstream cluster_file;
145 | cluster_file.open("/home/user01/Data/correct_clusters_params.csv");
146 | cluster_file << "Cluster #,Rotation,Height,Width,X,Y\n";
147 | int cluster_count = 0;
148 | for(count2 = 0; count2 < 28; count2++)
149 | {
150 | std::ostringstream cube_number;
151 | cube_number << "cube_" << count2;
152 | double width = -10.54 + (count2 * 1.122222);
153 | double height = -18.07222222222 + (count2 * 0.955555);
154 | Eigen::Vector3f position (width, height, 0);
155 | viewer->addCube (position, q, width_average, height_average, 0, cube_number.str());
156 | cluster_file << cluster_count << "," << orientation_average << "," << height_average << "," << width_average
157 | << "," << width << "," << height << "\n";
158 | cluster_count++;
159 | for(int i = 1; i < 4; i++) {
160 | cube_number << "_" << i;
161 | double width2 = width + (i * -3.25);
162 | double height2 = height + (i * 3.85);
163 | Eigen::Vector3f position2 (width2, height2, 0);
164 | viewer->addCube (position2, q, width_average, height_average, 0, cube_number.str());
165 | cluster_file << cluster_count << "," << orientation_average << "," << height_average << "," << width_average
166 | << "," << width2 << "," << height2 << "\n";
167 | cluster_count++;
168 | }
169 | }
170 |
171 | cluster_file.close();
172 |
173 | // Eigen::Vector3f position (10.9, 6.8, 0);
174 | // //Eigen::Quaternionf quat (rotational_matrix_OBB);
175 | // viewer->addCube (position, q, width_average, height_average, 0, "test");
176 | // Eigen::Vector3f position2 (0.8, -1.8, 0);
177 | // //Eigen::Quaternionf quat (rotational_matrix_OBB);
178 | // viewer->addCube (position2, q, width_average, height_average, 0, "test2");
179 | // Eigen::Vector3f position3 (8.656, 4.89, 0);
180 | // //Eigen::Quaternionf quat (rotational_matrix_OBB);
181 | // viewer->addCube (position3, q, width_average, height_average, 0, "test3");
182 |
183 | unsigned int microseconds = 100000;
184 |
185 | while(!viewer->wasStopped ())
186 | {
187 | viewer->spinOnce (100);
188 | usleep(microseconds);
189 | }
190 |
191 | return (0);
192 | }
193 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/icp.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 |
8 | int main (int argc, char** argv)
9 | {
10 | if(argc != 3)
11 | {
12 | std::cerr << "Expecting input argument: folder #_of_.pcd_files " << std::endl;
13 | return -1;
14 | }
15 |
16 | std::ostringstream oss;
17 | oss << argv[1] << "point_cloud_";
18 |
19 | std::istringstream ss(argv[2]);
20 | int x;
21 | if(!(ss >> x)) {
22 | std::cerr << "Invalid number: " << argv[1] << '\n';
23 | }
24 | else if (!ss.eof()) {
25 | std::cerr << "Trailing characters after number: " << argv[1] << '\n';
26 | }
27 |
28 | pcl::PointCloud::Ptr Final(new pcl::PointCloud);
29 | std::ostringstream oss2;
30 | oss2 << oss.str() << 1 << ".pcd";
31 | if(pcl::io::loadPCDFile (oss2.str(), *Final) == -1)
32 | {
33 | PCL_ERROR("Couldn't read file ");
34 | PCL_ERROR(oss.str().c_str());
35 | PCL_ERROR("\n");
36 | return (-1);
37 | }
38 | pcl::IterativeClosestPoint icp;
39 | pcl::visualization::CloudViewer viewer ("Simple Cloud Viewer");
40 |
41 | for(int i = 2; i <= x; i++) {
42 | std::cout << "Count: " << i << std::endl;
43 | std::ostringstream oss2;
44 | oss2 << oss.str() << i << ".pcd";
45 | pcl::PointCloud::Ptr cloud_out(new pcl::PointCloud);
46 | if(pcl::io::loadPCDFile (oss2.str(), *cloud_out) == -1)
47 | {
48 | PCL_ERROR("Couldn't read file ");
49 | PCL_ERROR(oss.str().c_str());
50 | PCL_ERROR("\n");
51 | return (-1);
52 | }
53 | icp.setInputSource(Final);
54 | icp.setInputTarget(cloud_out);
55 | icp.align(*Final);
56 | std::cout << "has converged:" << icp.hasConverged() << " score: " <<
57 | icp.getFitnessScore() << std::endl;
58 | std::cout << icp.getFinalTransformation() << std::endl;
59 | viewer.showCloud(Final);
60 | }
61 |
62 | return (0);
63 | }
--------------------------------------------------------------------------------
/point_cloud_processing/src/known_ground_plane_max_height_estimate.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | struct Vector3
19 | {
20 | double x;
21 | double y;
22 | double z;
23 | };
24 |
25 | int main(int argc, char** argv)
26 | {
27 | if(argc != 3)
28 | {
29 | std::cerr << "ground_plane_file point_cloud_file" << std::endl;
30 | return -1;
31 | }
32 |
33 | double distance_threshold = 0;
34 |
35 | pcl::PointCloud::Ptr ground_plane(new pcl::PointCloud);
36 | if(pcl::io::loadPCDFile (argv[1], *ground_plane) == -1)
37 | {
38 | PCL_ERROR("Couldn't read file ");
39 | PCL_ERROR(argv[1]);
40 | PCL_ERROR("\n");
41 | return (-1);
42 | }
43 |
44 | pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud);
45 | if(pcl::io::loadPCDFile (argv[2], *temp_cloud) == -1)
46 | {
47 | PCL_ERROR("Couldn't read file ");
48 | PCL_ERROR(argv[2]);
49 | PCL_ERROR("\n");
50 | return (-1);
51 | }
52 |
53 | Vector3 sum;
54 | sum.x = 0;
55 | sum.y = 0;
56 | sum.z = 0;
57 | for(size_t i = 0; i < ground_plane->points.size(); i++)
58 | {
59 | sum.x += ground_plane->points[i].x;
60 | sum.y += ground_plane->points[i].y;
61 | sum.z += ground_plane->points[i].z;
62 | }
63 |
64 | Vector3 centroid;
65 | centroid.x = sum.x / ground_plane->points.size();
66 | centroid.y = sum.y / ground_plane->points.size();
67 | centroid.z = sum.z / ground_plane->points.size();
68 |
69 | double xx = 0.0;
70 | double xy = 0.0;
71 | double xz = 0.0;
72 | double yy = 0.0;
73 | double yz = 0.0;
74 | double zz = 0.0;
75 |
76 | for(size_t i = 0; i < ground_plane->points.size(); i++)
77 | {
78 |
79 | Vector3 r;
80 | r.x = ground_plane->points[i].x - centroid.x;
81 | r.y = ground_plane->points[i].y - centroid.y;
82 | r.z = ground_plane->points[i].z - centroid.z;
83 | xx += r.x * r.x;
84 | xy += r.x * r.y;
85 | xz += r.x * r.z;
86 | yy += r.y * r.y;
87 | yz += r.y * r.z;
88 | zz += r.z * r.z;
89 | }
90 |
91 | double det_x = yy*zz - yz*yz;
92 | double det_y = xx*zz - xz*xz;
93 | double det_z = xx*yy - xy*xy;
94 |
95 | double max = det_x;
96 | int max_letter = 1;
97 | if(det_y > max)
98 | {
99 | max = det_y;
100 | max_letter = 2;
101 | }
102 | if(det_z > max)
103 | {
104 | max = det_z;
105 | max_letter = 3;
106 | }
107 |
108 | Vector3 dir;
109 | if(max_letter == 1)
110 | {
111 | dir.x = det_x;
112 | dir.y = xz*yz - xy*zz;
113 | dir.z = xy*yz - xz*yy;
114 | }
115 | else if(max_letter == 2)
116 | {
117 | dir.x = xz*yz - xy*zz;
118 | dir.y = det_y;
119 | dir.z = xy*xz - yz*xx;
120 | }
121 | else if(max_letter == 3)
122 | {
123 | dir.x = xy*yz - xz*yy;
124 | dir.y = xy*xz - yz*xx;
125 | dir.z = det_z;
126 | }
127 |
128 | double length = (dir.x * dir.x) + (dir.y * dir.y) + (dir.z * dir.z);
129 | length = sqrt(length);
130 |
131 | dir.x = dir.x / length;
132 | dir.y = dir.y / length;
133 | dir.z = dir.z / length;
134 |
135 | double distance = 0;
136 | Vector3 subtract;
137 | Vector3 point_max;
138 | int index = -1;
139 | for(size_t i = 0; i < temp_cloud->points.size(); i++)
140 | {
141 | double temp_distance = 0;
142 | subtract.x = temp_cloud->points[i].x - centroid.x;
143 | subtract.y = temp_cloud->points[i].y - centroid.y;
144 | subtract.z = temp_cloud->points[i].z - centroid.z;
145 | temp_distance = (dir.x * subtract.x) + (dir.y * subtract.y) + (dir.z * subtract.z);
146 |
147 | std::cout << temp_distance << std::endl;
148 | //std::cout << subtract.y << std::endl;
149 | //std::cout << subtract.z << std::endl;
150 | //std::cout << yy << std::endl;
151 | //std::cout << yz << std::endl;
152 | double mag_dist = std::abs(temp_distance);
153 | if(mag_dist > distance) {
154 | distance = mag_dist;
155 | point_max.x = temp_cloud->points[i].x;
156 | point_max.y = temp_cloud->points[i].y;
157 | point_max.z = temp_cloud->points[i].z;
158 | index = i;
159 | }
160 | }
161 |
162 | std::cerr << "Max distance in frame(meters): " << distance << " meters." << std::endl;
163 | std::cerr << "Max distance in frame(inches): " << (distance * 39.3701) << " inches." << std::endl;
164 |
165 | pcl::visualization::CloudViewer viewer ("Simple Cloud Viewer");
166 | viewer.showCloud(ground_plane);
167 | while(!viewer.wasStopped ())
168 | {
169 | }
170 |
171 | return 0;
172 | }
173 |
--------------------------------------------------------------------------------
/point_cloud_processing/src/map_height.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include