00001
00002 #include <vector>
00003 #include <iostream>
00004 #include <math.h>
00005
00006 #include "Point.h"
00007 #include "Shared/Measures.h"
00008 #include "ShapeTypes.h"
00009
00010 #include "SketchSpace.h"
00011 #include "Sketch.h"
00012 #include "ShapeSpace.h"
00013 #include "ShapeRoot.h"
00014
00015 #include "visops.h"
00016 #include "ShapeFuns.h"
00017 #include "ShapeEllipse.h"
00018 #include "Crew/MapBuilder.h"
00019 #include "VRmixin.h"
00020 #include "Motion/Kinematics.h"
00021
00022 #include "AgentData.h"
00023 #include "ShapeAgent.h"
00024
00025 using namespace std;
00026
00027 namespace DualCoding {
00028
00029 DATASTUFF_CC(AgentData);
00030
00031 AgentData::AgentData(ShapeSpace& _space, const Point &c, AngTwoPi orient)
00032 : BaseData(_space,agentDataType), center_pt(c), orientation(orient), hostAddr(0)
00033 { mobile = true; }
00034
00035 AgentData::AgentData(const AgentData& otherData)
00036 : BaseData(otherData),
00037 center_pt(otherData.center_pt),
00038 orientation(otherData.orientation),
00039 hostAddr(otherData.hostAddr)
00040 { mobile = true; }
00041
00042 BoundingBox2D AgentData::getBoundingBox() const {
00043 BoundingBox2D b;
00044 fmat::Column<3> bl = -RobotInfo::AgentBoundingBoxHalfDims - RobotInfo::AgentBoundingBoxBaseFrameOffset;
00045 fmat::Column<3> tr = RobotInfo::AgentBoundingBoxHalfDims - RobotInfo::AgentBoundingBoxBaseFrameOffset;
00046 fmat::Matrix<3,3> rot = fmat::rotationZN<3,float>(orientation);
00047 bl = rot*bl + RobotInfo::AgentBoundingBoxBaseFrameOffset + center_pt.getCoords();
00048 tr = rot*tr + RobotInfo::AgentBoundingBoxBaseFrameOffset + center_pt.getCoords();
00049 b.expand(bl);
00050 b.expand(tr);
00051 return b;
00052 }
00053
00054 bool AgentData::isMatchFor(const ShapeRoot&other) const {
00055
00056 if(!isSameTypeAs(other)) {
00057 return false;
00058 }
00059 const int MAX_CENTER_DIST = 100;
00060 float center_dist = (center_pt - other->getCentroid()).xyzNorm();
00061 return center_dist <= MAX_CENTER_DIST;
00062 }
00063
00064
00065 void AgentData::printParams() const {
00066 cout << "Type = " << getTypeName();
00067 cout << "Shape ID = " << getId() << endl;
00068 cout << "Parent ID = " << getParentId() << endl;
00069
00070
00071 cout << endl;
00072 cout << "center{" << getCentroid().coords[0] << ", " << getCentroid().coords[1] << "}" << endl;
00073
00074 cout << "orientation = " << orientation << endl;
00075
00076 printf("color = %d %d %d\n",getColor().red,getColor().green,getColor().blue);
00077
00078 cout << "mobile = " << getMobile() << endl;
00079 cout << "viewable = " << isViewable() << endl;
00080 }
00081
00082
00083
00084 void AgentData::applyTransform(const fmat::Transform& Tmat, const ReferenceFrameType_t newref) {
00085
00086
00087 center_pt.applyTransform(Tmat,newref);
00088 orientation = orientation - (AngTwoPi)atan2(Tmat(1,2),Tmat(1,1));
00089
00090 }
00091
00092
00093 void AgentData::setOrientation(AngTwoPi _orientation) {
00094 orientation = _orientation;
00095 deleteRendering();
00096 }
00097
00098 void AgentData::projectToGround(const fmat::Transform& camToBase,
00099 const PlaneEquation& groundplane) {
00100 center_pt.projectToGround(camToBase,groundplane);
00101 }
00102
00103 bool AgentData::updateParams(const ShapeRoot& other, bool force) {
00104 if (isMatchFor(other) || force) {
00105 const AgentData& other_agent = ShapeRootTypeConst(other,AgentData).getData();
00106 int other_conf = other_agent.getConfidence();
00107 if (other_conf <= 0)
00108 return true;
00109 center_pt = (center_pt*confidence + other_agent.getCentroid()*other_conf) / (confidence+other_conf);
00110 orientation = orientation*((orientation_t)confidence/(confidence+other_conf))
00111 + other_agent.getOrientation()*((orientation_t)other_conf/(confidence+other_conf));
00112 return true;
00113 }
00114 return false;
00115 }
00116
00117
00118 Sketch<bool>* AgentData::render() const {
00119 Sketch<bool>* draw_result =
00120 new Sketch<bool>(space->getDualSpace(), "render("+getName()+")");
00121 draw_result = 0;
00122
00123
00124
00125 int cx = int(getCentroid().coords[0]);
00126 int cy = int(getCentroid().coords[1]);
00127
00128
00129 const float a = 2.f;
00130 const float b = 2.f;
00131 const float x_skip = std::atan(1/(0.5f*a));
00132 for(float x = (cx-a); x<(cx+a); x+=x_skip) {
00133 float y_y0_sq = (b*b) * (1 - (x-cx)*(x-cx)/(a*a));
00134 if(y_y0_sq > 0) {
00135 int y_bot = cy + (int)(sqrt(y_y0_sq));
00136 int y_top = cy - (int)(sqrt(y_y0_sq));
00137 (*draw_result)((int)x,y_bot) = true;
00138 (*draw_result)((int)x,y_top) = true;
00139 }
00140 }
00141 (*draw_result)(cx-(int)a, cy) = true;
00142 (*draw_result)(cx+(int)a, cy) = true;
00143 return draw_result;
00144 }
00145
00146
00147
00148 int AgentData::getColorIdMatch(yuv pixelColor) {
00149
00150
00151 int distances[NUM_COLOR_IDS];
00152 for (int i = 0; i < NUM_COLOR_IDS; ++i) {
00153 float u_dist = (pixelColor.u - color_ids[i].u_0 - color_ids[i].u_slope*pixelColor.y);
00154 float v_dist = (pixelColor.v - color_ids[i].v_0 - color_ids[i].v_slope*pixelColor.y);
00155 distances[i] = u_dist*u_dist + v_dist*v_dist;
00156 }
00157
00158 int min_val = distances[0];
00159 int min_index = 0;
00160 for (int i = 1; i < NUM_COLOR_IDS; ++i) {
00161 if (distances[i] < min_val) {
00162 if (color_ids[i].y_low >= 0 &&
00163 (pixelColor.y < color_ids[i].y_low || pixelColor.y > color_ids[i].y_high)) {
00164 continue;
00165 }
00166 min_val = distances[i];
00167 min_index = i;
00168 }
00169 }
00170
00171 return color_ids[min_index].id;
00172 }
00173
00174 int AgentData::getIdFromCenter(const Sketch<yuv> &camFrameYUV, const Point &a, const Point &b, const Point &c) {
00175
00176 Point center = (a + b + c)/3;
00177 yuv pixelColor = camFrameYUV(center.coordX(), center.coordY());
00178 return getColorIdMatch(pixelColor);
00179 }
00180
00181 int AgentData::getIdFromCorner(const Sketch<yuv> &camFrameYUV, const Point &vert_a, const Point &vert_b, const Point &loner) {
00182
00183
00184 float vert_dist = vert_b.coordY() - vert_a.coordY();
00185 yuv pixelColor;
00186 pixelColor = camFrameYUV(loner.coordX(), loner.coordY() - vert_dist);
00187
00188 return getColorIdMatch(pixelColor);
00189 }
00190
00191 bool AgentData::circlesVerticallyAligned(const Shape<EllipseData> &a, const Shape<EllipseData> &b) {
00192
00193 const float VLEVEL_THRESHOLD = 0.25f;
00194 Point a_center = a->getCentroid();
00195 Point b_center = b->getCentroid();
00196 float atanValue;
00197 if (a_center.coordX() >= b_center.coordX())
00198 atanValue = fabs((a_center - b_center).atanYX());
00199 else
00200 atanValue = fabs((b_center - a_center).atanYX());
00201 return atanValue < VLEVEL_THRESHOLD;
00202 }
00203
00204 bool AgentData::circlesHorizontallyAligned(const Shape<EllipseData> &a, const Shape<EllipseData> &b) {
00205
00206 const float HLEVEL_THRESHOLD = 0.45f;
00207 Point a_center = a->getCentroid();
00208 Point b_center = b->getCentroid();
00209 float atanValue;
00210 if (a_center.coordY() >= b_center.coordY())
00211 atanValue = fabs((float)(a_center - b_center).atanYX() - M_PI_2);
00212 else
00213 atanValue = fabs((float)(b_center - a_center).atanYX() - M_PI_2);
00214 return atanValue < HLEVEL_THRESHOLD;
00215 }
00216
00217 void AgentData::findCirclesManual(const Sketch<uchar> &camFrame,
00218 std::vector<int> &neighbor_density,
00219 std::vector<Shape<EllipseData> > &agentIdCircles) {
00220
00221
00222 NEW_SKETCH_N(red_stuff, bool, visops::colormask(camFrame, "red"));
00223 NEW_SKETCH_N(blobs, usint, visops::labelcc(red_stuff));
00224 NEW_SKETCH_N(labeli, bool, visops::zeros(camFrame));
00225 NEW_SHAPEVEC(circles, EllipseData, 0);
00226
00227
00228
00229
00230 for (unsigned int i = 1; i <= blobs->max(); ++i) {
00231 labeli.bind(blobs == i);
00232 int count = 0;
00233 int x_sum = 0;
00234 int y_sum = 0;
00235 int min_index = labeli->findMinPlus();
00236 int xstart = min_index % labeli.width;
00237 int ystart = min_index / labeli.width;
00238 int lbound = labeli.width;
00239 int rbound = xstart;
00240 int tbound = ystart;
00241 int bbound = ystart;
00242 for (int y = ystart; y < labeli.height; ++y) {
00243 for (int x = 0; x < labeli.width; ++x) {
00244 if (labeli(x, y)) {
00245 if (x < lbound)
00246 lbound = x;
00247 else if (x > rbound)
00248 rbound = x;
00249 if (y > bbound) {
00250 bbound = y;
00251 }
00252 x_sum += x;
00253 y_sum += y;
00254 ++count;
00255 }
00256 }
00257 }
00258 if (count == 0) continue;
00259
00260 float major, minor;
00261 if (bbound - tbound > rbound - lbound) {
00262 major = bbound - tbound;
00263 minor = rbound - lbound;
00264 } else {
00265 major = rbound - lbound;
00266 minor = bbound - tbound;
00267 }
00268 ++major;
00269 ++minor;
00270
00271
00272 if (major/minor > 3) {
00273
00274 continue;
00275 }
00276
00277
00278 if ((major*minor)/count > 2) {
00279
00280 continue;
00281 }
00282
00283 minor = major;
00284 float center_x = x_sum/((float)count);
00285 float center_y = y_sum/((float)count);
00286 NEW_SHAPE_N(circle, EllipseData,
00287 new EllipseData(VRmixin::camShS,
00288 Point(center_x, center_y, 0),
00289 major/2, minor/2));
00290 circle->setColor("red");
00291 circles.push_back(circle);
00292 agentIdCircles.push_back(circle);
00293 }
00294
00295
00296
00297
00298
00299 const int deltaX = 60;
00300 const int deltaY = 60;
00301
00302 SHAPEVEC_ITERATE(circles, EllipseData, circle) {
00303 neighbor_density.push_back(0);
00304 Point centroid = circle->getCentroid();
00305 float center_x = centroid.coordX();
00306 float center_y = centroid.coordY();
00307 float left = max(center_x - deltaX, 0.0f);
00308 float right = min(center_x + deltaX, (float)blobs.width - 1);
00309 float top = max(center_y - deltaY, 0.0f);
00310 float bottom = min(center_y + deltaY, (float)blobs.height - 1);
00311
00312
00313 SHAPEVEC_ITERATE(circles, EllipseData, neighbor) {
00314 Point neighbor_centroid = neighbor->getCentroid();
00315 float neighbor_x = neighbor_centroid.coordX();
00316 float neighbor_y = neighbor_centroid.coordY();
00317 if (neighbor_x >= left && neighbor_x <= right && neighbor_y >= top && neighbor_y <= bottom) {
00318 ++neighbor_density.back();
00319 }
00320 } END_ITERATE;
00321 } END_ITERATE;
00322 }
00323
00324 void AgentData::findAgentsBelt(const Sketch<yuv> &camFrameYUV,
00325 const std::vector<int> &neighbor_density,
00326 const std::vector<Shape<EllipseData> > &circles) {
00327
00328
00329
00330
00331
00332
00333 const float robot_radius = VRmixin::theAgent->getBoundingBoxHalfDims()[1];
00334
00335
00336 enum RobotSide robot_side;
00337 vector<Shape<AgentData> > possible_agents;
00338
00339
00340
00341
00342 PlaneEquation above_ground(0, 0, 1, 65);
00343
00344 const fmat::Transform cam_transform = kine->linkToBase(CameraFrameOffset);
00345
00346 for (unsigned int i = 0; i < neighbor_density.size(); ++i) {
00347
00348 }
00349
00350
00351
00352
00353
00354 const int DENSITY_THRESHOLD = 6;
00355 for (unsigned int i = 0; i < circles.size(); ++i) {
00356 if (neighbor_density[i] > DENSITY_THRESHOLD)
00357 continue;
00358 for (unsigned int j = i + 1; j < circles.size(); ++j) {
00359 if (!circlesVerticallyAligned(circles[i], circles[j])) {
00360
00361 continue;
00362 }
00363 if (!compareCircleSize(circles[i], circles[j])) {
00364
00365
00366 continue;
00367 }
00368 for (unsigned int k = 0; k < circles.size(); ++k) {
00369 if (k == i || k == j) continue;
00370 unsigned int v, h;
00371 if (circlesHorizontallyAligned(circles[i], circles[k])) {
00372 v = i;
00373 h = j;
00374 } else if (circlesHorizontallyAligned(circles[j], circles[k])) {
00375 v = j;
00376 h = i;
00377 } else {
00378
00379
00380 continue;
00381 }
00382 if (!compareCircleSize(circles[i], circles[k]) &&
00383 !compareCircleSize(circles[j], circles[k]))
00384 continue;
00385 float radius = max(circles[i]->getSemimajor(),
00386 max(circles[j]->getSemimajor(),
00387 circles[k]->getSemimajor()));
00388
00389 if (fabs(circles[i]->getCentroid().coordX() - circles[j]->getCentroid().coordX()) >= 7*radius) {
00390
00391 continue;
00392 }
00393 if (fabs(circles[v]->getCentroid().coordY() - circles[k]->getCentroid().coordY()) >= 7*radius) {
00394
00395 continue;
00396 }
00397
00398 Point pi = circles[i]->getCentroid();
00399 Point pj = circles[j]->getCentroid();
00400 Point pk = circles[k]->getCentroid();
00401
00402 if (!pi.projectToGround(cam_transform, above_ground)) {
00403 cout << "project to ground failed." << endl;
00404 break;
00405 }
00406 if (!pj.projectToGround(cam_transform, above_ground)) {
00407 cout << "project to ground failed." << endl;
00408 break;
00409 }
00410 if (!pk.projectToGround(cam_transform, above_ground)) {
00411 cout << "project to ground failed." << endl;
00412 continue;
00413 }
00414 Point pv = circles[v]->getCentroid();
00415 Point ph = circles[h]->getCentroid();
00416
00417 if (!compareCircleDist(pi, pj) || !compareCircleDist(pj, pk)) {
00418
00419
00420
00421
00422 continue;
00423 }
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 int robot_id = getIdFromCorner(camFrameYUV,
00435 circles[k]->getCentroid(),
00436 circles[v]->getCentroid(),
00437 circles[h]->getCentroid());
00438
00439
00440 if (circles[k]->getCentroid().coordY() < pv.coordY()) {
00441 if (pv.coordX() < ph.coordX())
00442 robot_side = AgentData::FRONT;
00443 else
00444 robot_side = AgentData::LEFT;
00445 } else {
00446 if (pv.coordX() < ph.coordX())
00447 robot_side = AgentData::BACK;
00448 else
00449 robot_side = AgentData::RIGHT;
00450 }
00451
00452
00453
00454
00455
00456
00457 Point diff = (pi - pj);
00458 Point mid = pi + diff/2;
00459 fmat::Matrix<3,3,float> rotate = fmat::rotationZ(-copysign(1.0f,diff.coordY())*M_PI/2);
00460 fmat::Column<3,float> robot_center = robot_radius*rotate*diff.unitVector().getCoords();
00461 Point center(0, 0, 0, egocentric);
00462 center.setCoords(robot_center);
00463 AngTwoPi orient_to_dots((float)center.atanYX());
00464 center += mid;
00465
00466
00467
00468
00469 AngTwoPi orient;
00470 cout << "Saw agent '" << agent_names[robot_id] << "' ";
00471 switch (robot_side) {
00472 case AgentData::FRONT:
00473 cout << "front";
00474 orient = (float)orient_to_dots + M_PI;
00475 break;
00476 case AgentData::BACK:
00477 cout << "back";
00478 orient = (float)orient_to_dots;
00479 break;
00480 case AgentData::LEFT:
00481 cout << "left";
00482 orient = (float)orient_to_dots + M_PI/2;
00483 break;
00484 case AgentData::RIGHT:
00485 cout << "right";
00486 orient = (float)orient_to_dots + 3*M_PI/2;
00487 break;
00488 }
00489 cout << ", orientation " << float(orient)*180/M_PI << " deg." << endl;
00490
00491
00492
00493
00494
00495 Shape<AgentData> new_agent(VRmixin::localShS, center);
00496 new_agent->setOrientation(orient);
00497 new_agent->setName(agent_names[robot_id]);
00498 }
00499 }
00500 }
00501 }
00502
00503 void AgentData::extractAgents(const Sketch<uchar> &camFrame, const Sketch<yuv> &camFrameYUV,
00504 const std::set<color_index> &objcolors) {
00505 std::vector<int> neighbor_density;
00506 std::vector<Shape<EllipseData> > agentIdCircles;
00507 findCirclesManual(camFrame, neighbor_density, agentIdCircles);
00508 findAgentsBelt(camFrameYUV, neighbor_density, agentIdCircles);
00509 VRmixin::camShS.deleteShapes(agentIdCircles);
00510 }
00511
00512 const char* AgentData::agent_names[NUM_COLOR_IDS] = {
00513 "octopus",
00514 "turtle",
00515 "cycle",
00516 "kodu",
00517 };
00518
00519 AgentData::ColorIdTarget AgentData::color_ids[NUM_COLOR_IDS] = {
00520 { 0, -1, -1, 115, 1.086f, 135, -0.638f},
00521 { 1, -1, -1, 110, 0, 130, -0.186},
00522 { 2, -1, -1, 90, 0, 152, -0.121f},
00523 { 3, 0, 16, 128, 0, 128, 0},
00524 };
00525
00526 }