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 #include <models/shape/rcd_circle.h>
00026 #include <cmath>
00027 #include <sys/time.h>
00028 #include <cstdlib>
00029
00030 using namespace std;
00031 using namespace fawkes;
00032
00033 #define TBY_GRAYSCALE
00034 #ifdef TBY_GRAYSCALE
00035 #define TEST_IF_IS_A_PIXEL(x) ((x)>230)
00036 #else
00037 #define TEST_IF_IS_A_PIXEL(x) ((x)==0)
00038 #endif // TBY_GRAYSCALE
00039
00040 #define TBY_SQUARED_DIST(x1,y1,x2,y2) \
00041 (((x1)-(x2))*((x1)-(x2))+((y1)-(y2))*((y1)-(y2)))
00042 #define TBY_RADIUS_DIFF(x1, y1, x2, y2, r) \
00043 (((x1)-(x2))*((x1)-(x2))+((y1)-(y2))*((y1)-(y2))-(r)*(r))
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 RcdCircleModel::RcdCircleModel(unsigned int max_failures,
00061 unsigned int min_pixels,
00062 unsigned int min_interpix_dist,
00063 unsigned int max_dist_p4,
00064 unsigned int max_dist_a,
00065 float hw_ratio,
00066 float hollow_rate,
00067 float max_time
00068 )
00069 {
00070
00071 RCD_MAX_FAILURES = max_failures;
00072 RCD_MIN_PIXELS = min_pixels;
00073 RCD_MIN_INTERPIX_DIST = min_interpix_dist;
00074 RCD_MAX_DIST_P4 = max_dist_p4;
00075 RCD_MAX_DIST_A = max_dist_a;
00076 RCD_HW_RATIO = hw_ratio;
00077 RCD_MAX_TIME = max_time;
00078 RCD_ROI_HOLLOW_RATE = hollow_rate;
00079
00080 }
00081
00082
00083 RcdCircleModel::~RcdCircleModel(void)
00084 {
00085 m_Circles.clear();
00086 }
00087
00088 int RcdCircleModel::parseImage( unsigned char* buf,
00089 ROI *roi )
00090 {
00091
00092 unsigned char *buffer = roi->get_roi_buffer_start(buf);
00093 unsigned char *line_start = buffer;
00094
00095 unsigned int x, y;
00096 vector<point_t> pixels,
00097 remove_list;
00098 unsigned int f = 0;
00099 int count;
00100 int num_circles = 0;
00101 struct timeval start, now;
00102
00103
00104 m_Circles.clear();
00105
00106 const unsigned int roi_hollow_top = (int)(roi->height * ((1.0f - RCD_ROI_HOLLOW_RATE) / 2));
00107 const unsigned int roi_hollow_bottom = roi->height - roi_hollow_top;
00108 const unsigned int roi_hollow_left = (int)(roi->width * ((1.0f - RCD_ROI_HOLLOW_RATE) / 2));
00109 const unsigned int roi_hollow_right = roi->width - roi_hollow_left;
00110
00111
00112
00113
00114 buffer = roi->get_roi_buffer_start(buf);
00115 line_start = buffer;
00116
00117
00118
00119 unsigned int boundary_right = 0;
00120 unsigned int boundary_bottom = 0;
00121
00122 gettimeofday(&start, NULL);
00123
00124 pixels.clear();
00125
00126
00127 for (y = 0; y < roi_hollow_top; ++y) {
00128 for (x = 0; x < roi->width; ++x) {
00129 if (TEST_IF_IS_A_PIXEL(*buffer)) {
00130 point_t pt={x, y};
00131 pixels.push_back(pt);
00132 if (x > boundary_right) boundary_right = x;
00133 boundary_bottom = y;
00134 }
00135
00136 ++buffer;
00137 }
00138 line_start += roi->line_step;
00139 buffer = line_start;
00140 }
00141
00142 for (y = roi_hollow_top; y < roi_hollow_bottom; ++y) {
00143 for (x = 0; x < roi_hollow_left; ++x) {
00144 if (TEST_IF_IS_A_PIXEL(*buffer)) {
00145 point_t pt={x, y};
00146 pixels.push_back(pt);
00147 if (x > boundary_right) boundary_right = x;
00148 boundary_bottom = y;
00149 }
00150
00151 ++buffer;
00152 }
00153 buffer+=(roi_hollow_right - roi_hollow_left);
00154 for (x = roi_hollow_right; x < roi->width; ++x) {
00155 if (TEST_IF_IS_A_PIXEL(*buffer)) {
00156 point_t pt={x, y};
00157 pixels.push_back(pt);
00158 if (x > boundary_right) boundary_right = x;
00159 boundary_bottom = y;
00160 }
00161
00162 ++buffer;
00163 }
00164 line_start += roi->line_step;
00165 buffer = line_start;
00166 }
00167
00168 for (y = roi_hollow_bottom; y < roi->height; ++y) {
00169 for (x = 0; x < roi->width; ++x) {
00170 if (TEST_IF_IS_A_PIXEL(*buffer)) {
00171 point_t pt={x, y};
00172 pixels.push_back(pt);
00173 }
00174
00175 ++buffer;
00176 }
00177 line_start += roi->line_step;
00178 buffer = line_start;
00179 }
00180
00181
00182 point_t p[4];
00183 center_in_roi_t center;
00184 float radius;
00185 vector< point_t >::iterator pos;
00186
00187 if (pixels.size() < RCD_MIN_PIXELS) {
00188 return 0;
00189 }
00190
00191 do {
00192
00193
00194 for (int i=0; i < 4; ++i) {
00195 int ri = rand() % ((int)pixels.size());
00196 pos = pixels.begin() + ri;
00197 p[i] = *pos;
00198 pixels.erase(pos);
00199 remove_list.push_back(p[i]);
00200 }
00201
00202 if (TBY_SQUARED_DIST(p[1].x, p[1].y, p[2].x, p[2].y) < RCD_MIN_INTERPIX_DIST ||
00203 TBY_SQUARED_DIST(p[2].x, p[2].y, p[0].x, p[0].y) < RCD_MIN_INTERPIX_DIST ||
00204 TBY_SQUARED_DIST(p[0].x, p[0].y, p[1].x, p[1].y) < RCD_MIN_INTERPIX_DIST ) {
00205
00206
00207 ++f;
00208
00209
00210 pixels.push_back(p[0]);
00211 pixels.push_back(p[1]);
00212 pixels.push_back(p[2]);
00213 pixels.push_back(p[3]);
00214
00215 remove_list.clear();
00216
00217 gettimeofday(&now, NULL);
00218 continue;
00219 }
00220
00221
00222
00223 calcCircle(p[0], p[1], p[2], center, radius);
00224
00225
00226 int r = (int)sqrt(TBY_SQUARED_DIST(center.x, center.y, pixels[3].x, pixels[3].y));
00227 int dist = (int)(r - radius);
00228 dist = (dist >= 0) ? dist : -dist;
00229 if (radius <= 0 || (unsigned int)dist > RCD_MAX_DIST_P4 ) {
00230 ++f;
00231
00232
00233 pixels.push_back(p[0]);
00234 pixels.push_back(p[1]);
00235 pixels.push_back(p[2]);
00236 pixels.push_back(p[3]);
00237
00238 remove_list.clear();
00239
00240 gettimeofday(&now, NULL);
00241 continue;
00242 }
00243
00244
00245 count=0;
00246 for (unsigned int i=0; i < pixels.size(); ++i) {
00247 int r = (int)sqrt(TBY_SQUARED_DIST(center.x, center.y, pixels[i].x, pixels[i].y));
00248 int dist = (int)(r-radius);
00249 dist = (dist >= 0) ? dist : -dist;
00250 if ((unsigned int)dist <= RCD_MAX_DIST_A) {
00251 pos = pixels.begin() + i;
00252 ++count;
00253
00254 remove_list.push_back(pixels[i]);
00255 pixels.erase(pos--);
00256 }
00257 }
00258
00259
00260
00261 if ( (float)count >
00262 ( boundary_right > boundary_bottom ? boundary_right : boundary_bottom ) * RCD_HW_RATIO ) {
00263
00264 if ( radius > TBY_CIRCLE_RADIUS_MIN &&
00265 radius < TBY_CIRCLE_RADIUS_MAX ) {
00266
00267
00268
00269 Circle c;
00270 c.fitCircle(remove_list);
00271 c.count = count;
00272
00273
00274 m_Circles.push_back(c);
00275 }
00276 remove_list.clear();
00277 ++num_circles;
00278 } else {
00279
00280 ++f;
00281
00282 while(!remove_list.empty()) {
00283 pixels.push_back(remove_list.back());
00284 remove_list.pop_back();
00285 }
00286 gettimeofday(&now, NULL);
00287 continue;
00288 }
00289
00290 gettimeofday(&now, NULL);
00291
00292 diff_sec = now.tv_sec - start.tv_sec;
00293 diff_usec = now.tv_usec - start.tv_usec;
00294 if (diff_usec < 0) {
00295 diff_sec -= 1;
00296 diff_usec += 1000000;
00297 }
00298
00299 f_diff_sec = diff_sec + diff_usec / 1000000.f;
00300
00301 } while( (f < RCD_MAX_FAILURES) && (pixels.size() > RCD_MIN_PIXELS) &&
00302 ( f_diff_sec < RCD_MAX_TIME) );
00303
00304 return num_circles;
00305 }
00306
00307 int RcdCircleModel::getShapeCount(void) const
00308 {
00309 return m_Circles.size();
00310 }
00311
00312 Circle* RcdCircleModel::getShape(int id) const
00313 {
00314 if (id < 0 || (unsigned int)id >= m_Circles.size())
00315 {
00316 return NULL;
00317 }
00318 else
00319 {
00320 return const_cast<Circle*>(&m_Circles[id]);
00321 }
00322 }
00323
00324 Circle* RcdCircleModel::getMostLikelyShape(void) const
00325 {
00326 int cur=0;
00327 switch (m_Circles.size())
00328 {
00329 case 0:
00330 return NULL;
00331 case 1:
00332 return const_cast<Circle*>(&m_Circles[0]);
00333 default:
00334 for (unsigned int i=1; i < m_Circles.size(); ++i)
00335 if (m_Circles[i].radius > m_Circles[cur].radius)
00336 cur = i;
00337 return const_cast<Circle*>(&m_Circles[cur]);
00338 }
00339 }
00340
00341 void RcdCircleModel::calcCircle(
00342 const point_t& p1,
00343 const point_t& p2,
00344 const point_t& p3,
00345 center_in_roi_t& center,
00346 float& radius)
00347
00348
00349
00350 {
00351 const int &x1=p1.x, &y1=p1.y, &x2=p2.x, &y2=p2.y, &x3=p3.x, &y3=p3.y;
00352 float dx, dy;
00353 int div = 2*((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1));
00354
00355 if (div == 0)
00356 {
00357
00358 radius = -1.0;
00359 return;
00360 }
00361 center.x = ((float)((x2*x2+y2*y2-x1*x1-y1*y1)*(y3-y1)
00362 -(x3*x3+y3*y3-x1*x1-y1*y1)*(y2-y1))
00363 /div);
00364 center.y = ((float)((x2-x1)*(x3*x3+y3*y3-x1*x1-y1*y1)
00365 -(x3-x1)*(x2*x2+y2*y2-x1*x1-y1*y1))
00366 /div);
00367 dx = center.x - x1;
00368 dy = center.y - y1;
00369 radius = (float)sqrt(dx*dx+dy*dy);
00370 }
00371
00372