ページ 11

画像の前景抽出について

Posted: 2013年2月06日(水) 21:25
by Assert
GraphCutを試してみたいなぁと思って、以下のようなものを見つけました

http://www.wb.commufa.jp/nitmk/GraphCut ... tation.zip


どうやら、Visual Studio用だったので、Linuxで使えるようにしたいので書き直しているのですが・・・
windows.hをインクルードしていたので、その部分を消したり、__int64と書かれたところをuint64_tと書き直したり等したのですが・・・
なにがどう駄目なのか全くわかりません・・・

どうかご助力お願いします!

Re: 画像の前景抽出について

Posted: 2013年2月06日(水) 21:29
by h2so5
フォーラムルールをお読みください。
なにがどう問題なのか全くわかりません。

Re: 画像の前景抽出について

Posted: 2013年2月06日(水) 22:38
by Assert
失礼致しました。

書き直したソースコードとコンパイル時に出たエラーを載せます。

コード:

// block.h
#ifndef __BLOCK_H__
#define __BLOCK_H__

#include <stdlib.h>

template <class Type> class Block
{
 public:
  Block(int size, void (*err_function)(char *) = NULL) {
    first = last = NULL;
    block_size = size;
    error_function = err_function;
  }

  ~Block() {
    while (first) {
      block *next = first -> next;
      delete[] ((char *)first);
      first = next;
    }
  }

  Type *New(int num = 1) {
    Type *t;

    if (!last || last->current + num > last->last) {
      if (last && last->next) {
        last = last->next;
      }
      else {
        block *next = (block *)new char [sizeof(block) + (block_size-1) * sizeof(Type)];

        if (!next) {
          if (error_function) {
            (*error_function)("Not enough memory!");
            exit(1);
          }
        }

        if (last) {
          last->next = next;
        }
        else {
          first = next;
        }

        last = next;
        last->current = & (last->data[0]);
        last->last = last->current + block_size;
        last->next = NULL;
      }
    }

    t = last->current;
    last->current += num;

    return t;
  }

  Type *ScanFirst() {
    for (scan_current_block = first; scan_current_block; scan_current_block = scan_current_block->next) {
      scan_current_data = & (scan_current_block->data[0]);

      if (scan_current_data < scan_current_block->current) {
        return scan_current_data++;
      }
    }

    return NULL;
  }

  Type *ScanNext() {
    while (scan_current_data >= scan_current_block->current) {
      scan_current_block = scan_current_block->next;

      if (!scan_current_block) {
        return NULL;
      }

      scan_current_data = & (scan_current_block->data[0]);
    }

    return scan_current_data++;
  }

  void Reset() {
    block *b;

    if (!first) {
      return;
    }

    for (b = first; ; b = b->next) {
      b->current = & (b->data[0]);

      if (b == last) {
        break;
      }
    }
    last = first;
  }

 private:
  typedef struct block_st {
    Type *current, *last;
    struct block_st *next;
    Type data[1];
  } block;

  int block_size;
  block *first;
  block *last;

  block *scan_current_block;
  Type *scan_current_data;

  void (*error_function)(char *);
};

template <class Type> class DBlock
{
 public:
  DBlock(int size, void (*err_function)(char *) = NULL) {
    first = NULL;
    first_free = NULL;
    block_size = size;
    error_function = err_function;
  }

  ~DBlock() {
    while (first) {
      block *next = first->next;
      delete[] ((char*)first);
      first = next;
    }
  }

  Type *New() {
    block_item *item;

    if (!first_free) {
      block *next = first;
      first = (block *) new char [sizeof(block) + (block_size - 1) * sizeof(block_item)];
      if (!first) {
	if (error_function) {
	  (*error_function)("Not enough memory!");
	  exit(1);
	}
      }

      first_free = &(first->data[0]);
      for (item = first_free; item < first_free + block_size - 1; item++)
	item->next_free = item + 1;
      item->next_free = NULL;
      first->next = next;
    }

    item = first_free;
    first_free = item->next_free;

    return (Type *)item;
  }

  void Delete(Type *t) {
    ((block_item *)t)->next_free = first_free;
    first_free = (block_item *)t;
  }

 private:
  typedef union block_item_st {
    Type t;
    block_item_st *next_free;
  } block_item;

  typedef struct block_st {
    struct block_st *next;
    block_item data[1];
  } block;

  int block_size;
  block *first;
  block_item *first_free;

  void (*error_function)(char *);
};

#endif

コード:

// GCApplication.h
#include <iostream>
#include <fstream>
#include <cmath>
#include "graph.h"
#include "opencv/cv.h"
#include "opencv/highgui.h"
#include "GMM.h"

using namespace cv;
using namespace std;

class GCApplication {
 public:
  enum {
    NOT_SET = 0,
    IN_PROCESS = 1,
    SET = 2,
    LBUTTON = 3,
    RBUTTON = 4,
    BGR = 5,
    HSV = 6
  };

  static const int thickness = -1;
  int radius;

  double lambda;

  void MouseClick(int event, int x, int y, int flags, void *param);

  void SetImageAndWinName(const Mat &_image, const string &_winName);

  void ShowImage() const;

  void Reset();

  void GraphCut();

 private:
  const string *winName;
  const Mat *image;
  Mat mask;

  int width;
  int height;
  double beta;

  double maxCap;

  vector<Point> foregroundPixels, backgroundPixels;

  bool isInitialized;
  bool isCreateGraph;
  uchar labelsState;

  typedef Graph<double, double, double> GraphType;
  GraphType *graph;

  void SetLblsInMask(uchar flag, Point p);

  double CalcBeta(const Mat &img);

  void CreateGraph();

  double CalcNLink(Point p);
  double NeighborWeight(Point x, Point y);

  void SetTLink(GMM fgdGMM, GMM bgdGMM);

  void Init();

  void CreateMask();

  Mat bgdModel, fgdModel;
  void InitGMMs(const Mat &img, const Mat &mask, GMM &bgdGMM, GMM &fgdGMM);
  void AssignGMMsComponents(const Mat &img, const Mat &mask, const GMM &bgdGMM, const GMM &fgdGMM, Mat &compIdxs);
  void LearnGMMs(const Mat &img, const Mat &mask, const Mat &compIdxs, GMM &bgdGMM, GMM &fgdGMM);
};

コード:

// GMM.h
#include <iostream>
#include "graph.h"
#include "opencv/cv.h"
#include "opencv/highgui.h"

using namespace cv;
using namespace std;

class GMM
{
 public:
  static const int componentsCount = 5;

  GMM(Mat &_model);
  float operator()(Vec3f color) const;
  float operator()(int ci, Vec3f color) const;
  int WhichComponent(Vec3f color) const;

  void InitLearning();
  void AddSample(int ci, Vec3f color);
  void EndLearning();

 private:
  void CalcInverseCovAndDeterm(int ci);
  Mat model;
  float *coefs;
  float *mean;
  float *cov;

  float inverseCovs[componentsCount][3][3];
  float covDeterms[componentsCount];

  float sums[componentsCount][3];
  float prods[componentsCount][3][3];
  int sampleCounts[componentsCount];
  int totalSampleCount;
};

コード:

// graph.h
#ifndef __GRAPH_H__
#define __GRAPH_H__

#include <string.h>
#include <assert.h>
#include "block.h"

