00001
00002
00003 #include <math.h>
00004 #include "susan.h"
00005
00006 #include "visops.h"
00007
00008 using namespace DualCoding;
00009
00010 namespace visops {
00011
00012 Sketch<bool> zeros(SketchSpace& space) {
00013 Sketch<bool> result(space,"zeros()");
00014 *result.pixels = 0;
00015 return result;
00016 }
00017
00018 Sketch<bool> zeros(const SketchRoot& other) {
00019 const Sketch<bool>& fake = reinterpret_cast<const Sketch<bool>&>(other);
00020 Sketch<bool> result("zeros("+fake->getName()+")", fake);
00021 *result.pixels = 0;
00022 return result;
00023 }
00024
00025 Sketch<bool> colormask(const Sketch<uchar>& src, std::string colorname) {
00026 return colormask(src, ProjectInterface::getColorIndex(colorname));
00027 }
00028
00029 Sketch<bool> colormask(const Sketch<uchar>& src, int color_idx) {
00030 Sketch<bool> result(src == color_idx);
00031 result->setColor(ProjectInterface::getColorRGB(color_idx));
00032 return result;
00033 }
00034
00035 Sketch<usint> bdist(const Sketch<bool>& dest,
00036 const Sketch<bool>& obst,
00037 const int maxdist) {
00038 SketchSpace &space = dest->getSpace();
00039 space.requireIdx4way();
00040 Sketch<float> result("bdist("+dest->getName()+","+obst->getName()+")", dest);
00041 result = (usint)-1;
00042 result->setColorMap(jetMapScaled);
00043
00044
00045 SketchIndices frontier;
00046 frontier.addIndices(dest);
00047 result.setIndices(frontier, 0);
00048 SketchIndices obstInds;
00049 obstInds.addIndices(obst);
00050 SketchIndices newFrontier, oldFrontier;
00051
00052 for (float dist = 1; dist < maxdist; dist++) {
00053
00054
00055 newFrontier = frontier[*space.idxN] + frontier[*space.idxS]
00056 + frontier[*space.idxW] + frontier[*space.idxE]
00057 - (obstInds + frontier + oldFrontier);
00058 newFrontier.trimBounds(space);
00059
00060 if (newFrontier.table.empty())
00061 break;
00062 result.setIndices(newFrontier, dist);
00063 oldFrontier = frontier;
00064 frontier = newFrontier;
00065 }
00066
00067 return result;
00068 }
00069
00070 Sketch<usint> edist(const Sketch<bool>& target) {
00071 SketchSpace &space = target->getSpace();
00072 const int width = space.getWidth();
00073 const int height = space.getHeight();
00074 const usint maxdist = width + height + 1;
00075
00076
00077 Sketch<usint> dist("edist("+target->getName()+")", target);
00078 dist = maxdist;
00079 dist->setColorMap(jetMapScaled);
00080
00081
00082 for (int j = 0; j < height; j++) {
00083 for (int i = 0, cur_dist = maxdist; i < width; i++) {
00084 if (target(i,j) == 1)
00085 dist(i,j) = cur_dist = 0;
00086 else if (dist(i,j) < cur_dist)
00087 cur_dist = dist(i,j);
00088 else dist(i,j) = cur_dist;
00089 cur_dist++;
00090 }
00091 for (int i = width-1, cur_dist = maxdist; i >= 0; i--) {
00092 if (target(i,j) == true)
00093 dist(i,j) = cur_dist = 0;
00094 else if (dist(i,j) < cur_dist)
00095 cur_dist = dist(i,j);
00096 else
00097 dist(i,j) = cur_dist;
00098 cur_dist++;
00099 }
00100 }
00101
00102 for (int i = 0; i < width; i++) {
00103 for (int j = 0, cur_dist = maxdist; j < height; j++) {
00104 if (target(i,j) == 1)
00105 dist(i,j) = cur_dist = 0;
00106 else if (dist(i,j) < cur_dist)
00107 cur_dist = dist(i,j);
00108 else
00109 dist(i,j) = cur_dist;
00110 cur_dist++;
00111 }
00112 for (int j = height-1, cur_dist = maxdist; j >= 0; j--) {
00113 if (target(i,j) == 1)
00114 dist(i,j) = cur_dist = 0;
00115 else if (dist(i,j) < cur_dist)
00116 cur_dist = dist(i,j);
00117 else
00118 dist(i,j) = cur_dist;
00119 cur_dist++;
00120 }
00121 }
00122 return dist;
00123 }
00124
00125 Sketch<usint> labelcc(const Sketch<bool>& sketch, int minarea) {
00126 Sketch<uchar> temp;
00127 uchar *pixels;
00128 if ( sizeof(bool) == sizeof(uchar) )
00129 pixels = reinterpret_cast<uchar*>(&((*sketch.pixels)[0]));
00130 else {
00131 temp.bind((Sketch<uchar>)sketch);
00132 pixels = &((*temp.pixels)[0]);
00133 }
00134
00135
00136 int const maxRuns = (sketch.width * sketch.height) / 8;
00137 CMVision::run<uchar> *rle_buffer = new CMVision::run<uchar>[maxRuns];
00138 unsigned int const numRuns = CMVision::EncodeRuns(rle_buffer, pixels, sketch.width, sketch.height, maxRuns);
00139
00140
00141 CMVision::ConnectComponents(rle_buffer,numRuns);
00142 int const maxRegions = (sketch.width * sketch.height) / 16;
00143 CMVision::region *regions = new CMVision::region[maxRegions];
00144 unsigned int numRegions = CMVision::ExtractRegions(regions, maxRegions, rle_buffer, numRuns);
00145 int const numColors = 2;
00146 CMVision::color_class_state *ccs = new CMVision::color_class_state[numColors];
00147 unsigned int const maxArea = CMVision::SeparateRegions(ccs, numColors, regions, numRegions);
00148 CMVision::SortRegions(ccs, numColors, maxArea);
00149 CMVision::MergeRegions(ccs, numColors, rle_buffer);
00150
00151
00152 NEW_SKETCH(result, usint, visops::zeros(sketch));
00153 result->setColorMap(jetMapScaled);
00154 const CMVision::region* list_head = ccs[1].list;
00155 if ( list_head != NULL ) {
00156 for (int label=1; list_head!=NULL && list_head->area >= minarea;
00157 list_head = list_head->next, label++) {
00158
00159 for (int runidx = list_head->run_start; runidx != -1;
00160 runidx = rle_buffer[runidx].next ? rle_buffer[runidx].next : -1) {
00161 const CMVision::run<uchar> &this_run = rle_buffer[runidx];
00162 const int xstop = this_run.x + this_run.width;
00163 const int yi = this_run.y;
00164 for ( int xi = this_run.x; xi < xstop; xi++ )
00165 result(xi,yi) = label * sketch(xi,yi);
00166 }
00167 }
00168 }
00169
00170 delete[] ccs;
00171 delete[] regions;
00172 delete[] rle_buffer;
00173 return result;
00174 }
00175
00176
00177 Sketch<usint> oldlabelcc(const Sketch<bool>& source, Connectivity_t connectivity)
00178 {
00179 bool conn8 = (connectivity == EightWayConnect);
00180 const int width = source.width;
00181 const int height = source.height;
00182 Sketch<usint> labels("oldlabelcc("+source->getName()+")",source);
00183 labels = 0;
00184 labels->setColorMap(jetMapScaled);
00185
00186
00187
00188
00189 vector<int> eq_classes(500);
00190 eq_classes.clear();
00191 eq_classes.push_back(0);
00192 int highest_label = 0;
00193 int up_label = 0;
00194 int left_label = 0;
00195 int ul_label = 0;
00196 int ur_label = 0;
00197 for(int j = 0; j < height; j++) {
00198 for(int i = 0; i < width; i++) {
00199 if (source(i,j)) {
00200 up_label = (j == 0) ? 0 : labels(i,j-1);
00201 left_label = (i==0) ? 0 : labels(i-1,j);
00202 ul_label = (i==0||j==0) ? 0 : labels(i-1,j-1);
00203 ur_label = (i==(width-1)||j==0) ? 0 : labels(i+1,j-1);
00204 if (up_label == 0 && left_label == 0
00205 && (!conn8 || (ul_label == 0 && ur_label == 0))) {
00206 labels(i,j) = ++highest_label;
00207
00208 eq_classes.push_back(highest_label);
00209 } else if (up_label && !left_label) {
00210 labels(i,j) = up_label;
00211 } else if (conn8 && !up_label && ur_label) {
00212 labels(i,j) = ur_label;
00213 } else if (left_label && !up_label) {
00214 labels(i,j) = left_label;
00215 } else if (conn8 && !left_label && !up_label
00216 && ur_label && !ul_label) {
00217 labels(i,j) = ur_label;
00218 } else if (conn8 && !left_label && !up_label
00219 && ul_label && !ur_label){
00220 labels(i,j) = ul_label;
00221 }
00222
00223 if (up_label && left_label && (up_label != left_label)) {
00224
00225
00226
00227 int root = up_label;
00228 while (eq_classes[root] != root) {
00229 root = eq_classes[root];
00230 }
00231
00232 int tmp_root = up_label, next_root;
00233 while(eq_classes[tmp_root] != root) {
00234 next_root = eq_classes[tmp_root];
00235 eq_classes[tmp_root] = root;
00236 tmp_root = next_root;
00237 }
00238
00239 eq_classes[left_label] = root;
00240 labels(i,j) = root;
00241 } else if (up_label && (up_label == left_label)) {
00242 labels(i,j) = up_label;
00243 } else if (conn8 && ur_label && left_label
00244 && (ur_label != left_label)) {
00245
00246 int root = ur_label;
00247 while (eq_classes[root] != root) {
00248 root = eq_classes[root];
00249 }
00250
00251 int tmp_root = ur_label, next_root;
00252 while(eq_classes[tmp_root] != root) {
00253 next_root = eq_classes[tmp_root];
00254 eq_classes[tmp_root] = root;
00255 tmp_root = next_root;
00256 }
00257
00258 eq_classes[left_label] = root;
00259 labels(i,j) = root;
00260 }
00261 }
00262 }
00263 }
00264
00265
00266 int cur_label;
00267 for(int j = 0; j < height; j++) {
00268 for(int i = 0; i < width; i++) {
00269 cur_label = labels(i,j);
00270 if (cur_label != 0) {
00271 while(eq_classes[cur_label] != cur_label) {
00272 cur_label = eq_classes[cur_label];
00273 }
00274 labels(i,j) = cur_label;
00275 }
00276
00277 }
00278 }
00279
00280 return labels;
00281 }
00282
00283 Sketch<usint> areacc(const Sketch<bool>& source, Connectivity_t connectivity) {
00284 NEW_SKETCH_N(labels, usint, visops::oldlabelcc(source,connectivity));
00285 return visops::areacc(labels);
00286 }
00287
00288 Sketch<usint> areacc(const Sketch<usint>& labels) {
00289 vector<int> areas(1+labels->max(), 0);
00290 for (usint i = 0; i<labels->getNumPixels(); i++)
00291 ++areas[labels[i]];
00292 areas[0] = 0;
00293 Sketch<usint> result("areacc("+labels->getName()+")",labels);
00294 for (usint i = 0; i<labels->getNumPixels(); i++)
00295 result[i] = areas[labels[i]];
00296 return result;
00297 }
00298
00299 Sketch<bool> minArea(const Sketch<bool>& sketch, int minval) {
00300 NEW_SKETCH_N(labels, usint, visops::labelcc(sketch));
00301 NEW_SKETCH_N(areas, usint, visops::areacc(labels));
00302 NEW_SKETCH_N(result, bool, areas >= minval);
00303 return result;
00304 }
00305
00306 Sketch<uchar> neighborSum(const Sketch<bool>& im, Connectivity_t connectivity)
00307 {
00308
00309 SketchSpace &space = im->getSpace();
00310
00311 space.requireIdx4way();
00312 if (connectivity == EightWayConnect)
00313 space.requireIdx8way();
00314
00315 Sketch<uchar> result("neighborSum("+im->getName()+")", im);
00316 result->setColorMap(jetMapScaled);
00317 result = im[*space.idxN];
00318 result += im[*space.idxS];
00319 result += im[*space.idxW];
00320 result += im[*space.idxE];
00321 if (connectivity == EightWayConnect) {
00322 result += im[*space.idxNW];
00323 result += im[*space.idxNE];
00324 result += im[*space.idxSW];
00325 result += im[*space.idxSE];
00326 }
00327 return result;
00328 }
00329
00330 Sketch<bool> fillin(const Sketch<bool>& im, int iter,
00331 uchar min_thresh, uchar max_thresh, bool remove_only)
00332 {
00333 Sketch<bool> result(im);
00334 if ( remove_only )
00335 result.bind(visops::copy(im));
00336 Sketch<uchar> neighborCount(im);
00337 if (remove_only) {
00338 neighborCount.bind(neighborSum(result,EightWayConnect));
00339 result &= (neighborCount <= max_thresh);
00340 for (int i = 0; i < iter; i++)
00341 result &= (neighborCount >= min_thresh);
00342 }
00343 else {
00344 for (int i = 0; i < iter; i++) {
00345 neighborCount.bind(neighborSum(result,EightWayConnect));
00346 result.bind((neighborCount >= min_thresh) & (neighborCount <= max_thresh));
00347 }
00348 }
00349 result->setName("fillin("+im->getName()+")");
00350 result->setColor(im->getColor());
00351 return result;
00352 }
00353
00354 Sketch<bool> edge(const Sketch<bool> &im) {
00355 im->getSpace().requireIdx4way();
00356 SketchSpace &space = im->getSpace();
00357 return (im != im[*space.idxS] | im != im[*space.idxE]);
00358 }
00359
00360
00361 Sketch<bool> horsym(const Sketch<bool> &im, int minskip, int maxskip)
00362 {
00363 NEW_SKETCH_N(result, bool, visops::zeros(im));
00364 result->setName("horsym("+im->getName()+")");
00365 const int width = im->getWidth();
00366 const int height = im->getHeight();
00367
00368 for (int j = 0; j < height; j++) {
00369 for (int i = 0; i < width; i++) {
00370 while (i < width && !im(i,j)) i++;
00371 for (int k = i+1; k <= width; k++) {
00372 if ( k==width || !im(k,j)) {
00373 if ( (k-i) >= minskip && (k-i) <= maxskip ) {
00374 const int u = (i+k)/2;
00375 result(u,j) = true;
00376 }
00377 i=k+1;
00378 break;
00379 }
00380 }
00381 }
00382 }
00383 return result;
00384 }
00385
00386 Sketch<bool> versym(const Sketch<bool> &im, int minskip, int maxskip)
00387 {
00388 NEW_SKETCH_N(result, bool, visops::zeros(im));
00389 result->setName("horsym("+im->getName()+")");
00390 const int width = im->getWidth();
00391 const int height = im->getHeight();
00392
00393 for (int i = 0; i < width; i++) {
00394 for (int j = 0; j < height; j++) {
00395 while (j < height && !im(i,j)) j++;
00396 for (int k = j+1; k <= height; k++) {
00397 if ( k==height || !im(i,k)) {
00398 if ( (k-j) >= minskip && (k-j) <= maxskip ) {
00399 const int u = (j+k)/2;
00400 result(i,u) = true;
00401 }
00402 j=k+1;
00403 break;
00404 }
00405 }
00406 }
00407 }
00408 return result;
00409 }
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 Sketch<bool> skel(const Sketch<bool>& im)
00446 {
00447 NEW_SKETCH_N(result, bool, horsym(im) | versym(im));
00448 result->setName("skel("+im->getName()+")");
00449 return result;
00450 }
00451
00452 Sketch<bool> seedfill(const Sketch<bool>& borders, size_t index)
00453 {
00454
00455 NEW_SKETCH_N(regions, usint, oldlabelcc(! borders, visops::FourWayConnect));
00456 NEW_SKETCH_N(result, bool, regions == regions->at(index));
00457 return result;
00458 }
00459
00460 Sketch<bool> leftHalfPlane(const Shape<LineData> &ln) {
00461 SketchSpace &SkS = ln->getSpace().getDualSpace();
00462
00463 int const x1 = (int)ln->end1Pt().coordX();
00464 int const y1 = (int)ln->end1Pt().coordY();
00465 int const x2 = (int)ln->end2Pt().coordX();
00466 int const y2 = (int)ln->end2Pt().coordY();
00467 float const m = (x1 == x2) ? BIG_SLOPE : (y2-y1) / (x2-x1);
00468 int const b = (int) (y1 - x1*m);
00469 int seed;
00470 if ( x1 == x2 )
00471 seed = ( x1 <= 0 ) ? -1 : 0;
00472 else if ( ln->getOrientation() > M_PI/2 )
00473 seed = ( b <= 0) ? -1 : 0;
00474 else
00475 seed = ( b < (int)SkS.getHeight() - 1 ) ? (*SkS.idx)(0,SkS.getHeight()-1) : -1;
00476 if ( seed == -1 ) {
00477 NEW_SKETCH_N(result, bool, visops::zeros(SkS));
00478 result->inheritFrom(ln);
00479 return result;
00480 } else {
00481 NEW_SHAPE_N(line_copy, LineData, ln->copy());
00482 line_copy->setInfinite();
00483 NEW_SKETCH_N(bounds, bool, line_copy->getRendering());
00484 bounds->inheritFrom(ln);
00485 return visops::seedfill(bounds,seed);
00486 }
00487 }
00488
00489 Sketch<bool> rightHalfPlane(const Shape<LineData> &ln) {
00490 NEW_SHAPE_N(line_copy, LineData, ln->copy());
00491 line_copy->setInfinite();
00492 NEW_SKETCH_N(bounds, bool, line_copy->getRendering());
00493 bounds->inheritFrom(ln);
00494 return ! (visops::leftHalfPlane(ln) | bounds);
00495 }
00496
00497 Sketch<bool> topHalfPlane(const Shape<LineData> &ln) {
00498 SketchSpace &SkS = ln->getSpace().getDualSpace();
00499
00500 int const x1 = (int)ln->end1Pt().coordX();
00501 int const y1 = (int)ln->end1Pt().coordY();
00502 int const x2 = (int)ln->end2Pt().coordX();
00503 int const y2 = (int)ln->end2Pt().coordY();
00504 float const m = (x1 == x2) ? BIG_SLOPE : (y2-y1) / (x2-x1);
00505 int const b = (int) (y1 - x1*m);
00506 int seed;
00507 if ( x1 == x2 )
00508 seed = ( y1 <= 0 ) ? -1 : 0;
00509 else if ( ln->getOrientation() > M_PI/2 )
00510 seed = ( b <= 0) ? -1 : 0;
00511 else
00512 seed = ( int(m*(SkS.getWidth()-1)+b) > 0 ) ? (*SkS.idx)(SkS.getWidth()-1,0) : -1;
00513 if ( seed == -1 ) {
00514 NEW_SKETCH_N(result, bool, visops::zeros(SkS));
00515 result->inheritFrom(ln);
00516 return result;
00517 } else {
00518 NEW_SHAPE_N(line_copy, LineData, ln->copy());
00519 line_copy->setInfinite();
00520 NEW_SKETCH_N(bounds, bool, line_copy->getRendering());
00521 bounds->inheritFrom(ln);
00522 return visops::seedfill(bounds,seed);
00523 }
00524 }
00525
00526 Sketch<bool> bottomHalfPlane(const Shape<LineData> &ln) {
00527 NEW_SHAPE_N(line_copy, LineData, ln->copy());
00528 line_copy->setInfinite();
00529 NEW_SKETCH_N(bounds, bool, line_copy->getRendering());
00530 bounds->inheritFrom(ln);
00531 return ! (visops::topHalfPlane(ln) | bounds);
00532 }
00533
00534 Sketch<bool> non_bounds(const Sketch<bool>& im, int offset) {
00535 const int width = im->getWidth();
00536 const int height = im->getHeight();
00537 NEW_SKETCH_N(nbresult,bool,visops::copy(im));
00538 nbresult->setName("non_bounds("+im->getName()+")");
00539
00540 for (int i = 0; i < width; i++) {
00541 for (int j = 0; j < offset; j++) {
00542 nbresult(i,j) = false;
00543 nbresult(i,height-j-1) = false;
00544 }
00545 }
00546 for (int i = 0; i < offset; i++) {
00547 for (int j = offset; j < height-offset; j++) {
00548 nbresult(i,j) = false;
00549 nbresult(width-i-1,j) = false;
00550 }
00551 }
00552 return nbresult;
00553 }
00554
00555
00556 Sketch<uchar> susan_edges(const Sketch<uchar>& im, int brightness)
00557 {
00558 const int width = im->getWidth();
00559 const int height = im->getHeight();
00560 unsigned char *bp;
00561 Sketch<uchar> edges(visops::copy(im));
00562
00563 int *r = (int *)malloc(width*height*sizeof(int));
00564
00565 unsigned char *mid = (unsigned char *)malloc(width*height);
00566 memset (mid,100,width * height);
00567
00568 setup_brightness_lut(&bp,brightness,6);
00569
00570
00571
00572 susan_edges_internal(edges->getRawPixels(), r, mid, bp, 2650, width, height);
00573
00574 susan_thin(r, mid, width, height);
00575
00576 edge_draw(edges->getRawPixels(),mid,width,height,0);
00577
00578 free(r);
00579 free(mid);
00580 free(bp-258);
00581
00582 return edges;
00583 }
00584
00585
00586
00587 Sketch<bool> susan_edge_points(const Sketch<uchar>& im, int brightness)
00588 {
00589 const int width = im->getWidth();
00590 const int height = im->getHeight();
00591 unsigned char *bp;
00592 Sketch<uchar> orig(im);
00593 Sketch<uchar> edges(visops::zeros(im));
00594 int *r = (int *)malloc(width*height*sizeof(int));
00595 unsigned char *mid = (unsigned char *)malloc(width*height);
00596 memset(mid,100,width * height);
00597 setup_brightness_lut(&bp,brightness,6);
00598 susan_edges_internal(orig->getRawPixels(), r, mid, bp, 2650, width, height);
00599 susan_thin(r, mid, width, height);
00600 edge_draw(edges->getRawPixels(),mid,width,height,1);
00601 free(r);
00602 free(mid);
00603 Sketch<bool> result(edges);
00604 return result;
00605 }
00606
00607 Sketch<usint> convolve(const Sketch<uchar> &sketch, Sketch<uchar> &kernel,
00608 int istart, int jstart, int width, int height) {
00609 Sketch<usint> result("convolve("+sketch->getName()+")",sketch);
00610 result->setColorMap(jetMapScaled);
00611 int const di = - (int)(width/2);
00612 int const dj = - (int)(height/2);
00613 for (int si=0; si<sketch.width; si++)
00614 for (int sj=0; sj<sketch.height; sj++) {
00615 int sum = 0;
00616 for (int ki=0; ki<width; ki++)
00617 for (int kj=0; kj<height; kj++)
00618 if ( si+di+ki >= 0 && si+di+ki < sketch.width &&
00619 sj+dj+kj >= 0 && sj+dj+kj < sketch.height )
00620 sum += (usint)sketch(si+di+ki,sj+dj+kj) * (usint)kernel(istart+ki,jstart+kj);
00621 result(si,sj) = sum/(width*height);
00622 }
00623 return result;
00624 }
00625
00626 Sketch<usint> templateMatch(const Sketch<uchar> &sketch, Sketch<uchar> &kernel,
00627 int istart, int jstart, int width, int height) {
00628 Sketch<usint> result("convolve0("+sketch->getName()+")",sketch);
00629 result->setColorMap(jetMapScaled);
00630 int const npix = width * height;
00631 int const di = - (int)(width/2);
00632 int const dj = - (int)(height/2);
00633 for (int si=0; si<sketch.width; si++)
00634 for (int sj=0; sj<sketch.height; sj++) {
00635 int sum = 0;
00636 for (int ki=0; ki<width; ki++)
00637 for (int kj=0; kj<height; kj++) {
00638 int k_pix = kernel(istart+ki,jstart+kj);
00639 if ( si+di+ki >= 0 && si+di+ki < sketch.width &&
00640 sj+dj+kj >= 0 && sj+dj+kj < sketch.height ) {
00641 int s_pix = sketch(si+di+ki,sj+dj+kj);
00642 sum += (s_pix - k_pix) * (s_pix - k_pix);
00643 }
00644 else
00645 sum += k_pix * k_pix;
00646 }
00647 result(si,sj) = 65535 - usint(sqrt(sum/float(npix)));
00648 }
00649 result = result - result->min();
00650 return result;
00651 }
00652
00653
00654 }