PageRenderTime 63ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/player-3.0.2/server/drivers/blobfinder/cmvision/cmvision.cc

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