template <typename captype, typename tcaptype, typename flowtype> class Graph
{
 public:
  typedef enum {
    SOURCE = 0,
    SINK = 1
  } termtype;
  typedef int node_id;

  Graph(int node_num_max, int edge_num_max, void (*err_function)(char *) = NULL);

  ~Graph();

  node_id add_node(int num = 1);

  void add_edge(node_id i, node_id j, captype cap, captype rev_cap);

  void add_tweights(node_id i, tcaptype cap_source, tcaptype cap_sink);

  flowtype maxflow(bool reuse_trees = false, Block<node_id> *changed_list = NULL);

  termtype what_segment(node_id i, termtype default_segm = SOURCE);

 private:
  struct node;
  struct arc;

 public:
  void reset();

  typedef arc *arc_id;
  arc_id get_first_arc();
  arc_id get_next_arc(arc_id a);

  int get_node_num() {
    return node_num;
  }

  int get_arc_num() {
    return (int)(arc_last - arcs);
  }

  void get_arc_ends(arc_id a, node_id &i, node_id &j);

  tcaptype get_trcap(node_id i); 

  captype get_rcap(arc *a);

  void set_trcap(node_id i, tcaptype trcap); 
  void set_rcap(arc *a, captype rcap);

  void mark_node(node_id i);

  void remove_from_changed_list(node_id i) { 
    assert(i >= 0 && i<node_num && nodes[i].is_in_changed_list); 
    nodes[i].is_in_changed_list = 0;
  }
	
 private:
  struct node {
    arc *first;
    arc *parent;
    node *next;
    int TS;
    int DIST;
    int is_sink : 1;
    int is_marked : 1;
    int is_in_changed_list : 1;
    tcaptype tr_cap;
  };

  struct arc {
    node *head;
    arc *next;
    arc *sister;
    captype r_cap;
  };

  struct nodeptr {
    node *ptr;
    nodeptr *next;
  };

  static const int NODEPTR_BLOCK_SIZE = 128;

  node *nodes, *node_last, *node_max;
  arc *arcs, *arc_last, *arc_max;

  int node_num;

  DBlock<nodeptr> *nodeptr_block;

  void (*error_function)(char *);

  flowtype flow;

  int maxflow_iteration;
  Block<node_id> *changed_list;

  node *queue_first[2], *queue_last[2];
  nodeptr *orphan_first, *orphan_last;
  int TIME;

  void reallocate_nodes(int num);
  void reallocate_arcs();

  void set_active(node *i);
  node *next_active();

  void set_orphan_front(node *i);
  void set_orphan_rear(node *i);

  void add_to_changed_list(node *i);

  void maxflow_init();
  void maxflow_reuse_trees_init();
  void augment(arc *middle_arc);
  void process_source_orphan(node *i);
  void process_sink_orphan(node *i);

  void test_consistency(node *current_node = NULL);
};

template <typename captype, typename tcaptype, typename flowtype> inline typename Graph<captype, tcaptype, flowtype>::node_id Graph<captype, tcaptype, flowtype>::add_node(int num)
{
  assert(num > 0);

  if (node_last + num > node_max) {
    reallocate_nodes(num);
  }

  if (num == 1) {
    node_last->first = NULL;
    node_last->tr_cap = 0;
    node_last->is_marked = 0;
    node_last->is_in_changed_list = 0;

    node_last++;

    return node_num++;
  }
  else {
    memset(node_last, 0, num * sizeof(node));

    node_id i = node_num;
    node_num += num;
    node_last += num;

    return i;
  }
}

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::add_tweights(node_id i, tcaptype cap_source, tcaptype cap_sink)
{
  assert(i >= 0 && i < node_num);

  tcaptype delta = nodes[i].tr_cap;

  if (delta > 0) {
    cap_source += delta;
  }
  else {
    cap_sink -= delta;
  }

  flow += (cap_source < cap_sink) ? cap_source : cap_sink;
  nodes[i].tr_cap = cap_source - cap_sink;
}

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::add_edge(node_id _i, node_id _j, captype cap, captype rev_cap)
{
  assert(_i >= 0 && _i < node_num);
  assert(_j >= 0 && _j < node_num);
  assert(_i != _j);
  assert(cap >= 0);
  assert(rev_cap >= 0);

  if (arc_last == arc_max) {
    reallocate_arcs();
  }

  arc *a = arc_last++;
  arc *a_rev = arc_last++;

  node *i = nodes + _i;
  node *j = nodes + _j;

  a->sister = a_rev;
  a_rev->sister = a;
  a->next = i->first;
  i->first = a;
  a_rev->next = j->first;
  j->first = a_rev;
  a->head = j;
  a_rev->head = i;
  a->r_cap = cap;
  a_rev->r_cap = rev_cap;
}

template <typename captype, typename tcaptype, typename flowtype> inline typename Graph<captype, tcaptype, flowtype>::arc *Graph<captype, tcaptype, flowtype>::get_first_arc()
{
  return arcs;
}

template <typename captype, typename tcaptype, typename flowtype> inline typename Graph<captype, tcaptype, flowtype>::arc *Graph<captype, tcaptype, flowtype>::get_next_arc(arc *a) 
{
  return a + 1; 
}

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::get_arc_ends(arc *a, node_id &i, node_id &j)
{
  assert(a >= arcs && a < arc_last);
  i = (node_id) (a->sister->head - nodes);
  j = (node_id) (a->head - nodes);
}

template <typename captype, typename tcaptype, typename flowtype> inline tcaptype Graph<captype, tcaptype, flowtype>::get_trcap(node_id i)
{
  assert(i >= 0 && i < node_num);

  return nodes[i].tr_cap;
}

template <typename captype, typename tcaptype, typename flowtype> inline captype Graph<captype, tcaptype, flowtype>::get_rcap(arc *a)
{
  assert(a >= arcs && a < arc_last);

  return a->r_cap;
}

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::set_trcap(node_id i, tcaptype trcap)
{
  assert(i >= 0 && i < node_num); 
  nodes[i].tr_cap = trcap;
}

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::set_rcap(arc *a, captype rcap)
{
  assert(a >= arcs && a < arc_last);
  a->r_cap = rcap;
}

template <typename captype, typename tcaptype, typename flowtype> inline typename Graph<captype, tcaptype, flowtype>::termtype Graph<captype, tcaptype, flowtype>::what_segment(node_id i, termtype default_segm)
{
  if (nodes[i].parent) {
    return (nodes[i].is_sink) ? SINK : SOURCE;
  }
  else {
    return default_segm;
  }
}

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::mark_node(node_id _i)
{
  node *i = nodes + _i;

  if (!i->next) {
    if (queue_last[1]) {
      queue_last[1]->next = i;
    }
    else {
      queue_first[1] = i;
    }
    queue_last[1] = i;
    i->next = i;
  }
  i->is_marked = 1;
}

#endif

コード:

// Histgram.h
#include <iostream>
#include "graph.h"
#include "opencv/cv.h"
#include "opencv/highgui.h"

using namespace cv;
using namespace std;

class Histgram {
 public:
  Histgram();

  void CreateHistrgram(const Mat img, Mat mask);
  float operator()(Vec3f color) const;

 private:
  MatND histgram;

  int bins;
  float sum;	
};

コード:

// instances.inc
#include "graph.h"

#ifdef _MSC_VER
#pragma warning(disable: 4661)
#endif

template class Graph<int, int, int>;
template class Graph<short, int, int>;
template class Graph<float, float, float>;
template class Graph<double, double, double>;

コード:

// GCApplication.cpp
#include <stdint.h>
#include "GCApplication.h"

const Scalar RED = Scalar(0, 0, 255);
const Scalar PINK = Scalar(230, 130, 255);
const Scalar BLUE = Scalar(255, 0, 0);
const Scalar LIGHTBLUE = Scalar(255, 255, 160);
const Scalar GREEN = Scalar(0, 255, 0);

void getBinMask(const Mat &comMask, Mat &binMask)
{
  if (comMask.empty() || comMask.type() != CV_8UC1) {
    CV_Error(CV_StsBadArg, "comMask is empty or has incorrect type (not CV_8UC1)");
  }

  if (binMask.empty() || binMask.rows != comMask.rows || binMask.cols != comMask.cols) {
    binMask.create(comMask.size(), CV_8UC1);
  }
  binMask = comMask & 1;
}

void GCApplication::MouseClick(int event, int x, int y, int flags, void *param)
{
  vector<Point> *bpxls, *fpxls;
  bpxls = &backgroundPixels;
  fpxls = &foregroundPixels;

  switch (event) {
  case CV_EVENT_LBUTTONDOWN:
    labelsState = LBUTTON;
    break;

  case CV_EVENT_LBUTTONUP:
    if (labelsState == LBUTTON) {
      SetLblsInMask(LBUTTON, Point(x, y));
      ShowImage();
    }
    labelsState = SET;
    break;

  case CV_EVENT_RBUTTONDOWN:
    labelsState = RBUTTON;
    break;

  case CV_EVENT_RBUTTONUP:
    if (labelsState == RBUTTON) {
      SetLblsInMask(RBUTTON, Point(x, y));
      ShowImage();
    }
    labelsState = SET;
    break;

  case CV_EVENT_MOUSEMOVE:
    if (labelsState == LBUTTON) {
      SetLblsInMask(LBUTTON, Point(x, y));
      ShowImage();
    }
    else if(labelsState == RBUTTON) {
      SetLblsInMask(RBUTTON, Point(x, y));
      ShowImage();
    }
    break;
  }
}

