Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

visops.cc

Go to the documentation of this file.
00001 //-*-c++-*-
00002 
00003 #include <math.h>
00004 #include "susan.h"
00005 
00006 #include "visops.h"
00007 #include "Vision/cmvision.h"
00008 
00009 using namespace DualCoding;
00010 
00011 namespace visops {
00012 
00013 Sketch<bool> zeros(SketchSpace& space) {
00014   Sketch<bool> result(space,"zeros()");
00015   *result.pixels = 0;  // valarray assignment
00016   return result;
00017 }
00018 
00019 Sketch<bool> zeros(const SketchRoot& other) {
00020   const Sketch<bool>& fake = reinterpret_cast<const Sketch<bool>&>(other);
00021   Sketch<bool> result("zeros("+fake->getName()+")", fake);
00022   *result.pixels = 0;  // valarray assignment
00023   return result;
00024 }
00025 
00026 Sketch<bool> colormask(const Sketch<uchar>& src, const std::string &colorname) {
00027   return colormask(src, ProjectInterface::getColorIndex(colorname));
00028 }
00029 
00030 Sketch<bool> colormask(const Sketch<uchar>& src, color_index cindex) {
00031   Sketch<bool> result(src == cindex);
00032   result->setColor(ProjectInterface::getColorRGB(cindex));
00033   return result;
00034 }
00035 
00036 std::vector<xyPair> boundaryPoints(const Sketch<uint>& dest, uint& mindist, const uint maxval) {
00037   SketchSpace &space = dest->getSpace();
00038   const int width = space.getWidth();
00039   const int height = space.getHeight();
00040   std::vector<xyPair> boundaryPt;
00041   boundaryPt.clear();
00042   mindist = maxval;
00043   
00044   for (int i=1; i<width-1; i++)
00045     for (int j=1; j<height-1; j++)
00046       if (dest(i,j)<maxval)
00047       /*
00048         if ( dest(i-1,j-1)>=maxval || dest(i,j-1)>=maxval || dest(i+1,j-1)>=maxval || 
00049              dest(i-1,j)>=maxval || dest(i+1,j)>=maxval || 
00050              dest(i-1,j+1)>=maxval || dest(i,j+1)>=maxval || dest(i+1,j+1)>=maxval )
00051         {
00052           boundaryPt.push_back(xyPair(i,j));
00053           if (dest(i,j)<mindist) mindist = dest(i,j);
00054         }
00055       *//*
00056         if ( dest(i-1,j-1)==maxval || dest(i,j-1)==maxval || dest(i+1,j-1)==maxval || 
00057              dest(i-1,j)==maxval || dest(i+1,j)==maxval || 
00058              dest(i-1,j+1)==maxval || dest(i,j+1)==maxval || dest(i+1,j+1)==maxval )
00059         {
00060           boundaryPt.push_back(xyPair(i,j));
00061           if (dest(i,j)<mindist) mindist = dest(i,j);
00062         }
00063       */
00064         if ( dest(i,j-1)==maxval || 
00065              dest(i-1,j)==maxval || 
00066              dest(i+1,j)==maxval || 
00067              dest(i,j+1)==maxval )
00068         {
00069           boundaryPt.push_back(xyPair(i,j));
00070           if (dest(i,j)<mindist) mindist = dest(i,j);
00071         }
00072       
00073   return boundaryPt;
00074 }
00075 
00076 bool radiate(const xyPair center, Sketch<uint>& dist, const Sketch<bool>& dest, const Sketch<bool>& obst, const uint maxval) {
00077   SketchSpace &space = dist->getSpace();
00078   const int width = space.getWidth();
00079   const int height = space.getHeight();
00080   const int ctxiw = center.first;
00081   const int ctyjh = center.second;
00082   const uint centerdis = dist(ctxiw,ctyjh);
00083   
00084   float r[360];
00085   int theta[5];
00086   for (int i=0; i<360; i++) r[i]=maxval;
00087   for (int i=1; i<width-1; i++)
00088     for (int j=1; j<height-1; j++) {
00089       if (i==ctxiw && j== ctyjh) continue;
00090       //else if (obst(i,j)||dest(i,j)) {
00091       else if (obst(i,j)) {
00092         if ((i-1==ctxiw && j== ctyjh)) {r[0]=1;continue;}
00093         if ((i+1==ctxiw && j==ctyjh)) {r[180]=1;continue;}
00094         if ((i==ctxiw && j-1==ctyjh)) {r[270]=1;continue;}
00095         if ((i==ctxiw && j+1==ctyjh)) {r[90]=1;continue;}
00096         float temp = std::sqrt( (j-ctyjh)*(j-ctyjh) + (i-ctxiw)*(i-ctxiw) );
00097         theta[0] = int(std::atan2(j-ctyjh, i-ctxiw)*180/M_PI+360)%360;
00098         theta[1] = int(std::atan2(j-ctyjh, i+1-ctxiw)*180/M_PI+360)%360;
00099         theta[2] = int(std::atan2(j-1-ctyjh, i-ctxiw)*180/M_PI+360)%360;
00100         theta[3] = int(std::atan2(j-ctyjh, i-1-ctxiw)*180/M_PI+360)%360;
00101         theta[4] = int(std::atan2(j+1-ctyjh, i-ctxiw)*180/M_PI+360)%360;
00102         bool area1 = false;
00103         bool area4 = false;
00104         for (int k=0; k<5; k++) {
00105           if (theta[k] >=0 && theta[k] < 90) area1 = true;
00106           else if (theta[k] >=270 && theta[k] < 360) area4 = true;
00107         }
00108         if (area1 && area4) {
00109           for (int k=0; k<5; k++)
00110             if (theta[k]<=90) theta[k]+=360;
00111         }
00112         int start = 1000;
00113         int end = -1;
00114         for (int k=0; k<5; k++) {
00115           if (start>theta[k]) start = theta[k];
00116           if (end<theta[k]) end = theta[k];
00117         }
00118         for (int k=start; k<=end+1; k++)
00119           if (r[k%360] > temp) r[k%360] = temp;
00120       }
00121     }
00122   
00123   bool changed = false;
00124   for (int i=0; i<width; i++)
00125     for (int j=0; j<height; j++) {
00126       if (obst(i,j) || dest(i,j)) continue;
00127       int thet = int(std::atan2(j-ctyjh, i-ctxiw)*180/M_PI+360)%360;
00128       float temp = std::sqrt( (j-ctyjh)*(j-ctyjh) + (i-ctxiw)*(i-ctxiw) );
00129       //if ( temp<r[thet] && dist(i,j)>centerdis+temp && dist(i,j)!=maxval+1) {
00130       if ( temp<r[thet] && dist(i,j)>centerdis+temp) {
00131         dist(i,j) = centerdis+temp;
00132         changed = true;
00133       }
00134     }
00135   
00136   return changed;
00137 }
00138 
00139 Sketch<uint> ebdist(const Sketch<bool>& dest, const Sketch<bool>& obst, const uint maxdist, const uint time) {
00140   SketchSpace &space = dest->getSpace();
00141   const int width = space.getWidth();
00142   const int height = space.getHeight();
00143   const uint maxval = (uint)-2;
00144   
00145   Sketch<uint> distSk("ebdist("+dest->getName()+","+obst->getName()+")", dest);
00146   distSk = maxval;
00147   distSk->setColorMap(jetMapScaled);
00148   
00149   for (int i=0; i<width; i++)
00150     for (int j=0; j<height; j++)
00151       if (dest(i,j)) distSk(i,j)=0;
00152       
00153   for (int i=0; i<width; i++)
00154     for (int j=0; j<height; j++)
00155       if (obst(i,j)) distSk(i,j)=maxval+1;
00156       
00157   bool finish = false;
00158   uint t = 0;
00159   uint mindist;
00160   std::vector<xyPair> boundary = boundaryPoints(distSk, mindist, maxval);
00161   if (boundary.size() == 0) finish = true;
00162   else if (mindist >= maxval) finish = true;
00163   while (!finish) {
00164     bool changed = false;
00165     for(std::vector<xyPair>::iterator it=boundary.begin(); it!=boundary.end(); it++) {
00166       if (radiate(*it, distSk, dest, obst, maxval)) changed = true;
00167     }
00168     //for display only
00169     //for(std::vector<xyPair>::iterator it=boundary.begin(); it!=boundary.end(); it++) {
00170     //  distSk(it->first, it->second) = maxval+1;
00171     //}
00172     //end display
00173     t++;
00174     if (!changed) break;
00175     if (t >= time && time!=0) break;
00176     boundary = boundaryPoints(distSk, mindist, maxval);
00177     if (boundary.size() == 0) break;
00178     else if (mindist >= maxval) break;
00179   }
00180   
00181   std::cout << "Run radiate for " << t << " times." << std::endl;
00182   for (int i=0; i<width; i++)
00183     for (int j=0; j<height; j++)
00184       if ( distSk(i,j) > maxdist ) distSk(i,j)=maxdist;
00185       
00186   return distSk;
00187 }
00188 
00189 Sketch<uint> bdist(const Sketch<bool>& dest, 
00190           const Sketch<bool>& obst, 
00191           const uint maxdist) {
00192   SketchSpace &space = dest->getSpace();
00193   space.requireIdx4way();
00194   Sketch<uint> result("bdist("+dest->getName()+","+obst->getName()+")", dest);
00195   result = maxdist;
00196   result->setColorMap(jetMapScaled);
00197   
00198   // Start at the target and iteratively expand out the frontier
00199   SketchIndices frontier;
00200   frontier.addIndices(dest);
00201   result.setIndices(frontier, 0);
00202   SketchIndices obstInds;
00203   obstInds.addIndices(obst);
00204   SketchIndices newFrontier, oldFrontier;
00205 
00206   for (uint dist = 1; dist < maxdist; dist++) {
00207     // newFrontier should become all values adjacent to frontier, not
00208     // actually in the frontier, not a boundary, or in oldFrontier
00209     newFrontier = frontier[*space.idxN] + frontier[*space.idxS] 
00210       + frontier[*space.idxW] + frontier[*space.idxE]
00211       - (obstInds + frontier + oldFrontier);
00212     newFrontier.trimBounds(space);
00213     // if no more frontier, done
00214     if (newFrontier.table.empty())
00215       break;
00216     result.setIndices(newFrontier, dist);
00217     oldFrontier = frontier;
00218     frontier = newFrontier;
00219   }
00220   
00221   return result;
00222 }
00223 
00224 Sketch<uint> mdist(const Sketch<bool>& targetSk) {
00225   SketchSpace &space = targetSk->getSpace();
00226   const size_t width = space.getWidth();
00227   const size_t height = space.getHeight();
00228   const uint maxdist = width + height + 1;
00229   // at the moment doing 4-pass linear Manhattan distance, but should
00230   // probably use linear-time Euclidean algorithm described in 
00231   Sketch<uint> distSk("mdist("+targetSk->getName()+")", targetSk);
00232   distSk = maxdist;
00233   distSk->setColorMap(jetMapScaled);
00234   
00235   SketchData<bool>& target = *targetSk.data;
00236   SketchData<uint>& dist = *distSk.data;
00237   uint cur_dist;
00238   
00239   // find min distances within each row
00240   for (size_t j = 0; j < height; j++) {
00241     cur_dist = maxdist;
00242     const bool* targetrow = &target(0,j);
00243     uint* distrow = &dist(0,j);
00244     for (size_t i = 0; i < width; i++) {
00245       if (targetrow[i] == 1)
00246         distrow[i] = cur_dist = 0;
00247       else if (distrow[i] < (uint)cur_dist)
00248         cur_dist = distrow[i];
00249       else distrow[i] = cur_dist;
00250       cur_dist++;
00251     }
00252     cur_dist = maxdist;
00253     for (size_t i = width; i > 0; ) {
00254       --i;
00255       if (targetrow[i] == true)
00256   distrow[i] = cur_dist = 0;
00257       else if (distrow[i] < (uint)cur_dist)
00258   cur_dist = distrow[i];
00259       else
00260   distrow[i] = cur_dist;
00261       cur_dist++;
00262     }
00263   }
00264   // find min distances within each column
00265   for (size_t i = 0; i < width; i++) {
00266     cur_dist = maxdist;
00267     const bool* targetcol = &target(i,0);
00268     uint* distcol = &dist(i,0);
00269     for (size_t j = 0; j < height*width; j+=width) {
00270       if (targetcol[j] == 1)
00271         distcol[j] = cur_dist = 0;
00272       else if (distcol[j] < (uint)cur_dist)
00273         cur_dist = distcol[j];
00274       else
00275         distcol[j] = cur_dist;
00276       cur_dist++;
00277     }
00278     cur_dist = maxdist;
00279     for (size_t j = height*width; j  > 0; ) {
00280       j-=width;
00281       if (targetcol[j] == 1)
00282         distcol[j] = cur_dist = 0;
00283       else if (distcol[j] < (uint)cur_dist)
00284         cur_dist = distcol[j];
00285       else
00286         distcol[j] = cur_dist;
00287       cur_dist++;
00288     }
00289   }
00290   return distSk;
00291 }
00292 
00293   Sketch<float> edist(const Sketch<bool>& targetSk) {
00294     SketchSpace &space = targetSk->getSpace();
00295     const size_t width = space.getWidth();
00296     const size_t height = space.getHeight();
00297     const uint maxdist = width + height + 1;
00298   
00299     Sketch<uint> xVals("xVals(" + targetSk->getName() + ")", targetSk);
00300     Sketch<uint> yVals("yVals(" + targetSk->getName() + ")", targetSk);
00301     xVals = maxdist;
00302     yVals = maxdist;
00303     xVals->setColorMap(jetMapScaled);
00304     yVals->setColorMap(jetMapScaled);
00305     Sketch<float> distSk("edist("+targetSk->getName()+")", targetSk);
00306     distSk = maxdist;
00307     distSk->setColorMap(jetMapScaled);
00308   
00309     uint cur_xdist, cur_ydist;
00310     float cur_dist, this_dist;
00311 
00312     // There is probably a smarter way to compute this.  The present
00313     // algorithm is copied from mdist but requires at least two passes
00314     // because Euclidean distance requires us to maintain separate
00315     // xVal and yVal arrays.
00316 
00317     for (int pass=0; pass<2; pass++) {
00318       // find min distances within each row
00319       for (size_t j = 0; j < height; j++) {
00320   cur_xdist = maxdist;
00321   cur_ydist = maxdist;
00322   for (size_t i = 0; i < width; i++) {
00323     if (targetSk(i,j) == true) {
00324       xVals(i,j) = cur_xdist = 0;
00325       yVals(i,j) = cur_ydist = 0;
00326     } else {
00327       cur_dist = cur_xdist*cur_xdist + cur_ydist*cur_ydist;
00328       this_dist = xVals(i,j)*xVals(i,j) + yVals(i,j)*yVals(i,j);
00329       if (this_dist < cur_dist) {
00330         cur_xdist = xVals(i,j);
00331         cur_ydist = yVals(i,j);
00332       } else {
00333         xVals(i,j) = cur_xdist;
00334         yVals(i,j) = cur_ydist;
00335       }
00336     }
00337     cur_xdist++;
00338   }
00339   cur_xdist = maxdist;
00340   cur_ydist = maxdist;
00341   for (size_t i = width; i > 0; ) {
00342     i--;
00343     if (targetSk(i,j) == true) {
00344       xVals(i,j) = cur_xdist = 0;
00345       yVals(i,j) = cur_ydist = 0;
00346     } else {
00347       cur_dist = cur_xdist*cur_xdist + cur_ydist*cur_ydist;
00348       this_dist = xVals(i,j)*xVals(i,j) + yVals(i,j)*yVals(i,j);
00349       if (this_dist < cur_dist) {
00350         cur_xdist = xVals(i,j);
00351         cur_ydist = yVals(i,j);
00352       } else {
00353         xVals(i,j) = cur_xdist;
00354         yVals(i,j) = cur_ydist;
00355       }
00356     }
00357     cur_xdist++;
00358   }
00359       }
00360   
00361       // find min distances within each column
00362       for (size_t i = 0; i < width; i++) {
00363   cur_xdist = maxdist;
00364   cur_ydist = maxdist;
00365     
00366   for (size_t j = 0; j < height; j++) {
00367     if (targetSk(i,j) == true) {
00368       xVals(i,j) = cur_xdist = 0;
00369       yVals(i,j) = cur_ydist = 0;
00370     } else {
00371       cur_dist = cur_xdist*cur_xdist + cur_ydist*cur_ydist;
00372       this_dist = xVals(i,j)*xVals(i,j) + yVals(i,j)*yVals(i,j);
00373       if (this_dist < cur_dist) {
00374         cur_xdist = xVals(i,j);
00375         cur_ydist = yVals(i,j);
00376       } else {
00377         xVals(i,j) = cur_xdist;
00378         yVals(i,j) = cur_ydist;
00379       }
00380     }
00381     cur_ydist++;
00382   }
00383   cur_xdist = maxdist;
00384   cur_ydist = maxdist;
00385   for (size_t j = height; j > 0; ) {
00386     j--;
00387     if (targetSk(i,j) == true) {
00388       xVals(i,j) = cur_xdist = 0;
00389       yVals(i,j) = cur_ydist = 0;
00390     } else {
00391       cur_dist = cur_xdist*cur_xdist + cur_ydist*cur_ydist;
00392       this_dist = xVals(i,j)*xVals(i,j) + yVals(i,j)*yVals(i,j);
00393       if (this_dist < cur_dist) {
00394         cur_xdist = xVals(i,j);
00395         cur_ydist = yVals(i,j);
00396       } else {
00397         xVals(i,j) = cur_xdist;
00398         yVals(i,j) = cur_ydist;
00399       }
00400     }
00401     cur_ydist++;
00402   }
00403       }
00404     }
00405   
00406     for(unsigned i = 0; i < width; i++)
00407       for(unsigned j = 0; j < height; j++) {
00408   float x = (float)xVals(i,j), y = (float)yVals(i,j);
00409   distSk(i,j) = std::sqrt(x*x + y*y);
00410       }
00411   
00412     return distSk;
00413   }
00414   
00415 Sketch<uint> labelcc(const Sketch<bool>& sketch, int minarea) {
00416   Sketch<uchar> temp;
00417   uchar *pixels;
00418   if ( sizeof(bool) == sizeof(uchar) )
00419     pixels = reinterpret_cast<uchar*>(&((*sketch.pixels)[0]));
00420   else {
00421     temp.bind((Sketch<uchar>)sketch);
00422     pixels = &((*temp.pixels)[0]);
00423   }
00424 
00425   // convert pixel array to RLE
00426   int const maxRuns = (sketch.width * sketch.height) / 8;
00427   CMVision::run<uchar> *rle_buffer = new CMVision::run<uchar>[maxRuns];
00428   unsigned int const numRuns = CMVision::EncodeRuns(rle_buffer, pixels, sketch.width, sketch.height, maxRuns);
00429 
00430   // convert RLE to region list
00431   CMVision::ConnectComponents(rle_buffer,numRuns);
00432   int const maxRegions = (sketch.width * sketch.height) / 16;   // formula from RegionGenerator.h
00433   CMVision::region *regions = new CMVision::region[maxRegions];
00434   unsigned int numRegions = CMVision::ExtractRegions(regions, maxRegions, rle_buffer, numRuns);
00435   int const numColors = 2;  // only two colors in a Sketch<bool>: 0 and 1
00436   CMVision::color_class_state *ccs = new CMVision::color_class_state[numColors];
00437   unsigned int const maxArea = CMVision::SeparateRegions(ccs, numColors, regions, numRegions);
00438   CMVision::SortRegions(ccs, numColors, maxArea);
00439   CMVision::MergeRegions(ccs, numColors, rle_buffer);
00440 
00441   // extract regions from region list
00442   NEW_SKETCH_N(result, uint, visops::zeros(sketch));
00443   result->setColorMap(jetMapScaled);
00444   const CMVision::region* list_head = ccs[1].list;
00445   if ( list_head != NULL ) {
00446     for (int label=1; list_head!=NULL && list_head->area >= minarea;
00447      list_head = list_head->next, label++) {
00448       // the first run might be array element 0, so use -1 as end of list test
00449       for (int runidx = list_head->run_start; runidx != -1;
00450      runidx = rle_buffer[runidx].next ? rle_buffer[runidx].next : -1) {
00451   const CMVision::run<uchar> &this_run = rle_buffer[runidx];
00452   const int xstop = this_run.x + this_run.width;
00453   const int yi = this_run.y;
00454   for ( int xi = this_run.x; xi < xstop; xi++ )
00455     result(xi,yi) = label * sketch(xi,yi); // the * undoes some of CMVision's noise removal
00456       }
00457     }
00458   }
00459 
00460   delete[] ccs;
00461   delete[] regions;
00462   delete[] rle_buffer;
00463   return result;
00464 }
00465 
00466 // written with guidance from this page: http://www.dai.ed.ac.uk/HIPR2/label.htm
00467 Sketch<uint> oldlabelcc(const Sketch<bool>& source, Connectivity_t connectivity)
00468 {
00469   bool conn8 = (connectivity == EightWayConnect);
00470   const int width = source.width;
00471   const int height = source.height;
00472   Sketch<uint> labels("oldlabelcc("+source->getName()+")",source);
00473   labels = 0;
00474   labels->setColorMap(jetMapScaled);
00475   uint* data = labels->getRawPixels();
00476   const bool* srcdata = source->getRawPixels();
00477   
00478   // First scan: Give initial labels and sort connected label classes
00479   // into equivalence classes using UNION-FIND
00480   // Doing something similar to tree-based UNION-FIND, without the tree
00481   std::vector<int> eq_classes(500); // vector of equivalence classes for union-find
00482   eq_classes.clear();
00483   eq_classes.push_back(0); // added just so that indices match up with labels
00484   int highest_label = 0;
00485   int up_label = 0; // value above current pixel
00486   int left_label = 0; // value to left of current pixel
00487   int ul_label = 0; // value to upper-left of current pixel
00488   int ur_label = 0; // value to upper-right of current pixel
00489   for(int j = 0; j < height; j++) {
00490     uint* row = &data[j*width];
00491     const bool* srcrow = &srcdata[j*width];
00492     for(int i = 0; i < width; i++) {
00493       uint* p = &row[i];
00494       if (srcrow[i]) {
00495         up_label = (j == 0) ? 0 : *(p-width);
00496         left_label = (i==0) ? 0 : *(p-1); 
00497         ul_label = (i==0||j==0) ? 0 : *(p-1-width);
00498         ur_label = (i==(width-1)||j==0) ? 0 : *(p+1-width);
00499         if (up_label == 0 && left_label == 0 && (!conn8 || (ul_label == 0 && ur_label == 0))) {
00500           *p = ++highest_label;  // create new label
00501           // push back a new root label
00502           eq_classes.push_back(highest_label); // label value will be equal to index
00503         } else if (up_label && !left_label) {
00504           *p = up_label;
00505         } else if (conn8 && !up_label && ur_label) {
00506           *p = ur_label;
00507         } else if (left_label && !up_label) {
00508           *p = left_label;
00509         } else if (conn8 && !left_label && !up_label && ur_label && !ul_label) {
00510           *p = ur_label; 
00511         } else if (conn8 && !left_label && !up_label && ul_label && !ur_label){
00512           *p = ul_label;  
00513         }
00514         
00515         if (up_label && left_label && (up_label != left_label)) {
00516           // form union between two equivalence classes
00517           // if upper-left, assume equivalence class already made
00518           
00519           int root = up_label;
00520           while (eq_classes[root] != root) {
00521             root = eq_classes[root]; // "FIND" of UNION-FIND
00522           }
00523           // should do path compression to make more efficient
00524           int tmp_root = up_label, next_root;
00525           while(eq_classes[tmp_root] != root) {
00526             next_root = eq_classes[tmp_root];
00527             eq_classes[tmp_root] = root; // compress
00528             tmp_root = next_root;
00529           }
00530           
00531           eq_classes[left_label] = root; // "UNION" of UNION-FIND
00532           *p = root; // not sure why putting this here works, but it does
00533         } else if (up_label && (up_label == left_label)) {
00534           *p = up_label;  
00535         } else if (conn8 && ur_label && left_label && (ur_label != left_label)) {
00536           // form union between two equivalence classes
00537           int root = ur_label;
00538           while (eq_classes[root] != root) {
00539             root = eq_classes[root]; // "FIND" of UNION-FIND
00540           }
00541           // should do path compression to make more efficient
00542           int tmp_root = ur_label, next_root;
00543           while(eq_classes[tmp_root] != root) {
00544             next_root = eq_classes[tmp_root];
00545             eq_classes[tmp_root] = root; // compress
00546             tmp_root = next_root;
00547           }
00548           
00549           eq_classes[left_label] = root; // "UNION" of UNION-FIND
00550           *p = root; // not sure why putting this here works, but it does
00551         }
00552       }
00553     }
00554   }
00555   
00556   // Second scan: 
00557   uint *p = data, *end = &data[width*height];
00558   for(; p!=end; ++p) {
00559     int cur_label=*p;
00560     if (cur_label != 0) {
00561       while(eq_classes[cur_label] != cur_label) {
00562         cur_label = eq_classes[cur_label];  
00563       }
00564       *p = cur_label;
00565     }
00566   }
00567   
00568   return labels;
00569 }
00570 
00571 Sketch<uint> areacc(const Sketch<bool>& source, Connectivity_t connectivity) {
00572   NEW_SKETCH_N(labels, uint, visops::oldlabelcc(source,connectivity));
00573   return visops::areacc(labels);
00574 }
00575 
00576 Sketch<uint> areacc(const Sketch<uint>& labels) {
00577   int const numlabels = 1 + labels->max();
00578   std::vector<int> areas(numlabels, 0);
00579   for (uint i = 0; i<labels->getNumPixels(); i++)
00580     ++areas[labels[i]];
00581   areas[0] = 0;
00582   Sketch<uint> result("areacc("+labels->getName()+")",labels);
00583   for (uint i = 0; i<labels->getNumPixels(); i++)
00584     result[i] = areas[labels[i]];
00585   return result;
00586 }
00587 
00588 Sketch<bool> minArea(const Sketch<bool>& sketch, int minval) {
00589   NEW_SKETCH_N(labels, uint, visops::labelcc(sketch));
00590   NEW_SKETCH_N(areas, uint, visops::areacc(labels));
00591   NEW_SKETCH_N(result, bool, areas >= minval);
00592   return result;
00593 }
00594 
00595 Sketch<uchar> neighborSum(const Sketch<bool>& im, Connectivity_t connectivity) 
00596 {
00597   im.checkValid();
00598   const bool* imdata = im->getRawPixels();
00599   // using index redirection method
00600   SketchSpace &space = im->getSpace();
00601   
00602   space.requireIdx4way();
00603   
00604   skindex* idxN = (*space.idxN)->getRawPixels();
00605   skindex* idxS = (*space.idxS)->getRawPixels();
00606   skindex* idxE = (*space.idxE)->getRawPixels();
00607   skindex* idxW = (*space.idxW)->getRawPixels();
00608   skindex *idxNE=NULL, *idxNW=NULL, *idxSE=NULL, *idxSW=NULL;
00609   
00610   if (connectivity == EightWayConnect) {
00611     space.requireIdx8way();
00612     idxNE = (*space.idxNE)->getRawPixels();
00613     idxNW = (*space.idxNW)->getRawPixels();
00614     idxSE = (*space.idxSE)->getRawPixels();
00615     idxSW = (*space.idxSW)->getRawPixels();
00616   }
00617   
00618   Sketch<uchar> result("neighborSum("+im->getName()+")", im);
00619   uchar* rdata = result->getRawPixels();
00620   result->setColorMap(jetMapScaled);
00621   const unsigned int length = im->getNumPixels();
00622   for ( unsigned int i = 0; i < length; i++ ) {
00623     uchar cnt = imdata[idxN[i]] + imdata[idxS[i]] + imdata[idxE[i]] + imdata[idxW[i]];
00624     if (connectivity == EightWayConnect)
00625       cnt += imdata[idxNE[i]] + imdata[idxNW[i]] + imdata[idxSE[i]] + imdata[idxSW[i]];
00626     rdata[i] = cnt;
00627   }
00628   return result;
00629 }
00630     
00631 Sketch<bool> fillin(const Sketch<bool>& im, int iter, 
00632           uchar min_thresh, uchar max_thresh, bool remove_only)
00633 {
00634   Sketch<bool> result(im);
00635   if ( remove_only )
00636     result.bind(visops::copy(im));
00637   Sketch<uchar> neighborCount(im);
00638   if (remove_only) {
00639     neighborCount.bind(neighborSum(result,EightWayConnect));
00640     result &= (neighborCount <= max_thresh);
00641     for (int i = 0; i < iter; i++)
00642       result &= (neighborCount >= min_thresh);
00643   }
00644   else {
00645     for (int i = 0; i < iter; i++) {
00646       neighborCount.bind(neighborSum(result,EightWayConnect));
00647       result.bind((neighborCount >= min_thresh) & (neighborCount <= max_thresh));
00648     }
00649   }
00650   result->setName("fillin("+im->getName()+")");
00651   result->setColor(im->getColor());
00652   return result;
00653 }
00654 
00655 Sketch<bool> edge(const Sketch<bool> &im) {
00656   im->getSpace().requireIdx4way();
00657   SketchSpace &space = im->getSpace();
00658   return ((im != im[*space.idxS]) | (im != im[*space.idxE]));
00659 }
00660 
00661 
00662 Sketch<bool> horsym(const Sketch<bool> &im, size_t minskip, size_t maxskip)
00663 {
00664   NEW_SKETCH_N(result, bool, visops::zeros(im));
00665   result->setName("horsym("+im->getName()+")");
00666   bool * rdata = result->getRawPixels();
00667   const bool * imdata = im->getRawPixels();
00668   const size_t width = im->getWidth();
00669   const size_t height = im->getHeight();
00670 
00671   for (size_t j = 0; j < height; j++) {
00672     const bool * imrow = &imdata[j*width];
00673     for (size_t i = 0; i < width; i++) {
00674       while (i < width && !imrow[i]) i++; // skip over empty pixels
00675       for (size_t k = i+1; k <= width; k++) {
00676     if ( k==width || !imrow[k]) {
00677       if ( (k-i) >= minskip && (k-i) <= maxskip ) {
00678         const size_t u = (i+k)/2;
00679         rdata[j*width+u] = true;
00680       }
00681       i=k+1;
00682       break;
00683     }
00684       }
00685     }
00686   }
00687   return result;
00688 }
00689 
00690 Sketch<bool> versym(const Sketch<bool> &im, size_t minskip, size_t maxskip)
00691 {
00692   NEW_SKETCH_N(result, bool, visops::zeros(im));
00693   result->setName("horsym("+im->getName()+")");
00694   bool * rdata = result->getRawPixels();
00695   const bool * imdata = im->getRawPixels();
00696   const size_t width = im->getWidth();
00697   const size_t height = im->getHeight();
00698 
00699   for (size_t i = 0; i < width; i++) {
00700     const bool * imcol = &imdata[i];
00701     for (size_t j = 0; j < height; j++) {
00702       while (j < height && !imcol[j*width]) j++; // skip over empty pixels
00703       for (size_t k = j+1; k <= height; k++) {
00704     if ( k==height || !imcol[k*width]) {
00705       if ( (k-j) >= minskip && (k-j) <= maxskip ) {
00706         const size_t u = (j+k)/2;
00707         rdata[u*width+i] = true;
00708       }
00709       j=k+1;
00710       break;
00711     }
00712       }
00713     }
00714   }
00715   return result;
00716 }
00717 
00718 
00719 /*
00720 Sketch<bool> versym(const Sketch<bool>& im, int minskip, int maxskip)
00721 {
00722   NEW_SKETCH_N(result, bool, visops::zeros(im));
00723   result->setName("versym("+im->getName()+")");
00724   int height = im->getWidth();
00725   int width = im->getHeight();
00726   
00727   for (int j = 0; j < height; j++) {
00728     for (int i = 0; i < width; i++) {
00729       if (im(j,i)) {
00730   while (i < width-1 && im(j,i+1)) {
00731     i++; // skip over contiguous pixels
00732   }
00733   for (int k = i+1; k < width; k++) {
00734     if (k-i > maxskip)
00735       break;
00736     else if (im(j,k)) {
00737       if ((k-i) < minskip)
00738         break;
00739       int u = (i+k)/2;
00740       if (!im(j,u))
00741         result(j,u) = true; // was result(j,u) = k-i when this returned a Sketch<int>
00742       break; // only works well for non-'donut' ellipses
00743     }
00744   }
00745       }
00746     }
00747   }
00748   return result;
00749 }
00750 */
00751 
00752 Sketch<bool> skel(const Sketch<bool>& im) {
00753   NEW_SKETCH_N(result, bool, horsym(im) | versym(im));
00754   result->setName("skel("+im->getName()+")");
00755   return result;
00756 }
00757 
00758 Sketch<bool> seedfill(const Sketch<bool>& borders, size_t index) {
00759   // use four-way connect so thin diagonal line can function as a boundary
00760   NEW_SKETCH_N(regions, uint, oldlabelcc(! borders, visops::FourWayConnect));
00761   NEW_SKETCH_N(result, bool, regions == regions->at(index));  // use at() to do bounds checking
00762   return result;
00763 }
00764 
00765 // helper function called only inside visops::fillExterior
00766 void fillExteriorHelper(const Sketch<uint> &regions, Sketch<bool> &result, std::vector<bool> &processed, 
00767       const int x, const int y) {
00768   const uint c = regions(x,y);
00769   if ( c > 0 && !processed[c] ) {
00770     result |= (regions == c);
00771     processed[c] = true;
00772   }
00773 }
00774 
00775 Sketch<bool> fillExterior(const Sketch<bool>& borders) {
00776   // use four-way connect so thin diagonal line can function as a boundary
00777   NEW_SKETCH_N(regions, uint, oldlabelcc(! borders, visops::FourWayConnect));
00778   const uint numreg = regions->max();
00779   std::vector<bool> processed(numreg+1,false);
00780   NEW_SKETCH_N(result, bool, visops::zeros(borders));
00781   for ( int x = 0; x < result.width; x++ ) {
00782     fillExteriorHelper(regions,result,processed,x,0);
00783     fillExteriorHelper(regions,result,processed,x,result.height-1);
00784   }
00785   for ( int y = 0; y < result.height; y++ ) {
00786     fillExteriorHelper(regions,result,processed,0,y);
00787     fillExteriorHelper(regions,result,processed,result.width-1,y);
00788   }
00789   return result;
00790 }
00791 
00792 Sketch<bool> fillInterior(const Sketch<bool>& borders) {
00793   return ! (borders | fillExterior(borders));
00794 }
00795 
00796 Sketch<bool> leftHalfPlane(const Shape<LineData> &ln) {
00797   SketchSpace &SkS = ln->getSpace().getDualSpace();
00798   //! @todo **** THIS visops::leftHalfPlane CODE NEEDS TO CHECK THE SketchSpace ReferenceFrameType **** BECAUSE "left" MEANS DIFFERENT THINGS IN DIFFERENT FRAMES 
00799   float const x1 = ln->end1Pt().coordX();
00800   float const y1 = ln->end1Pt().coordY();
00801   float const x2 = ln->end2Pt().coordX();
00802   float const y2 = ln->end2Pt().coordY();
00803   bool const roughlyVertical = fabs(x1-x2) < 0.001;
00804   float const m = roughlyVertical ? BIG_SLOPE : (y2-y1) / (x2-x1);
00805   float const b = y1 - x1*m;
00806   int seed;
00807   if ( roughlyVertical )
00808     seed = ( x1 <= 0 ) ? -1 : 0;
00809   else if ( ln->getOrientation() > M_PI/2 )
00810     seed =  ( b <= 0) ? -1 : 0;
00811   else {
00812     int const lim = SkS.getHeight() - 1;
00813     seed =  ( b < lim ) ? (int)(*SkS.idx)(0,lim) : -1;
00814   }
00815   if ( seed == -1 ) {
00816     NEW_SKETCH_N(result, bool, visops::zeros(SkS));
00817     result->inheritFrom(ln);
00818     return result;
00819   } else {
00820     NEW_SHAPE_N(line_copy, LineData, ln->copy());
00821     line_copy->setInfinite();
00822     NEW_SKETCH_N(bounds, bool, line_copy->getRendering());
00823     bounds->inheritFrom(ln);
00824     return visops::seedfill(bounds,seed);
00825   }
00826 }
00827 
00828 Sketch<bool> rightHalfPlane(const Shape<LineData> &ln) {
00829     NEW_SHAPE_N(line_copy, LineData, ln->copy());
00830     line_copy->setInfinite();
00831     NEW_SKETCH_N(bounds, bool, line_copy->getRendering());
00832     bounds->inheritFrom(ln);
00833     return ! (visops::leftHalfPlane(ln) | bounds);
00834 }
00835 
00836 Sketch<bool> topHalfPlane(const Shape<LineData> &ln) {
00837   SketchSpace &SkS = ln->getSpace().getDualSpace();
00838   //! @todo **** visops::topHalfPlane needs to check the SketchSpace ReferenceFrameType because "left" means different things in different reference frames 
00839   float const x1 = ln->end1Pt().coordX();
00840   float const y1 = ln->end1Pt().coordY();
00841   float const x2 = ln->end2Pt().coordX();
00842   float const y2 = ln->end2Pt().coordY();
00843   bool const roughlyVertical = fabs(x1-x2) < 0.001;
00844   float const m = roughlyVertical ? BIG_SLOPE : (y2-y1) / (x2-x1);
00845   float const b = y1 - x1*m;
00846   int seed;
00847   if ( roughlyVertical )
00848     seed = ( y1 <= 0 ) ? -1 : 0;
00849   else if ( ln->getOrientation() > M_PI/2 )
00850     seed =  ( b <= 0) ? -1 : 0;
00851   else {
00852     int const lim = SkS.getWidth() - 1;
00853     seed =  ( int(m*lim+b) > 0 ) ? (int)(*SkS.idx)(lim,0) : -1;
00854   }
00855   if ( seed == -1 ) {
00856     NEW_SKETCH_N(result, bool, visops::zeros(SkS));
00857     result->inheritFrom(ln);
00858     return result;
00859   } else {
00860     NEW_SHAPE_N(line_copy, LineData, ln->copy());
00861     line_copy->setInfinite();
00862     NEW_SKETCH_N(bounds, bool, line_copy->getRendering());
00863     bounds->inheritFrom(ln);
00864     return visops::seedfill(bounds,seed);
00865   }
00866 }
00867 
00868 Sketch<bool> bottomHalfPlane(const Shape<LineData> &ln) {
00869     NEW_SHAPE_N(line_copy, LineData, ln->copy());
00870     line_copy->setInfinite();
00871     NEW_SKETCH_N(bounds, bool, line_copy->getRendering());
00872     bounds->inheritFrom(ln);
00873     return ! (visops::topHalfPlane(ln) | bounds);
00874 }
00875 
00876 Sketch<bool> non_bounds(const Sketch<bool>& im, int offset) {
00877   const int width = im->getWidth();
00878   const int height = im->getHeight();
00879   NEW_SKETCH_N(nbresult,bool,visops::copy(im));
00880   nbresult->setName("non_bounds("+im->getName()+")");
00881 
00882   for (int i = 0; i < width; i++) {
00883     for (int j = 0; j < offset; j++) {
00884       nbresult(i,j) = false;
00885       nbresult(i,height-j-1) = false;
00886     }
00887   }
00888   for (int i = 0; i < offset; i++) {
00889     for (int j = offset; j < height-offset; j++) {
00890       nbresult(i,j) = false;
00891       nbresult(width-i-1,j) = false;
00892     }
00893   }
00894   return nbresult;
00895 }
00896 
00897 
00898 Sketch<uchar> susan_edges(const Sketch<uchar>& im, int brightness)
00899 {
00900   const int width = im->getWidth();
00901   const int height = im->getHeight();
00902   unsigned char *bp;
00903   Sketch<uchar> edges(visops::copy(im));
00904 
00905   int *r = (int *)malloc(width*height*sizeof(int));
00906 
00907   unsigned char *mid = (unsigned char *)malloc(width*height);
00908   memset (mid,100,width * height); /* note not set to zero */
00909 
00910   setup_brightness_lut(&bp,brightness,6);
00911 
00912   // susan_principle(im->getRawPixels(),edges->getRawPixels(), &bp, 2650, width, height);
00913 
00914   susan_edges_internal(edges->getRawPixels(), r, mid, bp, 2650, width, height);
00915 
00916   susan_thin(r, mid, width, height);
00917 
00918   edge_draw(edges->getRawPixels(),mid,width,height,0);
00919 
00920    free(r);
00921    free(mid);
00922    free(bp-258);
00923 
00924   return edges;
00925 }
00926 
00927 
00928 // Default brightness was 20 for original algorithm
00929 Sketch<bool> susan_edge_points(const Sketch<uchar>& im, int brightness)
00930 {
00931   const int width = im->getWidth();
00932   const int height = im->getHeight();
00933   unsigned char *bp;
00934   Sketch<uchar> orig(im);
00935   Sketch<uchar> edges(visops::zeros(im));
00936   int *r = (int *)malloc(width*height*sizeof(int));
00937   unsigned char *mid = (unsigned char *)malloc(width*height);
00938   memset(mid,100,width * height); /* note not set to zero */
00939   setup_brightness_lut(&bp,brightness,6);
00940   susan_edges_internal(orig->getRawPixels(), r, mid, bp, 2650, width, height);
00941   susan_thin(r, mid, width, height);
00942   edge_draw(edges->getRawPixels(),mid,width,height,1);
00943   free(r);
00944   free(mid);
00945   Sketch<bool> result(edges);
00946   return result;
00947 }
00948 
00949 Sketch<uint> convolve(const Sketch<uchar> &sketch, Sketch<uchar> &kernel, 
00950            int istart, int jstart, int width, int height) {
00951   Sketch<uint> result("convolve("+sketch->getName()+")",sketch);
00952   result->setColorMap(jetMapScaled);
00953   int const di = - (int)(width/2);
00954   int const dj = - (int)(height/2);
00955   for (int si=0; si<sketch.width; si++)
00956     for (int sj=0; sj<sketch.height; sj++) {
00957       int sum = 0;
00958       for (int ki=0; ki<width; ki++)
00959   for (int kj=0; kj<height; kj++)
00960     if ( si+di+ki >= 0 && si+di+ki < sketch.width &&
00961          sj+dj+kj >= 0 && sj+dj+kj < sketch.height )
00962       sum += (uint)sketch(si+di+ki,sj+dj+kj) * (uint)kernel(istart+ki,jstart+kj);
00963       result(si,sj) = sum/(width*height);
00964     }
00965   return result;      
00966 }
00967 
00968 Sketch<uint> templateMatch(const Sketch<uchar> &sketch, Sketch<uchar> &kernel, 
00969            int istart, int jstart, int width, int height) {
00970   Sketch<uint> result("convolve0("+sketch->getName()+")",sketch);
00971   result->setColorMap(jetMapScaled);
00972   int const npix = width * height;
00973   int const di = - (int)(width/2);
00974   int const dj = - (int)(height/2);
00975   for (int si=0; si<sketch.width; si++)
00976     for (int sj=0; sj<sketch.height; sj++) {
00977       int sum = 0;
00978       for (int ki=0; ki<width; ki++)
00979   for (int kj=0; kj<height; kj++) {
00980     int k_pix = kernel(istart+ki,jstart+kj);
00981     if ( si+di+ki >= 0 && si+di+ki < sketch.width &&
00982          sj+dj+kj >= 0 && sj+dj+kj < sketch.height ) {
00983       int s_pix = sketch(si+di+ki,sj+dj+kj);
00984       sum +=  (s_pix - k_pix) * (s_pix - k_pix);
00985     }
00986     else
00987       sum += k_pix * k_pix;
00988   }
00989       result(si,sj) =  65535 - uint(sqrt(sum/float(npix)));
00990     }
00991   result = result - result->min();
00992   return result;
00993 }
00994 
00995 
00996 } // namespace

DualCoding 5.1CVS
Generated Mon May 9 04:56:28 2016 by Doxygen 1.6.3