1 #include <iostream>
2 #include <cstring>
3 #ifdef _MSC_VER
4 #  include "vcl_msvc_warnings.h"
5 #endif
6 
7 #include "vgl/vgl_box_2d.h"
8 #include "vgl/vgl_box_3d.h"
9 #include "vgl/vgl_point_2d.h"
10 #include "vgl/vgl_point_3d.h"
11 #include <vsol/vsol_box_2d.h>
12 
13 #include <vil/vil_config.h>  // for HAS_GEOTIFF definition
14 #include "vil/vil_load.h"
15 #include "vil/vil_image_resource.h"
16 #include <vil/file_formats/vil_tiff.h>
17 
18 #include <bprb/bprb_parameters.h>
19 #include <bprb/bprb_func_process.h>
20 
21 #include "vpgl/vpgl_lvcs.h"
22 #include <vpgl/file_formats/vpgl_geo_camera.h>
23 
24 #include <brip/brip_roi.h>
25 #include <brdb/brdb_value.h>
26 #include <bmdl/bmdl_classify.h>
27 
28 template<class T>
corners_of_box_3d(vgl_box_3d<T> box)29 std::vector<vgl_point_3d<T> > corners_of_box_3d(vgl_box_3d<T> box)
30 {
31   std::vector<vgl_point_3d<T> > corners;
32 
33   corners.push_back(box.min_point());
34   corners.push_back(vgl_point_3d<T> (box.min_x()+box.width(), box.min_y(), box.min_z()));
35   corners.push_back(vgl_point_3d<T> (box.min_x()+box.width(), box.min_y()+box.height(), box.min_z()));
36   corners.push_back(vgl_point_3d<T> (box.min_x(), box.min_y()+box.height(), box.min_z()));
37   corners.push_back(vgl_point_3d<T> (box.min_x(), box.min_y(), box.max_z()));
38   corners.push_back(vgl_point_3d<T> (box.min_x()+box.width(), box.min_y(), box.max_z()));
39   corners.push_back(box.max_point());
40   corners.push_back(vgl_point_3d<T> (box.min_x(), box.min_y()+box.height(), box.max_z()));
41   return corners;
42 }
43 
compute_ground(const vil_image_resource_sptr & ground,const vil_image_view_base_sptr & first_roi,const vil_image_view_base_sptr & last_roi,vil_image_view_base_sptr & ground_roi)44 bool compute_ground(const vil_image_resource_sptr& ground,
45                     const vil_image_view_base_sptr& first_roi,
46                     const vil_image_view_base_sptr& last_roi,
47                     vil_image_view_base_sptr& ground_roi)
48 {
49   if (ground == nullptr)
50   {
51     if ((first_roi->pixel_format() == VIL_PIXEL_FORMAT_FLOAT) &&
52         (last_roi->pixel_format() == VIL_PIXEL_FORMAT_FLOAT)) {
53       auto* ground_view = new vil_image_view<float>();
54       vil_image_view<float> first_view(first_roi);
55       vil_image_view<float> last_view(last_roi);
56       bmdl_classify<float> classifier;
57       classifier.set_lidar_data(first_view, last_view);
58       classifier.estimate_bare_earth();
59       ground_view->deep_copy(classifier.bare_earth());
60       ground_roi = ground_view;
61     }
62     else if ((first_roi->pixel_format() == VIL_PIXEL_FORMAT_DOUBLE) &&
63              (last_roi->pixel_format() == VIL_PIXEL_FORMAT_DOUBLE)) {
64       auto* ground_view = new vil_image_view<double>();
65       vil_image_view<double> first_view(first_roi);
66       vil_image_view<double> last_view(last_roi);
67       bmdl_classify<double> classifier;
68       classifier.set_lidar_data(first_view, last_view);
69       classifier.estimate_bare_earth();
70       ground_view->deep_copy(classifier.bare_earth());
71       ground_roi = ground_view;
72     }
73     else {
74       std::cout << "input images have different bit depths" << std::endl;
75       return false;
76     }
77   }
78   return true;
79 }
80 
81 
lidar_roi(unsigned type,const vil_image_resource_sptr & lidar_first,const vil_image_resource_sptr & lidar_last,const vil_image_resource_sptr & ground,float min_lat,float min_lon,float max_lat,float max_lon,vil_image_view_base_sptr & first_roi,vil_image_view_base_sptr & last_roi,vil_image_view_base_sptr & ground_roi,vpgl_geo_camera * & camera)82 bool lidar_roi(unsigned type,  //0 for geo coordinates, 1 for image coord
83                const vil_image_resource_sptr& lidar_first,
84                const vil_image_resource_sptr& lidar_last,
85                const vil_image_resource_sptr& ground,
86                float min_lat, float min_lon,
87                float max_lat, float max_lon,
88                vil_image_view_base_sptr& first_roi,
89                vil_image_view_base_sptr& last_roi,
90                vil_image_view_base_sptr& ground_roi,
91                vpgl_geo_camera*& camera)
92 {
93   // the file should be at least a tiff (better, geotiff)
94   if (std::strcmp(lidar_first->file_format(), "tiff") != 0 &&
95       std::strcmp(lidar_last->file_format(),"tiff") != 0) {
96     std::cout << "bmdl_lidar_roi_process::lidar_roi -- The lidar images should be a TIFF!\n";
97     return false;
98   }
99 
100 #if HAS_GEOTIFF
101   auto* tiff_first = static_cast<vil_tiff_image*> (lidar_first.ptr());
102   auto* tiff_last  = static_cast<vil_tiff_image*> (lidar_last.ptr());
103 
104   if (vpgl_geo_camera::init_geo_camera(tiff_first, nullptr, camera))
105   {
106     vgl_box_2d<double> roi_box;
107 
108     if (type == 0)    // geographic coordinates
109     {
110       // backproject the 3D world coordinates on the image
111       vgl_point_3d<double> min_pos(min_lon, min_lat, 0);
112       vgl_point_3d<double> max_pos(max_lon, max_lat, 30);
113       vgl_box_3d<double> world(min_pos, max_pos);
114       std::vector<vgl_point_3d<double> > corners = corners_of_box_3d<double>(world);
115       for (auto & corner : corners) {
116         double x = corner.x();
117         double y = corner.y();
118         double z = corner.z();
119         double lx, ly, lz;
120         camera->lvcs()->global_to_local(x, y, z,vpgl_lvcs::wgs84, lx, ly, lz);
121         double u,v;
122         camera->project(lx,ly,lz,u,v);
123         vgl_point_2d<double> p(u,v);
124         roi_box.add(p);
125       }
126     }
127     else if (type == 1) {
128       roi_box.add(vgl_point_2d<double> (min_lat, min_lon));
129       roi_box.add(vgl_point_2d<double> (max_lat, max_lon));
130     }
131 
132     brip_roi broi(tiff_first->ni(), tiff_first->nj());
133     vsol_box_2d_sptr bb = new vsol_box_2d();
134     bb->add_point(roi_box.min_x(), roi_box.min_y());
135     bb->add_point(roi_box.max_x(), roi_box.max_y());
136 
137     bb = broi.clip_to_image_bounds(bb);
138     //std::cout << "Cut out area------>" << std::endl;
139     //std::cout << *bb << std::endl;
140     first_roi = tiff_first->get_copy_view((unsigned int)bb->get_min_x(),
141                                           (unsigned int)bb->width(),
142                                           (unsigned int)bb->get_min_y(),
143                                           (unsigned int)bb->height());
144 
145     last_roi = tiff_last->get_copy_view((unsigned int)bb->get_min_x(),
146                                         (unsigned int)bb->width(),
147                                         (unsigned int)bb->get_min_y(),
148                                         (unsigned int)bb->height());
149 
150     // if no ground input, create an estimated one
151     if (ground == nullptr) {
152       compute_ground(ground, first_roi, last_roi, ground_roi);
153     }
154     else {   // crop the given one
155       ground_roi = ground->get_copy_view((unsigned int)bb->get_min_x(),
156                                          (unsigned int)bb->width(),
157                                          (unsigned int)bb->get_min_y(),
158                                          (unsigned int)bb->height());
159     }
160 
161     //add the translation to the camera
162     double ox = bb->get_min_x();
163     double oy = bb->get_min_y();
164     double elev = 0;
165     if (ground_roi->pixel_format() == VIL_PIXEL_FORMAT_FLOAT) {
166       vil_image_view<float> ground_view(ground_roi);
167       elev = ground_view(0,0);
168     }
169     else if (ground_roi->pixel_format() == VIL_PIXEL_FORMAT_DOUBLE) {
170       vil_image_view<double> ground_view(ground_roi);
171       elev = ground_view(0,0);
172     }
173     camera->translate(ox, oy, elev);
174 
175     if (!first_roi) {
176       std::cout << "bmdl_lidar_roi_process::lidar_init()-- clipping box is out of image boundaries\n";
177       return false;
178     }
179   }
180   else {
181     std::cout << "bmdl_lidar_roi_process::lidar_init()-- Only ProjectedCSTypeGeoKey=PCS_WGS84_UTM_zoneXX_X is defined rigth now, please define yours!!" << std::endl;
182     return false;
183   }
184 
185   return true;
186 #else // if !HAS_GEOTIFF
187   std::cout << "bmdl_lidar_roi_process::lidar_init()-- GEOTIFF lib is needed to run bmdl_lidar_roi_process--\n";
188   return false;
189 #endif // HAS_GEOTIFF
190 
191   return true;
192 }
193 
bmdl_lidar_roi_process(bprb_func_process & pro)194 bool bmdl_lidar_roi_process(bprb_func_process& pro)
195 {
196   if (pro.n_inputs()< 8) {
197     std::cout << "lidar_roi_process: The input number should be 8" << std::endl;
198     return false;
199   }
200 
201   unsigned int i=0;
202   std::string first = pro.get_input<std::string>(i++);
203   std::string last = pro.get_input<std::string>(i++);
204   std::string ground = pro.get_input<std::string>(i++);
205   auto min_lat = pro.get_input<float>(i++);
206   auto min_lon = pro.get_input<float>(i++);
207   auto max_lat = pro.get_input<float>(i++);
208   auto max_lon = pro.get_input<float>(i++);
209   auto type = pro.get_input<unsigned>(i++);
210 
211   // check first return's validity
212   vil_image_resource_sptr first_ret = vil_load_image_resource(first.c_str());
213   if (!first_ret) {
214     std::cout << "bmdl_lidar_roi_process -- First return image path is not valid!\n";
215     return false;
216   }
217 
218   // check last return's validity
219   vil_image_resource_sptr last_ret = vil_load_image_resource(last.c_str());
220   if (!last_ret) {
221     std::cout << "bmdl_lidar_roi_process -- Last return image path is not valid!\n";
222     return false;
223   }
224 
225   // Ground image path can be invalid or empty, in that case an estimated ground will be computed
226   vil_image_resource_sptr ground_img =nullptr;
227   if (ground.size() > 0) {
228     ground_img = vil_load_image_resource(ground.c_str());
229   }
230 
231   vil_image_view_base_sptr first_roi=nullptr, last_roi=nullptr, ground_roi;
232   vpgl_geo_camera* lidar_cam =nullptr;
233   if (!lidar_roi(type, first_ret, last_ret, ground_img,
234     min_lat, min_lon, max_lat, max_lon, first_roi, last_roi, ground_roi, lidar_cam)) {
235     std::cout << "bmdl_lidar_roi_process -- The process has failed!\n";
236     return false;
237   }
238 
239   unsigned j=0;
240   // store image output (first return roi)
241   pro.set_output_val<vil_image_view_base_sptr>(j++, first_roi);
242 
243   // store image output (last return roi)
244   pro.set_output_val<vil_image_view_base_sptr>(j++,last_roi);
245 
246   // store image output (ground roi)
247   pro.set_output_val<vil_image_view_base_sptr>(j++,ground_roi);
248 
249   // store the camera (camera of first return is sufficient)
250   pro.set_output_val<vpgl_camera_double_sptr >(j++, lidar_cam);
251 
252   return true;
253 }
254 
bmdl_lidar_roi_process_cons(bprb_func_process & pro)255 bool bmdl_lidar_roi_process_cons(bprb_func_process& pro)
256 {
257   bool ok=false;
258   std::vector<std::string> input_types;
259   input_types.emplace_back("vcl_string");
260   input_types.emplace_back("vcl_string");
261   input_types.emplace_back("vcl_string");
262   input_types.emplace_back("float");
263   input_types.emplace_back("float");
264   input_types.emplace_back("float");
265   input_types.emplace_back("float");
266   input_types.emplace_back("unsigned");
267   ok = pro.set_input_types(input_types);
268   if (!ok) return ok;
269 
270   std::vector<std::string> output_types;
271   output_types.emplace_back("vil_image_view_base_sptr"); // label image
272   output_types.emplace_back("vil_image_view_base_sptr"); // height image
273   output_types.emplace_back("vil_image_view_base_sptr"); // ground roi
274   output_types.emplace_back("vpgl_camera_double_sptr");  // lvcs
275   ok = pro.set_output_types(output_types);
276   if (!ok) return ok;
277 
278   return true;
279 }
280