void GCApplication::Reset()
{
  if (!mask.empty()) {
    mask.setTo(Scalar::all(GC_PR_BGD));
  }

  foregroundPixels.clear();
  backgroundPixels.clear();

  fgdModel = bgdModel = NULL;

  isInitialized = false;

  delete graph;
  isCreateGraph = false;
  mask.setTo(Scalar(GC_PR_BGD));
  CreateGraph();
}

void GCApplication::Init()
{
  lambda = 2;
  radius = 3;

  width = image->cols;
  height = image->rows;
  mask.create(image->size(), CV_8UC1);
}

void GCApplication::SetImageAndWinName(const Mat &_image, const string &_winName)
{
  if (_image.empty() || _winName.empty()) {
    return;
  }

  image = &_image;
  winName = &_winName;

  Init();
  Reset();
}

void GCApplication::SetLblsInMask(uchar flag, Point p)
{
  if (flag == RBUTTON) {
    backgroundPixels.push_back(p);
    circle(mask, p, radius, GC_BGD, thickness);
  }

  if (flag == LBUTTON) {
    foregroundPixels.push_back(p);
    circle(mask, p, radius, GC_FGD, thickness);
  }
}

void GCApplication::ShowImage() const
{
  if (image->empty() || winName->empty()) {
    return;
  }

  Mat res;
  Mat binMask;

  if (isInitialized == true) {
    getBinMask(mask, binMask);
    image->copyTo(res, binMask);
  }
  else {
    image->copyTo(res);
  }

  vector<Point>::const_iterator iterator;

  for (iterator = foregroundPixels.begin(); iterator != foregroundPixels.end(); iterator++) {
    circle(res, *iterator, radius, RED, thickness);
  }

  for (iterator = backgroundPixels.begin(); iterator != backgroundPixels.end(); iterator++) {
    circle(res, *iterator, radius, BLUE, thickness);
  }

  imshow(*winName, res);
}

void GCApplication::CreateGraph()
{
  if (image->empty()) {
    return ;
  }

  cout << "now create graph";
  maxCap = -1;

  if (isCreateGraph == false) {
    int vertexNum = width * height;
    graph = new GraphType(vertexNum, vertexNum * 4);

    graph->add_node(vertexNum);

    beta = CalcBeta(*image);
    double sumCap;

    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++) {
	sumCap = CalcNLink(Point(j, i));

	if (maxCap < sumCap) {
	  maxCap = sumCap;
	}
      }
    }
    maxCap *= 9.0;
  }
  cout << "...end" << endl;
  isCreateGraph = true;
}

double GCApplication::CalcNLink(Point p)
{
  double cap;
  double sumCap = 0.0;
  int width = image->cols;
  int height = image->rows;

  if (p.x - 1 >= 0) {
    cap = NeighborWeight(p, Point(p.x - 1, p.y));
    sumCap += cap;
    graph->add_edge((p.y * width) + p.x, (p.y * width) + p.x - 1, cap, cap);

    if (p.y - 1 >= 0) {
      cap = NeighborWeight(p, Point(p.x - 1, p.y - 1 )) * 0.707106781;
      sumCap += cap;
      graph->add_edge((p.y * width) + p.x, ((p.y -1) * width) + p.x - 1, cap, cap);
    }
  }

  if (p.x + 1 < width) {
    if (p.y - 1 >= 0) {
      cap = NeighborWeight(p, Point(p.x + 1, p.y - 1)) * 0.707106781;
      sumCap += cap;
      graph->add_edge((p.y * width) + p.x, ((p.y - 1) * width) + p.x + 1, cap, cap);
    }
  }

  if (p.y - 1 >= 0) {
    cap = NeighborWeight(p, Point(p.x, p.y - 1));
    sumCap += cap;
    graph->add_edge((p.y * width) + p.x, ((p.y - 1 ) * width) + p.x, cap, 0);
  }

  return sumCap * 2;
}

double GCApplication::NeighborWeight(Point x, Point y)
{
  Vec3f x_BGR = image->at<Vec3b>(x);
  Vec3f y_BGR = image->at<Vec3b>(y);

  Vec3f diff = x_BGR - y_BGR;
  double distance = diff.dot(diff);

  return (500.0 * exp(-distance * beta));
}

double GCApplication::CalcBeta(const Mat &img)
{
  double beta = 0;

  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      Vec3f color = img.at<Vec3b>(y, x);

      if (x > 0) {
	Vec3f diff = color - (Vec3f)img.at<Vec3b>(y, x - 1);
	beta += diff.dot(diff);
      }

      if (y > 0 && x > 0) {
	Vec3f diff = color - (Vec3f)img.at<Vec3b>(y - 1, x - 1);
	beta += diff.dot(diff);
      }

      if (y > 0) {
	Vec3f diff = color - (Vec3f)img.at<Vec3b>(y - 1, x);
	beta += diff.dot(diff);
      }

      if (y > 0 && x < img.cols - 1) {
	Vec3f diff = color - (Vec3f)img.at<Vec3b>(y - 1, x + 1);
	beta += diff.dot(diff);
      }
    }
  }
  beta = 1.f / (2 * beta / (4 * img.cols * img.rows - 3 * img.cols - 3 * img.rows + 2));

  return beta;
}

void GCApplication::SetTLink(GMM fgdGMM, GMM bgdGMM)
{
  double fromSource;
  double toSink;
  Vec3f color;
  Point p;

  for (p.y = 0; p.y < height; ++p.y) {
    for (p.x = 0; p.x < width; ++p.x) {
      int node_id = p.y * width + p.x;

      if (mask.at<uchar>(p) == GC_BGD) {
	fromSource = 0.0;
	toSink = maxCap;
      }
      else if (mask.at<uchar>(p) == GC_FGD) {
	fromSource = maxCap;
	toSink = 0.0;
      }
      else {
	color = (Vec3f)image->at<Vec3b>(p);

	fromSource = -log(bgdGMM(color));
	toSink = -log(fgdGMM(color));

	fromSource *= lambda;
	toSink *= lambda;
      }

      graph->add_tweights(node_id, fromSource, toSink);
    }
  }
}

void GCApplication::CreateMask()
{
  Point p;

  for (p.y = 0; p.y < height; ++p.y) {
    const uchar *t = mask.ptr(p.y);

    for (p.x = 0; p.x < width; ++p.x) {
      uchar flag = t[p.x];

      if (flag == GC_PR_FGD || flag == GC_PR_BGD) {
	if (graph->what_segment(p.y * width+p.x) == GraphType::SOURCE) {
	  mask.at<uchar>(p) = GC_PR_FGD;
	}
	else if (graph->what_segment(p.y * width + p.x) == GraphType::SINK) {
	  mask.at<uchar>(p) = GC_PR_BGD;
	}
      }
    }
  }
}

void GCApplication::GraphCut()
{
  if (!isInitialized && (foregroundPixels.empty() || backgroundPixels.empty() )) {
    cout << "seedを指定していください" << endl;
    return;
  }

  uint64_t appStart = getTickCount();

  GMM bgdGMM(bgdModel);
  GMM fgdGMM(fgdModel);

  if (lambda != 0) {
    cout << "now Calc GMM";
    Mat compIdxs(image->size(), CV_32SC1);
    cout << ".";
    InitGMMs(*image, mask, bgdGMM, fgdGMM);
    cout << ".";
    AssignGMMsComponents(*image, mask, bgdGMM, fgdGMM, compIdxs);
    cout << ".";
    LearnGMMs(*image, mask, compIdxs, bgdGMM, fgdGMM);
    cout << ".GMM終わり" << endl;
  }

  cout << "--- now start GraphCut ---" << endl;

  SetTLink(fgdGMM, bgdGMM);

  uint64_t start = getTickCount();
  double maxflowValue = graph->maxflow();

  CreateMask();

  backgroundPixels.clear();
  foregroundPixels.clear();
  isInitialized = true;

  ShowImage();
}

