Darwin  1.10(beta)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
drwnPartsModel.h
1 /*****************************************************************************
2 ** DARWIN: A FRAMEWORK FOR MACHINE LEARNING RESEARCH AND DEVELOPMENT
3 ** Distributed under the terms of the BSD license (see the LICENSE file)
4 ** Copyright (c) 2007-2015, Stephen Gould
5 ** All rights reserved.
6 **
7 ******************************************************************************
8 ** FILENAME: drwnPartsModel.h
9 ** AUTHOR(S): Stephen Gould <stephen.gould@anu.edu.au>
10 **
11 *****************************************************************************/
12 
13 #pragma once
14 
15 #include <cstdlib>
16 #include <cassert>
17 #include <vector>
18 
19 #include "cv.h"
20 
21 #include "drwnBase.h"
22 #include "drwnIO.h"
23 #include "drwnML.h"
24 
25 using namespace std;
26 
27 // Forward Declarations -----------------------------------------------------
28 
29 class drwnPartsModel;
30 
31 // drwnPartsAssignment ------------------------------------------------------
33 
35  public:
37  cv::Point centroid;
38  vector<cv::Point> locations;
39  vector<bool> occluded;
40  double score;
41 
42  public:
44  drwnPartsAssignment(unsigned numParts);
45  drwnPartsAssignment(const drwnPartsAssignment& assignment);
47 
48  int numParts() const { return (int)locations.size(); }
49  int numEqual(const drwnPartsAssignment& assignment) const;
50 
51  unsigned size() const { return locations.size() + occluded.size() + 1; }
52  bool empty() const { return locations.empty(); }
53  void clear();
54  void resize(unsigned numParts);
55 
56  void print(std::ostream& os = std::cout) const;
57 
58  drwnPartsAssignment& operator=(const drwnPartsAssignment& assignment);
59  bool operator==(const drwnPartsAssignment& assignment) const;
60  const cv::Point& operator[](unsigned indx) const { return locations[indx]; }
61 };
62 
63 // drwnDeformationCost ------------------------------------------------------
65 
67  public:
68  double dx, dy, dx2, dy2;
69 
70  public:
71  drwnDeformationCost() : dx(1.0), dy(1.0), dx2(0.0), dy2(0.0) { /* do nothing */ }
72  drwnDeformationCost(double a, double b, double c, double d) :
73  dx(a), dy(b), dx2(c), dy2(d) { /* do nothing */ }
75  dx(c.dx), dy(c.dy), dx2(c.dx2), dy2(c.dy2) { /* do nothing */ }
76  ~drwnDeformationCost() { /* do nothing */ }
77 
78  // i/o
79  const char *type() const { return "drwnDeformationCost"; }
80  drwnDeformationCost* clone() const { return new drwnDeformationCost(*this); }
81  bool save(drwnXMLNode& xml) const;
82  bool load(drwnXMLNode& xml);
83 
84  inline double cost(const cv::Point& p, const cv::Point& q) const {
85  const double deltaX = fabs((double)(p.x - q.x));
86  const double deltaY = fabs((double)(p.y - q.y));
87  return ((dx + dx2 * deltaX) * deltaX + (dy + dy2 * deltaY) * deltaY);
88  }
89 };
90 
91 // drwnPartsInference -------------------------------------------------------
101 
103  public:
104  static int MESSAGE_PASSING_SCALE;
105  static double DEFAULT_LAMBDA;
106  static double DEFAULT_OCCLUSION_COST;
107 
108  protected:
109  double _lambda;
110  double _occlusionCost;
111 
112  int _width;
113  int _height;
114  int _nParts;
115 
116  cv::Mat _centroidPrior;
117  vector<pair<cv::Mat, cv::Mat> > _partCosts;
118  vector<cv::Point> _partOffsets;
119  vector<drwnDeformationCost> _pairwiseCosts;
120 
121  public:
122  drwnPartsInference(int numParts, int width, int height);
124 
125  // define problem
126  void setCentroidPrior(const cv::Mat& centroidPrior = cv::Mat());
127  void setPartCosts(int partId, const cv::Mat& matchingCost,
128  const cv::Point& offset, const drwnDeformationCost& pairwiseCost,
129  const cv::Mat& occlusionCost = cv::Mat());
130 
131  // inference
132  drwnPartsAssignment inference() const;
133  drwnPartsAssignment inference(const cv::Point& centroid) const;
134 
135  // negative max marginals (for each centroid location)
136  cv::Mat energyLandscape() const;
137 
138  protected:
139  // inference message passing between location variables
140  cv::Mat computeLocationMessage(const cv::Mat& belief, const drwnDeformationCost& dcost,
141  const cv::Mat& msgIn = cv::Mat()) const;
142 };
143 
144 // drwnPart -----------------------------------------------------------------
151 
152 class drwnPart : public drwnStdObjIface {
153  public:
154  static int MATCH_MODE;
155 
156  protected:
157  cv::Size _extent;
158  vector<cv::Mat> _weights;
159  cv::Point _offset;
161 
162  public:
163  drwnPart();
164  drwnPart(const cv::Size& extent, unsigned channels = 1);
165  drwnPart(const drwnPart& part);
166  virtual ~drwnPart();
167 
168  // parameters
169  int channels() const { return (int)_weights.size(); }
170  int width() const { return _extent.width; }
171  int height() const { return _extent.height; }
172 
173  // i/o
174  const char *type() const { return "drwnPart"; }
175  drwnPart *clone() const { return new drwnPart(*this); }
176  void clear();
177  bool save(drwnXMLNode& xml) const;
178  bool load(drwnXMLNode& xml);
179  void swap(drwnPart& part);
180 
181  // learning (single and multi-channel variants)
182  void setExtent(const cv::Size& extent) { _extent = extent; }
183  void setExtent(int width, int height) { _extent = cv::Size(width, height); }
184  void setWeights(const cv::Mat& weights);
185  void setWeights(const vector<cv::Mat>& weights);
186  void setOffset(const cv::Point& offset) { _offset = offset; }
187  void setDCosts(const drwnDeformationCost& costs) { _dcost = costs; }
188  const vector<cv::Mat>& getWeights() const { return _weights; }
189  const cv::Point& getOffset() const { return _offset; }
190  const drwnDeformationCost& getDCosts() const { return _dcost; }
191 
192  // inference (single and multi-channel variants)
193  cv::Mat unaryCosts(const cv::Mat& features) const;
194  cv::Mat unaryCosts(const vector<cv::Mat>& features) const;
195  double pairwiseCost(const cv::Point& x, const cv::Point& c) const;
196 
197  // operators
198  drwnPart& operator=(const drwnPart& part);
199 
200  // friends (overlap in pixel space)
201  friend double overlap(const drwnPart& partA, const cv::Point& locationA,
202  const drwnPart& partB, const cv::Point& locationB);
203 };
204 
205 // drwnPartsModel -----------------------------------------------------------
214 
216  protected:
217  cv::Size _baseSize;
218  vector<drwnPart *> _parts;
219 
220  public:
221  drwnPartsModel();
222  drwnPartsModel(const drwnPartsModel& model);
223  virtual ~drwnPartsModel();
224 
225  // i/o
226  int numParts() const { return (int)_parts.size(); }
227  const cv::Size& getBaseSize() const { return _baseSize; }
228  void setBaseSize(const cv::Size& baseSize) { _baseSize = baseSize; }
229 
230  virtual void clear();
231  bool save(drwnXMLNode& xml) const;
232  bool load(drwnXMLNode& xml);
233  void swap(drwnPartsModel& model);
234 
235  virtual drwnPartsModel* clone() const = 0;
236 
237  // learning
238  // ?
239 
240  // inference
241  virtual double inference(const cv::Mat& img, drwnPartsAssignment& mapAssignment) const;
242  virtual double inference(const cv::Mat& img, drwnPartsAssignment& mapAssignment,
243  const cv::Point &centroidPrior) const;
244  virtual double inference(const cv::Mat& img, drwnPartsAssignment& mapAssignment,
245  const vector<cv::Mat>& partPriors, const cv::Mat& centroidPrior) const;
246  virtual double inference(const cv::Mat& img, drwnPartsAssignment& mapAssignment,
247  double& bestScale, double startScale, double endScale, int numLevels) const;
248  //virtual double inference(const cv::Mat& img, drwnPartsAssignment& mapAssignment,
249  // const vector<drwnPartsAssignment>& constraints) const;
250 
251  // negative max marginals (for each centroid location)
252  cv::Mat energyLandscape(const cv::Mat& img) const;
253 
254  // populate list of objects
255  void slidingWindowDetections(const cv::Mat& img, drwnObjectList& detections) const;
256  void slidingWindowDetections(const cv::Mat& img, drwnObjectList& detections,
257  int numLevelsPerOctave) const;
258 
259  // visualization
260  cv::Mat showMAPPartLocations(const cv::Mat& img) const;
261  cv::Mat showMAPPartLocations(const cv::Mat& img,
262  const drwnPartsAssignment& assignment,
263  double energy = DRWN_DBL_MAX, double scale = 1.0) const;
264  cv::Mat showPartEnergyLandscape(const cv::Mat& img) const;
265 
266  // operators
267  drwnPartsModel& operator=(const drwnPartsModel& model);
268  drwnPart *operator[](unsigned indx) { return _parts[indx]; }
269  const drwnPart *operator[](unsigned indx) const { return _parts[indx]; }
270 
271  protected:
272  // computation of dense part matching costs
273  virtual vector<cv::Mat> computeMatchingCosts(const cv::Mat& img) const = 0;
274 
275  // initial part locations
276  static vector<pair<cv::Point, cv::Size> > initializePartLocations(int nParts,
277  const cv::Size& imgSize);
278 
279  // colormap for visualization
280  static cv::Scalar partColorMap(int v);
281 };
282 
283 // drwnPartsModelMixture --------------------------------------------------
286 
287 template<typename T>
289  protected:
290  vector<T *> _models;
291 
292  public:
293  drwnPartsModelMixture() { /* do nothing */ }
295  for (unsigned i = 0; i < _models.size(); i++) {
296  delete _models[i];
297  }
298  }
299 
300  // i/o
301  bool empty() const { return _models.empty(); }
302  int size() const { return (int)_models.size(); }
303 
304  void clear() {
305  for (int i = 0; i < (int)_models.size(); i++) {
306  delete _models[i];
307  }
308  _models.clear();
309  }
310 
311  void write(const char *filename) const {
312  DRWN_ASSERT(filename != NULL);
313  drwnXMLDoc xml;
314  drwnXMLNode *node = drwnAddXMLChildNode(xml, "drwnPartsModelMixture");
315  for (unsigned i = 0; i < _models.size(); i++) {
316  drwnXMLNode *child = drwnAddXMLChildNode(*node, "drwnPartsModel");
317  _models[i]->save(*child);
318  }
319  ofstream ofs(filename);
320  ofs << xml << endl;
321  DRWN_ASSERT_MSG(!ofs.fail(), "could not write XML file " << filename);
322  ofs.close();
323  }
324 
325  void read(const char *filename) {
326  DRWN_ASSERT(filename != NULL);
327  clear();
328 
329  drwnXMLDoc xml;
330  drwnParseXMLFile(xml, filename, "drwnPartsModelMixture");
331  DRWN_ASSERT(!drwnIsXMLEmpty(xml));
332 
333  for (drwnXMLNode *node = xml.first_node("drwnPartsModel"); node != NULL;
334  node = node->next_sibling("drwnPartsModel")) {
335  DRWN_ASSERT(!drwnIsXMLEmpty(*node));
336 
337  T *m = new T();
338  m->load(*node);
339  add(m);
340  }
341  }
342 
343  // define models (add takes ownership, copy doesn't)
344  void add(T *model) { _models.push_back(model); }
345  void copy(const T *model) { _models.push_back(model->clone()); }
346 
347  // inference
348  std::pair<int, double> inference(const cv::Mat& img, drwnPartsAssignment& mapAssignment) const {
349  DRWN_FCN_TIC;
350  std::pair<int, double> bestModel(-1, DRWN_DBL_MAX);
351 
352  mapAssignment.clear();
353  for (int i = 0; i < (int)_models.size(); i++) {
354  drwnPartsAssignment assignment;
355  double energy = _models[i]->inference(img, assignment);
356  DRWN_LOG_DEBUG("...component " << i << " has energy " << energy);
357  if (energy < bestModel.second) {
358  bestModel = make_pair(i, energy);
359  mapAssignment = assignment;
360  }
361  }
362 
363  DRWN_ASSERT(_models.empty() || (bestModel.first != -1));
364  DRWN_FCN_TOC;
365  return bestModel;
366  }
367 
368  // inference with priors
369  std::pair<int, double> inference(const cv::Mat& img, drwnPartsAssignment& mapAssignment,
370  const vector<vector<cv::Mat> >& partPriors, const cv::Mat& centroidPrior) const {
371  DRWN_FCN_TIC;
372  std::pair<int, double> bestModel(-1, DRWN_DBL_MAX);
373 
374  mapAssignment.clear();
375  for (int i = 0; i < (int)_models.size(); i++) {
376  drwnPartsAssignment assignment;
377  double energy = _models[i]->inference(img, assignment, partPriors[i], centroidPrior);
378  DRWN_LOG_DEBUG("...component " << i << " has energy " << energy);
379  if (energy < bestModel.second) {
380  bestModel = make_pair(i, energy);
381  mapAssignment = assignment;
382  }
383  }
384 
385  DRWN_ASSERT(_models.empty() || (bestModel.first != -1));
386  DRWN_FCN_TOC;
387  return bestModel;
388  }
389 
390  // inference at different scales
391  std::pair<int, double> inference(const cv::Mat& img, drwnPartsAssignment& mapAssignment,
392  double& bestScale, double startScale, double endScale, int numLevels) const {
393 
394  DRWN_ASSERT((endScale <= startScale) && (numLevels > 0));
395  const double scaleFactor = exp(log(endScale / startScale) / (double)numLevels);
396 
397  bestScale = 0.0;
398  std::pair<int, double> bestModel(-1, DRWN_DBL_MAX);
399  mapAssignment.clear();
400 
401  cv::Mat scaledImage(img.clone());
402  drwnResizeInPlace(scaledImage, startScale * img.rows, startScale * img.cols);
403  for (int i = 0; i < numLevels; i++) {
404  drwnPartsAssignment assignment;
405  std::pair<int, double> result = inference(scaledImage, assignment);
406  if (result.second < bestModel.second) {
407  bestModel = result;
408  bestScale = (double)img.cols / (double)scaledImage.cols;
409  mapAssignment = assignment;
410  }
411 
412  if ((scaleFactor * scaledImage.rows < 1.0) ||
413  (scaleFactor * scaledImage.cols < 1.0)) break;
414 
415  drwnResizeInPlace(scaledImage, scaleFactor * scaledImage.rows,
416  scaleFactor * scaledImage.cols);
417  }
418 
419  return bestModel;
420  }
421 
422  // negative max marginals (for each centroid location)
423  std::pair<cv::Mat, cv::Mat> energyLandscape(const cv::Mat& img) const {
424  std::pair<cv::Mat, cv::Mat> energy;
425  energy.first = cv::Mat(img.rows, img.cols, CV_32FC1, cv::Scalar(DRWN_FLT_MIN));
426  energy.second = cv::Mat(img.rows, img.cols, CV_32SC1, cv::Scalar(-1));
427 
428  cv::Mat mask(img.rows, img.cols, CV_8UC1);
429  for (int i = 0; i < (int)_models.size(); i++) {
430  cv::Mat e = _models->energyLandscape(img);
431  cv::compare(energy.first, e, mask, CV_CMP_GT);
432  energy.first.setTo(e, mask);
433  energy.second.setTo(cv::Scalar(i), mask);
434  }
435 
436  return energy;
437  }
438 
439  // populate list of objects (reference field set to model index)
440  void slidingWindowDetections(const cv::Mat& img, drwnObjectList& detections) const {
441  for (int i = 0; i < (int)_models.size(); i++) {
442  drwnObjectList d;
443  _models[i]->slidingWindowDetections(img, d);
444  for (drwnObjectList::iterator it = d.begin(); it != d.end(); ++it) {
445  it->ref = i;
446  }
447  detections.insert(detections.end(), d.begin(), d.end());
448  }
449  }
450 
451  void slidingWindowDetections(const cv::Mat& img, drwnObjectList& detections,
452  int numLevelsPerOctave) const {
453  for (int i = 0; i < (int)_models.size(); i++) {
454  drwnObjectList d;
455  _models[i]->slidingWindowDetections(img, d, numLevelsPerOctave);
456  for (drwnObjectList::iterator it = d.begin(); it != d.end(); ++it) {
457  it->ref = i;
458  }
459  detections.insert(detections.end(), d.begin(), d.end());
460  }
461  }
462 
463 
464  // operators
465  T* operator[](unsigned indx) { return _models[indx]; }
466  const T* operator[](unsigned indx) const { return _models[indx]; }
467 };
468 
469 
470 // drwnTemplatePartsModel ---------------------------------------------------
471 
473  public:
476  virtual ~drwnTemplatePartsModel();
477 
478  // i/o
479  const char *type() const { return "drwnTemplatePartsModel"; }
480  drwnTemplatePartsModel *clone() const { return new drwnTemplatePartsModel(*this); }
481 
482  // learning
483  void learnModel(int nParts, const vector<cv::Mat>& imgs);
484 
485  protected:
486  // computation of dense part matching costs
487  virtual vector<cv::Mat> computeMatchingCosts(const cv::Mat& img) const;
488 };
489 
490 // drwnHOGPartsModel --------------------------------------------------------
491 
493  public:
494  static int X_STEP_SIZE;
495  static int Y_STEP_SIZE;
496 
497  public:
499  drwnHOGPartsModel(const drwnHOGPartsModel& model);
500  virtual ~drwnHOGPartsModel();
501 
502  // i/o
503  const char *type() const { return "drwnHOGPartsModel"; }
504  drwnHOGPartsModel *clone() const { return new drwnHOGPartsModel(*this); }
505 
506  // learning
507  void learnModel(int nParts, const vector<cv::Mat>& imgs);
508  void learnModel(const vector<cv::Size>& partSizes,
509  const vector<pair<cv::Mat, drwnPartsAssignment> >& imgs);
510 
511  protected:
512  // computation of dense part matching costs
513  virtual vector<cv::Mat> computeMatchingCosts(const cv::Mat& img) const;
514 };
cv::Point _offset
centroid offset (in pixels)
Definition: drwnPartsModel.h:159
Definition: drwnPartsModel.h:472
vector< bool > occluded
only includes parts
Definition: drwnPartsModel.h:39
drwnXMLNode * drwnAddXMLChildNode(drwnXMLNode &parent, const char *name, const char *value=NULL, bool bCopyName=true)
adds a child node for a given parent (set bCopyName to false if it's a static string) and returns a r...
Definition: drwnXMLParser.cpp:102
List of objects for the same image (see drwnObject)
Definition: drwnObject.h:101
void drwnResizeInPlace(cv::Mat &m, const cv::Size &size, int interpolation=CV_INTER_LINEAR)
resize an image in place
Definition: drwnOpenCVUtils.cpp:463
Definition: drwnPartsModel.h:492
double score
score or multiplier (for constraints)
Definition: drwnPartsModel.h:40
vector< cv::Point > locations
parts locations
Definition: drwnPartsModel.h:38
Helper class for running inference in a (constellation) parts-based model. Supports linear and quadra...
Definition: drwnPartsModel.h:102
Structure for holding dx, dy, dx^2 and dy^2 deformation costs.
Definition: drwnPartsModel.h:66
Interface for implementing a part-based constellation model (i.e., pictorial structures model) for ob...
Definition: drwnPartsModel.h:215
const drwnPartsModel * model
model that generated this assignment
Definition: drwnPartsModel.h:36
vector< cv::Mat > _weights
template coefficients (in feature space)
Definition: drwnPartsModel.h:158
const char * type() const
returns object type as a string (e.g., Foo::type() { return "Foo"; })
Definition: drwnPartsModel.h:174
Mixture of parts models (T must have a parts model interface). Inference returns the best scoring mod...
Definition: drwnPartsModel.h:288
bool drwnIsXMLEmpty(drwnXMLNode &xml)
checks whether an xml document is empty
Definition: drwnXMLParser.cpp:55
drwnDeformationCost _dcost
deformation cost (dx, dy, dx^2, dy^2) (in pixels)
Definition: drwnPartsModel.h:160
Class for holding as assignment to part locations and occlusion variables.
Definition: drwnPartsModel.h:34
drwnPart * clone() const
returns a copy of the class usually implemented as virtual Foo* clone() { return new Foo(*this); } ...
Definition: drwnPartsModel.h:175
drwnXMLNode * drwnParseXMLFile(drwnXMLDoc &xml, const char *filename, const char *tag=NULL)
parse an xml file into xml (loads all data into memory) and return a pointer to the first node (with ...
Definition: drwnXMLParser.cpp:22
cv::Point centroid
centroid location
Definition: drwnPartsModel.h:37
A part is defined as a template over a number of channels (possibly one), an offset from the object c...
Definition: drwnPartsModel.h:152
cv::Size _extent
width and height of template (in pixels)
Definition: drwnPartsModel.h:157
drwnHOGPartsModel * clone() const
returns a copy of the class usually implemented as virtual Foo* clone() { return new Foo(*this); } ...
Definition: drwnPartsModel.h:504
drwnDeformationCost * clone() const
returns a copy of the class usually implemented as virtual Foo* clone() { return new Foo(*this); } ...
Definition: drwnPartsModel.h:80
const char * type() const
returns object type as a string (e.g., Foo::type() { return "Foo"; })
Definition: drwnPartsModel.h:79
const char * type() const
returns object type as a string (e.g., Foo::type() { return "Foo"; })
Definition: drwnPartsModel.h:479
standard Darwin object interface (cloneable and writeable)
Definition: drwnInterfaces.h:72
const char * type() const
returns object type as a string (e.g., Foo::type() { return "Foo"; })
Definition: drwnPartsModel.h:503
drwnTemplatePartsModel * clone() const
returns a copy of the class usually implemented as virtual Foo* clone() { return new Foo(*this); } ...
Definition: drwnPartsModel.h:480
bool operator==(const CvRect &r, const CvRect &s)
equality operator for CvRect objects
Definition: drwnOpenCVUtils.cpp:83