slic.cpp
Go to the documentation of this file.
1 #include "slic.h"
2 
3 
4 /*
5  * Constructor. Nothing is done here.
6  */
8 
9 }
10 
11 /*
12  * Destructor. Clear any present data.
13  */
15 }
16 
17 /*
18  * Clear the data as saved by the algorithm.
19  *
20  * Input : -
21  * Output: -
22  */
24  clusters.release();
25  distances.release();
26  centers.release();
27  center_counts.clear();
28 }
29 
30 /*
31  * Initialize the cluster centers and initial values of the pixel-wise cluster
32  * assignment and distance values.
33  *
34  * Input : The image (cv::Mat).
35  * Output: -
36  */
37 void Slic::init_data(const cv::Mat &image) {
38  /* Initialize the cluster and distance matrices. */
39 
40  clusters = cv::Mat_<int>(image.cols,image.rows,-1);
41  distances = cv::Mat_<double>(image.cols,image.rows,DBL_MAX);
42 
43  /* Initialize the centers and counters. */
44  for (int i = step; i < image.cols - step/2; i += step) {
45  for (int j = step; j < image.rows - step/2; j += step) {
46  /* Find the local minimum (gradient-wise). */
47  cv::Point nc = find_local_minimum(image, cv::Point(i,j));
48  cv::Vec3b colour = image.at<cv::Vec3b>(nc.y, nc.x);
49 
50  /* Generate the center vector. */
51  Vec5d center(colour[0], colour[1], colour[2], nc.x, nc.y);
52 
53  /* Append to vector of centers. */
54  centers.push_back(center);
55  center_counts.push_back(0);
56  }
57  }
58 }
59 
60 /*
61  * Compute the distance between a cluster center and an individual pixel.
62  *
63  * Input : The cluster index (int), the pixel (cv::Point), and the Lab values of
64  * the pixel (cv::Scalar).
65  * Output: The distance (double).
66  */
67 double Slic::compute_dist(int ci, cv::Point pixel, cv::Vec3b colour) {
68  Vec5d cen(centers(ci));
69  double dc = sqrt(pow(cen[0] - colour[0], 2) + pow(cen[1]
70  - colour[1], 2) + pow(cen[2] - colour[2], 2));
71  double ds = sqrt(pow(cen[3] - pixel.x, 2) + pow(cen[4] - pixel.y, 2));
72 
73  return sqrt(pow(dc / nc, 2) + pow(ds / ns, 2));
74 
75  //double w = 1.0 / (pow(ns / nc, 2));
76  //return sqrt(dc) + sqrt(ds * w);
77 }
78 
79 /*
80  * Find a local gradient minimum of a pixel in a 3x3 neighbourhood. This
81  * method is called upon initialization of the cluster centers.
82  *
83  * Input : The image (cv::Mat &) and the pixel center (cv::Point).
84  * Output: The local gradient minimum (cv::Point).
85  */
86 cv::Point Slic::find_local_minimum(const cv::Mat_<cv::Vec3b> &image, cv::Point center) {
87  double min_grad = DBL_MAX;
88  cv::Point loc_min(center.x, center.y);
89 
90  for (int i = center.x-1; i < center.x+2; i++) {
91  for (int j = center.y-1; j < center.y+2; j++) {
92  cv::Vec3b c1 = image(j+1, i);
93  cv::Vec3b c2 = image(j, i+1);
94  cv::Vec3b c3 = image(j, i);
95  /* Convert colour values to grayscale values. */
96  double i1 = c1[0];
97  double i2 = c2[0];
98  double i3 = c3[0];
99  /*double i1 = c1.val[0] * 0.11 + c1.val[1] * 0.59 + c1.val[2] * 0.3;
100  double i2 = c2.val[0] * 0.11 + c2.val[1] * 0.59 + c2.val[2] * 0.3;
101  double i3 = c3.val[0] * 0.11 + c3.val[1] * 0.59 + c3.val[2] * 0.3;*/
102 
103  /* Compute horizontal and vertical gradients and keep track of the
104  minimum. */
105  if (sqrt(pow(i1 - i3, 2)) + sqrt(pow(i2 - i3,2)) < min_grad) {
106  min_grad = fabs(i1 - i3) + fabs(i2 - i3);
107  loc_min.x = i;
108  loc_min.y = j;
109  }
110  }
111  }
112 
113  return loc_min;
114 }
115 
116 /*
117  * Compute the over-segmentation based on the step-size and relative weighting
118  * of the pixel and colour values.
119  *
120  * Input : The Lab image (cv::Mat), the stepsize (int), and the weight (int).
121  * Output: -
122  */
123 void Slic::generate_superpixels(const cv::Mat &img, int step, int nc) {
124  this->step = step;
125  this->nc = nc;
126  this->ns = step;
127 
128  /* make a new Mat header, that allows us to iterate the image more efficiently. */
129  cv::Mat_<cv::Vec3b> image(img);
130 
131  /* Clear previous data (if any), and re-initialize it. */
132  clear_data();
133  init_data(image);
134 
135  /* Run EM for 10 iterations (as prescribed by the algorithm). */
136  for (int i = 0; i < NR_ITERATIONS; i++) {
137  /* Reset distance values. */
138  distances = FLT_MAX;
139 
140  for (int j = 0; j < centers.rows; j++) {
141  Vec5d cen(centers(j));
142  /* Only compare to pixels in a 2 x step by 2 x step region. */
143  for (int k = int(cen[3]) - step; k < int(cen[3]) + step; k++) {
144  for (int l = int(cen[4]) - step; l < int(cen[4]) + step; l++) {
145 
146  if (k >= 0 && k < image.cols && l >= 0 && l < image.rows) {
147  cv::Vec3b colour = image(l, k);
148  double d = compute_dist(j, cv::Point(k,l), colour);
149 
150  /* Update cluster allocation if the cluster minimizes the
151  distance. */
152  if (d < distances(k,l)) {
153  distances(k,l) = d;
154  clusters(k,l) = j;
155  }
156  }
157  }
158  }
159  }
160 
161  /* Clear the center values. */
162  for (int j = 0; j < centers.rows; j++) {
163  centers(j) = 0;
164  center_counts[j] = 0;
165  }
166 
167  /* Compute the new cluster centers. */
168  for (int j = 0; j < image.cols; j++) {
169  for (int k = 0; k < image.rows; k++) {
170  int c_id = clusters(j,k);
171 
172  if (c_id != -1) {
173  cv::Vec3b colour = image(k, j);
174  centers(c_id) += Vec5d(colour[0], colour[1], colour[2], j, k);
175  center_counts[c_id] += 1;
176  }
177  }
178  }
179 
180  /* Normalize the clusters. */
181  for (int j = 0; j < centers.rows; j++) {
182  centers(j) /= center_counts[j];
183  }
184  }
185 }
186 
187 /*
188  * Enforce connectivity of the superpixels. This part is not actively discussed
189  * in the paper, but forms an active part of the implementation of the authors
190  * of the paper.
191  *
192  * Input : The image (cv::Mat).
193  * Output: -
194  */
195 void Slic::create_connectivity(const cv::Mat &image) {
196  int label = 0, adjlabel = 0;
197  const int lims = (image.cols * image.rows) / (centers.rows);
198 
199  const int dx4[4] = {-1, 0, 1, 0};
200  const int dy4[4] = { 0, -1, 0, 1};
201 
202  /* Initialize the new cluster matrix. */
203  cv::Mat_<int> new_clusters(image.cols,image.rows,-1);
204 
205  for (int i = 0; i < image.cols; i++) {
206  for (int j = 0; j < image.rows; j++) {
207  if (new_clusters(i,j) == -1) {
208  vector<cv::Point> elements;
209  elements.push_back(cv::Point(i, j));
210 
211  /* Find an adjacent label, for possible use later. */
212  for (int k = 0; k < 4; k++) {
213  int x = elements[0].x + dx4[k], y = elements[0].y + dy4[k];
214 
215  if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) {
216  if (new_clusters(x,y) >= 0) {
217  adjlabel = new_clusters(x,y);
218  }
219  }
220  }
221 
222  int count = 1;
223  for (int c = 0; c < count; c++) {
224  for (int k = 0; k < 4; k++) {
225  int x = elements[c].x + dx4[k], y = elements[c].y + dy4[k];
226 
227  if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) {
228  if (new_clusters(x,y) == -1 && clusters(i,j) == clusters(x,y)) {
229  elements.push_back(cv::Point(x, y));
230  new_clusters(x,y) = label;
231  count += 1;
232  }
233  }
234  }
235  }
236 
237  /* Use the earlier found adjacent label if a segment size is
238  smaller than a limit. */
239  if (count <= lims >> 2) {
240  for (int c = 0; c < count; c++) {
241  new_clusters(elements[c].x, elements[c].y) = adjlabel;
242  }
243  label -= 1;
244  }
245  label += 1;
246  }
247  }
248  }
249  //clusters = new_clusters;
250 }
251 
252 /*
253  * Display the cluster centers.
254  *
255  * Input : The image to display upon (cv::Mat) and the colour (cv::Vec3b).
256  * Output: -
257  */
258 void Slic::display_center_grid(cv::Mat &image, cv::Scalar colour) {
259  for (int i = 0; i < centers.rows; i++) {
260  cv::circle(image, cv::Point2d(centers(i)[3], centers(i)[4]), 2, colour, 2);
261  }
262 }
263 
264 /*
265  * Display a single pixel wide contour around the clusters.
266  *
267  * Input : The target image (cv::Mat) and contour colour (cv::Vec3b).
268  * Output: -
269  */
270 void Slic::display_contours(cv::Mat &image, cv::Vec3b colour) {
271  const int dx8[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
272  const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1, 1};
273 
274  /* Initialize the contour vector and the matrix detailing whether a pixel
275  * is already taken to be a contour. */
276  vector<cv::Point> contours;
277  cv::Mat_<uchar> istaken(image.cols, image.rows, uchar(0));
278 
279  /* Go through all the pixels. */
280  for (int i = 0; i < image.cols; i++) {
281  for (int j = 0; j < image.rows; j++) {
282  int nr_p = 0;
283 
284  /* Compare the pixel to its 8 neighbours. */
285  for (int k = 0; k < 8; k++) {
286  int x = i + dx8[k], y = j + dy8[k];
287 
288  if (x >= 0 && x < image.cols && y >= 0 && y < image.rows) {
289  if (istaken(x,y) == false && clusters(i,j) != clusters(x,y)) {
290  nr_p += 1;
291  }
292  }
293  }
294 
295  /* Add the pixel to the contour list if desired. */
296  if (nr_p >= 2) {
297  contours.push_back(cv::Point(i,j));
298  istaken(i,j) = true;
299  }
300  }
301  }
302 
303  /* Draw the contour pixels. */
304  for (int i = 0; i < (int)contours.size(); i++) {
305  image.at<cv::Vec3b>(contours[i].y, contours[i].x) = colour;
306  }
307 }
308 
309 /*
310  * Give the pixels of each cluster the same colour values. The specified colour
311  * is the mean RGB colour per cluster.
312  *
313  * Input : The target image (cv::Mat).
314  * Output: -
315  */
316 void Slic::colour_with_cluster_means(cv::Mat &image) {
317  vector<cv::Vec3i> colours(centers.rows);
318  /* fill */
319  for (size_t i = 0; i < colours.size(); i++) {
320  colours[i] = cv::Vec3i(0, 0, 0);
321  }
322  /* Gather the colour values per cluster. */
323  for (int i = 0; i < image.cols; i++) {
324  for (int j = 0; j < image.rows; j++) {
325  int index = clusters(i,j);
326  if (index < 0) {
327  continue;
328  }
329  cv::Vec3b c = image.at<cv::Vec3b>(j, i);
330  colours[index][0] += (c[0]);
331  colours[index][1] += (c[1]);
332  colours[index][2] += (c[2]);
333  }
334  }
335 
336  /* Divide by the number of pixels per cluster to get the mean colour. */
337  for (int i = 0; i < (int)colours.size(); i++) {
338  colours[i] /= center_counts[i];
339  }
340 
341  /* Fill in. */
342  for (int i = 0; i < image.cols; i++) {
343  for (int j = 0; j < image.rows; j++) {
344  cv::Vec3i c = colours[clusters(i,j)];
345  image.at<cv::Vec3b>(j, i) = cv::Vec3b(c[0], c[1], c[2]);
346  }
347  }
348 }
d
Definition: setup.py:6
void create_connectivity(const cv::Mat &image)
Definition: slic.cpp:195
cv::Mat_< Vec5d > centers
Definition: slic.h:73
vector< int > center_counts
Definition: slic.h:75
double compute_dist(int ci, cv::Point pixel, cv::Vec3b colour)
Definition: slic.cpp:67
cv::Vec< double, 5 > Vec5d
Definition: slic.h:28
int nc
Definition: slic.h:43
long l
void clear_data()
Definition: slic.cpp:23
double sqrt()
int step
Definition: slic.h:43
pointer size
cv::Point find_local_minimum(const cv::Mat_< cv::Vec3b > &image, cv::Point center)
Definition: slic.cpp:86
x
y
dc
#define NR_ITERATIONS
Definition: slic.h:26
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
int ns
Definition: slic.h:43
label
void generate_superpixels(const cv::Mat &image, int step, int nc)
Definition: slic.cpp:123
int count
char * index(char *sp, char c)
Slic()
Definition: slic.cpp:7
c
cv::Mat_< int > clusters
Definition: slic.h:69
~Slic()
Definition: slic.cpp:14
void display_contours(cv::Mat &image, cv::Vec3b colour)
Definition: slic.cpp:270
void init_data(const cv::Mat &image)
Definition: slic.cpp:37
void colour_with_cluster_means(cv::Mat &image)
Definition: slic.cpp:316
void display_center_grid(cv::Mat &image, cv::Scalar colour)
Definition: slic.cpp:258
cv::Mat_< double > distances
Definition: slic.h:70


jsk_perception
Author(s): Manabu Saito, Ryohei Ueda
autogenerated on Mon May 3 2021 03:03:27