void testPotts() { MRFEnergy<TypePotts>* mrf; MRFEnergy<TypePotts>::NodeId* nodes; MRFEnergy<TypePotts>::Options options; TypePotts::REAL energy, lowerBound; const int nodeNum = 2; // number of nodes const int K = 3; // number of labels TypePotts::REAL D[K]; int x, y; mrf = new MRFEnergy<TypePotts>(TypePotts::GlobalSize(K)); nodes = new MRFEnergy<TypePotts>::NodeId[nodeNum]; // construct energy D[0] = 0; D[1] = 1; D[2] = 2; nodes[0] = mrf->AddNode(TypePotts::LocalSize(), TypePotts::NodeData(D)); D[0] = 3; D[1] = 4; D[2] = 5; nodes[1] = mrf->AddNode(TypePotts::LocalSize(), TypePotts::NodeData(D)); mrf->AddEdge(nodes[0], nodes[1], TypePotts::EdgeData(6)); // Function below is optional - it may help if, for example, nodes are added in a random order // mrf->SetAutomaticOrdering(); /////////////////////// TRW-S algorithm ////////////////////// options.m_iterMax = 30; // maximum number of iterations mrf->Minimize_TRW_S(options, lowerBound, energy); // read solution x = mrf->GetSolution(nodes[0]); y = mrf->GetSolution(nodes[1]); printf("Solution: %d %d\n", x, y); //////////////////////// BP algorithm //////////////////////// mrf->ZeroMessages(); // in general not necessary - it may be faster to start // with messages computed in previous iterations. // NOTE: in most cases, immediately after creating the energy // all messages are zero. EXCEPTION: typeBinary and typeBinaryFast. // So calling ZeroMessages for these types will NOT transform // the energy to the original state. options.m_iterMax = 30; // maximum number of iterations mrf->Minimize_BP(options, energy); // read solution x = mrf->GetSolution(nodes[0]); y = mrf->GetSolution(nodes[1]); printf("Solution: %d %d\n", x, y); // done delete nodes; delete mrf; }
void add_grid_edges_direction(MRFEnergy<T>& mrfenergy, const PyArrayObject* nodeids, const typename T::EdgeData& ed, int direction) { typedef typename T::REAL REAL; typedef typename MRFEnergy<T>::NodeId NodeId; int ndim = PyArray_NDIM(nodeids); npy_intp* shape = PyArray_DIMS(nodeids); if(direction >= ndim || direction < 0) throw std::runtime_error("invalid direction"); for(pyarray_iterator it(nodeids); !it.atEnd(); ++it) { npy_intp* coord = it.getIndex(); if(coord[direction] - 1 < 0) continue; NodeId id1 = reinterpret_cast<NodeId>(PyArray_SafeGet<numeric_pointer>(nodeids, coord)); --coord[direction]; NodeId id2 = reinterpret_cast<NodeId>(PyArray_SafeGet<numeric_pointer>(nodeids, coord)); ++coord[direction]; mrfenergy.AddEdge(id2, id1, ed); } }
void add_grid_edges(MRFEnergy<T>& mrfenergy, const PyArrayObject* nodeids, const typename T::EdgeData& ed) { typedef typename T::REAL REAL; typedef typename MRFEnergy<T>::NodeId NodeId; int ndim = PyArray_NDIM(nodeids); npy_intp* shape = PyArray_DIMS(nodeids); for(pyarray_iterator it(nodeids); !it.atEnd(); ++it) { npy_intp* coord = it.getIndex(); NodeId id1 = reinterpret_cast<NodeId>(PyArray_SafeGet<numeric_pointer>(nodeids, coord)); for(int d=0; d < ndim; ++d) { if(coord[d] - 1 < 0) continue; --coord[d]; NodeId id2 = reinterpret_cast<NodeId>(PyArray_SafeGet<numeric_pointer>(nodeids, coord)); ++coord[d]; mrfenergy.AddEdge(id2, id1, ed); } } }
py::object add_grid_nodes(MRFEnergy<T>& mrfenergy, const PyArrayObject* unaryterms, int axis=0) { typedef typename T::REAL REAL; typedef typename T::LocalSize LocalSize; typedef typename T::NodeData NodeData; int ndim = PyArray_NDIM(unaryterms); npy_intp* shape = PyArray_DIMS(unaryterms); if(-axis > ndim || axis >= ndim) throw std::runtime_error("axis is out of bounds"); if(axis < 0) axis = ndim + axis; int num_labels = shape[axis]; npy_intp* nodeids_shape = new npy_intp[ndim-1]; // Copy the shape except for the axis given. std::copy(shape, shape+axis, nodeids_shape); std::copy(shape+axis+1, shape+ndim, nodeids_shape+axis); PyArrayObject* nodeids = reinterpret_cast<PyArrayObject*>( PyArray_SimpleNew(ndim-1, nodeids_shape, NPY_ULONG)); std::vector<REAL> d(num_labels); pyarray_index unaryterms_idx(ndim); for(pyarray_iterator it(nodeids); !it.atEnd(); ++it) { const pyarray_index& nodeids_idx = it.getIndex(); // Extract unary terms for this node. std::copy(nodeids_idx.idx, nodeids_idx.idx+axis, &unaryterms_idx[0]); std::copy(nodeids_idx.idx+axis, nodeids_idx.idx+nodeids_idx.ndim, &unaryterms_idx[axis+1]); // std::copy(nodeids_idx.idx, nodeids_idx.idx+nodeids_idx.ndim, &unaryterms_idx[1]); for(int j=0; j<num_labels; ++j) { unaryterms_idx[axis] = j; d[j] = PyArray_SafeGet<REAL>(unaryterms, unaryterms_idx); } // Create the node. typename MRFEnergy<T>::NodeId id = mrfenergy.AddNode(LocalSize(num_labels), NodeData(d)); // Store the node. PyArray_SafeSet<numeric_pointer>(nodeids, nodeids_idx, reinterpret_cast<numeric_pointer>(id)); } delete [] nodeids_shape; return py::object(nodeids); }
py::object get_solution(MRFEnergy<T>& mrfenergy, const PyArrayObject* nodeids) { typedef typename MRFEnergy<T>::NodeId NodeId; typedef typename T::Label Label; int ndim = PyArray_NDIM(nodeids); npy_intp* shape = PyArray_DIMS(nodeids); PyArrayObject* solution = reinterpret_cast<PyArrayObject*>( PyArray_SimpleNew(ndim, shape, (mpl::at<numpy_typemap,Label>::type::value))); for(pyarray_iterator it(nodeids); !it.atEnd(); ++it) { NodeId id = reinterpret_cast<NodeId>(PyArray_SafeGet<numeric_pointer>(nodeids, it.getIndex())); Label label = mrfenergy.GetSolution(id); PyArray_SafeSet(solution, it.getIndex(), label); } return py::object(solution); }
py::object minimize_bp(MRFEnergy<T>& mrfenergy, typename T::REAL eps=-1, int itermax=50, int printiter=5, int printminiter=0, bool details=false) { typename MRFEnergy<T>::Options opt; opt.m_eps = eps; opt.m_iterMax = itermax; opt.m_printIter = printiter; opt.m_printMinIter = printminiter; std::vector<int> iterVector; std::vector<typename T::REAL> energyVector; int num_iters = mrfenergy.Minimize_BP(opt, iterVector, energyVector); if(details) return py::make_tuple(vector2pylist(iterVector), vector2pylist(energyVector)); else return py::make_tuple(num_iters, energyVector.back()); }
void add_grid_edges_direction_local(MRFEnergy<T>& mrfenergy, const PyArrayObject* nodeids, const PyArrayObject* ed, int direction, int axis=0) { typedef typename T::REAL REAL; typedef typename MRFEnergy<T>::NodeId NodeId; typedef typename MRFEnergy<T>::EdgeData EdgeData; int ndim = PyArray_NDIM(nodeids); npy_intp* shape = PyArray_DIMS(nodeids); int ed_ndim = PyArray_NDIM(ed); npy_intp* ed_shape = PyArray_DIMS(ed); if(direction >= ndim || direction < 0) throw std::runtime_error("invalid direction"); if(ed_ndim != ndim+1) throw std::runtime_error("invalid number of dimensions for the edge data array"); // Check and fix the axis parameter. if(-axis > ed_ndim || axis >= ed_ndim) throw std::runtime_error("axis is out of bounds"); if(axis < 0) axis = ed_ndim + axis; // Check the shapes. // First, take the axis dimension out of the ed_shape. npy_intp* ed_shape_fix = new npy_intp[ndim]; std::copy(ed_shape, ed_shape+axis, ed_shape_fix); std::copy(ed_shape+axis+1, ed_shape+ed_ndim, ed_shape_fix+axis); if(std::mismatch(shape, shape+direction, ed_shape_fix, std::less_equal<int>()).first != shape+direction || std::mismatch(shape+direction+1, shape+ndim, ed_shape_fix+direction+1, std::less_equal<int>()).first != shape+ndim) throw std::runtime_error("invalid shape for the edge data array"); if(ed_shape_fix[direction] < shape[direction]-1) throw std::runtime_error("invalid shape for the edge data array"); delete [] ed_shape_fix; for(pyarray_iterator it(nodeids); !it.atEnd(); ++it) { npy_intp* coord = it.getIndex(); if(coord[direction] - 1 < 0) continue; NodeId id1 = reinterpret_cast<NodeId>(PyArray_SafeGet<numeric_pointer>(nodeids, coord)); --coord[direction]; // Create a list to access the EdgeData. py::list lcoord; int d; for(d=0; d<ndim; ++d) { if(d == axis) lcoord.append(py::slice()); lcoord.append(coord[d]); } if(d == axis) lcoord.append(py::slice()); PyArrayObject* localed = reinterpret_cast<PyArrayObject*>( PyObject_GetItem((PyObject*)ed, py::tuple(lcoord).ptr())); NodeId id2 = reinterpret_cast<NodeId>(PyArray_SafeGet<numeric_pointer>(nodeids, coord)); ++coord[direction]; mrfenergy.AddEdge(id2, id1, EdgeData(py::object(localed))); } }
///----------------------------------------------------------------------------- //extern __declspec(dllexport) double trw_potts( int nnodes, // number of nodes int nlabels, // number of labels double const* unary, // unary potentials int npairs, // number of pairs int const *pairs, // pairs (ith pair = pairs[2*i], pairs[2*i+1]) double const *wpairs, // binary potentials int* solution, // return array int max_iter, // max number of iterations bool randomize_order, // bool use_bp, // belief propagation bool verbose // print debug info ) { MRFEnergy<TypePotts>* mrf; MRFEnergy<TypePotts>::NodeId* nodes; MRFEnergy<TypePotts>::Options options; TypePotts::REAL energy, lowerBound; mrf = new MRFEnergy<TypePotts>(TypePotts::GlobalSize(nlabels)); nodes = new MRFEnergy<TypePotts>::NodeId[nnodes]; // construct energy TypePotts::REAL * U = new TypePotts::REAL[nlabels]; for (int i=0; i < nnodes; i++) { for (int l=0; l < nlabels; l++) { U[l] = unary[i*nlabels + l]; } nodes[i] = mrf->AddNode( TypePotts::LocalSize(), TypePotts::NodeData(U) ); } delete[] U; /// pairs for (int i = 0; i < npairs; ++i) { mrf->AddEdge( nodes[pairs[i*2]], nodes[pairs[i*2+1]], TypePotts::EdgeData(wpairs[i]) ); } // TypeGeneral::REAL * E = new TypeGeneral::REAL[nlabels*nlabels]; // for (int i=0; i < npairs; i++) // { // for (int l1 = 0; l1 < nlabels; l1++) // for (int l2 = 0; l2 < nlabels; l2++) // {{ // E[l1 + l2*nlabels] = wpairs[i*nlabels*nlabels + l1 + l2*nlabels]; // }} // mrf->AddEdge( // nodes[pairs[i*2]], // nodes[pairs[i*2+1]], // TypeGeneral::EdgeData(TypeGeneral::GENERAL, E) // ); // } // Function below is optional - it may help if, for example, nodes are added in a random order if (randomize_order) mrf->SetAutomaticOrdering(); /////////////////////// TRW-S algorithm ////////////////////// if (verbose) options.m_printMinIter = 0; else options.m_printMinIter = max_iter+1; options.m_iterMax = max_iter; // maximum number of iterations if (use_bp) mrf->Minimize_BP(options, energy); else mrf->Minimize_TRW_S(options, lowerBound, energy); // read solution for (int i = 0; i<nnodes; i++) { solution[i] = mrf->GetSolution(nodes[i]); } delete mrf; delete[] nodes; return energy; }