libeblearntools
|
00001 /*************************************************************************** 00002 * Copyright (C) 2010 by Pierre Sermanet * 00003 * pierre.sermanet@gmail.com * 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are met: 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Redistribution under a license not approved by the Open Source 00014 * Initiative (http://www.opensource.org) must display the 00015 * following acknowledgement in all advertising material: 00016 * This product includes software developed at the Courant 00017 * Institute of Mathematical Sciences (http://cims.nyu.edu). 00018 * * The names of the authors may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00023 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00024 * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY 00025 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00026 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00027 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00028 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00029 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 ***************************************************************************/ 00032 00033 #ifndef TRACKING_THREAD_HPP_ 00034 #define TRACKING_THREAD_HPP_ 00035 00036 #include <map> 00037 #include <string> 00038 #include <iostream> 00039 #include <algorithm> 00040 #include <vector> 00041 #include <stdlib.h> 00042 #include <sstream> 00043 #include <iomanip> 00044 #include <time.h> 00045 #include "libeblearn.h" 00046 00047 #ifdef __GUI__ 00048 #include "libeblearngui.h" 00049 #endif 00050 00051 using namespace std; 00052 00053 namespace ebl { 00054 00056 // tracking thread 00057 00058 template <typename Tnet> 00059 tracking_thread<Tnet>::tracking_thread(configuration &conf_, 00060 const char *arg2_) 00061 : conf(conf_), arg2(arg2_), mutex_out(), 00062 out_updated(false), dt(conf, arg2_), tpl(10, 10, 1) { 00063 dt.start(); 00064 } 00065 00066 template <typename Tnet> 00067 tracking_thread<Tnet>::~tracking_thread() { 00068 } 00069 00070 template <typename Tnet> 00071 void tracking_thread<Tnet>::copy_bboxes(vector<bbox*> &bb) { 00072 // lock data 00073 pthread_mutex_lock(&mutex_out); 00074 // clear bboxes 00075 bboxes.clear(); 00076 // copy bboxes 00077 for (ibox = bb.begin(); ibox != bb.end(); ++ibox) { 00078 bboxes.push_back(new bbox(**ibox)); 00079 } 00080 // unlock data 00081 pthread_mutex_unlock(&mutex_out); 00082 } 00083 00084 template <typename Tnet> 00085 void tracking_thread<Tnet>::set_out_updated() { 00086 // lock data 00087 pthread_mutex_lock(&mutex_out); 00088 // set flag 00089 out_updated = true; 00090 // unlock data 00091 pthread_mutex_unlock(&mutex_out); 00092 } 00093 00094 template <typename Tnet> 00095 bool tracking_thread<Tnet>::get_data(vector<bbox*> &bboxes2, 00096 idx<ubyte> &frame2, idx<ubyte> &tpl2) { 00097 // lock data 00098 pthread_mutex_lock(&mutex_out); 00099 // only read data if it has been updated 00100 if (!out_updated) { 00101 // unlock data 00102 pthread_mutex_unlock(&mutex_out); 00103 return false; 00104 } 00105 // clear bboxes 00106 for (ibox = bboxes2.begin(); ibox != bboxes2.end(); ++ibox) { 00107 if (*ibox) 00108 delete *ibox; 00109 } 00110 bboxes2.clear(); 00111 // copy bboxes pointers (now responsible for deleting them). 00112 for (ibox = bboxes.begin(); ibox != bboxes.end(); ++ibox) { 00113 bboxes2.push_back(*ibox); 00114 } 00115 // check frame is correctly allocated, if not, allocate. 00116 if (frame2.order() != frame.order()) 00117 frame2 = idx<ubyte>(frame.get_idxdim()); 00118 else if (frame2.get_idxdim() != frame.get_idxdim()) 00119 frame2.resize(frame.get_idxdim()); 00120 // copy frame 00121 idx_copy(frame, frame2); 00122 // check tpl is correctly allocated, if not, allocate. 00123 if (tpl2.order() != tpl.order()) 00124 tpl2 = idx<ubyte>(tpl.get_idxdim()); 00125 else if (tpl2.get_idxdim() != tpl.get_idxdim()) 00126 tpl2.resize(tpl.get_idxdim()); 00127 // copy tpl 00128 idx_copy(tpl, tpl2); 00129 // reset updated flag 00130 out_updated = false; 00131 // unlock data 00132 pthread_mutex_unlock(&mutex_out); 00133 // confirm that we copied data. 00134 return true; 00135 } 00136 00137 template <typename Tnet> 00138 void tracking_thread<Tnet>::draw(bbox *b) { 00139 #ifdef __GUI__ 00140 disable_window_updates(); 00141 clear_window(); 00142 draw_matrix(frame, "in"); 00143 draw_matrix(tpl, "tpl", 0, frame.dim(1)); 00144 if (b) { 00145 ubyte red = 0, green = 0, blue = 0; 00146 if (b->class_id == -42) 00147 green = 255; 00148 else 00149 blue = 255; 00150 draw_box(b->h0, b->w0, b->width, b->height, red, green, blue); 00151 } 00152 enable_window_updates(); 00153 #endif 00154 } 00155 00156 template <typename Tnet> 00157 void tracking_thread<Tnet>::execute() { 00158 try { 00159 // configuration 00160 string cam_type = conf.get_string("camera"); 00161 int height = conf.get_int("input_height"); 00162 int width = conf.get_int("input_width"); 00163 bool save_video = conf.exists_bool("save_video"); 00164 bool display = conf.exists_bool("tracking_display"); 00165 // initialize camera (opencv, directory, shmem or video) 00166 camera<ubyte> *cam = NULL; 00167 if (!strcmp(cam_type.c_str(), "directory")) { 00168 if (arg2) cam = new camera_directory<ubyte>(arg2, height,width); 00169 else eblerror("expected 2nd argument"); 00170 } else if (!strcmp(cam_type.c_str(), "opencv")) 00171 cam = new camera_opencv<ubyte>(-1, height, width); 00172 #ifdef __LINUX__ 00173 else if (!strcmp(cam_type.c_str(), "v4l2")) 00174 cam = new camera_v4l2<ubyte>(conf.get_cstring("device"), height, width); 00175 #endif 00176 else if (!strcmp(cam_type.c_str(), "shmem")) 00177 cam = new camera_shmem<ubyte>("shared-mem", height, width); 00178 else if (!strcmp(cam_type.c_str(), "video")) { 00179 if (arg2) 00180 cam = new camera_video<ubyte> 00181 (arg2, height, width, conf.get_uint("input_video_sstep"), 00182 conf.get_uint("input_video_max_duration")); 00183 else eblerror("expected 2nd argument"); 00184 } else eblerror("unknown camera type"); 00185 if (save_video) 00186 cam->start_recording(); 00187 // other variables 00188 bool updated = false; 00189 bbox *b = new bbox; 00190 vector<bbox*> bb; 00191 #ifdef __OPENCV__ 00192 IplImage *iplframe = NULL; 00193 IplImage *ipltpl = NULL; 00194 #endif 00195 // main loop 00196 while(!cam->empty()) { 00197 try { 00198 frame = cam->grab(); 00199 // send new frame to vision_thread and check if new data was output 00200 dt.set_data(frame); 00201 updated = dt.get_data(bb, detframe); 00202 // update target position if vision thread ready 00203 if (updated) { 00204 // find bbox with max confidence 00205 if (bb.size() > 0) { 00206 double maxconf = -5.0; 00207 uint maxi = 0; 00208 for (uint i = 0; i < bb.size(); ++i) 00209 if (bb[i]->confidence > maxconf) { 00210 maxconf = bb[i]->confidence; 00211 maxi = i; 00212 } 00213 // cout << "found bbox" << endl; 00214 b = bb[maxi]; 00215 if (b) { 00216 // update template 00217 idx<ubyte> tmptpl = detframe.narrow(0, b->height, b->h0); 00218 tmptpl = tmptpl.narrow(1, b->width, b->w0); 00219 tpl = idx<ubyte>(tmptpl.get_idxdim()); 00220 idx_copy(tmptpl, tpl); 00221 } 00222 } 00223 } else { // tracking (only when we didnt just receive an update) 00224 #ifdef __OPENCV__ 00225 iplframe = idx_to_iplptr(frame); 00226 ipltpl = idx_to_iplptr(tpl); 00227 CvPoint minloc, maxloc; 00228 double minval, maxval; 00229 // vector<CvPoint> found; 00230 // vector<double> confidences; 00231 // FastMatchTemplate(*iplframe, *ipltpl, &found, &confidences, 1, false, 00232 // 5, 1, 15); 00233 // CvRect searchRoi; 00234 // cvSetImageROI( searchImage, searchRoi ); 00235 // vector<CvPoint>::iterator p = found.begin(); 00236 // vector<double>::iterator c = confidences.begin(); 00237 // for ( ; p != found.end() && c != confidences.end(); ++p, ++c) { 00238 // gui << at(p->x, p->y) << *c; 00239 // } 00240 IplImage *tm = cvCreateImage(cvSize(frame.dim(1) - tpl.dim(1) + 1, 00241 frame.dim(0) - tpl.dim(0) + 1 ), 00242 IPL_DEPTH_32F, 1 ); 00243 cvMatchTemplate(iplframe, ipltpl, tm, CV_TM_SQDIFF_NORMED); 00244 cvMinMaxLoc(tm, &minval, &maxval, &minloc, &maxloc, 0); 00245 // gui << at(minloc.y, minloc.x) << "M"; 00246 b->class_id = -42; // tell that this bbox is result of tracking 00247 b->h0 = minloc.y; 00248 b->w0 = minloc.x; 00249 // cout << "maxloc h: " << maxloc.y << " w: " << maxloc.x << " minloc h:" << minloc.y << " w: " << minloc.x << endl; 00250 #endif 00251 } 00252 // make a copy of found bounding boxes 00253 copy_bboxes(bb); 00254 // switch 'updated' flag on to warn we just added new data 00255 set_out_updated(); 00256 // display 00257 if (display) 00258 draw(b); 00259 } catch (string &err) { 00260 cerr << err << endl; 00261 } 00262 } 00263 if (save_video) 00264 cam->stop_recording(conf.exists_bool("use_original_fps") ? 00265 cam->fps() : conf.get_uint("save_video_fps")); 00266 if (cam) delete cam; 00267 } catch(string &err) { eblerror(err.c_str()); } 00268 } 00269 00270 } // end namespace ebl 00271 00272 #endif /* TRACKING_THREAD_HPP_ */