Hexagon Cell  v.1.1.1
Cell.cpp
1 #include "Cell.h"
2 #include "macroses.h"
3 #include "core\core.hpp"
4 
5 namespace HexagonCells
6 {
7  // Default Constructor
8  CCell::CCell(void) : m_img(Mat()), m_imgSize(cvSize(0, 0)), m_LUT(Mat()), m_R(-1.0), m_r(-1.0), m_nCells(-1), m_cellIntApp(CELL_AVG), m_cellData(Mat())
9  {
10  }
11 
12  // Constructor
13  CCell::CCell(CvSize imgSize, cell_int_app cellIntApp) : m_img(Mat()), m_imgSize(imgSize), m_LUT(Mat()), m_R(-1.0), m_r(-1.0), m_nCells(-1), m_cellIntApp(cellIntApp), m_cellData(Mat())
14  {
15  }
16 
17  // Constructor
18  CCell::CCell(Mat &img, cell_int_app cellIntApp) : m_LUT(Mat()), m_R(-1.0), m_r(-1.0), m_nCells(-1), m_cellIntApp(cellIntApp), m_cellData(Mat())
19  {
20  img.copyTo(m_img);
21  m_imgSize = img.size();
22  }
23 
24  // Constructor
25  CCell::CCell(double R) : m_img(Mat()), m_imgSize(cvSize(0, 0)), m_LUT(Mat()), m_R(R), m_r(0.5*sqrt(3.0)*R), m_nCells(-1), m_cellIntApp(CELL_AVG), m_cellData(Mat())
26  {
27  }
28 
29  // Constructor
30  CCell::CCell(CvSize imgSize, double R, cell_int_app cellIntApp) : m_img(Mat()), m_imgSize(imgSize), m_LUT(Mat()), m_R(R), m_r(0.5*sqrt(3.0)*R), m_nCells(-1), m_cellIntApp(cellIntApp), m_cellData(Mat())
31  {
32  }
33 
34  // Constructor
35  CCell::CCell(Mat &img, double R, cell_int_app cellIntApp) : m_LUT(Mat()), m_R(R), m_r(0.5*sqrt(3.0)*R), m_nCells(-1), m_cellIntApp(cellIntApp), m_cellData(Mat())
36  {
37  img.copyTo(m_img);
38  m_imgSize = img.size();
39  }
40 
41  // Destructor
43  {
44  if (!m_img.empty()) m_img.release();
45  if (!m_LUT.empty()) m_LUT.release();
46  if (!m_cellData.empty()) m_cellData.release();
47  }
48 
49  void CCell::clear(void)
50  {
51  if (!m_img.empty()) m_img.release();
52  m_imgSize = cvSize(0, 0);
53  if (!m_LUT.empty()) m_LUT.release();
54  m_R = -1.0;
55  m_r = -1.0;
56  m_cellIntApp = CELL_AVG;
57  if (!m_cellData.empty()) m_cellData.release();
58  }
59 
60  void CCell::setImage(Mat &img)
61  {
62  // Assertions
63  HCELL_ASSERT_MSG(!img.empty(), "The image is not set");
64 
65  if (!m_img.empty()) m_img.release();
66  img.copyTo(m_img);
67 
68  if ((m_imgSize.width != img.size().width) || (m_imgSize.height != img.size().height)) { // if new size
69  if (!m_LUT.empty()) m_LUT.release(); // release LUT
70  m_nCells = -1; // reset nCells;
71  }
72  m_imgSize = img.size();
73  if (!m_cellData.empty()) m_cellData.release();
74  }
75 
76  void CCell::setRadius(double R)
77  {
78  // Assertions
79  HCELL_ASSERT_MSG(R >= MIN_RADIUS, "The cell radius is not set or has a wrong value");
80  if (R == m_R) return;
81 
82  if (!m_LUT.empty()) m_LUT.release(); // release LUT
83  m_R = R;
84  m_r = 0.5 * sqrt(3.0) * R;
85  m_nCells = -1;
86  if (!m_cellData.empty()) m_cellData.release();
87  }
88 
90  {
91  m_cellIntApp = cellIntApp;
92  if (!m_cellData.empty()) m_cellData.release();
93  }
94 
96  {
97  cell_params res;
98  res.R = m_R;
99  res.r = m_r;
100  res.S = m_R;
101  if (res.S >= 0) res.S *= 3 * m_r;
102  if (m_nCells < 0) calculate_nCells();
103  res.N = m_nCells;
104  return res;
105  }
106 
107  int CCell::getIDX(int x, int y)
108  {
109  return d2idx(cvPoint2D64f(x, y));
110  }
111 
112  int CCell::getNeighbourIDX(int idx, int i)
113  {
114  if (m_nCells < 0) calculate_nCells();
115 
116  double dx = 2.0 * m_r;
117  double imgWidth = static_cast<double>(m_imgSize.width);
118  int width0 = static_cast<int> (0.99 + imgWidth / dx);
119  int width1 = 1 + static_cast<int> (0.99 + (imgWidth - m_r) / dx);
120 
121  Point c = idx2h(idx, m_R, m_imgSize);
122 
123  int d = 0;
124  if ((c.y % 2) == 0) d = 1;
125 
126  int res = 0;
127  switch (i) {
128  case 0: c.x += 1; break;
129  case 1: c.x += d; c.y += 1; break;
130  case 2: c.x += d - 1; c.y += 1; break;
131  case 3: c.x -= 1; break;
132  case 4: c.x += d - 1; c.y -= 1; break;
133  case 5: c.x += d; c.y -= 1; break;
134  default: res = -1; break;
135  }
136  if ((c.x < 0) || (c.y < 0)) res = -1;
137  if (((c.y % 2) == 0) && (c.x >= width0)) res = -1;
138  if (((c.y % 2) != 0) && (c.x >= width1)) res = -1;
139  if (res == 0) {
140  res = h2idx(c);
141  if (res >= m_nCells) res = -1;
142  }
143  return res;
144  }
145 
146  int * CCell::getNeighbourhood(int idx)
147  {
148  int *res = new int[6];
149  for (int i = 0; i < 6; i++) res[i] = getNeighbourIDX(idx, i);
150  return res;
151  }
152 
153  CvScalar CCell::getVal(int idx)
154  {
155  if (m_cellData.empty()) calculate_cellData();
156 
157  CvScalar res;
158 
159  int C = m_img.channels();
160  for (int c = 0; c < C; c++) res.val[c] = m_cellData.at<double>(0, C * idx + c);
161 
162  return res;
163  }
164 
165  // =================== Auxilary functions ==================
166  bool ifInsideTriangle(CvPoint2D64f x, CvPoint2D64f a, CvPoint2D64f b, CvPoint2D64f c)
167  {
168  double r1, r2, r3;
169  r1 = (a.x - x.x) * (b.y - a.y) - (b.x - a.x) * (a.y - x.y);
170  r2 = (b.x - x.x) * (c.y - b.y) - (c.x - b.x) * (b.y - x.y);
171  r3 = (c.x - x.x) * (a.y - c.y) - (a.x - c.x) * (c.y - x.y);
172  if (SIGN(r1) == SIGN(r2) == SIGN(r3)) return true;
173  return false;
174  }
175 
176  // =================== Private functions ===================
177  int CCell::calculate_LUT(void)
178  {
179  // Assertions
180  HCELL_ASSERT_MSG((m_imgSize.height != 0) && (m_imgSize.width != 0), "The image size is not set");
181 
182  if (!m_LUT.empty()) m_LUT.release();
183  m_LUT.create(m_imgSize, CV_32SC1);
184 
185  double dx = 2.0 * m_r; // x - distance between cells
186  double dy = 1.5 * m_R; // y - distance between cells
187 
188  for (register int y = 0; y < m_LUT.rows; y++) {
189  dword *pLUT = m_LUT.ptr<dword>(y);
190  for (register int x = 0; x < m_LUT.cols; x++) {
191  CvPoint2D64f X = cvPoint2D64f(x, y); // X - point in image cartesian <d> coordinate
192  Point c = d2h(X); // cell indexes in hexagonical <h> coordinate system
193 
194  // cell center coordinates in image
195  CvPoint2D64f C;
196  C.y = c.y * dy + 0.5 * m_R;
197  C.x = c.x * dx + m_r;
198 
199  if ((c.y % 2) == 1) X.x += m_r;
200  bool inside = ifInsideCell(X, C);
201  if (!inside) {
202  if ((c.y % 2) == 0) {
203  if (X.x >= C.x) c.x++;
204  }
205  else {
206  if (X.x < C.x) c.x--;
207  }
208  c.y--;
209  }
210  pLUT[x] = h2idx(c);
211  } // x
212  } // y
213  return 0;
214  }
215 
216  int CCell::calculate_nCells(void)
217  {
218  // Assertions
219  HCELL_ASSERT_MSG(((m_R >= 0) && (m_r >= 0)), "The cell radius is not set or has a wrong value");
220 
221  int res;
222  if (m_LUT.empty()) if ((res = calculate_LUT()) < 0) return res;
223 
224  double maxVal;
225  minMaxLoc(m_LUT, NULL, &maxVal, NULL, NULL);
226  m_nCells = static_cast<int>(maxVal) + 1;
227 
228  return 0;
229  }
230 
231  int CCell::calculate_cellData(void)
232  {
233  // Assertions
234  HCELL_ASSERT_MSG(!m_img.empty(), "The image is not set");
235 
236  int C = m_img.channels();
237 
238  if (m_nCells < 0) calculate_nCells();
239  if (m_cellData.empty()) {
240  m_cellData.create(1, m_nCells, CV_MAKE_TYPE(CV_64F, C));
241  m_cellData.setTo(0);
242  }
243 
244  double * pData = m_cellData.ptr<double>(0);
245  int * pNumVal = NULL;
246  int * pMaxVal = NULL;
247  int len = m_nCells;
248 
249  if (m_cellIntApp == CELL_MV) len *= 256;
250  pNumVal = new int[len];
251  if (m_cellIntApp == CELL_MV) pMaxVal = new int[m_nCells];
252 
253  for (int c = 0; c < C; c++) {
254  memset(pNumVal, 0, len * sizeof(int));
255  if (pMaxVal != NULL) memset(pMaxVal, 0, m_nCells * sizeof(int));
256  for (register int y = 0; y < m_img.rows; y++) {
257  byte *pImg = m_img.ptr<byte>(y);
258  for (register int x = 0; x < m_img.cols; x++) {
259  int id = d2idx(cvPoint2D64f(x, y));
260  byte val = pImg[C*x + c];
261 
262  if (pMaxVal != NULL) {
263  pNumVal[256 * id + val]++;
264  if (pNumVal[256 * id + val] > pMaxVal[id]) {
265  pMaxVal[id]++;
266  pData[C*id + c] = val;
267  }
268  }
269  else {
270  pData[C*id + c] = (pNumVal[id] * pData[C*id + c] + val) / (pNumVal[id] + 1);
271  pNumVal[id]++;
272  }
273 
274  } // x
275  } // y
276  } // c
277 
278 
279  delete[] pNumVal;
280  if (pMaxVal != NULL) delete[] pMaxVal;
281  return 0;
282 
283  }
284 
285  bool CCell::ifInsideCell(CvPoint2D64f x, CvPoint2D64f C) const
286  {
287  bool res;
288  for (int i = 0; i < 6; i++) {
289  int j = (i + 1) % 6;
290  res = ifInsideTriangle(x, C, getBoundaryPoint(C, i, m_R), getBoundaryPoint(C, j, m_R));
291  if (res) break;
292  }
293  return res;
294  }
295 
296  CvPoint2D64f CCell::getBoundaryPoint(CvPoint2D64f C, int i, double R)
297  {
298  double r = 0.5 * sqrt(3.0) * R;
299  switch (i) {
300  case 0: return cvPoint2D64f(C.x, C.y - R);
301  case 1: return cvPoint2D64f(C.x + r, C.y - 0.5*R);
302  case 2: return cvPoint2D64f(C.x + r, C.y + 0.5*R);
303  case 3: return cvPoint2D64f(C.x, C.y + R);
304  case 4: return cvPoint2D64f(C.x - r, C.y + 0.5*R);
305  case 5: return cvPoint2D64f(C.x - r, C.y - 0.5*R);
306  default: return cvPoint2D64f(0, 0);
307  }
308  }
309 
310  Point CCell::idx2h(int idx, double R, CvSize imgSize)
311  {
312  double r = 0.5 * sqrt(3.0) * R;
313  double dx = 2.0 * r;
314  double imgWidth = static_cast<double>(imgSize.width);
315  int width0 = static_cast<int> (0.99 + imgWidth / dx);
316  int width1 = 1 + static_cast<int> (0.99 + (imgWidth - r) / dx);
317  int widthD = width0 + width1;
318 
319  // cell indexes
320  Point res;
321  res.y = idx / widthD;
322  res.x = idx - res.y * widthD;
323  res.y *= 2;
324  if (res.x >= width0) {
325  res.y++;
326  res.x -= width0;
327  }
328  return res;
329  }
330 
331  int CCell::h2idx(Point c) const
332  {
333  double dx = 2.0 * m_r;
334  double imgWidth = static_cast<double>(m_imgSize.width);
335  int width0 = static_cast<int> (0.99 + imgWidth / dx);
336  int width1 = 1 + static_cast<int> (0.99 + (imgWidth - m_r) / dx);
337  int widthD = width0 + width1;
338 
339  // index
340  int res;
341  int a = c.y / 2;
342  int b = c.y - 2 * a;
343  res = a * widthD;
344  if (b == 1) res += width0;
345  res += c.x;
346 
347  return res;
348  }
349 
350  CvPoint2D64f CCell::idx2d(int idx, double R, CvSize imgSize)
351  {
352  double r = 0.5 * sqrt(3.0) * R;
353  double dx = 2.0 * r; // x - distance between cells
354  double dy = 1.5 * R; // y - distance between cells
355 
356  // cell indexes
357  Point C = idx2h(idx, R, imgSize);
358 
359  // cell coordinates in image
360  CvPoint2D64f res;
361  res.y = C.y * dy + 0.5 * R;
362  res.x = C.x * dx + r;
363  if ((C.y % 2) != 0) res.x -= r;
364 
365  return res;
366  }
367 
368  int CCell::d2idx(CvPoint2D64f C) {
369  if (m_LUT.empty()) { if (calculate_LUT() != 0) return -1; }
370  return m_LUT.at<int>(static_cast<int>(C.y), static_cast<int>(C.x));
371  }
372 
373  Point CCell::d2h(CvPoint2D64f C) const
374  {
375  double dx = 2.0 * m_r; // x - distance between cells
376  double dy = 1.5 * m_R; // y - distance between cells
377 
378  Point c;
379  c.y = static_cast<int>((C.y + 0.5 * m_R) / dy);
380  c.x = static_cast<int>(C.x / dx);
381 
382  return c;
383  }
384 
385 }
386 
387 
int N
Number of hexagons in the image.
Definition: Cell.h:16
int getNeighbourIDX(int idx, int i)
Returns the neighbouring cell index.
Definition: Cell.cpp:112
cell_int_app
Cell interpolation approach.
Definition: Cell.h:25
void setRadius(double R)
(Re-) sets the hexagon outer radius
Definition: Cell.cpp:76
CvScalar getVal(int idx)
Returns the color of the specified cell.
Definition: Cell.cpp:153
double r
Hexagon inner radius.
Definition: Cell.h:14
void setInterpolationApproach(cell_int_app cellIntApp)
(Re-) sets the interpolation approach for cell color generation
Definition: Cell.cpp:89
double R
Hexagon outer radius.
Definition: Cell.h:13
bool ifInsideTriangle(CvPoint2D64f x, CvPoint2D64f a, CvPoint2D64f b, CvPoint2D64f c)
Definition: Cell.cpp:166
int * getNeighbourhood(int idx)
Returns all 6 neighbouring cell indexs.
Definition: Cell.cpp:146
int getIDX(int x, int y)
Returns the cell index.
Definition: Cell.cpp:107
cell_params getInfo(void)
Returns the cell parameters.
Definition: Cell.cpp:95
double S
Hexagon area in pixels.
Definition: Cell.h:15
Majority voting approach.
Definition: Cell.h:27
Average value approach.
Definition: Cell.h:26
void setImage(Mat &img)
(Re-) sets the image
Definition: Cell.cpp:60
CCell(void)
Default constuctor.
Definition: Cell.cpp:8
Cell parameters structure.
Definition: Cell.h:12
void clear(void)
Resets the class by releasing memory and setting the class variable by default.
Definition: Cell.cpp:49