cmvision.cc
Go to the documentation of this file.
1 /*=========================================================================
2  CMVision.cc
3  -------------------------------------------------------------------------
4  Implementation of the CMVision real time Color Machine Vision library
5  -------------------------------------------------------------------------
6  Copyright 1999, 2000 #### ### ### ## ## ## #### ## ### ## ##
7  James R. Bruce ## ####### ## ## ## ## ## ## ## ######
8  School of Computer Science ## ## # ## ## ## ## ### ## ## ## ## ###
9  Carnegie Mellon University #### ## ## ### ## #### ## ### ## ##
10  -------------------------------------------------------------------------
11  This library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU Lesser General Public
13  License as published by the Free Software Foundation; either
14  version 2.1 of the License, or (at your option) any later version.
15 
16  This library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  Lesser General Public License for more details.
20 
21  You should have received a copy of the GNU Lesser General Public
22  License along with this library; if not, write to the Free Software
23  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  -------------------------------------------------------------------------
25  Revision History:
26  1999-11-18: Initial release version (JRB)
27  2000-05-20: Added Bugfixes from Peter,
28  fixed bounding box bug (JRB)
29  2000-06-04: Some other minor fixes (JRB)
30  2000-07-02: Added average color and density merging (JRB)
31  2000-07-20: Added dual threshold capability (JRB)
32  =========================================================================*/
33 
34 #include "cmvision/cmvision.h"
35 #include <string.h>
36 #if !defined (WIN32)
37  #include <strings.h>
38 #endif
39 
40 #if defined (WIN32)
41  #define strncasecmp _strnicmp
42  #define strdup _strdup
43 #endif
44 
45 //==== Utility Functions ===========================================//
46 // These could be coded as macros, but the inline versions seem to
47 // optimize better, and tend to have cleaner definitions
48 
49 // sum of integers over range [x,x+w)
50 inline int range_sum(int x,int w)
51 {
52  return(w*(2*x + w-1) / 2);
53 }
54 
55 // returns maximal value of two parameters
56 template <class num>
57 inline num max(num a,num b)
58 {
59  return((a > b)? a : b);
60 }
61 
62 // returns minimal value of two parameters
63 template <class num>
64 inline num min(num a,num b)
65 {
66  return((a < b)? a : b);
67 }
68 
69 // returns index of least significant set bit
70 int log2modp[37] = {
71  0, 1, 2,27, 3,24,28, 0, 4,17,25,31,29,12, 0,14, 5, 8,18,
72  0,26,23,32,16,30,11,13, 7, 0,22,15,10, 6,21, 9,20,19
73 };
74 
75 template <class num>
76 inline int bottom_bit(num n)
77 {
78  return(log2modp[(n & -n) % 37]);
79 }
80 
81 /* Marginally slower naive version of above function
82 template <class num>
83 inline num bottom_bit(num n)
84 {
85  int i = 0;
86  if(!n) return(0);
87  while(!(n&(1<<i))) i++;
88  return(i + 1);
89 }
90 */
91 
92 // returns index of most significant set bit
93 template <class num>
94 inline num top_bit(num n)
95 {
96  int i = 1;
97  if(!n) return(0);
98  while(n>>i) i++;
99  return(i);
100 }
101 
102 
103 //==== Class Implementation ========================================//
104 
106 // Classifies an image passed in as img, saving bits in the entries
107 // of map representing which thresholds that pixel satisfies.
108 {
109  int i,s;
110  image_pixel p;
111 
112  unsigned *aclas = a_class;
113  unsigned *bclas = b_class;
114 
115  s = width * height;
116 
117  for(i=0; i<s; i++){
118  p = img[i];
119  map[i] = aclas[p.a] & bclas[p.b];
120  }
121 
122 }
123 
124 int CMVision::encodeRuns(rle * restrict out,unsigned * restrict map)
125 // Changes the flat array version of the threshold satisfaction map
126 // into a run length encoded version, which speeds up later processing
127 // since we only have to look at the points where values change.
128 {
129  int x,y,j,l;
130  unsigned m,save;
131  int size;
132  unsigned *row;
133  rle r;
134 
135  size = width * height;
136 
137  // initialize terminator restore
138  save = map[0];
139 
140  j = 0;
141  for(y=0; y<height; y++){
142  row = &map[y * width];
143 
144  // restore previous terminator and store next
145  // one in the first pixel on the next row
146  row[0] = save;
147  save = row[width];
148  row[width] = CMV_NONE;
149 
150  x = 0;
151  while(x < width){
152  m = row[x];
153  // m = m & (~m + 1); // get last bit
154  l = x;
155  while(row[x] == m) x++;
156  // x += (row[x] == CMV_NONE); // && (last & m);
157 
158  r.color = m;
159  r.length = x - l;
160  r.parent = j;
161  out[j++] = r;
162  if(j >= CMV_MAX_RUNS) return(0);
163  }
164  }
165 
166  return(j);
167 }
168 
170 // Connect components using four-connecteness so that the runs each
171 // identify the global parent of the connected region they are a part
172 // of. It does this by scanning adjacent rows and merging where similar
173 // colors overlap. Used to be union by rank w/ path compression, but now
174 // is just uses path compression as the global parent index seems to be
175 // a simpler fast approximation of rank in practice.
176 // WARNING: This code is *extremely* complicated and twitchy. It appears
177 // to be a correct implementation, but minor changes can easily cause
178 // big problems. Read the papers on this library and have a good
179 // understanding of tree-based union find before you touch it
180 {
181  int x1,x2;
182  int l1,l2;
183  rle r1,r2;
184  int i,p,s,n;
185 
186  l1 = l2 = 0;
187  x1 = x2 = 0;
188 
189  // Lower scan begins on second line, so skip over first
190  while(x1 < width){
191  x1 += map[l1++].length;
192  }
193  x1 = 0;
194 
195  // Do rest in lock step
196  r1 = map[l1];
197  r2 = map[l2];
198  s = l1;
199  while(l1 < num){
200  if(r1.color==r2.color && r1.color){
201  if((x1>=x2 && x1<x2+r2.length) || (x2>=x1 && x2<x1+r1.length)){
202  if(s != l1){
203  map[l1].parent = r1.parent = r2.parent;
204  s = l1;
205  }else{
206  // find terminal roots of each path
207  n = r1.parent;
208  while(n != map[n].parent) n = map[n].parent;
209  p = r2.parent;
210  while(p != map[p].parent) p = map[p].parent;
211 
212  // must use smaller of two to preserve DAGness!
213  if(n < p){
214  map[p].parent = n;
215  }else{
216  map[n].parent = p;
217  }
218  }
219  }
220  }
221 
222  // Move to next point where values may change
223  if(x1+r1.length < x2+r2.length){
224  x1 += r1.length;
225  r1 = map[++l1];
226  }else{
227  x2 += r2.length;
228  r2 = map[++l2];
229  }
230  }
231 
232  // Now we need to compress all parent paths
233  for(i=0; i<num; i++){
234  p = map[i].parent;
235  if(p > i){
236  while(p != map[p].parent) p = map[p].parent;
237  map[i].parent = p;
238  }else{
239  map[i].parent = map[p].parent;
240  }
241  }
242 
243  // Ouch, my brain hurts.
244 }
245 
247 // Takes the list of runs and formats them into a region table,
248 // gathering the various statistics we want along the way.
249 // num is the number of runs in the rmap array, and the number of
250 // unique regions in reg[] (< CMV_MAX_REGIONS) is returned.
251 // Implemented as a single pass over the array of runs.
252 {
253  int x,y,i;
254  int b,n,a;
255  rle r;
256  lab black = {0,0,0};
257 
258  x = y = n = 0;
259  for(i=0; i<num; i++){
260  r = rmap[i];
261 
262  if(r.color){
263  if(r.parent == i){
264  // Add new region if this run is a root (i.e. self parented)
265  rmap[i].parent = b = n; // renumber to point to region id
266  reg[b].color = bottom_bit(r.color) - 1;
267  reg[b].area = r.length;
268  reg[b].x1 = x;
269  reg[b].y1 = y;
270  reg[b].x2 = x + r.length;
271  reg[b].y2 = y;
272  reg[b].sum_x = range_sum(x,r.length);
273  reg[b].sum_y = y * r.length;
274  reg[b].average = black;
275  // reg[b].area_check = 0; // DEBUG ONLY
276  n++;
277  if(n >= CMV_MAX_REGIONS) return(CMV_MAX_REGIONS);
278  }else{
279  // Otherwise update region stats incrementally
280  b = rmap[r.parent].parent;
281  rmap[i].parent = b; // update to point to region id
282  reg[b].area += r.length;
283  reg[b].x2 = max(x + r.length,reg[b].x2);
284  reg[b].x1 = min(x,reg[b].x1);
285  reg[b].y2 = y; // last set by lowest run
286  reg[b].sum_x += range_sum(x,r.length);
287  reg[b].sum_y += y * r.length;
288  }
289  /* DEBUG
290  if(r.color == 1){
291  printf("{%d,%d,%d} ",i,rmap[i].parent,b);
292  }
293  */
294  }
295 
296  // step to next location
297  x = (x + r.length) % width;
298  y += (x == 0);
299  }
300 
301  // printf("\n");
302 
303  // calculate centroids from stored temporaries
304  for(i=0; i<n; i++){
305  a = reg[i].area;
306  reg[i].cen_x = (float)reg[i].sum_x / a;
307  reg[i].cen_y = (float)reg[i].sum_y / a;
308  }
309 
310  return(n);
311 }
312 
314  image_pixel * restrict img,
315  rle * restrict rmap,int num_runs)
316 // calculates the average color for each region.
317 // num is the number of runs in the rmap array, and the number of
318 // unique regions in reg[] (< CMV_MAX_REGIONS) is returned.
319 // Implemented as a single pass over the image, and a second pass over
320 // the regions.
321 {
322  int i,j,x,l; // TODO: This needs testing after conversion to lab
323  image_pixel p;
324  rle r;
325  int sum_l,sum_a,sum_b;
326  int b,xs;
327 
328  lab avg;
329  int area;
330 
331  // clear out temporaries
332  for(i=0; i<num_reg; i++){
333  reg[i].sum_x = 0;
334  reg[i].sum_y = 0;
335  reg[i].sum_z = 0;
336  }
337 
338  x = 0;
339 
340  // printf("FRAME_START\n");
341 
342  // sum up color components for each region, by traversing image and runs
343  for(i=0; i<num_runs; i++){
344  r = rmap[i];
345  l = r.length;
346 
347  if(!r.color){
348  x += l;
349  }else{
350  xs = x;
351  p = img[x];
352 
353  if(x & 1){
354  sum_l = p.l;
355  sum_a = p.a;
356  sum_b = p.b;
357  // area = 1;
358  x++;
359  l--;
360  }else{
361  sum_l = sum_a = sum_b = 0;
362  area = 0;
363  }
364 
365  for(j=0; j<l; j++){
366  p = img[x];
367  sum_l += p.l;
368  sum_a += p.a;
369  sum_b += p.b;
370  x+=1;
371  // area += 2;
372  }
373 
374  if(l & 1){
375  x++;
376  p = img[x];
377  sum_l += p.l;
378  sum_a += p.a;
379  sum_b += p.b;
380  // area++;
381  }
382 
383  // add sums to region
384  b = r.parent;
385  reg[b].sum_x += sum_l;
386  reg[b].sum_y += sum_a;
387  reg[b].sum_z += sum_b;
388  // reg[b].area_check += area;
389 
390  /*
391  if((r.color & (1 << reg[b].color)) != (1 << reg[b].color)){
392  printf("(%d,%d)",r.color,reg[b].color);
393  }
394 
395  if(x != xs + r.length){
396  printf("Length mismatch %d:%d\n",x,xs + r.length);
397  }
398  */
399 
400  x = xs + r.length;
401  }
402  }
403 
404  // Divide sums by area to calculate average colors
405  for(i=0; i<num_reg; i++){
406  area = reg[i].area;
407  avg.l = reg[i].sum_x / area;
408  avg.a = reg[i].sum_y / area;
409  avg.b = reg[i].sum_z / area;
410 
411  /*
412  if(reg[i].area != reg[i].area_check){
413  printf("Area Mismatch: %d %d\n",reg[i].area,reg[i].area_check);
414  }
415 
416  x = (y_class[avg.y] & u_class[avg.u] & v_class[avg.v]);
417  j = reg[i].color;
418  l = (1 << j);
419  if((x & l) != l){
420  printf("Error: c=%d a=%d (%d,%d) (%d,%d,%d)\n",
421  reg[i].color,area,
422  (int)reg[i].cen_x,(int)reg[i].cen_y,
423  avg.y,avg.u,avg.v);
424  }
425  */
426 
427  reg[i].average = avg;
428  }
429 }
430 
432 // Splits the various regions in the region table a separate list
433 // for each color. The lists are threaded through the table using
434 // the region's 'next' field. Returns the maximal area of the
435 // regions, which we use below to speed up sorting.
436 {
437  region *p;
438  int i,l;
439  int area,max_area;
440 
441  // clear out the region table
442  for(i=0; i<CMV_MAX_COLORS; i++){
443  region_count[i] = 0;
444  region_list[i] = NULL;
445  }
446 
447  // step over the table, adding successive
448  // regions to the front of each list
449  max_area = 0;
450  for(i=0; i<num; i++){
451  p = &reg[i];
452  area = p->area;
453  if(area >= CMV_MIN_AREA){
454  if(area > max_area) max_area = area;
455  l = p->color;
456  region_count[l]++;
457  p->next = region_list[l];
458  region_list[l] = p;
459  }
460  }
461 
462  return(max_area);
463 }
464 
465 // These are the tweaking values for the radix sort given below
466 // Feel free to change them, though these values seemed to work well
467 // in testing. Don't worry about extra passes to get all 32 bits of
468 // the area; the implementation only does as many passes as needed to
469 // touch the most significant set bit (MSB of biggest region's area)
470 #define CMV_RBITS 6
471 #define CMV_RADIX (1 << CMV_RBITS)
472 #define CMV_RMASK (CMV_RADIX-1)
473 
475 // Sorts a list of regions by their area field.
476 // Uses a linked list based radix sort to process the list.
477 {
478  region *tbl[CMV_RADIX],*p,*pn;
479  int slot,shift;
480  int i,j;
481 
482  // handle trivial cases
483  if(!list || !list->next) return(list);
484 
485  // Initialize table
486  for(j=0; j<CMV_RADIX; j++) tbl[j] = NULL;
487 
488  for(i=0; i<passes; i++){
489  // split list into buckets
490  shift = CMV_RBITS * i;
491  p = list;
492  while(p){
493  pn = p->next;
494  slot = ((p->area) >> shift) & CMV_RMASK;
495  p->next = tbl[slot];
496  tbl[slot] = p;
497  p = pn;
498  }
499 
500  // integrate back into partially ordered list
501  list = NULL;
502  for(j=0; j<CMV_RADIX; j++){
503  p = tbl[j];
504  tbl[j] = NULL; // clear out table for next pass
505  while(p){
506  pn = p->next;
507  p->next = list;
508  list = p;
509  p = pn;
510  }
511  }
512  }
513 
514  return(list);
515 }
516 
517 void CMVision::sortRegions(int max_area)
518 // Sorts entire region table by area, using the above
519 // function to sort each threaded region list.
520 {
521  int i,p;
522 
523  // do minimal number of passes sufficient to touch all set bits
524  p = top_bit((max_area + CMV_RBITS-1) / CMV_RBITS);
525 
526  // sort each list
527  for(i=0; i<CMV_MAX_COLORS; i++){
529  }
530 }
531 
532 int CMVision::mergeRegions(region *p,int num,double density_thresh)
533 // Looks through regions and merges pairs of the same color that would
534 // have a high density after combining them (where density is the area
535 // in pixels of the region divided by the bounding box area). This
536 // implementation sucks, and I promise real spatial data structures in
537 // the future so n^2 ugliness like this is not necessary.
538 {
539  region *q,*s;
540  int l,r,t,b;
541  int a;
542  int merged;
543 
544  //double tmp;
545 
546  merged = 0;
547 
548  while(p && merged<num){
549  q = p->next;
550  s = p;
551 
552  while(q){
553  // find union box and get its total area
554  l = min(p->x1,q->x1);
555  r = max(p->x2,q->x2);
556  t = min(p->y1,q->y1);
557  b = max(p->y2,q->y2);
558  a = (r-l) * (b-t);
559 
560  // if density of merged region is still above threshold
561  if((double)(p->area + q->area) / a > density_thresh){
562  // merge them to create a new region
563  a = p->area + q->area;
564  p->x1 = l;
565  p->x2 = r;
566  p->y1 = t;
567  p->y2 = b;
568  p->cen_x = ((p->cen_x * p->area) + (q->cen_x * q->area)) / a;
569  p->cen_y = ((p->cen_y * p->area) + (q->cen_y * q->area)) / a;
570  p->area = a;
571 
572  // remove q from list (old smaller region)
573  q = q->next;
574  s->next = q;
575  merged++;
576  }else{
577  s = q;
578  q = q->next;
579  }
580  }
581  p = p->next;
582  }
583 
584  return(merged);
585 }
586 
588 // Apply merge operation to all regions using the above function.
589 {
590  int i,m;
591  int num;
592 
593  num = 0;
594 
595  for(i=0; i<CMV_MAX_COLORS; i++){
596  m = mergeRegions(region_list[i],colors[i].expected_num,colors[i].merge);
597  region_count[i] -= m;
598  num += m;
599  }
600 
601  return(num);
602 }
603 
604 //==== Interface/Public Functions ==================================//
605 
606 #define ZERO(x) memset(x,0,sizeof(x))
607 
609 {
610  ZERO(a_class);
611  ZERO(b_class);
612 
613  ZERO(region_list);
615 
616  ZERO(colors);
617 
618  map = NULL;
619 }
620 
621 bool CMVision::initialize(int nwidth,int nheight)
622 // Initializes library to work with images of specified size
623 {
624  width = nwidth;
625  height = nheight;
626 
627  if(map) delete(map);
628 
629  map = new unsigned[width * height + 1];
630  // Need 1 extra element to store terminator value in encodeRuns()
631 
633 
634  return(map != NULL);
635 }
636 
637 // sets bits in k in array arr[l..r]
638 template <class num>
639 void set_bits(num *arr,int len,int l,int r,num k)
640 {
641  int i;
642 
643  l = max(l,0);
644  r = min(r+1,len);
645 
646  for(i=l; i<r; i++) arr[i] |= k;
647 }
648 
649 template <class num>
650 void clear_bits(num *arr,int len,int l,int r,num k)
651 {
652  int i;
653 
654  l = max(l,0);
655  r = min(r+1,len);
656 
657  k = ~k;
658  for(i=l; i<r; i++) arr[i] &= k;
659 }
660 
661 #define CMV_STATE_SCAN 0
662 #define CMV_STATE_COLORS 1
663 #define CMV_STATE_THRESH 2
664 #define CMV_MAX_BUF 256
665 
666 bool CMVision::loadOptions(const char *filename)
667 // Loads in options file specifying color names and representative
668 // rgb triplets. Also loads in color class threshold values.
669 {
670  char buf[CMV_MAX_BUF],str[CMV_MAX_BUF];
671  FILE *in;
672  int state,i,n;
673 
674  int r,g,b;
675  int exp_num;
676  double merge;
677  color_info *c;
678 
679  int a1,a2,b1,b2;
680  unsigned k;
681 
682  // Open options file
683  in = fopen(filename,"rt");
684  if(!in) return(false);
685 
686  // Clear out previously set options
687  for(i=0; i<CMV_COLOR_LEVELS; i++){
688  a_class[i] = b_class[i] = 0;
689  }
690  for(i=0; i<CMV_MAX_COLORS; i++){
691  if(colors[i].name){
692  delete(colors[i].name);
693  colors[i].name = NULL;
694  }
695  }
696 
697  // Loop ever lines, processing via a simple parser
698  state = 0;
699  while (fgets(buf, CMV_MAX_BUF, in)) {
700  // skip comment lines
701  if (buf[0] == '#')
702  continue;
703 
704  switch (state) {
705  case CMV_STATE_SCAN:
706  n = sscanf(buf, "[%s", str);
707  if (n == 1) {
708 
709  if (!strncasecmp(str, "colors]", CMV_MAX_BUF)) {
710  state = CMV_STATE_COLORS;
711  i = 0;
712  } else if (!strncasecmp(str, "thresholds]", CMV_MAX_BUF)) {
713  state = CMV_STATE_THRESH;
714  i = 0;
715  } else {
716  printf("CMVision: Ignoring unknown option header '%s'.\n", str);
717  }
718  }
719  break;
720  case CMV_STATE_COLORS:
721  n = sscanf(buf, "(%d,%d,%d) %lf %d %s", &r, &g, &b, &merge, &exp_num, str);
722  if (n == 6) {
723  // printf("RGB: (%d,%d,%d) %lf %d '%s'\n",
724  // r,g,b,merge,exp_num,str); fflush(stdout);
725  if (i < CMV_MAX_COLORS) {
726  c = &colors[i];
727  c->color.red = r;
728  c->color.green = g;
729  c->color.blue = b;
730  c->name = strdup(str);
731  c->merge = merge;
732  c->expected_num = exp_num;
733  i++;
734  } else {
735  printf("CMVision: Too many colors, ignoring '%s'.\n", str);
736  }
737  } else if (n == 0) {
738  state = CMV_STATE_SCAN;
739  }
740  break;
741  case CMV_STATE_THRESH:
742  n = sscanf(buf, "(%d:%d,%d:%d)", &a1, &a2, &b1, &b2);
743  if (n == 4) {
744  if (i < CMV_MAX_COLORS) {
745  c = &colors[i];
746  c->a_low = a1;
747  c->a_high = a2;
748  c->b_low = b1;
749  c->b_high = b2;
750 
751  k = (1 << i);
752  set_bits(a_class, CMV_COLOR_LEVELS, a1, a2, k);
753  set_bits(b_class, CMV_COLOR_LEVELS, b1, b2, k);
754  i++;
755  } else {
756  printf("CMVision: Too many thresholds.\n");
757  }
758  } else if (n == 0) {
759  state = CMV_STATE_SCAN;
760  }
761  break;
762  }
763  }
764 
765  /*
766  for(i=0; i<CMV_COLOR_LEVELS; i++){
767  printf("a:%08X b:%08X\n", a_class[i],b_class[i]);
768  }
769  */
770 
771  fclose(in);
772 
773  return(true);
774 }
775 
776 bool CMVision::saveOptions(char *filename)
777 {
778  color_info *c;
779  FILE *out;
780  int i;
781 
782  out = fopen(filename,"wt");
783  if(!out) return(false);
784 
785  fprintf(out,"[Colors]\n");
786  i = 0;
787  while(colors[i].name){
788  c = &colors[i];
789  fprintf(out,"(%3d,%3d,%3d) %6.4f %d %s\n",
790  c->color.red,c->color.green,c->color.blue,
791  c->merge,c->expected_num,c->name);
792  i++;
793  }
794 
795  fprintf(out,"\n[Thresholds]\n");
796  i = 0;
797  while(colors[i].name){
798  c = &colors[i];
799  fprintf(out,"(%3d:%3d,%3d:%3d)\n",
800  c->a_low,c->a_high,
801  c->b_low,c->b_high);
802  i++;
803  }
804 
805  fclose(out);
806 
807  return(true);
808 }
809 
810 bool CMVision::enable(unsigned opt)
811 {
812  unsigned int valid;
813 
814  valid = opt & CMV_VALID_OPTIONS;
815  options |= valid;
816 
817  return(opt == valid);
818 }
819 
820 bool CMVision::disable(unsigned opt)
821 {
822  unsigned int valid;
823 
824  valid = opt & CMV_VALID_OPTIONS;
825  options &= ~valid;
826 
827  return(opt == valid);
828 }
829 
831 {
832  if(map) delete(map);
833  map = NULL;
834 }
835 
836 
837 //==== Vision Testing Functions ====================================//
838 
840 {
841  int i,s;
842  rgb black = {0,0,0};
843 
844  if(!image || !out) return(false);
845 
846  classifyFrame(image,map);
847 
848  s = width * height;
849 
850  i = 0;
851  while(i < s){
852  while(i<s && !map[i]){
853  out[i] = black;
854  i++;
855  }
856  while(i<s && map[i]){
857  out[i] = colors[bottom_bit(map[i])-1].color;
858  i++;
859  }
860  }
861 
862  return(true);
863 }
864 
865 bool CMVision::getThreshold(int color,
866  int &a_low,int &a_high,
867  int &b_low,int &b_high)
868 {
869  color_info *c;
870 
871  if(color<0 || color>=CMV_MAX_COLORS) return(false);
872 
873  c = &colors[color];
874  a_low = c->a_low; a_high = c->a_high;
875  b_low = c->b_low; b_high = c->b_high;
876 
877  return(true);
878 }
879 
880 bool CMVision::setThreshold(int color,
881  int a_low,int a_high,
882  int b_low,int b_high)
883 {
884  color_info *c;
885  unsigned k;
886 
887  if(color<0 || color>=CMV_MAX_COLORS) return(false);
888 
889  c = &colors[color];
890  k = 1 << color;
891 
894 
895  c->a_low = a_low; c->a_high = a_high;
896  c->b_low = b_low; c->b_high = b_high;
897 
898  set_bits(a_class,CMV_COLOR_LEVELS,a_low,a_high,k);
899  set_bits(b_class,CMV_COLOR_LEVELS,b_low,b_high,k);
900 
901  return(true);
902 }
903 
904 //==== Main Vision Functions =======================================//
905 
907 {
908  int runs;
909  int regions;
910  int max_area;
911 
912  if(!image) return(false);
913 
914  if(options & CMV_THRESHOLD){
915 
916  classifyFrame(image,map);
917  runs = encodeRuns(rmap,map);
918  connectComponents(rmap,runs);
919 
920  regions = extractRegions(region_table,rmap,runs);
921 
923  calcAverageColors(region_table,regions,image,rmap,runs);
924  }
925 
926  max_area = separateRegions(region_table,regions);
927  sortRegions(max_area);
928 
930  mergeRegions();
931  }
932  }
933 
934  return(true);
935 }
936 
937 bool CMVision::processFrame(unsigned *map)
938 {
939  int runs;
940  int regions;
941  int max_area;
942 
943  if(!map) return(false);
944 
945  runs = encodeRuns(rmap,map);
946  connectComponents(rmap,runs);
947 
948  regions = extractRegions(region_table,rmap,runs);
949 
950  // if(options & CMV_COLOR_AVERAGES){
951  // calcAverageColors(region_table,regions,image,rmap,runs);
952  // }
953 
954  max_area = separateRegions(region_table,regions);
955  sortRegions(max_area);
956 
958  mergeRegions();
959  }
960 
961  return(true);
962 }
963 
964 int CMVision::numRegions(int color_id)
965 {
966  if(color_id<0 || color_id>=CMV_MAX_COLORS) return(CMV_NONE);
967  return(region_count[color_id]);
968 }
969 
971 {
972  if(color_id<0 || color_id>=CMV_MAX_COLORS) return(NULL);
973  return(region_list[color_id]);
974 }
CMVision::rmap
rle rmap[CMV_MAX_RUNS]
Definition: cmvision.h:160
CMV_NONE
#define CMV_NONE
Definition: cmvision.h:79
lab::a
unsigned char a
Definition: cmvision.h:86
CMVision::classifyFrame
void classifyFrame(image_pixel *restrict img, unsigned *restrict map)
Definition: cmvision.cc:105
CMVision::mergeRegions
int mergeRegions()
Definition: cmvision.cc:587
rgb::green
unsigned char green
Definition: cmvision.h:94
CMVision::region::cen_x
float cen_x
Definition: cmvision.h:114
CMV_STATE_COLORS
#define CMV_STATE_COLORS
Definition: cmvision.cc:662
lab::l
unsigned char l
Definition: cmvision.h:86
CMVision::saveOptions
bool saveOptions(char *filename)
Definition: cmvision.cc:776
CMVision::color_info::b_high
int b_high
Definition: cmvision.h:137
s
XmlRpcServer s
CMV_VALID_OPTIONS
#define CMV_VALID_OPTIONS
Definition: cmvision.h:105
CMVision::color_info::b_low
int b_low
Definition: cmvision.h:137
CMV_DENSITY_MERGE
#define CMV_DENSITY_MERGE
Definition: cmvision.h:103
CMVision::initialize
bool initialize(int nwidth, int nheight)
Definition: cmvision.cc:621
rgb
Definition: cmvision.h:93
CMVision::setThreshold
bool setThreshold(int color, int a_low, int a_high, int b_low, int b_high)
Definition: cmvision.cc:880
CMVision::color_info
Definition: cmvision.h:131
CMVision::region
Definition: cmvision.h:110
max
num max(num a, num b)
Definition: cmvision.cc:57
CMVision::connectComponents
void connectComponents(rle *restrict map, int num)
Definition: cmvision.cc:169
CMVision::a_class
unsigned a_class[CMV_COLOR_LEVELS]
Definition: cmvision.h:153
CMVision::getThreshold
bool getThreshold(int color, int &a_low, int &a_high, int &b_low, int &b_high)
Definition: cmvision.cc:865
top_bit
num top_bit(num n)
Definition: cmvision.cc:94
rgb::red
unsigned char red
Definition: cmvision.h:94
CMVision::rle
Definition: cmvision.h:125
CMVision::enable
bool enable(unsigned opt)
Definition: cmvision.cc:810
CMVision::close
void close()
Definition: cmvision.cc:830
CMVision::clear
void clear()
Definition: cmvision.cc:608
CMVision::region_table
region region_table[CMV_MAX_REGIONS]
Definition: cmvision.h:156
CMVision::calcAverageColors
void calcAverageColors(region *restrict reg, int num_reg, image_pixel *restrict img, rle *restrict rmap, int num_runs)
Definition: cmvision.cc:313
CMVision::region_count
int region_count[CMV_MAX_COLORS]
Definition: cmvision.h:158
CMVision::loadOptions
bool loadOptions(const char *filename)
Definition: cmvision.cc:666
CMVision::separateRegions
int separateRegions(region *restrict reg, int num)
Definition: cmvision.cc:431
CMVision::region_list
region * region_list[CMV_MAX_COLORS]
Definition: cmvision.h:157
cmvision.h
CMVision::region::next
region * next
Definition: cmvision.h:120
CMVision::encodeRuns
int encodeRuns(rle *restrict out, unsigned *restrict map)
Definition: cmvision.cc:124
log2modp
int log2modp[37]
Definition: cmvision.cc:70
lab
Definition: cmvision.h:85
CMV_THRESHOLD
#define CMV_THRESHOLD
Definition: cmvision.h:100
CMVision::sortRegionListByArea
region * sortRegionListByArea(region *restrict list, int passes)
Definition: cmvision.cc:474
CMVision::color_info::color
rgb color
Definition: cmvision.h:132
CMV_MAX_BUF
#define CMV_MAX_BUF
Definition: cmvision.cc:664
CMV_COLOR_LEVELS
#define CMV_COLOR_LEVELS
Definition: cmvision.h:67
CMVision::region::x1
int x1
Definition: cmvision.h:113
restrict
#define restrict
Definition: cmvision.h:31
CMVision::color_info::a_low
int a_low
Definition: cmvision.h:136
range_sum
int range_sum(int x, int w)
Definition: cmvision.cc:50
min
num min(num a, num b)
Definition: cmvision.cc:64
CMVision::sortRegions
void sortRegions(int max_area)
Definition: cmvision.cc:517
CMV_STATE_SCAN
#define CMV_STATE_SCAN
Definition: cmvision.cc:661
CMVision::height
int height
Definition: cmvision.h:163
CMVision::extractRegions
int extractRegions(region *restrict reg, rle *restrict rmap, int num)
Definition: cmvision.cc:246
CMVision::colors
color_info colors[CMV_MAX_COLORS]
Definition: cmvision.h:162
CMVision::color_info::name
char * name
Definition: cmvision.h:133
CMVision::region::x2
int x2
Definition: cmvision.h:113
CMVision::region::y1
int y1
Definition: cmvision.h:113
CMV_MAX_RUNS
#define CMV_MAX_RUNS
Definition: cmvision.h:75
CMV_MAX_COLORS
#define CMV_MAX_COLORS
Definition: cmvision.h:68
ZERO
#define ZERO(x)
Definition: cmvision.cc:606
CMVision::color_info::expected_num
int expected_num
Definition: cmvision.h:135
CMVision::region::cen_y
float cen_y
Definition: cmvision.h:114
CMV_RMASK
#define CMV_RMASK
Definition: cmvision.cc:472
CMVision::processFrame
bool processFrame(image_pixel *image)
Definition: cmvision.cc:906
CMVision::getRegions
region * getRegions(int color_id)
Definition: cmvision.cc:970
CMVision::disable
bool disable(unsigned opt)
Definition: cmvision.cc:820
CMV_MIN_AREA
#define CMV_MIN_AREA
Definition: cmvision.h:77
CMVision::b_class
unsigned b_class[CMV_COLOR_LEVELS]
Definition: cmvision.h:154
set_bits
void set_bits(num *arr, int len, int l, int r, num k)
Definition: cmvision.cc:639
CMV_RADIX
#define CMV_RADIX
Definition: cmvision.cc:471
CMVision::region::area
int area
Definition: cmvision.h:112
CMVision::rle::length
int length
Definition: cmvision.h:127
CMVision::width
int width
Definition: cmvision.h:163
CMVision::options
unsigned options
Definition: cmvision.h:166
CMVision::rle::parent
int parent
Definition: cmvision.h:128
CMV_MAX_REGIONS
#define CMV_MAX_REGIONS
Definition: cmvision.h:76
bottom_bit
int bottom_bit(num n)
Definition: cmvision.cc:76
CMVision::region::color
int color
Definition: cmvision.h:111
CMVision::color_info::a_high
int a_high
Definition: cmvision.h:136
CMVision::map
unsigned * map
Definition: cmvision.h:164
CMVision::color_info::merge
double merge
Definition: cmvision.h:134
NULL
#define NULL
Definition: cmvision.h:82
CMVision::numRegions
int numRegions(int color_id)
Definition: cmvision.cc:964
CMV_COLOR_AVERAGES
#define CMV_COLOR_AVERAGES
Definition: cmvision.h:101
CMVision::testClassify
bool testClassify(rgb *restrict out, image_pixel *restrict image)
Definition: cmvision.cc:839
rgb::blue
unsigned char blue
Definition: cmvision.h:94
CMV_RBITS
#define CMV_RBITS
Definition: cmvision.cc:470
CMV_STATE_THRESH
#define CMV_STATE_THRESH
Definition: cmvision.cc:663
CMVision::rle::color
unsigned color
Definition: cmvision.h:126
clear_bits
void clear_bits(num *arr, int len, int l, int r, num k)
Definition: cmvision.cc:650
CMVision::region::y2
int y2
Definition: cmvision.h:113
lab::b
unsigned char b
Definition: cmvision.h:86


cmvision
Author(s): Nate Koenig, Nate Koenig
autogenerated on Wed Mar 2 2022 00:03:25