void GCApplication::InitGMMs(const cv::Mat &img, const cv::Mat &mask, GMM &bgdGMM, GMM &fgdGMM)
{
  const int kMeansItCount = 10;
  const int kMeansType = KMEANS_PP_CENTERS;

  Mat bgdLabels;
  Mat fgdLabels;

  vector<Vec3f> bgdSamples, fgdSamples;
  Point p;

  for (p.y = 0; p.y < height; p.y++) {
    for (p.x = 0; p.x < width; p.x++) {
      if (mask.at<uchar>(p) == GC_BGD || mask.at<uchar>(p) == GC_PR_BGD) {
	bgdSamples.push_back((Vec3f)img.at<Vec3b>(p));
      }
      else {
	fgdSamples.push_back((Vec3f)img.at<Vec3b>(p));
      }
    }
  }

  CV_Assert(!bgdSamples.empty() && !fgdSamples.empty());
  Mat _bgdSamples((int)bgdSamples.size(), 3, CV_32FC1, &bgdSamples[0][0]);
  kmeans(_bgdSamples, GMM::componentsCount, bgdLabels, TermCriteria(CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType, 0);

  Mat _fgdSamples((int)fgdSamples.size(), 3, CV_32FC1, &fgdSamples[0][0]);
  kmeans(_fgdSamples, GMM::componentsCount, fgdLabels, TermCriteria(CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType, 0);

  bgdGMM.InitLearning();

  for (int i = 0; i < (int)bgdSamples.size(); i++) {
    bgdGMM.AddSample(bgdLabels.at<int>(i, 0), bgdSamples[i]);
  }
  bgdGMM.EndLearning();
  fgdGMM.InitLearning();

  for (int i = 0; i < (int)fgdSamples.size(); i++) {
    fgdGMM.AddSample(fgdLabels.at<int>(i, 0), fgdSamples[i]);
  }
  fgdGMM.EndLearning();
}

void GCApplication::AssignGMMsComponents(const Mat &img, const Mat &mask, const GMM &bgdGMM, const GMM &fgdGMM, Mat &compIdxs)
{
  Point p;

  for (p.y = 0; p.y < height; p.y++) {
    for (p.x = 0; p.x < width; p.x++) {
      Vec3f color = img.at<Vec3b>(p);
      compIdxs.at<int>(p) = mask.at<uchar>(p) == GC_BGD || mask.at<uchar>(p) == GC_PR_BGD ? bgdGMM.WhichComponent(color) : fgdGMM.WhichComponent(color);
    }
  }
}

void GCApplication::LearnGMMs(const Mat &img, const Mat &mask, const Mat &compIdxs, GMM &bgdGMM, GMM &fgdGMM)
{
  bgdGMM.InitLearning();
  fgdGMM.InitLearning();

  Point p;

  for (int ci = 0; ci < GMM::componentsCount; ci++) {
    for (p.y = 0; p.y < height; p.y++) {
      for (p.x = 0; p.x < width; p.x++) {
	if (compIdxs.at<int>(p) == ci) {
	  if (mask.at<uchar>(p) == GC_BGD || mask.at<uchar>(p) == GC_PR_BGD) {
	    bgdGMM.AddSample(ci, img.at<Vec3b>(p));
	  }
	  else {
	    fgdGMM.AddSample(ci, img.at<Vec3b>(p));
	  }
	}
      }
    }
  }
  bgdGMM.EndLearning();
  fgdGMM.EndLearning();
}

コード:

// GMM.cpp
#include <limits>
#include "GMM.h"

using namespace cv;

GMM::GMM(Mat &_model)
{
  const int modelSize = 3 + 9 + 1;

  if (_model.empty()) {
    _model.create(1, modelSize*componentsCount, CV_32FC1);
    _model.setTo(Scalar(0));
  }
  else if((_model.type() != CV_32FC1) || (_model.rows != 1) || (_model.cols != modelSize * componentsCount)) {
    std::cout << "test" << std::endl;
    CV_Error(CV_StsBadArg, "_model must have CV_32FC1 type, rows == 1 and cols == 13 * componentsCount");
  }

  model = _model;

  coefs = model.ptr<float>(0);
  mean = coefs + componentsCount;
  cov = mean + 3 * componentsCount;

  for (int ci = 0; ci < componentsCount; ci++) {
    if (coefs[ci] > 0) {
      CalcInverseCovAndDeterm(ci);
    }
  }
}

float GMM::operator ()(Vec3f color) const
{
  float res = 0;

  for (int ci = 0; ci < componentsCount; ci++) {
    res += coefs[ci] * (*this)(ci, color);
  }

  return res;
}

float GMM::operator ()(int ci, Vec3f color) const
{
  float res = 0;

  if (coefs[ci] > 0) {
    if (covDeterms[ci] > std::numeric_limits<float>::epsilon()) {
      Vec3f diff = color;
      float *m = mean + 3 * ci;

      diff[0] -= m[0];
      diff[1] -= m[1];
      diff[2] -= m[2];

      float mult = diff[0] * (diff[0] * inverseCovs[ci][0][0] + diff[1] * inverseCovs[ci][1][0] + diff[2] * inverseCovs[ci][2][0]) + diff[1] * (diff[0] * inverseCovs[ci][0][1] + diff[1] * inverseCovs[ci][1][1] + diff[2] * inverseCovs[ci][2][1]) + diff[2] * (diff[0] * inverseCovs[ci][0][2] + diff[1] * inverseCovs[ci][1][2] + diff[2] * inverseCovs[ci][2][2]);
      res = 1.0f / sqrt(covDeterms[ci]) * exp(-0.5f * mult);
    }
  }

  return res;
}

int GMM::WhichComponent(Vec3f color) const
{
  int k = 0;
  float max = 0;

  for (int ci = 0; ci < componentsCount; ci++) {
    float p = (*this)(ci, color);

    if (p > max) {
      k = ci;
      max = p;
    }
  }

  return k;
}

void GMM::InitLearning()
{
  for (int ci = 0; ci < componentsCount; ci++) {
    sums[ci][0] = sums[ci][1] = sums[ci][2] = 0;
    prods[ci][0][0] = prods[ci][0][1] = prods[ci][0][2] = 0;
    prods[ci][1][0] = prods[ci][1][1] = prods[ci][1][2] = 0;
    prods[ci][2][0] = prods[ci][2][1] = prods[ci][2][2] = 0;
    sampleCounts[ci] = 0;
  }
  totalSampleCount = 0;
}

void GMM::AddSample(int ci, cv::Vec3f color)
{
  sums[ci][0] += color[0];
  sums[ci][1] += color[1];
  sums[ci][2] += color[2];

  prods[ci][0][0] += color[0] * color[0];
  prods[ci][0][1] += color[0] * color[1];
  prods[ci][0][2] += color[0] * color[2];
  prods[ci][1][0] += color[1] * color[0];
  prods[ci][1][1] += color[1] * color[1];
  prods[ci][1][2] += color[1] * color[2];
  prods[ci][2][0] += color[2] * color[0];
  prods[ci][2][1] += color[2] * color[1];
  prods[ci][2][2] += color[2] * color[2];

  sampleCounts[ci]++;
  totalSampleCount++;
}

void GMM::EndLearning()
{
  for (int ci = 0; ci < componentsCount; ci++) {
    int n = sampleCounts[ci];

    if (n == 0) {
      coefs[ci] = 0;
    }
    else {
      coefs[ci] = (float)n / totalSampleCount;

      float *m = mean + 3 * ci;

      m[0] = sums[ci][0] / n;
      m[1] = sums[ci][1] / n;
      m[2] = sums[ci][2] / n;

      float *c = cov + 9 * ci;

      c[0] = prods[ci][0][0] / n - m[0] * m[0];
      c[1] = prods[ci][0][1] / n - m[0] * m[1];
      c[2] = prods[ci][0][2] / n - m[0] * m[2];
      c[3] = prods[ci][1][0] / n - m[1] * m[0];
      c[4] = prods[ci][1][1] / n - m[1] * m[1];
      c[5] = prods[ci][1][2] / n - m[1] * m[2];
      c[6] = prods[ci][2][0] / n - m[2] * m[0];
      c[7] = prods[ci][2][1] / n - m[2] * m[1];
      c[8] = prods[ci][2][2] / n - m[2] * m[2];

      CalcInverseCovAndDeterm(ci);
    }
  }
}

void GMM::CalcInverseCovAndDeterm(int ci)
{
  if (coefs[ci] > 0) {
    float *c = cov + 9 * ci;
    float dtrm = covDeterms[ci] = c[0] * (c[4] * c[8] - c[5] * c[7]) - c[1] * (c[3] * c[8] - c[5] * c[6]) + c[2] * (c[3] * c[7] - c[4] * c[6]);

    if (dtrm > std::numeric_limits<float>::epsilon()) {
      inverseCovs[ci][0][0] = (c[4] * c[8] - c[5] * c[7]) / dtrm;
      inverseCovs[ci][1][0] = -(c[3] * c[8] - c[5] * c[6]) / dtrm;
      inverseCovs[ci][2][0] = (c[3] * c[7] - c[4] * c[6]) / dtrm;
      inverseCovs[ci][0][1] = -(c[1] * c[8] - c[2] * c[7]) / dtrm;
      inverseCovs[ci][1][1] = (c[0] * c[8] - c[2] * c[6]) / dtrm;
      inverseCovs[ci][2][1] = -(c[0] * c[7] - c[1] * c[6]) / dtrm;
      inverseCovs[ci][0][2] = (c[1] * c[5] - c[2] * c[4]) / dtrm;
      inverseCovs[ci][1][2] = -(c[0] * c[5] - c[2] * c[3]) / dtrm;
      inverseCovs[ci][2][2] = (c[0] * c[4] - c[1] * c[3]) / dtrm;
    }
  }
}

コード:

// graph.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "graph.h"
#include "instances.inc"

using namespace std;

template <typename captype, typename tcaptype, typename flowtype> Graph<captype, tcaptype, flowtype>::Graph(int node_num_max, int edge_num_max, void (*err_function)(char *)) : node_num(0), nodeptr_block(NULL), error_function(err_function)
{
  if (node_num_max < 16) {
    node_num_max = 16;
  }

  if (edge_num_max < 16) {
    edge_num_max = 16;
  }

#if DEBUG
  cout << "size of node : " << sizeof(node) << endl;
  cout << "size of edge : " << sizeof(arc) << endl;
  cout << "size of nodes : " << node_num_max * sizeof(node) / 1000000 << endl;
  cout << "size of edges : " << 2 * edge_num_max * sizeof(arc) / 1000000 << endl;
#endif
  nodes = (node *)malloc(node_num_max * sizeof(node));
  arcs = (arc *)malloc(2 * edge_num_max * sizeof(arc));

  if (!nodes || !arcs) {
    if (error_function) {
      (*error_function)("Not enough memory!");

      exit(1);
    }
  }

  node_last = nodes;
  node_max = nodes + node_num_max;
  arc_last = arcs;
  arc_max = arcs + 2 * edge_num_max;

  maxflow_iteration = 0;
  flow = 0;
}

template <typename captype, typename tcaptype, typename flowtype> Graph<captype, tcaptype, flowtype>::~Graph()
{
  if (nodeptr_block) { 
    delete nodeptr_block; 
    nodeptr_block = NULL; 
  }

  free(nodes);
  free(arcs);
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype,tcaptype,flowtype>::reset()
{
  node_last = nodes;
  arc_last = arcs;
  node_num = 0;

  if (nodeptr_block) { 
    delete nodeptr_block; 
    nodeptr_block = NULL; 
  }

  maxflow_iteration = 0;
  flow = 0;
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype,tcaptype,flowtype>::reallocate_nodes(int num)
{
  int node_num_max = (int)(node_max - nodes);
  node *nodes_old = nodes;

  node_num_max += node_num_max / 2;

  if (node_num_max < node_num + num) {
    node_num_max = node_num + num;
  }

  nodes = (node *)realloc(nodes_old, node_num_max * sizeof(node));

  if (!nodes) {
    if (error_function) {
      (*error_function)("Not enough memory!");

      exit(1);
    }
  }

  node_last = nodes + node_num;
  node_max = nodes + node_num_max;

  if (nodes != nodes_old) {
    arc *a;

    for (a = arcs; a < arc_last; a++) {
      a->head = (node *)((char *)a->head + (((char *)nodes) - ((char *)nodes_old)));
    }
  }
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype, tcaptype, flowtype>::reallocate_arcs()
{
  int arc_num_max = (int)(arc_max - arcs);
  int arc_num = (int)(arc_last - arcs);
  arc *arcs_old = arcs;

  arc_num_max += arc_num_max / 2;

  if (arc_num_max & 1) {
    arc_num_max ++;
  }

  arcs = (arc *)realloc(arcs_old, arc_num_max * sizeof(arc));

  if (!arcs) {
    if (error_function) {
      (*error_function)("Not enough memory!");
      exit(1);
    }
  }

  arc_last = arcs + arc_num;
  arc_max = arcs + arc_num_max;

  if (arcs != arcs_old) {
    node *i;
    arc *a;

    for (i = nodes; i < node_last; i++) {
      if (i->first) i->first = (arc *)((char *)i->first + (((char *) arcs) - ((char *) arcs_old)));
    }

    for (a = arcs; a < arc_last; a++) {
      if (a->next) a->next = (arc *)((char *)a->next + (((char *)arcs) - ((char *)arcs_old)));
      a->sister = (arc *)((char *)a->sister + (((char *)arcs) - ((char *)arcs_old)));
    }
  }
}

コード:

// Histgram.cpp
#include "Histgram.h"

using namespace cv;

Histgram::Histgram()
{
  bins = 4;
}

float Histgram::operator()(Vec3f color) const
{
  int num = 256 / bins;

  return (histgram.at<float>((int)color[0] / num, (int)color[1] / num, (int)color[2] / num)) / sum;
}

void Histgram::CreateHistrgram(const Mat img, Mat mask)
{
  float RGBranges[] = {0,
		       256};
  int histSize[] = {bins,
		    bins,
		    bins};
  const float *ranges[] = {RGBranges,
			   RGBranges,
			   RGBranges};
  int channels[] = {0,
		    1,
		    2};

  calcHist(&img, 1, channels, mask, histgram, 3, histSize, ranges, true, false);

  sum = 0.0;
  float binVal;

  for (int b = 0; b < bins; b++) {
    for (int g = 0; g < bins; g++) {
      for (int r = 0; r < bins; r++) {
	binVal = histgram.at<float>(b, g, r);
	sum += binVal;
      }
    }
  }
}

コード:

// maxflow.cpp
#include <stdio.h>
#include <iostream>
#include "graph.h"
#include "instances.inc"

using namespace std;

#define TERMINAL ((arc *) 1)
#define ORPHAN ((arc *) 2)
#define INFINITE_D ((int)(((unsigned)-1) / 2))

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::set_active(node *i)
{
  if (!i->next) {
    if (queue_last[1]) {
      queue_last[1]->next = i;
    }
    else {
      queue_first[1] = i;
    }
    queue_last[1] = i;
    i->next = i;
  }
}

template <typename captype, typename tcaptype, typename flowtype> inline typename Graph<captype, tcaptype, flowtype>::node *Graph<captype, tcaptype, flowtype>::next_active()
{
  node *i;

  while (1) {
    if (!(i = queue_first[0])) {
      queue_first[0] = i = queue_first[1];
      queue_last[0] = queue_last[1];
      queue_first[1] = NULL;
      queue_last[1] = NULL;
      if (!i) {
	return NULL;
      }
    }

    if (i->next == i) {
      queue_first[0] = queue_last[0] = NULL;
    }
    else {
      queue_first[0] = i->next;
    }

    i->next = NULL;

    if (i->parent) {
      return i;
    }
  }
}
template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::set_orphan_front(node *i)
{
  nodeptr *np;
  i->parent = ORPHAN;
  np = nodeptr_block->New();
  np->ptr = i;
  np->next = orphan_first;
  orphan_first = np;
}

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::set_orphan_rear(node *i)
{
  nodeptr *np;
  i->parent = ORPHAN;
  np = nodeptr_block->New();
  np->ptr = i;

  if (orphan_last) {
    orphan_last->next = np;
  }
  else {
    orphan_first = np;
  }
  orphan_last = np;
  np->next = NULL;
}

template <typename captype, typename tcaptype, typename flowtype> inline void Graph<captype, tcaptype, flowtype>::add_to_changed_list(node *i)
{
  if (changed_list && !i->is_in_changed_list) {
    node_id *ptr = changed_list->New();
    *ptr = (node_id)(i - nodes);
    i->is_in_changed_list = true;
  }
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype, tcaptype, flowtype>::maxflow_init()
{
  node *i;

  queue_first[0] = queue_last[0] = NULL;
  queue_first[1] = queue_last[1] = NULL;
  orphan_first = NULL;

  TIME = 0;

  for (i = nodes; i<node_last; i++) {
    i->next = NULL;
    i->is_marked = 0;
    i->is_in_changed_list = 0;
    i->TS = TIME;

    if (i->tr_cap > 0) {
      i->is_sink = 0;
      i->parent = TERMINAL;
      set_active(i);
      i->DIST = 1;
    }
    else if (i->tr_cap < 0) {
      i->is_sink = 1;
      i->parent = TERMINAL;
      set_active(i);
      i->DIST = 1;
    }
    else {
      i->parent = NULL;
    }
  }
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype, tcaptype, flowtype>::maxflow_reuse_trees_init()
{
  node *i;
  node *j;
  node *queue = queue_first[1];
  arc *a;
  nodeptr *np;

  queue_first[0] = queue_last[0] = NULL;
  queue_first[1] = queue_last[1] = NULL;
  orphan_first = orphan_last = NULL;

  TIME++;

  while ((i = queue)) {
    queue = i->next;

    if (queue == i) {
      queue = NULL;
    }

    i->next = NULL;
    i->is_marked = 0;
    set_active(i);

    if (i->tr_cap == 0) {
      if (i->parent) set_orphan_rear(i);
      continue;
    }

    if (i->tr_cap > 0) {
      if (!i->parent || i->is_sink) {
	i->is_sink = 0;

	for (a = i->first; a; a = a->next) {
	  j = a->head;

	  if (!j->is_marked) {
	    if (j->parent == a->sister) set_orphan_rear(j);
	    if (j->parent && j->is_sink && a->r_cap > 0) set_active(j);
	  }
	}
	add_to_changed_list(i);
      }
    }
    else {
      if (!i->parent || !i->is_sink) {
	i->is_sink = 1;

	for (a = i->first; a; a = a->next) {
	  j = a->head;
	  if (!j->is_marked) {
	    if (j->parent == a->sister) {
	      set_orphan_rear(j);
	    }

	    if (j->parent && !j->is_sink && a->sister->r_cap > 0) {
	      set_active(j);
	    }
	  }
	}
	add_to_changed_list(i);
      }
    }
    i->parent = TERMINAL;
    i->TS = TIME;
    i->DIST = 1;
  }

  while ((np = orphan_first)) {
    orphan_first = np->next;
    i = np->ptr;
    nodeptr_block->Delete(np);

    if (!orphan_first) {
      orphan_last = NULL;
    }

    if (i->is_sink) {
      process_sink_orphan(i);
    }
    else {
      process_source_orphan(i);
    }
  }
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype, tcaptype, flowtype>::augment(arc *middle_arc)
{
  node *i;
  arc *a;
  tcaptype bottleneck;

  bottleneck = middle_arc->r_cap;

  for (i = middle_arc->sister->head; ; i = a->head) {
    a = i->parent;

    if (a == TERMINAL) {
      break;
    }

    if (bottleneck > a->sister->r_cap) {
      bottleneck = a->sister->r_cap;
    }
  }

  if (bottleneck > i->tr_cap) {
    bottleneck = i->tr_cap;
  }

  for (i = middle_arc->head; ; i = a->head) {
    a = i->parent;

    if (a == TERMINAL) {
      break;
    }

    if (bottleneck > a->r_cap) {
      bottleneck = a->r_cap;
    }
  }

  if (bottleneck > - i->tr_cap) {
    bottleneck = - i->tr_cap;
  }

  middle_arc->sister->r_cap += bottleneck;
  middle_arc->r_cap -= bottleneck;

  for (i = middle_arc->sister->head; ; i = a->head) {
    a = i->parent;

    if (a == TERMINAL) {
      break;
    }

    a->r_cap += bottleneck;
    a->sister->r_cap -= bottleneck;

    if (!a->sister->r_cap) {
      set_orphan_front(i);
    }
  }

  i->tr_cap -= bottleneck;

  if (!i->tr_cap) {
    set_orphan_front(i);
  }

  for (i = middle_arc->head; ; i = a->head) {
    a = i->parent;

    if (a == TERMINAL) {
      break;
    }

    a->sister->r_cap += bottleneck;
    a->r_cap -= bottleneck;

    if (!a->r_cap) {
      set_orphan_front(i);
    }
  }

  i->tr_cap += bottleneck;

  if (!i->tr_cap) {
    set_orphan_front(i);
  }

  flow += bottleneck;
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype, tcaptype, flowtype>::process_source_orphan(node *i)
{
  node *j;
  arc *a0, *a0_min = NULL, *a;
  int d, d_min = INFINITE_D;

  for (a0 = i->first; a0; a0 = a0->next)
    if (a0->sister->r_cap) {
      j = a0->head;

      if (!j->is_sink && (a = j->parent)) {
	d = 0;

	while (1) {
	  if (j->TS == TIME) {
	    d += j->DIST;
	    break;
	  }

	  a = j->parent;
	  d++;

	  if (a == TERMINAL) {
	    j->TS = TIME;
	    j->DIST = 1;
	    break;
	  }

	  if (a == ORPHAN) {
	    d = INFINITE_D;
	    break;
	  }

	  j = a->head;
	}

	if (d<INFINITE_D) {
	  if (d < d_min) {
	    a0_min = a0;
	    d_min = d;
	  }

	  for (j = a0->head; j->TS != TIME; j = j->parent->head) {
	    j->TS = TIME;
	    j->DIST = d--;
	  }
	}
      }
    }

  if (i->parent = a0_min) {
    i->TS = TIME;
    i->DIST = d_min + 1;
  }
  else {
    add_to_changed_list(i);

    for (a0 = i->first; a0; a0 = a0->next) {
      j = a0->head;

      if (!j->is_sink && (a = j->parent)) {
	if (a0->sister->r_cap) {
	  set_active(j);
	}

	if (a != TERMINAL && a!=ORPHAN && a->head == i) {
	  set_orphan_rear(j);
	}
      }
    }
  }
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype, tcaptype, flowtype>::process_sink_orphan(node *i)
{
  node *j;
  arc *a0, *a0_min = NULL, *a;
  int d, d_min = INFINITE_D;

  for (a0 = i->first; a0; a0 = a0->next)
    if (a0->r_cap) {
      j = a0->head;

      if (j->is_sink && (a = j->parent)) {
	d = 0;

	while (1) {
	  if (j->TS == TIME) {
	    d += j->DIST;
	    break;
	  }

	  a = j->parent;
	  d++;

	  if (a == TERMINAL) {
	    j->TS = TIME;
	    j->DIST = 1;
	    break;
	  }

	  if (a == ORPHAN) {
	    d = INFINITE_D;
	    break;
	  }

	  j = a->head;
	}

	if (d < INFINITE_D) {
	  if (d < d_min) {
	    a0_min = a0;
	    d_min = d;
	  }

	  for (j = a0->head; j->TS != TIME; j = j->parent->head) {
	    j->TS = TIME;
	    j->DIST = d--;
	  }
	}
      }
    }

  if (i->parent = a0_min) {
    i->TS = TIME;
    i->DIST = d_min + 1;
  }
  else {
    add_to_changed_list(i);

    for (a0 = i->first; a0; a0 = a0->next) {
      j = a0->head;

      if (j->is_sink && (a = j->parent)) {
	if (a0->r_cap) set_active(j);
	if (a != TERMINAL && a != ORPHAN && a->head == i) {
	  set_orphan_rear(j);
	}
      }
    }
  }
}

template <typename captype, typename tcaptype, typename flowtype> flowtype Graph<captype, tcaptype, flowtype>::maxflow(bool reuse_trees, Block<node_id> *_changed_list)
{
  node *i, *j, *current_node = NULL;
  arc *a;
  nodeptr *np, *np_next;

  if (!nodeptr_block) {
    nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function);
  }

  changed_list = _changed_list;

  if (maxflow_iteration == 0 && reuse_trees) {
    if (error_function) {
      (*error_function)("reuse_trees cannot be used in the first call to maxflow()!");
      exit(1);
    }
  }

  if (changed_list && !reuse_trees) {
    if (error_function) {
      (*error_function)("changed_list cannot be used without reuse_trees!");
      exit(1);
    }
  }

  if (reuse_trees) {
    maxflow_reuse_trees_init();
  }
  else {
    maxflow_init();
  }

  while (1) {
    if ((i = current_node)) {
      i->next = NULL;

      if (!i->parent) {
	i = NULL;
      }
    }

    if (!i) {
      if (!(i = next_active())) {
	break;
      }
    }

    if (!i->is_sink) {
      for (a = i->first; a; a = a->next) {
	if (a->r_cap) {
	  j = a->head;
	  if (!j->parent) {
	    j->is_sink = 0;
	    j->parent = a->sister;
	    j->TS = i->TS;
	    j->DIST = i->DIST + 1;
	    set_active(j);
	    add_to_changed_list(j);
	  }
	  else if (j->is_sink) {
	    break;
	  }
	  else if (j->TS <= i->TS && j->DIST > i->DIST) {
	    j->parent = a->sister;
	    j->TS = i->TS;
	    j->DIST = i->DIST + 1;
	  }
	}
      }
    }
    else {
      for (a = i->first; a; a = a->next)
	if (a->sister->r_cap) {
	  j = a->head;
	  if (!j->parent) {
	    j->is_sink = 1;
	    j->parent = a->sister;
	    j->TS = i->TS;
	    j->DIST = i->DIST + 1;
	    set_active(j);
	    add_to_changed_list(j);
	  }
	  else if (!j->is_sink) {
	    a = a->sister;
	    break;
	  }
	  else if (j->TS <= i->TS && j->DIST > i->DIST) {
	    j->parent = a->sister;
	    j->TS = i->TS;
	    j->DIST = i->DIST + 1;
	  }
	}
    }

    TIME++;

    if (a) {
      i->next = i;
      current_node = i;

      augment(a);

      while ((np = orphan_first)) {
	np_next = np->next;
	np->next = NULL;

	while ((np = orphan_first)) {
	  orphan_first = np->next;
	  i = np->ptr;
	  nodeptr_block->Delete(np);

	  if (!orphan_first) {
	    orphan_last = NULL;
	  }

	  if (i->is_sink) {
	    process_sink_orphan(i);
	  }
	  else {
	    process_source_orphan(i);
	  }
	}

	orphan_first = np_next;
      }
    }
    else current_node = NULL;
  }

  if (!reuse_trees || (maxflow_iteration % 64) == 0) {
    delete nodeptr_block; 
    nodeptr_block = NULL; 
  }

  maxflow_iteration++;

  return flow;
}

template <typename captype, typename tcaptype, typename flowtype> void Graph<captype, tcaptype, flowtype>::test_consistency(node *current_node)
{
  node *i;
  arc *a;
  int r;
  int num1 = 0, num2 = 0;

  for (i = nodes; i < node_last; i++) {
    if (i->next || i==current_node) {
      num1++;
    }
  }

  for (r = 0; r < 3; r++) {
    i = (r == 2) ? current_node : queue_first[r];

    if (i) {
      for ( ; ; i = i->next) {
	num2 ++;

	if (i->next == i) {
	  if (r < 2) {
	    assert(i == queue_last[r]);
	  }
	  else {
	    assert(i == current_node);
	    break;
	  }
	}
      }
    }
  }

  assert(num1 == num2);

  for (i = nodes; i < node_last; i++) {
    if (i->parent == NULL) {
    }
    else if (i->parent == ORPHAN) {
    }
    else if (i->parent == TERMINAL) {
      if (!i->is_sink) {
	assert(i->tr_cap > 0);
      }
      else {
	assert(i->tr_cap < 0);
      }
    }
    else {
      if (!i->is_sink) {
	assert (i->parent->sister->r_cap > 0);
      }
      else {
	assert (i->parent->r_cap > 0);
      }
    }

    if (i->parent && !i->next) {
      if (!i->is_sink) {
	assert(i->tr_cap >= 0);
	for (a = i->first; a; a = a->next) {
	  if (a->r_cap > 0) {
	    assert(a->head->parent && !a->head->is_sink);
	  }
	}
      }
      else {
	assert(i->tr_cap <= 0);

	for (a = i->first; a; a = a->next) {
	  if (a->sister->r_cap > 0) {
	    assert(a->head->parent && a->head->is_sink);
	  }
	}
      }
    }

    if (i->parent && i->parent!=ORPHAN && i->parent != TERMINAL) {
      assert(i->TS <= i->parent->head->TS);
      if (i->TS == i->parent->head->TS) {
	assert(i->DIST > i->parent->head->DIST);
      }
    }
  }
}

コード:

// main.cpp
#include "GCApplication.h"

using namespace cv;
using namespace std;

GCApplication gcApp;

void on_mouse1(int event, int x, int y, int flags, void *param)
{
  gcApp.MouseClick(event, x, y, flags, param);
}

int main(int argc, char *argv[])
{
  Mat img;

  if (argc == 1) {
    string fileName;

    cout << "Image name : ";
    cin >> fileName;

    if (fileName.empty()) {
      return -1;
    }

    img = imread(fileName);
  }
  else {
    img = imread(argv[1]);
  }

  if (img.empty()) {
    cout << "Not image!" << endl;

    return -1;
  }

  const string winName = "graph cut";
  cvNamedWindow(winName.c_str(), 0);

  cout << "-------------- How to use --------------" << endl;
  cout << "Left mouse button  : Foreground seed" << endl;
  cout << "Right mouse button : Background seed" << endl;
  cout << "s                  : Run of GraphCut" << endl;
  cout << "Esc                : Exit\n" << endl;

  gcApp.SetImageAndWinName(img, winName);
  gcApp.ShowImage();

  cvSetMouseCallback(winName.c_str(), on_mouse1, 0);

  int c = cvWaitKey(0);

  switch ((char)c) {
  case 's':
    gcApp.GraphCut();
    cout << "End of run of GraphCut!\n" << endl;
    cout << "Press any key to continue..." << endl;
    waitKey();

	return 0;

  case '\x1b':
    cout << "Exiting..." << endl;
    cvDestroyWindow(winName.c_str());

	return 0;
  }

  return 0;
}

コード:

$ ls
GCApplication.cpp  GCApplication.h  GMM.cpp  GMM.h  Histgram.cpp  Histgram.h  block.h  graph.cpp  graph.h  instances.inc  main.cpp  maxflow.cpp
$ g++ -c GCApplication.cpp
GCApplication.cpp: In member function ‘void GCApplication::Reset()’:
GCApplication.cpp:75: error: ambiguous overload for ‘operator=’ in ‘((GCApplication*)this)->GCApplication::bgdModel = 0’
/usr/local/include/opencv2/core/mat.hpp:281: note: candidates are: cv::Mat& cv::Mat::operator=(const cv::Mat&)
/usr/local/include/opencv2/core/core.hpp:1730: note:                 cv::Mat& cv::Mat::operator=(const cv::Scalar&)
GCApplication.cpp: In member function ‘void GCApplication::InitGMMs(const cv::Mat&, const cv::Mat&, GMM&, GMM&)’:
GCApplication.cpp:385: error: invalid initialization of reference of type ‘const cv::_OutputArray&’ from expression of type ‘int’
/usr/local/include/opencv2/core/core.hpp:2478: error: in passing argument 7 of ‘double cv::kmeans(const cv::_InputArray&, int, const cv::_OutputArray&, cv::TermCriteria, int, int, const cv::_OutputArray&)’
GCApplication.cpp:388: error: invalid initialization of reference of type ‘const cv::_OutputArray&’ from expression of type ‘int’
/usr/local/include/opencv2/core/core.hpp:2478: error: in passing argument 7 of ‘double cv::kmeans(const cv::_InputArray&, int, const cv::_OutputArray&, cv::TermCriteria, int, int, const cv::_OutputArray&)’
$ g++ -c GMM.cpp
$ g++ -c Histgram.cpp
$ g++ -c graph.cpp
graph.cpp: In constructor ‘Graph<captype, tcaptype, flowtype>::Graph(int, int, void (*)(char*)) [with captype = int, tcaptype = int, flowtype = int]’:
instances.inc:7:   instantiated from here
graph.cpp:31: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In member function ‘void Graph<captype, tcaptype, flowtype>::reallocate_nodes(int) [with captype = int, tcaptype = int, flowtype = int]’:
instances.inc:7:   instantiated from here
graph.cpp:87: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In member function ‘void Graph<captype, tcaptype, flowtype>::reallocate_arcs() [with captype = int, tcaptype = int, flowtype = int]’:
instances.inc:7:   instantiated from here
graph.cpp:121: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In constructor ‘Graph<captype, tcaptype, flowtype>::Graph(int, int, void (*)(char*)) [with captype = short int, tcaptype = int, flowtype = int]’:
instances.inc:8:   instantiated from here
graph.cpp:31: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In member function ‘void Graph<captype, tcaptype, flowtype>::reallocate_nodes(int) [with captype = short int, tcaptype = int, flowtype = int]’:
instances.inc:8:   instantiated from here
graph.cpp:87: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In member function ‘void Graph<captype, tcaptype, flowtype>::reallocate_arcs() [with captype = short int, tcaptype = int, flowtype = int]’:
instances.inc:8:   instantiated from here
graph.cpp:121: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In constructor ‘Graph<captype, tcaptype, flowtype>::Graph(int, int, void (*)(char*)) [with captype = float, tcaptype = float, flowtype = float]’:
instances.inc:9:   instantiated from here
graph.cpp:31: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In member function ‘void Graph<captype, tcaptype, flowtype>::reallocate_nodes(int) [with captype = float, tcaptype = float, flowtype = float]’:
instances.inc:9:   instantiated from here
graph.cpp:87: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In member function ‘void Graph<captype, tcaptype, flowtype>::reallocate_arcs() [with captype = float, tcaptype = float, flowtype = float]’:
instances.inc:9:   instantiated from here
graph.cpp:121: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In constructor ‘Graph<captype, tcaptype, flowtype>::Graph(int, int, void (*)(char*)) [with captype = double, tcaptype = double, flowtype = double]’:
instances.inc:10:   instantiated from here
graph.cpp:31: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In member function ‘void Graph<captype, tcaptype, flowtype>::reallocate_nodes(int) [with captype = double, tcaptype = double, flowtype = double]’:
instances.inc:10:   instantiated from here
graph.cpp:87: 警告: deprecated conversion from string constant to ‘char*’
graph.cpp: In member function ‘void Graph<captype, tcaptype, flowtype>::reallocate_arcs() [with captype = double, tcaptype = double, flowtype = double]’:
instances.inc:10:   instantiated from here
graph.cpp:121: 警告: deprecated conversion from string constant to ‘char*’
$ g++ -c main.cpp
$ g++ -c maxflow.cpp
maxflow.cpp: In member function ‘flowtype Graph<captype, tcaptype, flowtype>::maxflow(bool, Block<int>*) [with captype = int, tcaptype = int, flowtype = int]’:
instances.inc:7:   instantiated from here
maxflow.cpp:457: 警告: deprecated conversion from string constant to ‘char*’
maxflow.cpp:464: 警告: deprecated conversion from string constant to ‘char*’
maxflow.cpp: In member function ‘flowtype Graph<captype, tcaptype, flowtype>::maxflow(bool, Block<int>*) [with captype = short int, tcaptype = int, flowtype = int]’:
instances.inc:8:   instantiated from here
maxflow.cpp:457: 警告: deprecated conversion from string constant to ‘char*’
maxflow.cpp:464: 警告: deprecated conversion from string constant to ‘char*’
maxflow.cpp: In member function ‘flowtype Graph<captype, tcaptype, flowtype>::maxflow(bool, Block<int>*) [with captype = float, tcaptype = float, flowtype = float]’:
instances.inc:9:   instantiated from here
maxflow.cpp:457: 警告: deprecated conversion from string constant to ‘char*’
maxflow.cpp:464: 警告: deprecated conversion from string constant to ‘char*’
maxflow.cpp: In member function ‘flowtype Graph<captype, tcaptype, flowtype>::maxflow(bool, Block<int>*) [with captype = double, tcaptype = double, flowtype = double]’:
instances.inc:10:   instantiated from here
maxflow.cpp:457: 警告: deprecated conversion from string constant to ‘char*’
maxflow.cpp:464: 警告: deprecated conversion from string constant to ‘char*’
In file included from graph.h:6,
                 from maxflow.cpp:3:
block.h: In member function ‘Type* DBlock<Type>::New() [with Type = Graph<int, int, int>::nodeptr]’:
maxflow.cpp:59:   instantiated from ‘void Graph<captype, tcaptype, flowtype>::set_orphan_front(Graph<captype, tcaptype, flowtype>::node*) [with captype = int, tcaptype = int, flowtype = int]’
instances.inc:7:   instantiated from here
block.h:146: 警告: deprecated conversion from string constant to ‘char*’
block.h: In member function ‘Type* Block<Type>::New(int) [with Type = int]’:
maxflow.cpp:85:   instantiated from ‘void Graph<captype, tcaptype, flowtype>::add_to_changed_list(Graph<captype, tcaptype, flowtype>::node*) [with captype = int, tcaptype = int, flowtype = int]’
instances.inc:7:   instantiated from here
block.h:35: 警告: deprecated conversion from string constant to ‘char*’
block.h: In member function ‘Type* DBlock<Type>::New() [with Type = Graph<short int, int, int>::nodeptr]’:
maxflow.cpp:59:   instantiated from ‘void Graph<captype, tcaptype, flowtype>::set_orphan_front(Graph<captype, tcaptype, flowtype>::node*) [with captype = short int, tcaptype = int, flowtype = int]’
instances.inc:8:   instantiated from here
block.h:146: 警告: deprecated conversion from string constant to ‘char*’
block.h: In member function ‘Type* DBlock<Type>::New() [with Type = Graph<float, float, float>::nodeptr]’:
maxflow.cpp:59:   instantiated from ‘void Graph<captype, tcaptype, flowtype>::set_orphan_front(Graph<captype, tcaptype, flowtype>::node*) [with captype = float, tcaptype = float, flowtype = float]’
instances.inc:9:   instantiated from here
block.h:146: 警告: deprecated conversion from string constant to ‘char*’
block.h: In member function ‘Type* DBlock<Type>::New() [with Type = Graph<double, double, double>::nodeptr]’:
maxflow.cpp:59:   instantiated from ‘void Graph<captype, tcaptype, flowtype>::set_orphan_front(Graph<captype, tcaptype, flowtype>::node*) [with captype = double, tcaptype = double, flowtype = double]’
instances.inc:10:   instantiated from here
block.h:146: 警告: deprecated conversion from string constant to ‘char*’

main.cppとGCApplication.cppは個人的に必要のない機能を削除したり、他のコードはwindows.hを消したりしました。
GMM.cppやHistgram.cpp、main.cpp以外はコンパイルすると上記のようなエラーや警告が出ているのですが、エラーや警告の意味がわからないのと、どう書き直せばいいのかがわかりません・・・

Re: 画像の前景抽出について

Posted: 2013年2月06日(水) 23:10
by h2so5
このサンプルコードが良くないですね。VC++なら通るんでしょうけど、C++のコードとして不正です。

とりあえず、いま出ているエラーを消すだけなら、
kmeans 関数を呼び出している部分をすべて探して、最後の引数を消してください。

コード:

kmeans(_fgdSamples, GMM::componentsCount, fgdLabels, TermCriteria(CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType, 0);

コード:

kmeans(_fgdSamples, GMM::componentsCount, fgdLabels, TermCriteria(CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType);