segmentation
All Data Structures Namespaces Files Functions Variables Modules Pages
segment-image.h
1 /*
2 Copyright (C) 2006 Pedro Felzenszwalb
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #ifndef SEGMENT_IMAGE
20 #define SEGMENT_IMAGE
21 
22 #include <cstdlib>
23 #include <image.h>
24 #include <misc.h>
25 #include <filter.h>
26 #include "segment-graph.h"
27 
28 // random color
29 rgb random_rgb(){
30  rgb c;
31 
32  c.r = (uchar)rand();
33  c.g = (uchar)rand();
34  c.b = (uchar)rand();
35 
36  return c;
37 }
38 
39 // dissimilarity measure between pixels
40 static inline float diff(image<float> *r, image<float> *g, image<float> *b,
41  int x1, int y1, int x2, int y2) {
42  return sqrt(square(imRef(r, x1, y1)-imRef(r, x2, y2)) +
43  square(imRef(g, x1, y1)-imRef(g, x2, y2)) +
44  square(imRef(b, x1, y1)-imRef(b, x2, y2)));
45 }
46 
47 /*
48  * Segment an image
49  *
50  * Returns a color image representing the segmentation.
51  *
52  * im: image to segment.
53  * sigma: to smooth the image.
54  * c: constant for treshold function.
55  * min_size: minimum component size (enforced by post-processing stage).
56  * num_ccs: number of connected components in the segmentation.
57  */
58 image<rgb> *segment_image(image<rgb> *im, float sigma, float c, int min_size,
59  int *num_ccs) {
60  int width = im->width();
61  int height = im->height();
62 
63  image<float> *r = new image<float>(width, height);
64  image<float> *g = new image<float>(width, height);
65  image<float> *b = new image<float>(width, height);
66 
67  // smooth each color channel
68  for (int y = 0; y < height; y++) {
69  for (int x = 0; x < width; x++) {
70  imRef(r, x, y) = imRef(im, x, y).r;
71  imRef(g, x, y) = imRef(im, x, y).g;
72  imRef(b, x, y) = imRef(im, x, y).b;
73  }
74  }
75  image<float> *smooth_r = smooth(r, sigma);
76  image<float> *smooth_g = smooth(g, sigma);
77  image<float> *smooth_b = smooth(b, sigma);
78  delete r;
79  delete g;
80  delete b;
81 
82  // build graph
83  edge *edges = new edge[width*height*4];
84  int num = 0;
85  for (int y = 0; y < height; y++) {
86  for (int x = 0; x < width; x++) {
87  if (x < width-1) {
88  edges[num].a = y * width + x;
89  edges[num].b = y * width + (x+1);
90  edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x+1, y);
91  num++;
92  }
93 
94  if (y < height-1) {
95  edges[num].a = y * width + x;
96  edges[num].b = (y+1) * width + x;
97  edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x, y+1);
98  num++;
99  }
100 
101  if ((x < width-1) && (y < height-1)) {
102  edges[num].a = y * width + x;
103  edges[num].b = (y+1) * width + (x+1);
104  edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x+1, y+1);
105  num++;
106  }
107 
108  if ((x < width-1) && (y > 0)) {
109  edges[num].a = y * width + x;
110  edges[num].b = (y-1) * width + (x+1);
111  edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x+1, y-1);
112  num++;
113  }
114  }
115  }
116  delete smooth_r;
117  delete smooth_g;
118  delete smooth_b;
119 
120  // segment
121  universe *u = segment_graph(width*height, num, edges, c);
122 
123  // post process small components
124  for (int i = 0; i < num; i++) {
125  int a = u->find(edges[i].a);
126  int b = u->find(edges[i].b);
127  if ((a != b) && ((u->size(a) < min_size) || (u->size(b) < min_size)))
128  u->join(a, b);
129  }
130  delete [] edges;
131  *num_ccs = u->num_sets();
132 
133  image<rgb> *output = new image<rgb>(width, height);
134 
135  // pick random colors for each component
136  rgb *colors = new rgb[width*height];
137  for (int i = 0; i < width*height; i++)
138  colors[i] = random_rgb();
139 
140  for (int y = 0; y < height; y++) {
141  for (int x = 0; x < width; x++) {
142  int comp = u->find(y * width + x);
143  imRef(output, x, y) = colors[comp];
144  }
145  }
146 
147  delete [] colors;
148  delete u;
149 
150  return output;
151 }
152 
153 #endif