00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <labust/blueview/ImageProcessing.hpp>
00035 #include <labust/blueview/TrackerROI.hpp>
00036 #include <labust/math/uBlasOperations.hpp>
00037
00038 #include <opencv2/imgproc/imgproc.hpp>
00039 #include <opencv2/highgui/highgui.hpp>
00040 #include <boost/numeric/ublas/matrix.hpp>
00041
00042 #define deg2rad M_PI/180;
00043
00044 using namespace labust::blueview;
00045
00046 BVImageProcessor::BVImageProcessor():
00047 roi_len(1.5),
00048 resolution(0),
00049 hasVehicle(false),
00050 foundVehicle(false),
00051 hasTarget(false){};
00052
00053 BVImageProcessor::~BVImageProcessor(){};
00054
00055
00056 bool BVImageProcessor::processROI(TrackerROI& roi)
00057 {
00058 resolution = roi.headData.resolution;
00059 if (hasVehicle || foundVehicle)
00060 {
00061 std::cout<<"ROI h-p:"<<","<<roi.headData.heading<<","<<roi.headData.panAngle<<std::endl;
00062
00063
00064
00065
00066 llz2xy(roi.headData,tracklet);
00067 meter2pixel(roi,tracklet);
00068
00069 if (hasTarget)
00070 {
00071 llz2xy(roi.headData,target);
00072 meter2pixel(roi,target);
00073 }
00074 std::cout<<"debug point 2"<<std::endl;
00075
00076
00077 cv::Mat disp = roi.roi.clone();
00078
00079 std::cout<<"debug point 3"<<std::endl;
00080 cv::circle(disp,getTracklet().pposition,10,cv::Scalar(65536));
00081
00082 cv::imshow("Expected",disp*500);
00083
00084
00085 std::cout<<"Before:"<<std::scientific<<tracklet.pposition.x<<","<<tracklet.pposition.y<<std::endl;
00086 std::cout<<"After:"<<std::scientific<<tracklet.position.x<<","<<tracklet.position.y<<std::endl;
00087
00088
00089
00090
00091 roi_len = 3;
00092 int add = int(roi_len/roi.headData.resolution);
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 roiImg = roi.roi;
00104
00105 roiOffset.x = 0;
00106
00107 roiOffset.y = 0;
00108
00109 std::cout<<"ROI width:"<<add<<std::endl;
00110
00111
00112
00113 cv::Mat adjusted = adjust(roiImg);
00114 cv::imshow("Adjusted",adjusted);
00115
00116
00117 cv::Mat binary = threshold(adjusted);
00118 cv::imshow("Binary",binary);
00119
00120
00121 boost::shared_ptr<std::vector<TrackedFeature> > features = label(binary);
00122
00123 bool retVal = associate(features);
00124
00125 pixel2meter(roi,tracklet);
00126 xy2llz(roi.headData,tracklet);
00127
00128
00129
00130 std::cout<<"After:"<<std::scientific<<tracklet.position.x<<","<<tracklet.position.y<<std::endl;
00131 std::cout<<"After:"<<std::scientific<<tracklet.latlon.x<<","<<tracklet.latlon.y<<std::endl;
00132 std::cout<<"After:"<<std::scientific<<tracklet.pposition.x<<","<<tracklet.pposition.y<<std::endl;
00133
00134 return retVal;
00135
00136
00137 }
00138 else
00139 {
00140
00141 }
00142
00143 return false;
00144 }
00145
00146 cv::Mat BVImageProcessor::adjust(cv::Mat& original)
00147 {
00148 cv::Mat adjust(original.size(),CV_32FC1);
00149 double min = 0, max = 0;
00150 cv::minMaxLoc(original,&min,&max);
00151 original.convertTo(adjust,CV_32FC1,1/max);
00152
00153 return adjust;
00154 }
00155
00156 cv::Mat BVImageProcessor::threshold(cv::Mat& adjusted)
00157 {
00158 cv::Mat thresholded(adjusted.size(),CV_8UC1);
00159 cv::threshold(adjusted, thresholded, 0.5, 255, CV_THRESH_BINARY);
00160
00161 thresholded.convertTo(thresholded,CV_8UC1);
00162
00163 return thresholded;
00164 }
00165
00166 cv::Mat BVImageProcessor::histthresh(const cv::Mat& img, float min,float max, uchar max_val)
00167 {
00168
00169 cv::Mat retVal(img);
00170
00171 for(int i=1; i<img.size().width-1; ++i)
00172 {
00173 for(int j=1; j<img.size().height-1; ++j)
00174 {
00175 cv::Mat thehood = img(cv::Range(i-1,i+1),cv::Range(j-1,j+1));
00176 cv::Mat rethood = retVal(cv::Range(i-1,i+1),cv::Range(j-1,j+1));
00177
00178 bool flag = false;
00179 for (int k=0; k<thehood.size().width; ++k)
00180 {
00181 for (int k2=0; k2<thehood.size().height; ++k2)
00182 {
00183
00184 if ((flag = thehood.at<float>(k,k2) >= max)) break;
00185 }
00186 }
00187
00188 if (flag)
00189 {
00190 for (int k=0; k<thehood.size().width; ++k)
00191 {
00192 for (int k2=0; k2<thehood.size().height; ++k2)
00193 {
00194 if (thehood.at<float>(k,k2) >= min)
00195 {
00196 rethood.at<float>(k,k2) = max_val;
00197 }
00198 else
00199 {
00200 rethood.at<float>(k,k2) = 0;
00201 }
00202 }
00203 }
00204 }
00205 else
00206 {
00207 cv::Mat(3,3,CV_8U,cv::Scalar(0)).copyTo(rethood);
00208 }
00209 }
00210 }
00211
00212 return retVal;
00213 }
00214
00215 boost::shared_ptr<std::vector<TrackedFeature> > BVImageProcessor::label(cv::Mat& binary)
00216 {
00217
00218 cv::morphologyEx(binary, binary, cv::MORPH_OPEN,cv::Mat());
00219
00220 std::vector< std::vector<cv::Point> > contours;
00221 std::vector<cv::Vec4i> hierarchy;
00222
00223 cv::findContours(binary,contours,hierarchy,cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
00224
00225 boost::shared_ptr<std::vector<TrackedFeature> > info(new std::vector<TrackedFeature>);
00226
00227 for (size_t i = 0; i < contours.size(); ++i)
00228 {
00229 std::vector<cv::Point> c_new;
00230 cv::convexHull(cv::Mat(contours[i]),c_new,true);
00231 contours[i] = c_new;
00232 cv::Moments moments = cv::moments(cv::Mat(contours[i]),true);
00233
00234 TrackedFeature tfeature;
00235 tfeature.perimeter = cv::arcLength(cv::Mat(contours[i]),true);
00236 tfeature.area = moments.m00;
00237 tfeature.pposition.x = (moments.m10)/moments.m00 + roiOffset.x;
00238 tfeature.pposition.y = (moments.m01)/moments.m00 + roiOffset.y;
00239
00240 info->push_back(tfeature);
00241 }
00242
00243 return info;
00244 }
00245
00246 bool BVImageProcessor::associate(boost::shared_ptr<std::vector<TrackedFeature> > features)
00247 {
00248 int idx = -1;
00249 double mindiff = 10000;
00250
00251
00252 if (features->size()>10) return false;
00253
00254 for (size_t i=0;i<features->size();++i)
00255 {
00256 TrackedFeature& tfeature = (*features)[i];
00257
00258 double tt_dx = tfeature.pposition.x - target.pposition.x;
00259 double tt_dy = tfeature.pposition.y - target.pposition.y;
00260 double tt_distance = sqrt(tt_dx*tt_dx + tt_dy*tt_dy);
00261
00262 double dx = (tfeature.pposition.x) - tracklet.pposition.x;
00263 double dy = (tfeature.pposition.y) - tracklet.pposition.y;
00264 double distance = sqrt(dx*dx + dy*dy);
00265
00266 if (!hasTarget) tt_distance = 100;
00267
00268
00269
00270 if (hasTarget) std::cout<<"Distance to target:"<<tt_distance*resolution<<std::endl;
00271
00272 if (distance<mindiff)
00273 {
00274 mindiff = distance;
00275 idx = i;
00276 }
00277
00278
00279
00280
00281
00282 }
00283
00284 if (idx != -1)
00285 {
00286 tracklet.pposition = (*features)[idx].pposition;
00287 foundVehicle = true;
00288 hasVehicle = true;
00289 return true;
00290 }
00291 else
00292 {
00293 return false;
00294 }
00295 }
00296
00297 void BVImageProcessor::setPosition(const SonarHead& cnt)
00298 {
00299
00300
00301 tracklet.position.x = cnt.range*cos((cnt.bearing - cnt.panAngle)*M_PI/180);
00302 tracklet.position.y = cnt.range*sin((cnt.bearing - cnt.panAngle)*M_PI/180);
00303
00304
00305 xy2llz(cnt,tracklet);
00306
00307
00308
00309
00310 std::cout<<"Contact:"<<tracklet.position.x<<","<<tracklet.position.y<<std::endl;
00311 std::cout<<"R-b-h-p:"<<cnt.range<<","<<cnt.bearing<<","<<cnt.heading<<","<<cnt.panAngle<<std::endl;
00312
00313 foundVehicle = hasVehicle = true;
00314 }
00315
00316 void BVImageProcessor::setTarget(const SonarHead& cnt)
00317 {
00318
00319
00320 target.position.x = cnt.range*cos((cnt.bearing - cnt.panAngle)*M_PI/180);
00321 target.position.y = cnt.range*sin((cnt.bearing - cnt.panAngle)*M_PI/180);
00322
00323
00324 xy2llz(cnt,target);
00325
00326
00327
00328
00329 std::cout<<"Target contact:"<<target.position.x<<","<<target.position.y<<std::endl;
00330 std::cout<<"R-b-h-p:"<<cnt.range<<","<<cnt.bearing<<","<<cnt.heading<<","<<cnt.panAngle<<std::endl;
00331
00332 hasTarget = true;
00333 }
00334
00335 void BVImageProcessor::llz2xy(const SonarHead& head, TrackedFeature& tracklet)
00336 {
00337
00338 _update(head);
00339
00340
00341 std::pair<double,double>
00342 value = deg2meter(tracklet.latlon.x - head.latlon.x,tracklet.latlon.y - head.latlon.y,head.latlon.x);
00343
00344
00345
00346
00347 enum {x = 0,y,z};
00348 cv::Mat pos_n(3,1,CV_64F);
00349 pos_n.at<double>(x,0) = value.first;
00350 pos_n.at<double>(y,0) = value.second;
00351
00352 pos_n.at<double>(z,0) = tracklet.latlon.z;
00353
00354 std::cout<<"debug point 0"<<std::endl;
00355
00356 using namespace boost::numeric;
00357 ublas::matrix<double> uR(3,3);
00358 ublas::vector<double> uPos(3);
00359
00360 uPos(0) = pos_n.at<double>(0,0);
00361 uPos(1) = pos_n.at<double>(1,0);
00362 uPos(2) = pos_n.at<double>(2,0);
00363
00364 uR(0,0) = R.at<double>(0,0);
00365 uR(0,1) = R.at<double>(0,1);
00366 uR(0,2) = R.at<double>(0,2);
00367 uR(1,0) = R.at<double>(1,0);
00368 uR(1,1) = R.at<double>(1,1);
00369 uR(1,2) = R.at<double>(1,2);
00370 uR(2,0) = R.at<double>(2,0);
00371 uR(2,1) = R.at<double>(2,1);
00372 uR(2,2) = R.at<double>(2,2);
00373
00374 ublas::matrix<double> invR(ublas::zero_matrix<double>(3));
00375 labust::math::gjinverse(uR,invR);
00376 ublas::vector<double> upos = prod(invR,uPos);
00377
00378 cv::Mat pos(3,1,CV_64F);
00379 pos.at<double>(0,0) = upos(0);
00380 pos.at<double>(1,0) = upos(1);
00381 pos.at<double>(2,0) = upos(2);
00382 std::cout<<"debug point 1"<<std::endl;
00383
00384
00385 tracklet.position.x = pos.at<double>(x,0);
00386 tracklet.position.y = pos.at<double>(y,0);
00387 }
00388
00389 void BVImageProcessor::xy2llz(const SonarHead& head, TrackedFeature& tracklet)
00390 {
00391
00392 _update(head);
00393
00394 enum {x = 0,y,z};
00395 cv::Mat pos(3,1,CV_64F);
00396 pos.at<double>(x,0) = tracklet.position.x;
00397 pos.at<double>(y,0) = tracklet.position.y;
00398
00399 pos.at<double>(z,0) = 0;
00400
00401
00402 cv::Mat pos_n = R*pos;
00403 std::pair<double,double>
00404 value = meter2deg(pos_n.at<double>(x,0), pos_n.at<double>(y,0), head.latlon.x);
00405
00406
00407
00408
00409
00410 tracklet.latlon.x = head.latlon.x + value.first;
00411 tracklet.latlon.y = head.latlon.y + value.second;
00412 tracklet.latlon.z = head.latlon.z + pos_n.at<double>(z,0);
00413 }
00414
00415 void BVImageProcessor::meter2pixel(TrackerROI& roi, TrackedFeature& tracklet)
00416 {
00417
00418 std::cout<<"Meter position:"<<(tracklet.position.x)<<","<<(tracklet.position.y)<<std::endl;
00419
00420 double pxrange = sqrt(tracklet.position.y*tracklet.position.y + tracklet.position.x*tracklet.position.x) / roi.headData.resolution;
00421 double bearing = atan2(tracklet.position.y,tracklet.position.x);
00422
00423 tracklet.pposition.y = roi.origin.y - int(pxrange*cos(bearing));
00424 tracklet.pposition.x = roi.origin.x + int(pxrange*sin(bearing));
00425
00426 std::cout<<"Pixel position: ("<<tracklet.pposition.x<<","<<tracklet.pposition.y<<")"<<std::endl;
00427
00428 }
00429
00430 inline void BVImageProcessor::pixel2meter(TrackerROI& roi, TrackedFeature& tracklet)
00431 {
00432
00433
00434
00435 tracklet.position.y = (-roi.origin.x + tracklet.pposition.x)*roi.headData.resolution;
00436 tracklet.position.x = (roi.origin.y - tracklet.pposition.y)*roi.headData.resolution;
00437
00438
00439
00440
00441 }
00442
00443 void BVImageProcessor::_update(const SonarHead& head)
00444 {
00445 double c1 = 1, s1 = 0;
00446 double c2 = cos(head.tiltAngle*M_PI/180), s2 = sin(head.tiltAngle*M_PI/180);
00447 double c3 = cos(head.panAngle*M_PI/180), s3 = sin(head.panAngle*M_PI/180);
00448
00449 cv::Mat R_hb(3,3,CV_64F);
00450 R_hb.at<double>(0,0) = c3*c2;
00451 R_hb.at<double>(0,1) = c3*s2*s1-s3*c1;
00452 R_hb.at<double>(0,2) = s3*s1+c3*c1*s2;
00453 R_hb.at<double>(1,0) = s3*c2;
00454 R_hb.at<double>(1,1) = c1*c3+s1*s2*s3;
00455 R_hb.at<double>(1,2) = c1*s2*s3-c3*s1;
00456 R_hb.at<double>(2,0) = -s2;
00457 R_hb.at<double>(2,1) = c2*s1;
00458 R_hb.at<double>(2,2) = c1*c2;
00459
00460 c1 = 1, s1 = 0;
00461 c2 = 1, s2 = 0;
00462 c3 = cos(head.heading*M_PI/180), s3 = sin(head.heading*M_PI/180);
00463
00464 cv::Mat R_bn(3,3,CV_64F);
00465 R_bn.at<double>(0,0) = c3;
00466 R_bn.at<double>(0,1) = -s3;
00467 R_bn.at<double>(0,2) = 0;
00468 R_bn.at<double>(1,0) = s3;
00469 R_bn.at<double>(1,1) = c3;
00470 R_bn.at<double>(1,2) = 0;
00471 R_bn.at<double>(2,0) = 0;
00472 R_bn.at<double>(2,1) = 0;
00473 R_bn.at<double>(2,2) = 1;
00474
00475 R = R_bn*R_hb;
00476
00477
00478
00479
00480
00481 }
00482
00483 std::pair<double,double> BVImageProcessor::meter2deg(double x, double y, double lat)
00484 {
00485 static const double radius = 6378137;
00486 static const double ratio = 0.99664719;
00491 double mpdlat = 111132.954 - 559.822*cos(2*lat*M_PI/180) + 1.175*cos(4*lat*M_PI/180);
00492 double mpdlon = M_PI*radius*cos(atan(ratio*tan(lat*M_PI/180)))/180;
00493
00494 return std::pair<double,double>(x/mpdlat,y/mpdlon);
00495 }
00496
00497 std::pair<double,double> BVImageProcessor::deg2meter(double difflat, double difflon, double lat)
00498 {
00499 static const double radius = 6378137;
00500 static const double ratio = 0.99664719;
00505 double mpdlat = 111132.954 - 559.822*cos(2*lat*M_PI/180) + 1.175*cos(4*lat*M_PI/180);
00506 double mpdlon = M_PI*radius*cos(atan(ratio*tan(lat*M_PI/180)))/180;
00507
00508 return std::pair<double,double>(difflat*mpdlat,difflon*mpdlon);
00509 }