Guest User

Untitled

a guest
May 21st, 2013
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.02 KB | None | 0 0
  1. #include "segmentation.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <algorithm>
  6.  
  7. unsigned char thres[3][256];
  8. unsigned char ad_thres[3][256];
  9.  
  10.  
  11. SEGMENTATION::SEGMENTATION( int width, int height ) {
  12.     this->width = width;
  13.     this->height = height;
  14.     this->max_runs = width*height/6;
  15.     this->max_reg = width*height/16;
  16.  
  17.     this->data = NULL;
  18.     this->th_data = new unsigned char[ width*height ];
  19.     this->rle = new run[ max_runs ];
  20.     this->run_c = 0;
  21.     this->regions = new region[ max_reg ];
  22.     this->region_c = 0;
  23.     this->max_area = 0;
  24.     this->colors = new color_class_state[ COLOR_COUNT ];
  25. }
  26.  
  27.  
  28. SEGMENTATION::~SEGMENTATION() {
  29.     delete this->th_data;
  30.     if( this->rle )
  31.         delete this->rle;
  32.     if( this->regions )
  33.         delete this->regions;
  34.     if( this->colors )
  35.         delete this->colors;
  36. }
  37.  
  38.  
  39. void SEGMENTATION::readThresholds( const char path[100] )
  40. {
  41.     FILE *in = fopen( path, "r" );
  42.     if( !in ) {
  43.         printf( "VisionConf faili ei leitud.\n" );
  44.         exit(0);
  45.     }
  46.  
  47.     for( int i = 0; i < 3; i++ ) {
  48.         memset( thres[i], 0, 255 );
  49.         memset( ad_thres[i], 0, 255 );
  50.     }
  51.  
  52.     for( int i = 0; i < 3; i++ ) {
  53.         for( int j = 0; j < 256; j++ ) fscanf( in, "%c", &thres[i][j] );
  54.         for( int j = 0; j < 256; j++ ) fscanf( in, "%c", &ad_thres[i][j] );
  55.     }
  56.  
  57.     fclose( in );
  58. }
  59.  
  60.  
  61. void SEGMENTATION::thresholdImage( unsigned char *data )
  62. {
  63.     int pix_c = 0;
  64.     unsigned char col;
  65.     unsigned char c;
  66.     this->data = data;
  67.  
  68.     for( int i = 0; i < 3 * this->width * this->height; i += 3 ) {
  69.        
  70.         col = thres[0][data[i]] & thres[1][data[i + 1]] & thres[2][data[i + 2]];
  71.  
  72.         if( col > 31 ) c = GREEN;
  73.         else if( col > 15 ) c = WHITE;
  74.         else if( col > 7 ) c = ORANGE;
  75.         else if( col > 3 ) c = YELLOW;
  76.         else if( col > 1 ) c = BLUE;
  77.         else if( col > 0 ) c = BLACK;
  78.         else c = NOCOLOR;
  79.  
  80.  
  81.         this->th_data[ pix_c ] = c;
  82.         pix_c++;
  83.     }
  84. }
  85.  
  86.  
  87. void SEGMENTATION::EncodeRuns()
  88. // Changes the flat array version of the thresholded image into a run
  89. // length encoded version, which speeds up later processing since we
  90. // only have to look at the points where values change.
  91. {
  92.   unsigned char m, save;
  93.   unsigned char *row;
  94.   int x, y, j, l;
  95.   run r;
  96.   unsigned char *map = this->th_data;
  97.   run *rle = this->rle;
  98.  
  99.   r.next = 0;
  100.  
  101.   // initialize terminator restore
  102.   save = map[0];
  103.  
  104.  
  105.   j = 0;
  106.   for(y = 0; y < this->height; y++){
  107.     row = &map[y * this->width];
  108.  
  109.     // restore previous terminator and store next
  110.     // one in the first pixel on the next row
  111.     row[0] = save;
  112.     save = row[this->width];
  113.     row[this->width] = 255;
  114.     r.y = y;
  115.  
  116.     x = 0;
  117.     while(x < this->width){
  118.       m = row[x];
  119.       r.x = x;
  120.  
  121.       l = x;
  122.       while(row[x] == m) x++;
  123.  
  124.       if( m != NOCOLOR || x >= this->width ) {
  125.         r.color = m;
  126.         r.width = x - l;
  127.         r.parent = j;
  128.         rle[j++] = r;
  129.  
  130.  
  131.         if(j >= this->max_runs) {
  132.             row[this->width] = save;
  133.  
  134.             printf( "Runlength buffer exceeded.\n" );
  135.             this->run_c = j;
  136.             return;
  137.         }
  138.       }
  139.     }
  140.   }
  141.  
  142.   this->run_c = j;
  143. }
  144.  
  145.  
  146. void SEGMENTATION::ConnectComponents()
  147. // Connect components using four-connecteness so that the runs each
  148. // identify the global parent of the connected region they are a part
  149. // of.  It does this by scanning adjacent rows and merging where
  150. // similar colors overlap.  Used to be union by rank w/ path
  151. // compression, but now it just uses path compression as the global
  152. // parent index, a simpler rank bound in practice.
  153. // WARNING: This code is complicated.  I'm pretty sure it's a correct
  154. //   implementation, but minor changes can easily cause big problems.
  155. //   Read the papers on this library and have a good understanding of
  156. //   tree-based union find before you touch it
  157. {
  158.   int l1, l2;
  159.   run r1, r2;
  160.   int i, j, s;
  161.   int num = this->run_c;
  162.   run *map = this->rle;
  163.  
  164.  
  165.   // l2 starts on first scan line, l1 starts on second
  166.   l2 = 0;
  167.   l1 = 1;
  168.   while(map[l1].y == 0) l1++; // skip first line
  169.  
  170.   // Do rest in lock step
  171.   r1 = map[l1];
  172.   r2 = map[l2];
  173.   s = l1;
  174.   while(l1 < num){
  175.  
  176.     if(r1.color==r2.color && r1.color){
  177.       // case 1: r2.x <= r1.x < r2.x + r2.width
  178.       // case 2: r1.x <= r2.x < r1.x + r1.width
  179.       if((r2.x<=r1.x && r1.x<r2.x+r2.width) ||
  180.      (r1.x<=r2.x && r2.x<r1.x+r1.width)){
  181.         if(s != l1){
  182.           // if we didn't have a parent already, just take this one
  183.           map[l1].parent = r1.parent = r2.parent;
  184.           s = l1;
  185.         }else if(r1.parent != r2.parent){
  186.           // otherwise union two parents if they are different
  187.  
  188.           // find terminal roots of each path up tree
  189.           i = r1.parent;
  190.           while(i != map[i].parent) i = map[i].parent;
  191.           j = r2.parent;
  192.           while(j != map[j].parent) j = map[j].parent;
  193.  
  194.           // union and compress paths; use smaller of two possible
  195.           // representative indicies to preserve DAG property
  196.           if(i < j){
  197.         map[j].parent = i;
  198.             map[l1].parent = map[l2].parent = r1.parent = r2.parent = i;
  199.           }else{
  200.             map[i].parent = j;
  201.             map[l1].parent = map[l2].parent = r1.parent = r2.parent = j;
  202.           }
  203.         }
  204.       }
  205.     }
  206.  
  207.     // Move to next point where values may change
  208.     i = (r2.x + r2.width) - (r1.x + r1.width);
  209.     if(i >= 0) r1 = map[++l1];
  210.     if(i <= 0) r2 = map[++l2];
  211.   }
  212.  
  213.   // Now we need to compress all parent paths
  214.   for(i=0; i<num; i++){
  215.     j = map[i].parent;
  216.     map[i].parent = map[j].parent;
  217.   }
  218. }
  219.  
  220.  
  221. // sum of integers over range [x,x+w)
  222. inline int range_sum(int x, int w)
  223. {
  224.     return(w*(2*x + w-1) / 2);
  225. }
  226.  
  227.  
  228.  
  229. void SEGMENTATION::ExtractRegions()
  230. // Takes the list of runs and formats them into a region table,
  231. // gathering the various statistics along the way.  num is the number
  232. // of runs in the rmap array, and the number of unique regions in
  233. // reg[] (bounded by max_reg) is returned.  Implemented as a single
  234. // pass over the array of runs.
  235. {
  236.   int b, i, n, a;
  237.   int num = this->run_c;
  238.   run *rmap = this->rle;
  239.   region *reg = this->regions;
  240.   run r;
  241.  
  242.   n = 0;
  243.  
  244.  
  245.   for(i=0; i<num; i++){
  246.     if( rmap[i].color != NOCOLOR ){
  247.       r = rmap[i];
  248.       if(r.parent == i){
  249.         // Add new region if this run is a root (i.e. self parented)
  250.         rmap[i].parent = b = n;  // renumber to point to region id
  251.         reg[b].color = r.color;
  252.         reg[b].area = r.width;
  253.         reg[b].x1 = r.x;
  254.         reg[b].y1 = r.y;
  255.         reg[b].x2 = r.x + r.width;
  256.         reg[b].y2 = r.y;
  257.         reg[b].cen_x = range_sum(r.x,r.width);
  258.         reg[b].cen_y = r.y * r.width;
  259.     reg[b].run_start = i;
  260.     reg[b].iterator_id = i; // temporarily use to store last run
  261.         n++;
  262.         if(n >= this->max_reg) {
  263.             printf( "Regions buffer exceeded.\n" );
  264.             this->region_c = this->max_reg;
  265.             return;
  266.         }
  267.       }else{
  268.         // Otherwise update region stats incrementally
  269.         b = rmap[r.parent].parent;
  270.         rmap[i].parent = b; // update parent to identify region id
  271.         reg[b].area += r.width;
  272.         reg[b].x2 = std::max(r.x + r.width,reg[b].x2);
  273.         reg[b].x1 = std::min((int)r.x,reg[b].x1);
  274.         reg[b].y2 = r.y; // last set by lowest run
  275.         reg[b].cen_x += range_sum(r.x,r.width);
  276.         reg[b].cen_y += r.y * r.width;
  277.     // set previous run to point to this one as next
  278.     rmap[reg[b].iterator_id].next = i;
  279.     reg[b].iterator_id = i;
  280.       }
  281.     }
  282.   }
  283.  
  284.   // calculate centroids from stored sums
  285.   for(i=0; i<n; i++){
  286.     a = reg[i].area;
  287.     reg[i].cen_x = (float)reg[i].cen_x / a;
  288.     reg[i].cen_y = (float)reg[i].cen_y / a;
  289.     rmap[reg[i].iterator_id].next = 0; // -1;
  290.     reg[i].iterator_id = 0;
  291.     reg[i].x2--; // change to inclusive range
  292.   }
  293.  
  294.   this->region_c = n;
  295. }
  296.  
  297.  
  298. void SEGMENTATION::SeparateRegions()
  299. // Splits the various regions in the region table a separate list for
  300. // each color.  The lists are threaded through the table using the
  301. // region's 'next' field.  Returns the maximal area of the regions,
  302. // which can be used later to speed up sorting.
  303. {
  304.   region *p;
  305.   int i;
  306.   int c;
  307.   int area;
  308.   int num = this->region_c;
  309.   region *reg = this->regions;
  310.   color_class_state *color = this->colors;
  311.  
  312.  
  313.   // clear out the region list head table
  314.   for(i=0; i<COLOR_COUNT; i++) {
  315.     color[i].list = NULL;
  316.     color[i].num  = 0;
  317.     color[i].min_area = 0;
  318.     color[i].color = i;
  319.   }
  320.  
  321.   // step over the table, adding successive
  322.   // regions to the front of each list
  323.   max_area = 0;
  324.   for(i=0; i<num; i++){
  325.     p = &reg[i];
  326.     c = p->color;
  327.     area = p->area;
  328.  
  329.     if(area >= color[c].min_area){
  330.       if(area > max_area) max_area = area;
  331.       color[c].num++;
  332.       p->next = color[c].list;
  333.       color[c].list = p;
  334.     }
  335.   }
  336. }
  337.  
  338.  
  339.  
  340. void SEGMENTATION::SortRegions()
  341. // Sorts entire region table by area, using the above
  342. // function to sort each threaded region list.
  343. {
  344.   int i, p;
  345.  
  346.   // do minimal number of passes sufficient to touch all set bits
  347.   p = 0;
  348.   while( this->max_area != 0 ) {
  349.     this->max_area >>= CMV_RBITS;
  350.     p++;
  351.   }
  352.  
  353.   // sort each list
  354.   for(i=0; i<COLOR_COUNT; i++){
  355.     this->colors[i].list = SortRegionListByArea(this->colors[i].list, p);
  356.   }
  357. }
  358.  
  359.  
  360.  
  361. region* SEGMENTATION::SortRegionListByArea( region *list, int passes )
  362. // Sorts a list of regions by their area field.
  363. // Uses a linked list based radix sort to process the list.
  364. {
  365.   region *tbl[CMV_RADIX], *p, *pn;
  366.   int slot, shift;
  367.   int i, j;
  368.  
  369.   // Handle trivial cases
  370.   if(!list || !list->next) return(list);
  371.  
  372.   // Initialize table
  373.   for(j=0; j<CMV_RADIX; j++) tbl[j] = NULL;
  374.  
  375.   for(i=0; i<passes; i++){
  376.     // split list into buckets
  377.     shift = CMV_RBITS * i;
  378.     p = list;
  379.     while(p){
  380.       pn = p->next;
  381.       slot = ((p->area) >> shift) & CMV_RMASK;
  382.       p->next = tbl[slot];
  383.       tbl[slot] = p;
  384.       p = pn;
  385.     }
  386.  
  387.     // integrate back into partially ordered list
  388.     list = NULL;
  389.     for(j=0; j<CMV_RADIX; j++){
  390.       p = tbl[j];
  391.       tbl[j] = NULL; // clear out table for next pass
  392.       while(p){
  393.         pn = p->next;
  394.         p->next = list;
  395.         list = p;
  396.         p = pn;
  397.       }
  398.     }
  399.   }
  400.  
  401.   return(list);
  402. }
Advertisement
Add Comment
Please, Sign In to add comment