Direct Graphical Models  v.1.7.0
Marker.cpp
1 #include "Marker.h"
2 #include "ColorSpaces.h"
3 #include "macroses.h"
4 
5 
6 namespace DirectGraphicalModels { namespace vis
7 {
8 // Constants
9 const byte CMarker::bkgIntencity = 222;
10 const byte CMarker::frgIntensity = 255;
11 const int CMarker::ds = 70; // px
12 
13 // Constuctor
15 {
16  switch(palette) {
17  case DEF_PALETTE_3: for (int h = 0; h < 360; h += 120) m_vPalette.push_back(std::make_pair(colorspaces::hsv2rgb(DGM_HSV(h, 255, 255)), "")); break;
18  case DEF_PALETTE_3_INV: for (int h = 0; h < 360; h += 120) m_vPalette.push_back(std::make_pair(colorspaces::hsv2bgr(DGM_HSV(h, 255, 255)), "")); break;
19  case DEF_PALETTE_6: for (int h = 0; h < 360; h += 60) m_vPalette.push_back(std::make_pair(colorspaces::hsv2rgb(DGM_HSV(h, 255, 255)), "")); break;
20  case DEF_PALETTE_6_INV: for (int h = 0; h < 360; h += 60) m_vPalette.push_back(std::make_pair(colorspaces::hsv2bgr(DGM_HSV(h, 255, 255)), "")); break;
21  case DEF_PALETTE_12: for (int h = 0; h < 360; h += 30) m_vPalette.push_back(std::make_pair(colorspaces::hsv2rgb(DGM_HSV(h, 255, 255)), "")); break;
22  case DEF_PALETTE_12_INV: for (int h = 0; h < 360; h += 30) m_vPalette.push_back(std::make_pair(colorspaces::hsv2bgr(DGM_HSV(h, 255, 255)), "")); break;
23  case DEF_PALETTE_24: for (int h = 0; h < 360; h += 15) m_vPalette.push_back(std::make_pair(colorspaces::hsv2rgb(DGM_HSV(h, 255, 255)), "")); break;
24  case DEF_PALETTE_24_INV: for (int h = 0; h < 360; h += 15) m_vPalette.push_back(std::make_pair(colorspaces::hsv2bgr(DGM_HSV(h, 255, 255)), "")); break;
25  case DEF_PALETTE_24_M: for (int i = 0; i < 24; i++) m_vPalette.push_back(std::make_pair(colors24[i], "")); break;
26  case DEF_PALETTE_36: for (int h = 0; h < 360; h += 10) m_vPalette.push_back(std::make_pair(colorspaces::hsv2rgb(DGM_HSV(h, 255, 255)), "")); break;
27  case DEF_PALETTE_36_INV: for (int h = 0; h < 360; h += 10) m_vPalette.push_back(std::make_pair(colorspaces::hsv2bgr(DGM_HSV(h, 255, 255)), "")); break;
28  case DEF_PALETTE_72: for (int h = 0; h < 360; h += 5) m_vPalette.push_back(std::make_pair(colorspaces::hsv2rgb(DGM_HSV(h, 255, 255)), "")); break;
29  case DEF_PALETTE_72_INV: for (int h = 0; h < 360; h += 5) m_vPalette.push_back(std::make_pair(colorspaces::hsv2bgr(DGM_HSV(h, 255, 255)), "")); break;
30  }
31 }
32 
33 // Constuctor
34 CMarker::CMarker(const vec_nColor_t &vPalette) : m_vPalette(vPalette)
35 {}
36 
37 // Destructor:
39 {
40  m_vPalette.clear();
41 }
42 
43 void CMarker::markClasses(Mat &base, const Mat &classes, byte flag) const
44 {
45  size_t n = m_vPalette.size();
46  bool mapping = true;
47  if (base.empty()) {
48  base = Mat(classes.size(), CV_8UC3);
49  base.setTo(0);
50  mapping = false;
51  }
52 
53  // Desaturating
54  if (mapping && !((flag & MARK_OVER) == MARK_OVER)) { // desaturate
55  cvtColor(base, base, cv::ColorConversionCodes::COLOR_BGR2GRAY);
56  cvtColor(base, base, cv::ColorConversionCodes::COLOR_GRAY2RGB);
57  }
58 
59  // Assertions
60  DGM_ASSERT_MSG(base.channels() == 3, "Base image has %d channel(s), but must have 3.", base.channels());
61  DGM_ASSERT_MSG(classes.channels() == 1, "Class Map has %d channel(s), but must have 1.", classes.channels());
62 
63  for (int y = 0; y < base.rows; y++) {
64  byte * pBase = base.ptr<byte>(y);
65  const byte * pClass = classes.ptr<byte>(y);
66  for (int x = 0; x < base.cols; x++) {
67  if (((flag & MARK_NO_ZERO) == MARK_NO_ZERO) && (pClass[x] == 11)) continue;
68  //if (((flag & MARK_GRID) == MARK_GRID) && ((x+y) % 2 == 0)) continue;
69  for (int c = 0; c < 3; c++)
70  if (mapping && !((flag & MARK_OVER) == MARK_OVER)) pBase[3 * x + c] = static_cast<byte>((pBase[3 * x + c] + m_vPalette.at(pClass[x] % n).first.val[c]) / 2);
71  else pBase[3 * x + c] = static_cast<byte>(m_vPalette.at(pClass[x] % n).first.val[c]);
72  } // x
73  } // y
74 }
75 
76 Mat CMarker::drawPotentials(const Mat &potential, byte flag) const
77 {
78  DGM_ASSERT(!potential.empty());
79 
80  if (potential.dims == 2) {
81  if (potential.cols == 1) return drawVector(potential, flag); // Node potential
82  else return drawMatrix(potential, flag); // Edge potential
83  } else return drawVoxel(potential, flag); // Triplet potential
84 }
85 
86 Mat CMarker::drawConfusionMatrix(const Mat &confusionMat, byte flag) const
87 {
88  const byte nStates = confusionMat.rows;
89  const cv::Scalar frgColor = CV_RGB(frgIntensity, frgIntensity, frgIntensity);
90 
91  bool perClass = (flag & MARK_PERCLASS) == MARK_PERCLASS;
92 
93  Mat cMat;
94  if (perClass) {
95  Mat tmp;
96  confusionMat.copyTo(tmp);
97  for (byte y = 0; y < nStates; y++) {
98  float *pTmp = tmp.ptr<float>(y);
99  float sum = 0;
100  for (byte x = 0; x < nStates; x++) sum += pTmp[x];
101  for (byte x = 0; x < nStates; x++) pTmp[x] = (sum > 0.0f) ? 100.0f * pTmp[x] / sum : 0.0f;
102  } // y
103  cMat = drawMatrix(tmp, flag | TP_PERCENT);
104  tmp.release();
105  } else cMat = drawMatrix(confusionMat, flag | TP_PERCENT);
106 
107  cv::Size resSize = cMat.size();
108  if (!perClass) {
109  resSize.width += ds;
110  resSize.height += ds;
111  }
112  Mat tmp(resSize, CV_8UC3); tmp.setTo(bkgIntencity);
113  Rect roi = Rect(Point(0, 0), cMat.size());
114  cMat.copyTo(tmp(roi));
115  cMat.release();
116 
117  if (!perClass) {
118  drawSquare(tmp, nStates + 1, 0, frgColor, "Recall", 0.45, TP_BOTTOM);
119  for (byte y = 0; y < nStates; y++) {
120  const float *pCM = confusionMat.ptr<float>(y);
121  float sum = 0;
122  for (byte x = 0; x < nStates; x++) sum += pCM[x];
123  float val = (sum > 0.0f) ? 100.0f * pCM[y] / sum : 0.0f;
124  drawSquare(tmp, nStates + 1, y + 1, frgColor, val, 0.35, TP_CENTER | TP_PERCENT);
125  } // y
126 
127  drawSquare(tmp, 0, nStates + 1, frgColor, "Precision", 0.45, TP_RIGHT);
128  for (byte x = 0; x < nStates; x++) {
129  float sum = 0;
130  for (byte y = 0; y < nStates; y++) sum += confusionMat.at<float>(y, x);
131  float val = (sum > 0.0f) ? 100.0f * confusionMat.at<float>(x, x) / sum : 0.0f;
132  drawSquare(tmp, x + 1, nStates + 1, frgColor, val, 0.35, TP_CENTER | TP_PERCENT);
133  } // x
134 
135  // Overall Accuracy
136  float sum = 0;
137  for (byte s = 0; s < nStates; s++) sum += confusionMat.at<float>(s, s);
138  drawSquare(tmp, nStates + 1, nStates + 1, frgColor, sum, 0.4, TP_CENTER | TP_PERCENT);
139  }
140 
141  // tmp -> res
142  resSize.width += 25;
143  resSize.height += 25;
144  Mat res(resSize, CV_8UC3); res.setTo(bkgIntencity);
145  //rectangle(res, Point(0, 0), Point(res.cols, res.rows), CV_RGB(255,0,0), -1);
146  roi = Rect(Point(25, 25), tmp.size());
147  tmp.copyTo(res(roi));
148  tmp.release();
149 
150 
151  // Horizontal bar
152  drawRectangle(res, Point(1, 1), Point(25 + ds - 1, 25 - 1), frgColor);
153  drawRectangle(res, Point(25 + 1 + ds, 1), Point(25 + (nStates + 1) * ds - 1, 25 - 1), frgColor, "Predicted state", 0.45, TP_BOTTOM);
154  drawRectangle(res, Point(25 + 1 + (nStates + 1) * ds, 1), Point(25 + (nStates + 2) * ds - 1, 25 - 1), frgColor);
155 
156  // Vertical bar
157  drawRectangle(res, Point(1, 1), Point(25 - 1, 25 + ds - 1), frgColor);
158  tmp = Mat(25 - 1, nStates * ds - 1, CV_8UC3); tmp.setTo(bkgIntencity);
159  drawRectangle(tmp, Point(0, 0), tmp.size(), frgColor, "Actual state", 0.45, TP_BOTTOM);
160  flip(tmp.t(), tmp, 0);
161  roi = Rect(Point(1, 25 + 1 + ds), tmp.size());
162  tmp.copyTo(res(roi));
163  tmp.release();
164  drawRectangle(res, Point(1, 25 + 1 + (nStates + 1) * ds), Point(25 - 1, 25 + (nStates + 2) * ds - 1), frgColor);
165 
166 
167  return res;
168 }
169 
170 // ======================================== Private ========================================
171 
172 Mat CMarker::drawVector(const Mat &potential, byte flag) const
173 {
174  const byte nStates = potential.rows;
175  const size_t n = m_vPalette.size();
176 
177  bool bw = (flag & MARK_BW) == MARK_BW;
178 
179  Size textSize;
180  char str[256];
181  double max;
182  minMaxLoc(potential, NULL, &max);
183 
184  Mat res(ds + 1, ds * nStates + 1, CV_8UC3); res.setTo(bkgIntencity);
185 
186  for (byte s = 0; s < nStates; s++) {
187  float potVal = potential.at<float>(s, 0);
188 
189  double sat = (std::isnan(potVal)) ? 1.0 : potVal / max;
190  Scalar color_Tgt = (std::isnan(potVal) || bw) ? Scalar(0) : m_vPalette.at(s % n).first;
191  Scalar color_Cur;
192  double intensity = 0;
193  for (int i = 0; i < 3; i++) {
194  color_Cur.val[i] = sat * color_Tgt.val[i] + (1.0 - sat) * frgIntensity;
195  intensity += color_Cur.val[i] / 3;
196  }
197  drawSquare(res, s, 0, color_Cur, potVal, 0.35, (flag & TP_PERCENT) | TP_BOTTOM);
198 
199  // Text
200  color_Cur = (intensity < 128) ? CV_RGB(255, 255, 255) : CV_RGB(0, 0, 0);
201 
202  if (m_vPalette.at(s % n).second.empty()) sprintf(str, "c%d", s);
203  else sprintf(str, "%s", m_vPalette.at(s % n).second.c_str());
204  textSize = getTextSize(str, cv::HersheyFonts::FONT_HERSHEY_SIMPLEX, 0.45, 1, NULL);
205  putText(res, str, Point(ds * s + (MAX(ds - textSize.width, 6)) / 2, 15), FONT_HERSHEY_SIMPLEX, 0.45, color_Cur, 1, cv::LineTypes::LINE_AA);
206  } // s
207  return res;
208 }
209 
210 Mat CMarker::drawMatrix(const Mat &potential, byte flag) const
211 {
212  const byte nStates = potential.rows;
213  const size_t n = m_vPalette.size();
214  const cv::Scalar frgColor = CV_RGB(frgIntensity, frgIntensity, frgIntensity);
215 
216  bool bw = (flag & MARK_BW) == MARK_BW;
217 
218  char str[256];
219  double max;
220  minMaxLoc(potential, NULL, &max);
221 
222  Mat res(ds * (nStates + 1) + 1, ds * (nStates + 1) + 1, CV_8UC3); res.setTo(bkgIntencity);
223 
224  drawSquare(res, 0, 0, frgColor, "");
225 
226  for (byte x = 1; x < nStates + 1; x++) {
227  if (m_vPalette.at((x - 1) % n).second.empty()) sprintf(str, "W%d", x - 1);
228  else sprintf(str, "%s",m_vPalette.at((x - 1) % n).second.c_str());
229  if (x == 1) sprintf(str, "Bkgrd.");
230  drawSquare(res, x, 0, frgColor, str, 0.45, TP_BOTTOM);
231  } // x
232 
233  for (byte y = 1; y < nStates + 1; y++) {
234  if (m_vPalette.at((y - 1) % n).second.empty()) sprintf(str, "W%d", y - 1);
235  else sprintf(str, "%s", m_vPalette.at((y - 1) % n).second.c_str());
236  if (y == 1) sprintf(str, "Bkgrd.");
237  drawSquare(res, 0, y, frgColor, str, 0.45, TP_RIGHT);
238 
239  const float *pPot = potential.ptr<float>(y - 1);
240  for (byte x = 1; x < nStates + 1; x++) {
241  float potVal = pPot[x - 1];
242 
243  double sat = (std::isnan(potVal)) ? 1.0 : potVal / max;
244  Scalar color_Tgt = (std::isnan(potVal) || bw) ? Scalar(0) : m_vPalette.at(MAX(0/*x - 1*/, y - 1) % n).first;
245  Scalar color_Cur;
246  double intensity = 0;
247  for (int i = 0; i < 3; i++) {
248  color_Cur.val[i] = sat * color_Tgt.val[i] + (1.0 - sat) * frgIntensity;
249  intensity += color_Cur.val[i] / 3;
250  }
251  drawSquare(res, x, y, color_Cur, potVal, 0.35, (flag & TP_PERCENT) | TP_CENTER);
252  } // x
253  } // y
254  rectangle(res, Point(ds, ds), Point(ds * (nStates + 1), ds * (nStates + 1)), CV_RGB(0, 0, 0));
255 
256  return res;
257 }
258 
259 Mat CMarker::drawVoxel(const Mat &potential, byte flag) const
260 {
261  DGM_WARNING("This function is not implemented yet!");
262  return Mat();
263 }
264 
265 template<typename T>
266 void CMarker::drawSquare(Mat &img, byte x, byte y, const Scalar &color, T val, double fontScale, byte textProp) const
267 {
268  Point pt1(1 + x * ds, 1 + y * ds);
269  Point pt2((x + 1) * ds - 1, (y + 1) * ds - 1);
270  drawRectangle(img, pt1, pt2, color, val, fontScale, textProp);
271 }
272 
273 void CMarker::drawRectangle(Mat &img, Point pt1, Point pt2, const Scalar &color, float val, double fontScale, byte textProp) const
274 {
275  char str[256];
276 
277  bool procent = (textProp & TP_PERCENT) == TP_PERCENT;
278 
279  if (procent) {
280  if (std::isnan(val)) sprintf(str, "N A N");
281  else if (val == 0) sprintf(str, "O");
282  else if (val < 0.01f) sprintf(str, "0.00");
283  else sprintf(str, "%3.2f", val);
284  } else {
285  if (std::isnan(val)) sprintf(str, "N A N");
286  else if (val == 0) sprintf(str, "O");
287  else if ((val < 0.01f) || (val > 9999.99f)) sprintf(str, "%1.1E", val);
288  else sprintf(str, "%4.2f", val);
289  }
290 
291  drawRectangle(img, pt1, pt2, color, str, 0.65, textProp);
292 
293  if (std::isnan(val)) {
294  line(img, pt1, pt2, CV_RGB(127, 127, 127), 1, cv::LineTypes::LINE_AA);
295  line(img, Point(pt2.x, pt1.y), Point(pt1.x, pt2.y), CV_RGB(127, 127, 127), 1, cv::LineTypes::LINE_AA);
296  }
297 }
298 
299 void CMarker::drawRectangle(Mat &img, Point pt1, Point pt2, const Scalar &color, const std::string &str, double fontScale, byte textProp) const
300 {
301  rectangle(img, pt1, pt2, color, -1);
302 
303  if (!str.empty()) {
304  Size textSize = getTextSize(str, cv::HersheyFonts::FONT_HERSHEY_SIMPLEX, fontScale, 1, NULL);
305  Size rectSize = cv::Size(abs(pt2.x - pt1.x), abs(pt2.y - pt1.y));
306 
307  Point org(MAX(rectSize.width- textSize.width, 6) / 2, (rectSize.height + textSize.height) / 2);
308  if (textProp & TP_LEFT) org.x = 3;
309  if (textProp & TP_RIGHT) org.x = MAX(rectSize.width - textSize.width - 3, 3);
310  if (textProp & TP_TOP) org.y = textSize.height + 5;
311  if (textProp & TP_BOTTOM) org.y = rectSize.height - 5;
312  org += Point(MIN(pt1.x, pt2.x), MIN(pt1.y, pt2.y));
313 
314  double intensity = 0;
315  for (int i = 0; i < 3; i++) intensity += color.val[i] / 3;
316  cv::Scalar fontColor = (intensity < 128) ? CV_RGB(255, 255, 255) : CV_RGB(0, 0, 0);
317 
318  putText(img, str, org, FONT_HERSHEY_SIMPLEX, fontScale, fontColor, 1, cv::LineTypes::LINE_AA); // TODO: color
319  }
320 }
321 
322 // ======================================== Non-Member ========================================
323 
324 Mat drawDictionary(const Mat &dictionary, double m)
325 {
326  const int margin = 2;
327  const int nWords = dictionary.rows;
328  const int blockSize = static_cast<int>(sqrt(dictionary.cols));
329 
330  int width = static_cast<int>(sqrt(nWords));
331  int height = nWords / width;
332  if (width * height < nWords) width++;
333 
334  Mat res(height * (blockSize + margin) + margin, width * (blockSize + margin) + margin, CV_8UC1, cv::Scalar(0));
335 
336  for (int w = 0; w < nWords; w++) {
337  Mat word = dictionary.row(w);
338  word = 127.5 + m * 127.5 * word.reshape(0, blockSize);
339 
340  int y = w / width;
341  int x = w % width;
342 
343  int y0 = y * (blockSize + margin) + margin;
344  int x0 = x * (blockSize + margin) + margin;
345 
346  word.convertTo(res(cv::Rect(x0, y0, blockSize, blockSize)), res.type());
347  }
348 
349  return res;
350 }
351 
352 } }
Mat drawVoxel(const Mat &potential, byte flag) const
Definition: Marker.cpp:259
void drawSquare(Mat &img, byte x, byte y, const Scalar &color, T val, double fontScale=1.0, byte textProp=0) const
Definition: Marker.cpp:266
Default Pallete with 3 colors.
Definition: Marker.h:43
Blends the base image.
Definition: Marker.h:63
void drawRectangle(Mat &img, Point pt1, Point pt2, const Scalar &color, float val, double fontScale=1.0, byte textProp=TP_CENTER) const
Definition: Marker.cpp:273
Default Pallete with 12 colors.
Definition: Marker.h:48
Mark per-class accuracies in the confusion matrix.
Definition: Marker.h:66
The class with index 0 will not be visualized.
Definition: Marker.h:64
Default Pallete with 24 colors.
Definition: Marker.h:49
Default Pallete with 72 colors.
Definition: Marker.h:55
static const byte bkgIntencity
Definition: Marker.h:151
std::vector< std::pair< Scalar, std::string > > vec_nColor_t
Definition: types.h:73
Default Pallete with 72 colors.
Definition: Marker.h:54
Mat drawConfusionMatrix(const Mat &confusionMat, byte flag=0) const
Visualizes a confusion matrix.
Definition: Marker.cpp:86
Default Pallete with 36 colors.
Definition: Marker.h:53
Default Pallete with 24 colors.
Definition: Marker.h:50
Default Pallete with 36 colors.
Definition: Marker.h:52
Default Pallete with 12 colors.
Definition: Marker.h:47
CMarker(default_pallete palette=DEF_PALETTE_12)
Constructor with a default palette.
Definition: Marker.cpp:14
Mat drawDictionary(const Mat &dictionary, double m)
Visualizes a sparse coding dictionary.
Definition: Marker.cpp:324
static const byte frgIntensity
Definition: Marker.h:152
Default Pallete with 3 colors.
Definition: Marker.h:44
void markClasses(Mat &base, const Mat &classes, byte flag=0) const
Visualizes the classes.
Definition: Marker.cpp:43
default_pallete
Default palettes.
Definition: Marker.h:42
Mat drawVector(const Mat &potential, byte flag) const
Definition: Marker.cpp:172
cv::Scalar hsv2rgb(cv::Scalar hsv)
Transforms color from HSV to RGB space.
Definition: ColorSpaces.h:107
Default Pallete with 24 colors.
Definition: Marker.h:51
Mark in "black and white" palette.
Definition: Marker.h:65
Mat drawMatrix(const Mat &potential, byte flag) const
Definition: Marker.cpp:210
Default Pallete with 6 colors.
Definition: Marker.h:45
cv::Scalar hsv2bgr(cv::Scalar hsv)
Transforms color from HSV to BGR space.
Definition: ColorSpaces.h:44
Default Pallete with 6 colors.
Definition: Marker.h:46
vec_nColor_t m_vPalette
Pointer to the container with the palette.
Definition: Marker.h:136
Mat drawPotentials(const Mat &potential, byte flag=0) const
Visualizes the potentials.
Definition: Marker.cpp:76