QXRD  0.11.16
qxrdroicoordinates.cpp
Go to the documentation of this file.
1 #include "qxrdroicoordinates.h"
2 #include "qxrdexperiment.h"
3 #include <QtMath>
4 #include <QMatrix4x4>
5 
8  int roiType,
9  double left,
10  double top,
11  double right,
12  double bottom)
13  : QcepObject("coords", exp.data()),
14  m_RoiType(saver, this, "roiType", roiType, "ROI Type"),
15  m_RoiTypeName(QcepSettingsSaverWPtr(), this, "roiTypeName", roiTypeName(roiType), "ROI Type Name"),
16  m_Coords(saver, this, "coords", QRectF(left, top, right-left, bottom-top), "ROI Coords"),
17  m_Width2(saver, this, "width2", 0, "Width of inner region"),
18  m_Height2(saver, this, "height2", 0, "Height of inner region"),
19  m_Sum(QcepSettingsSaverWPtr(), this, "sum", 0, "ROI Pixel Sum"),
20  m_Average(QcepSettingsSaverWPtr(), this, "average", 0, "ROI Pixel Average"),
21  m_Minimum(QcepSettingsSaverWPtr(), this, "minimum", 0, "ROI Pixel Minimum"),
22  m_Maximum(QcepSettingsSaverWPtr(), this, "maximum", 0, "ROI Pixel Maximum"),
23  m_NPixels(QcepSettingsSaverWPtr(), this, "nPixels", 0, "ROI N Pixels"),
24  m_Background(QcepSettingsSaverWPtr(), this, "background", 0, "ROI Background"),
25  m_XGradient(QcepSettingsSaverWPtr(), this, "xGradient", 0, "ROI X Gradient"),
26  m_YGradient(QcepSettingsSaverWPtr(), this, "yGradient", 0, "ROI Y Gradient")
27 {
28 }
29 
31 {
32 }
33 
34 QScriptValue QxrdROICoordinates::toScriptValue(QScriptEngine *engine, const QxrdROICoordinatesPtr &coords)
35 {
36  return engine->newQObject(coords.data());
37 }
38 
40 {
41  QObject *qobj = obj.toQObject();
42 
43  if (qobj) {
44  QxrdROICoordinates *qcoords = qobject_cast<QxrdROICoordinates*>(qobj);
45 
46  if (qcoords) {
47  coords = QxrdROICoordinatesPtr(qcoords);
48  }
49  }
50 }
51 
53 {
54  if (roiType == Rectangle) {
55  return "Rectangle";
56  } else if (roiType == Ellipse) {
57  return "Ellipse";
58  } else if (roiType == RectangleInRectangle) {
59  return "Rectangle inside Rectangle";
60  } else if (roiType == EllipseInRectangle) {
61  return "Ellipse inside Rectangle";
62  } else if (roiType == RectangleInEllipse) {
63  return "Rectangle inside Ellipse";
64  } else if (roiType == EllipseInEllipse) {
65  return "Ellipse inside Ellipse";
66  }
67 
68  return "";
69 }
70 
72 {
73  for (int i=0; i<roiTypeCount(); i++) {
74  if (roiTypeName(i) == nm) {
75  set_RoiType(i);
76  set_RoiTypeName(nm);
77  emit roiChanged();
78  return;
79  }
80  }
81 }
82 
84 {
85  return ROITypeCount;
86 }
87 
89 {
90  return get_Coords().left();
91 }
92 
94 {
95  return get_Coords().top();
96 }
97 
99 {
100  return get_Coords().right();
101 }
102 
104 {
105  return get_Coords().bottom();
106 }
107 
109 {
110  return get_Coords().width();
111 }
112 
114 {
115  return get_Coords().height();
116 }
117 
119 {
120  return get_Coords().center();
121 }
122 
124 {
125  return get_Coords().size();
126 }
127 
128 double QxrdROICoordinates::width2() const
129 {
130  return get_Width2();
131 }
132 
133 double QxrdROICoordinates::height2() const
134 {
135  return get_Height2();
136 }
137 
139 {
140  return QSizeF(get_Width2(), get_Height2());
141 }
142 
144 {
145  return center().x() - width2()/2.0;
146 }
147 
149 {
150  return center().x() + width2()/2.0;
151 }
152 
154 {
155  return center().y() - height2()/2.0;
156 }
157 
159 {
160  return center().y() + height2()/2.0;
161 }
162 
164 {
165  QRectF c = get_Coords();
166 
167  c.setLeft(l);
168 
169  set_Coords(c);
170 
171  emit roiChanged();
172 }
173 
175 {
176  QRectF c = get_Coords();
177 
178  c.setTop(t);
179 
180  set_Coords(c);
181 
182  emit roiChanged();
183 }
184 
186 {
187  QRectF c = get_Coords();
188 
189  c.setRight(r);
190 
191  set_Coords(c);
192 
193  emit roiChanged();
194 }
195 
197 {
198  QRectF c = get_Coords();
199 
200  c.setBottom(b);
201 
202  set_Coords(c);
203 
204  emit roiChanged();
205 }
206 
208 {
209  QRectF crd = get_Coords();
210 
211  crd.moveCenter(c);
212 
213  set_Coords(crd);
214 
215  emit roiChanged();
216 }
217 
218 void QxrdROICoordinates::setCenter(double cx, double cy)
219 {
220  setCenter(QPointF(cx, cy));
221 }
222 
224 {
225  QRectF c = get_Coords();
226  QPointF cen = c.center();
227 
228  c.setSize(s);
229  c.moveCenter(cen);
230 
231  set_Coords(c);
232 
233  emit roiChanged();
234 }
235 
236 void QxrdROICoordinates::setSize(double w, double h)
237 {
238  setSize(QSizeF(w,h));
239 }
240 
242 {
243  QRectF c = get_Coords();
244  QPointF cen = c.center();
245 
246  cen.setX(cx);
247  c.moveCenter(cen);
248 
249  set_Coords(c);
250 
251  emit roiChanged();
252 }
253 
255 {
256  QRectF c = get_Coords();
257  QPointF cen = c.center();
258 
259  cen.setY(cy);
260  c.moveCenter(cen);
261 
262  set_Coords(c);
263 
264  emit roiChanged();
265 }
266 
268 {
269  QRectF c = get_Coords();
270  QPointF cen = c.center();
271 
272  c.setWidth(w);
273  c.moveCenter(cen);
274 
275  set_Coords(c);
276 
277  emit roiChanged();
278 }
279 
281 {
282  QRectF c = get_Coords();
283  QPointF cen = c.center();
284 
285  c.setHeight(h);
286  c.moveCenter(cen);
287 
288  set_Coords(c);
289 
290  emit roiChanged();
291 }
292 
294 {
295  set_Width2(s.width());
296  set_Height2(s.height());
297 
298  emit roiChanged();
299 }
300 
301 void QxrdROICoordinates::setSize2(double w, double h)
302 {
303  setSize2(QSizeF(w,h));
304 }
305 
307 {
308  set_Width2(w);
309 
310  emit roiChanged();
311 }
312 
314 {
315  set_Height2(w);
316 
317  emit roiChanged();
318 }
319 
321 {
322  QVector<QPointF> res;
323  QRectF c = get_Coords();
324 
325  switch (get_RoiType()) {
326  case Rectangle:
327  default:
328  {
329  res.append(c.topLeft());
330  res.append(c.bottomLeft());
331  res.append(c.bottomRight());
332  res.append(c.topRight());
333  res.append(c.topLeft());
334  }
335  break;
336 
337  case Ellipse:
338  {
339  double a=c.width()/2.0;
340  double b=c.height()/2.0;
341  QPointF cen = c.center();
342 
343  for (int i=0; i<=16; i++) {
344  double theta = M_PI*i/8.0;
345  double x = cen.x() + a*cos(theta);
346  double y = cen.y() + b*sin(theta);
347 
348  res.append(QPointF(x,y));
349  }
350  }
351  break;
352 
354  {
355  QRectF pkr;
356  pkr.setSize(size2());
357  pkr.moveCenter(c.center());
358 
359  res.append(c.topLeft());
360  res.append(c.bottomLeft());
361  res.append(c.bottomRight());
362  res.append(c.topRight());
363  res.append(c.topLeft());
364 
365  res.append(QPointF(qQNaN(), qQNaN()));
366 
367  res.append(pkr.topLeft());
368  res.append(pkr.bottomLeft());
369  res.append(pkr.bottomRight());
370  res.append(pkr.topRight());
371  res.append(pkr.topLeft());
372  }
373  break;
374 
375  case RectangleInEllipse:
376  {
377  QRectF pkr;
378  pkr.setSize(size2());
379  pkr.moveCenter(c.center());
380 
381  double a=c.width()/2.0;
382  double b=c.height()/2.0;
383  QPointF cen = c.center();
384 
385  for (int i=0; i<=16; i++) {
386  double theta = M_PI*i/8.0;
387  double x = cen.x() + a*cos(theta);
388  double y = cen.y() + b*sin(theta);
389 
390  res.append(QPointF(x,y));
391  }
392 
393  res.append(QPointF(qQNaN(), qQNaN()));
394 
395  res.append(pkr.topLeft());
396  res.append(pkr.bottomLeft());
397  res.append(pkr.bottomRight());
398  res.append(pkr.topRight());
399  res.append(pkr.topLeft());
400  }
401  break;
402 
403  case EllipseInRectangle:
404  {
405  res.append(c.topLeft());
406  res.append(c.bottomLeft());
407  res.append(c.bottomRight());
408  res.append(c.topRight());
409  res.append(c.topLeft());
410 
411  res.append(QPointF(qQNaN(), qQNaN()));
412 
413  double a2=width2()/2.0;
414  double b2=height2()/2.0;
415  QPointF cen = center();
416 
417  for (int i=0; i<=16; i++) {
418  double theta = M_PI*i/8.0;
419  double x = cen.x() + a2*cos(theta);
420  double y = cen.y() + b2*sin(theta);
421 
422  res.append(QPointF(x,y));
423  }
424  }
425  break;
426 
427  case EllipseInEllipse:
428  {
429  double a=c.width()/2.0;
430  double b=c.height()/2.0;
431  QPointF cen = c.center();
432 
433  for (int i=0; i<=16; i++) {
434  double theta = M_PI*i/8.0;
435  double x = cen.x() + a*cos(theta);
436  double y = cen.y() + b*sin(theta);
437 
438  res.append(QPointF(x,y));
439  }
440 
441  res.append(QPointF(qQNaN(), qQNaN()));
442 
443  double a2=width2()/2.0;
444  double b2=height2()/2.0;
445 
446  for (int i=0; i<=16; i++) {
447  double theta = M_PI*i/8.0;
448  double x = cen.x() + a2*cos(theta);
449  double y = cen.y() + b2*sin(theta);
450 
451  res.append(QPointF(x,y));
452  }
453  }
454  break;
455  }
456 
457  return res;
458 }
459 
461 {
462  recalculatePrivate(img, mask, VisualizeNone);
463 }
464 
466 {
468 }
469 
471 {
472  recalculatePrivate(img, mask, VisualizePeak);
473 }
474 
476 {
477  int outerBounds = NoBounds;
478  int innerBounds = NoBounds;
479 
480  switch (get_RoiType()) {
481  case Rectangle:
482  outerBounds = RectangleBounds;
483  break;
484  case Ellipse:
485  outerBounds = EllipseBounds;
486  break;
488  outerBounds = RectangleBounds;
489  innerBounds = RectangleBounds;
490  break;
491  case RectangleInEllipse:
492  outerBounds = EllipseBounds;
493  innerBounds = RectangleBounds;
494  break;
495  case EllipseInRectangle:
496  outerBounds = RectangleBounds;
497  innerBounds = EllipseBounds;
498  break;
499  case EllipseInEllipse:
500  outerBounds = EllipseBounds;
501  innerBounds = EllipseBounds;
502  break;
503  }
504 
505  int first = true;
506  double min = 0;
507  double max = 0;
508  double sum = 0;
509  double npx = 0;
510 
511  double sumvn = 0;
512  double sumvx = 0;
513  double sumvy = 0;
514 
515  double sumct = 0;
516  double sumnn = 0;
517  double sumnx = 0;
518  double sumny = 0;
519  double sumxy = 0;
520  double sumxx = 0;
521  double sumyy = 0;
522 
523  double bkgd = 0;
524  double gradx = 0;
525  double grady = 0;
526 
527  if (img) {
528  int tp = qRound(top());
529  int bt = qRound(bottom());
530  int lf = qRound(left());
531  int rt = qRound(right());
532 
533  int tp2 = qRound(top2());
534  int bt2 = qRound(bottom2());
535  int lf2 = qRound(left2());
536  int rt2 = qRound(right2());
537 
538  double cx = center().x();
539  double cy = center().y();
540  double a = width()/2.0;
541  double b = height()/2.0;
542  double a2 = width2()/2.0;
543  double b2 = height2()/2.0;
544 
545  for (int row=tp; row<=bt; row++) {
546  double dy = row - cy;
547 
548  if (outerBounds == EllipseBounds) {
549  double xx = a*sqrt(1 - pow(dy/b,2));
550  lf = qRound(cx - xx);
551  rt = qRound(cx + xx);
552  }
553 
554  for (int col=lf; col<=rt; col++) {
555  double dx = col - cx;
556 
557  if (innerBounds == EllipseBounds) {
558  double xx2 = a2*sqrt(1 - pow(dy/b2,2));
559  if (xx2==xx2) {
560  lf2 = qRound(cx - xx2);
561  rt2 = qRound(cx + xx2);
562  } else {
563  lf2 = rt;
564  rt2 = rt;
565  }
566  }
567 
568  if (innerBounds == NoBounds
569  || (row <= tp2)
570  || (row >= bt2)
571  || (col <= lf2)
572  || (col >= rt2)) {
573  if (mask == NULL || mask->value(col, row)) {
574  double val = img->getImageData(col, row);
575 
576  if (val == val) {
577  sumct += 1;
578  sumnn += 1;
579  sumnx += dx;
580  sumny += dy;
581  sumxy += dx*dy;
582  sumxx += dx*dx;
583  sumyy += dy*dy;
584 
585  sumvn += val;
586  sumvx += val*dx;
587  sumvy += val*dy;
588 
589  if (innerBounds == NoBounds) {
590  if (first) {
591  min = val;
592  max = val;
593  first = false;
594  } else if (val > max) {
595  max = val;
596  } else if (val < min) {
597  min = val;
598  }
599  }
600 
601  sum += val;
602  npx += 1;
603 
604  if (vis == VisualizeBackground) {
605  img->setImageData(col, row, 1000 - val);
606  }
607  }
608  }
609  }
610  }
611  }
612 
613  if (sumct > 5) {
614  QMatrix4x4 m;
615 
616  m(0,0) = sumnn;
617  m(1,0) = sumnx;
618  m(0,1) = sumnx;
619  m(2,0) = sumny;
620  m(0,2) = sumny;
621  m(1,1) = sumxx;
622  m(2,1) = sumxy;
623  m(1,2) = sumxy;
624  m(2,2) = sumyy;
625 
626  bool invertible;
627 
628  QMatrix4x4 inv = m.inverted(&invertible);
629 
630  if (invertible) {
631  bkgd = inv(0,0)*sumvn + inv(0,1)*sumvx + inv(0,2)*sumvy;
632  gradx = inv(1,0)*sumvn + inv(1,1)*sumvx + inv(1,2)*sumvy;
633  grady = inv(2,0)*sumvn + inv(2,1)*sumvx + inv(2,2)*sumvy;
634  } else {
635  bkgd = sumvn/sumct;
636  }
637  } else if (sumct > 0) {
638  bkgd = sumvn/sumct;
639  }
640  if (innerBounds != NoBounds) {
641  first = true;
642  min = 0;
643  max = 0;
644  sum = 0;
645  npx = 0;
646 
647  for (int row=tp2; row<=bt2; row++) {
648  double dy = row - cy;
649 
650  if (innerBounds == EllipseBounds) {
651  double xx2 = a2*sqrt(1 - pow(dy/b2,2));
652  if (xx2==xx2) {
653  lf2 = qRound(cx - xx2);
654  rt2 = qRound(cx + xx2);
655  } else {
656  lf2 = rt;
657  rt2 = rt-1;
658  }
659  }
660 
661  for (int col=lf2; col<=rt2; col++) {
662  if (mask == NULL || mask->value(col, row)) {
663  double val = img->getImageData(col, row);
664 
665  if (val == val) {
666  double dx = col - cx;
667  double bk = bkgd + dx*gradx + dy*grady;
668  double v = val - bk;
669 
670  if (first) {
671  min = v;
672  max = v;
673  first = false;
674  } else if (v > max) {
675  max = v;
676  } else if (v < min) {
677  min = v;
678  }
679 
680  sum += v;
681  npx += 1;
682 
683  if (vis == VisualizePeak) {
684  img->setImageData(col, row, 1000 - val);
685  }
686  }
687  }
688  }
689  }
690  }
691  }
692 
693  set_Sum(sum);
694 
695  set_NPixels(npx);
696  set_Minimum(min);
697  set_Maximum(max);
698 
699  if (npx > 0) {
700  set_Average(sum/npx);
701  } else {
702  set_Average(0);
703  }
704 
705  set_Background(bkgd);
706  set_XGradient(gradx);
707  set_YGradient(grady);
708 }
709 
710 QVector<double> QxrdROICoordinates::values() const
711 {
712  QVector<double> res;
713 
714  res.append(get_Sum());
715  res.append(get_Average());
716  res.append(get_Minimum());
717  res.append(get_Maximum());
718  res.append(get_NPixels());
719  res.append(get_Background());
720  res.append(get_XGradient());
721  res.append(get_YGradient());
722 
723  return res;
724 }
725 
727 {
728  return OutputCount;
729 }
730 
732 {
733  QString res;
734 
735  switch (opt) {
736  case SumOutput:
737  res = "Sum";
738  break;
739  case AverageOutput:
740  res = "Average";
741  break;
742  case MinimumOutput:
743  res = "Minimum";
744  break;
745  case MaximumOutput:
746  res = "Maximum";
747  break;
748  case NPixelsOutput:
749  res = "# Pixels";
750  break;
751  case BackgroundOutput:
752  res = "Background";
753  break;
754  case XGradientOutput:
755  res = "X Gradient";
756  break;
757  case YGradientOutput:
758  res = "Y Gradient";
759  break;
760  }
761 
762  return res;
763 }
static QString outputName(int opt)
QPointF center() const
QSharedPointer< QxrdROICoordinates > QxrdROICoordinatesPtr
void recalculate(QcepImageDataBasePtr img, QcepMaskDataPtr mask)
double width2() const
QWeakPointer< QxrdExperiment > QxrdExperimentWPtr
void setCenterX(double cx)
void setCenterY(double cy)
void visualizeBackground(QcepImageDataBasePtr img, QcepMaskDataPtr mask)
QVector< QPointF > markerCoords()
void setCenter(QPointF c)
void recalculatePrivate(QcepImageDataBasePtr img, QcepMaskDataPtr mask, int vis)
QVector< double > values() const
void visualizePeak(QcepImageDataBasePtr img, QcepMaskDataPtr mask)
void selectNamedROIType(QString nm)
QxrdROICoordinates(QcepSettingsSaverWPtr saver, QxrdExperimentWPtr exp, int roiType, double left=0, double top=0, double right=0, double bottom=0)
QSharedPointer< QcepImageDataBase > QcepImageDataBasePtr
QSharedPointer< QcepMaskData > QcepMaskDataPtr
double height2() const
static QScriptValue toScriptValue(QScriptEngine *engine, const QxrdROICoordinatesPtr &coords)
QWeakPointer< QcepSettingsSaver > QcepSettingsSaverWPtr
static void fromScriptValue(const QScriptValue &obj, QxrdROICoordinatesPtr &coords)