parent
1aad484ccf
commit
b6f379350d
7 changed files with 954 additions and 248 deletions
@ -0,0 +1,63 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __ALGO_HPP__ |
||||
#define __ALGO_HPP__ |
||||
|
||||
#include <vector> |
||||
#include <algorithm> |
||||
#include <cmath> |
||||
|
||||
template <typename Tp> static inline int min_idx(std::vector <Tp> vec) |
||||
{ |
||||
return std::min_element(vec.begin(), vec.end()) - vec.begin(); |
||||
} |
||||
|
||||
static inline int hamming_length(int x) |
||||
{ |
||||
int res = 0; |
||||
while (x) |
||||
{ |
||||
res += x&1; |
||||
x >>= 1; |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
#endif /* __ALGO_HPP__ */ |
@ -0,0 +1,125 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __ANNF_HPP__ |
||||
#define __ANNF_HPP__ |
||||
|
||||
#include "algo.hpp" |
||||
|
||||
static void plusToMinusUpdate(const cv::Mat ¤t, cv::Mat &next, const int dx, const int dy) |
||||
{ |
||||
for (int i = 0; i < next.rows; ++i) |
||||
for (int j = 0; j < next.cols; ++j) |
||||
{ |
||||
int y = cv::borderInterpolate(i - dy, next.rows, cv::BORDER_CONSTANT); |
||||
int x = cv::borderInterpolate(j - dx, next.cols, cv::BORDER_CONSTANT); |
||||
|
||||
next.at<float>(i, j) = -next.at<float>(y, x) |
||||
+ current.at<float>(i, j) - current.at<float>(y, x); |
||||
} |
||||
} |
||||
|
||||
static void minusToPlusUpdate(const cv::Mat ¤t, cv::Mat &next, const int dx, const int dy) |
||||
{ |
||||
for (int i = 0; i < next.rows; ++i) |
||||
for (int j = 0; j < next.cols; ++j) |
||||
{ |
||||
int y = cv::borderInterpolate(i - dy, next.rows, cv::BORDER_CONSTANT); |
||||
int x = cv::borderInterpolate(j - dx, next.cols, cv::BORDER_CONSTANT); |
||||
|
||||
next.at<float>(i, j) = next.at<float>(y, x) |
||||
- current.at<float>(i, j) + current.at<float>(y, x); |
||||
} |
||||
} |
||||
|
||||
static void getWHSeries(const cv::Mat &src, cv::Mat &dst, const int nProjections, const int psize = 8) |
||||
{ |
||||
CV_Assert(nProjections <= psize*psize && src.type() == CV_32FC3); |
||||
CV_Assert( hamming_length(psize) == 1 ); |
||||
|
||||
std::vector <cv::Mat> projections; |
||||
|
||||
cv::Mat proj; |
||||
cv::boxFilter(proj, proj, CV_32F, cv::Size(psize, psize), |
||||
cv::Point(-1,-1), false, cv::BORDER_REFLECT); |
||||
|
||||
projections.push_back(proj); |
||||
|
||||
std::vector <int> snake_idx(1, 0); |
||||
std::vector <int> snake_idy(1, 0); |
||||
|
||||
for (int k = 1, num = 1; k < psize && num <= nProjections; ++k) |
||||
{ |
||||
int dx[] = { (k % 2 == 0) ? +1 : 0, (k % 2 == 0) ? 0 : -1}; |
||||
int dy[] = { (k % 2 == 0) ? 0 : +1, (k % 2 == 0) ? -1 : 0}; |
||||
|
||||
snake_idx.push_back(snake_idx[num - 1] - dx[1]); |
||||
snake_idy.push_back(snake_idy[num++ - 1] - dy[1]); |
||||
|
||||
for (int i = 0; i < k && num < nProjections; ++i, ++num) |
||||
{ |
||||
snake_idx.push_back(snake_idx[num - 1] + dx[0]); |
||||
snake_idy.push_back(snake_idy[num - 1] + dy[0]); |
||||
} |
||||
|
||||
for (int i = 0; i < k && num < nProjections; ++i, ++num) |
||||
{ |
||||
snake_idx.push_back(snake_idx[num - 1] + dx[1]); |
||||
snake_idy.push_back(snake_idy[num - 1] + dy[1]); |
||||
} |
||||
} |
||||
|
||||
for (int i = 1; i < nProjections; ++i) |
||||
{ |
||||
int dx = (snake_idx[i] - snake_idx[i - 1]); |
||||
int dy = (snake_idy[i] - snake_idy[i - 1]); |
||||
|
||||
dx <<= hamming_length(psize - 1) - hamming_length(snake_idx[i - 1] ^ snake_idx[i]); |
||||
dy <<= hamming_length(psize - 1) - hamming_length(snake_idy[i - 1] ^ snake_idy[i]); |
||||
|
||||
if (i % 2 == 0) |
||||
plusToMinusUpdate(proj, proj, dx, dy); |
||||
else |
||||
minusToPlusUpdate(proj, proj, dx, dy); |
||||
} |
||||
|
||||
cv::merge(projections, dst); |
||||
} |
||||
|
||||
#endif /* __ANNF_HPP__ */ |
@ -0,0 +1,385 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _CV_GCGRAPH_H_ |
||||
#define _CV_GCGRAPH_H_ |
||||
|
||||
template <class TWeight> class GCGraph |
||||
{ |
||||
public: |
||||
GCGraph(); |
||||
GCGraph( unsigned int vtxCount, unsigned int edgeCount ); |
||||
~GCGraph(); |
||||
void create( unsigned int vtxCount, unsigned int edgeCount ); |
||||
int addVtx(); |
||||
void addEdges( int i, int j, TWeight w, TWeight revw ); |
||||
void addTermWeights( int i, TWeight sourceW, TWeight sinkW ); |
||||
TWeight maxFlow(); |
||||
bool inSourceSegment( int i ); |
||||
private: |
||||
class Vtx |
||||
{ |
||||
public: |
||||
Vtx *next; // initialized and used in maxFlow() only
|
||||
int parent; |
||||
int first; |
||||
int ts; |
||||
int dist; |
||||
TWeight weight; |
||||
unsigned char t; |
||||
}; |
||||
class Edge |
||||
{ |
||||
public: |
||||
int dst; |
||||
int next; |
||||
TWeight weight; |
||||
}; |
||||
|
||||
std::vector<Vtx> vtcs; |
||||
std::vector<Edge> edges; |
||||
TWeight flow; |
||||
}; |
||||
|
||||
template <class TWeight> |
||||
GCGraph<TWeight>::GCGraph() |
||||
{ |
||||
flow = 0; |
||||
} |
||||
template <class TWeight> |
||||
GCGraph<TWeight>::GCGraph( unsigned int vtxCount, unsigned int edgeCount ) |
||||
{ |
||||
create( vtxCount, edgeCount ); |
||||
} |
||||
template <class TWeight> |
||||
GCGraph<TWeight>::~GCGraph() |
||||
{ |
||||
} |
||||
template <class TWeight> |
||||
void GCGraph<TWeight>::create( unsigned int vtxCount, unsigned int edgeCount ) |
||||
{ |
||||
vtcs.reserve( vtxCount ); |
||||
edges.reserve( edgeCount + 2 ); |
||||
flow = 0; |
||||
} |
||||
|
||||
template <class TWeight> |
||||
int GCGraph<TWeight>::addVtx() |
||||
{ |
||||
Vtx v; |
||||
memset( &v, 0, sizeof(Vtx)); |
||||
vtcs.push_back(v); |
||||
return (int)vtcs.size() - 1; |
||||
} |
||||
|
||||
template <class TWeight> |
||||
void GCGraph<TWeight>::addEdges( int i, int j, TWeight w, TWeight revw ) |
||||
{ |
||||
CV_Assert( i>=0 && i<(int)vtcs.size() ); |
||||
CV_Assert( j>=0 && j<(int)vtcs.size() ); |
||||
CV_Assert( w>=0 && revw>=0 ); |
||||
CV_Assert( i != j ); |
||||
|
||||
if( !edges.size() ) |
||||
edges.resize( 2 ); |
||||
|
||||
Edge fromI, toI; |
||||
fromI.dst = j; |
||||
fromI.next = vtcs[i].first; |
||||
fromI.weight = w; |
||||
vtcs[i].first = (int)edges.size(); |
||||
edges.push_back( fromI ); |
||||
|
||||
toI.dst = i; |
||||
toI.next = vtcs[j].first; |
||||
toI.weight = revw; |
||||
vtcs[j].first = (int)edges.size(); |
||||
edges.push_back( toI ); |
||||
} |
||||
|
||||
template <class TWeight> |
||||
void GCGraph<TWeight>::addTermWeights( int i, TWeight sourceW, TWeight sinkW ) |
||||
{ |
||||
CV_Assert( i>=0 && i<(int)vtcs.size() ); |
||||
|
||||
TWeight dw = vtcs[i].weight; |
||||
if( dw > 0 ) |
||||
sourceW += dw; |
||||
else |
||||
sinkW -= dw; |
||||
flow += (sourceW < sinkW) ? sourceW : sinkW; |
||||
vtcs[i].weight = sourceW - sinkW; |
||||
} |
||||
|
||||
template <class TWeight> |
||||
TWeight GCGraph<TWeight>::maxFlow() |
||||
{ |
||||
const int TERMINAL = -1, ORPHAN = -2; |
||||
Vtx stub, *nilNode = &stub, *first = nilNode, *last = nilNode; |
||||
int curr_ts = 0; |
||||
stub.next = nilNode; |
||||
Vtx *vtxPtr = &vtcs[0]; |
||||
Edge *edgePtr = &edges[0]; |
||||
|
||||
std::vector<Vtx*> orphans; |
||||
|
||||
// initialize the active queue and the graph vertices
|
||||
for( int i = 0; i < (int)vtcs.size(); i++ ) |
||||
{ |
||||
Vtx* v = vtxPtr + i; |
||||
v->ts = 0; |
||||
if( v->weight != 0 ) |
||||
{ |
||||
last = last->next = v; |
||||
v->dist = 1; |
||||
v->parent = TERMINAL; |
||||
v->t = v->weight < 0; |
||||
} |
||||
else |
||||
v->parent = 0; |
||||
} |
||||
first = first->next; |
||||
last->next = nilNode; |
||||
nilNode->next = 0; |
||||
|
||||
// run the search-path -> augment-graph -> restore-trees loop
|
||||
for(;;) |
||||
{ |
||||
Vtx* v, *u; |
||||
int e0 = -1, ei = 0, ej = 0; |
||||
TWeight minWeight, weight; |
||||
uchar vt; |
||||
|
||||
// grow S & T search trees, find an edge connecting them
|
||||
while( first != nilNode ) |
||||
{ |
||||
v = first; |
||||
if( v->parent ) |
||||
{ |
||||
vt = v->t; |
||||
for( ei = v->first; ei != 0; ei = edgePtr[ei].next ) |
||||
{ |
||||
if( edgePtr[ei^vt].weight == 0 ) |
||||
continue; |
||||
u = vtxPtr+edgePtr[ei].dst; |
||||
if( !u->parent ) |
||||
{ |
||||
u->t = vt; |
||||
u->parent = ei ^ 1; |
||||
u->ts = v->ts; |
||||
u->dist = v->dist + 1; |
||||
if( !u->next ) |
||||
{ |
||||
u->next = nilNode; |
||||
last = last->next = u; |
||||
} |
||||
continue; |
||||
} |
||||
|
||||
if( u->t != vt ) |
||||
{ |
||||
e0 = ei ^ vt; |
||||
break; |
||||
} |
||||
|
||||
if( u->dist > v->dist+1 && u->ts <= v->ts ) |
||||
{ |
||||
// reassign the parent
|
||||
u->parent = ei ^ 1; |
||||
u->ts = v->ts; |
||||
u->dist = v->dist + 1; |
||||
} |
||||
} |
||||
if( e0 > 0 ) |
||||
break; |
||||
} |
||||
// exclude the vertex from the active list
|
||||
first = first->next; |
||||
v->next = 0; |
||||
} |
||||
|
||||
if( e0 <= 0 ) |
||||
break; |
||||
|
||||
// find the minimum edge weight along the path
|
||||
minWeight = edgePtr[e0].weight; |
||||
CV_Assert( minWeight > 0 ); |
||||
// k = 1: source tree, k = 0: destination tree
|
||||
for( int k = 1; k >= 0; k-- ) |
||||
{ |
||||
for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst ) |
||||
{ |
||||
if( (ei = v->parent) < 0 ) |
||||
break; |
||||
weight = edgePtr[ei^k].weight; |
||||
minWeight = MIN(minWeight, weight); |
||||
CV_Assert( minWeight > 0 ); |
||||
} |
||||
weight = fabs(v->weight); |
||||
minWeight = MIN(minWeight, weight); |
||||
CV_Assert( minWeight > 0 ); |
||||
} |
||||
|
||||
// modify weights of the edges along the path and collect orphans
|
||||
edgePtr[e0].weight -= minWeight; |
||||
edgePtr[e0^1].weight += minWeight; |
||||
flow += minWeight; |
||||
|
||||
// k = 1: source tree, k = 0: destination tree
|
||||
for( int k = 1; k >= 0; k-- ) |
||||
{ |
||||
for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst ) |
||||
{ |
||||
if( (ei = v->parent) < 0 ) |
||||
break; |
||||
edgePtr[ei^(k^1)].weight += minWeight; |
||||
if( (edgePtr[ei^k].weight -= minWeight) == 0 ) |
||||
{ |
||||
orphans.push_back(v); |
||||
v->parent = ORPHAN; |
||||
} |
||||
} |
||||
|
||||
v->weight = v->weight + minWeight*(1-k*2); |
||||
if( v->weight == 0 ) |
||||
{ |
||||
orphans.push_back(v); |
||||
v->parent = ORPHAN; |
||||
} |
||||
} |
||||
|
||||
// restore the search trees by finding new parents for the orphans
|
||||
curr_ts++; |
||||
while( !orphans.empty() ) |
||||
{ |
||||
Vtx* v2 = orphans.back(); |
||||
orphans.pop_back(); |
||||
|
||||
int d, minDist = INT_MAX; |
||||
e0 = 0; |
||||
vt = v2->t; |
||||
|
||||
for( ei = v2->first; ei != 0; ei = edgePtr[ei].next ) |
||||
{ |
||||
if( edgePtr[ei^(vt^1)].weight == 0 ) |
||||
continue; |
||||
u = vtxPtr+edgePtr[ei].dst; |
||||
if( u->t != vt || u->parent == 0 ) |
||||
continue; |
||||
// compute the distance to the tree root
|
||||
for( d = 0;; ) |
||||
{ |
||||
if( u->ts == curr_ts ) |
||||
{ |
||||
d += u->dist; |
||||
break; |
||||
} |
||||
ej = u->parent; |
||||
d++; |
||||
if( ej < 0 ) |
||||
{ |
||||
if( ej == ORPHAN ) |
||||
d = INT_MAX-1; |
||||
else |
||||
{ |
||||
u->ts = curr_ts; |
||||
u->dist = 1; |
||||
} |
||||
break; |
||||
} |
||||
u = vtxPtr+edgePtr[ej].dst; |
||||
} |
||||
|
||||
// update the distance
|
||||
if( ++d < INT_MAX ) |
||||
{ |
||||
if( d < minDist ) |
||||
{ |
||||
minDist = d; |
||||
e0 = ei; |
||||
} |
||||
for( u = vtxPtr+edgePtr[ei].dst; u->ts != curr_ts; u = vtxPtr+edgePtr[u->parent].dst ) |
||||
{ |
||||
u->ts = curr_ts; |
||||
u->dist = --d; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if( (v2->parent = e0) > 0 ) |
||||
{ |
||||
v2->ts = curr_ts; |
||||
v2->dist = minDist; |
||||
continue; |
||||
} |
||||
|
||||
/* no parent is found */ |
||||
v2->ts = 0; |
||||
for( ei = v2->first; ei != 0; ei = edgePtr[ei].next ) |
||||
{ |
||||
u = vtxPtr+edgePtr[ei].dst; |
||||
ej = u->parent; |
||||
if( u->t != vt || !ej ) |
||||
continue; |
||||
if( edgePtr[ei^(vt^1)].weight && !u->next ) |
||||
{ |
||||
u->next = nilNode; |
||||
last = last->next = u; |
||||
} |
||||
if( ej > 0 && vtxPtr+edgePtr[ej].dst == v2 ) |
||||
{ |
||||
orphans.push_back(u); |
||||
u->parent = ORPHAN; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return flow; |
||||
} |
||||
|
||||
template <class TWeight> |
||||
bool GCGraph<TWeight>::inSourceSegment( int i ) |
||||
{ |
||||
CV_Assert( i>=0 && i<(int)vtcs.size() ); |
||||
return vtcs[i].t == 0; |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,52 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __NORM2_HPP__ |
||||
#define __NORM2_HPP__ |
||||
|
||||
template <typename Tp> static inline Tp sqr(Tp x) { return x*x; } |
||||
|
||||
template <typename Tp, int cn> static inline Tp sqr( cv::Vec<Tp, cn> x) { return x.dot(x); } |
||||
|
||||
template <typename Tp> static inline Tp norm2(const Tp &a, const Tp &b) { return sqr(a - b); } |
||||
|
||||
template <typename Tp, int cn> static inline |
||||
Tp norm2(const cv::Vec <Tp, cn> &a, const cv::Vec<Tp, cn> &b) { return sqr(a - b); } |
||||
|
||||
#endif /* __NORM2_HPP__ */ |
@ -0,0 +1,259 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __PHOTOMONTAGE_HPP__ |
||||
#define __PHOTOMONTAGE_HPP__ |
||||
|
||||
#include <opencv2/core.hpp> |
||||
|
||||
#include "norm2.hpp" |
||||
#include "algo.hpp" |
||||
#include "annf.hpp" |
||||
#include "gcgraph.hpp" |
||||
|
||||
#define GCInfinity 10*1000*1000*1000.0 |
||||
#define EFFECTIVE_HEIGHT 600 |
||||
#define EFFECTIVE_WIDTH 800 |
||||
|
||||
|
||||
|
||||
template <typename Tp> class Photomontage |
||||
{ |
||||
private: |
||||
const std::vector <cv::Mat> &images; // vector of images for different labels
|
||||
const std::vector <cv::Mat> &masks; // vector of definition domains for each image
|
||||
|
||||
std::vector <cv::Mat> labelings; // vector of labelings for different expansions
|
||||
std::vector <double> distances; // vector of max-flow costs for different labeling
|
||||
|
||||
const int height; |
||||
const int width; |
||||
const int type; |
||||
const int channels; |
||||
const int lsize; |
||||
|
||||
bool multiscale; // if true, Photomontage use coarse-to-fine scheme
|
||||
|
||||
double singleExpansion(const cv::Mat &x_i, const int alpha); // single neighbor computing
|
||||
void gradientDescent(const cv::Mat &x_0, cv::Mat x_n); // gradient descent in alpha-expansion topology
|
||||
|
||||
protected: |
||||
virtual double dist(const Tp &l1p1, const Tp &l1p2, const Tp &l2p1, const Tp &l2p2); |
||||
virtual void setWeights(GCGraph <double> &graph, const cv::Point &pA, const cv::Point &pB, const int lA, const int lB, const int lX); |
||||
|
||||
public: |
||||
Photomontage(const std::vector <cv::Mat> &images, const std::vector <cv::Mat> &masks, bool multiscale = true); |
||||
virtual ~Photomontage(){}; |
||||
|
||||
void assignLabeling(cv::Mat &img); |
||||
void assignResImage(cv::Mat &img); |
||||
}; |
||||
|
||||
template <typename Tp> double Photomontage <Tp>:: |
||||
dist(const Tp &l1p1, const Tp &l1p2, const Tp &l2p1, const Tp &l2p2) |
||||
{ |
||||
return norm2(l1p1, l2p1) + norm2(l1p2, l2p2); |
||||
} |
||||
|
||||
template <typename Tp> void Photomontage <Tp>:: |
||||
setWeights(GCGraph <double> &graph, const cv::Point &pA, const cv::Point &pB, const int lA, const int lB, const int lX) |
||||
{ |
||||
if (lA == lB) |
||||
{ |
||||
/** Link from A to B **/ |
||||
double weightAB = dist( images[lA].at<Tp>(pA), |
||||
images[lA].at<Tp>(pB), |
||||
images[lX].at<Tp>(pA), |
||||
images[lX].at<Tp>(pB) ); |
||||
graph.addEdges(pA.y*width + pA.x, pB.y*width + pB.x, weightAB, weightAB); |
||||
} |
||||
else |
||||
{ |
||||
int X = graph.addVtx(); |
||||
|
||||
/** Link from X to sink **/ |
||||
double weightXS = dist( images[lA].at<Tp>(pA), |
||||
images[lA].at<Tp>(pB), |
||||
images[lB].at<Tp>(pA), |
||||
images[lB].at<Tp>(pB) ); |
||||
graph.addTermWeights(X, 0, weightXS); |
||||
|
||||
/** Link from A to X **/ |
||||
double weightAX = dist( images[lA].at<Tp>(pA), |
||||
images[lA].at<Tp>(pB), |
||||
images[lX].at<Tp>(pA), |
||||
images[lX].at<Tp>(pB) ); |
||||
graph.addEdges(pA.y*width + pA.x, X, weightAX, weightAX); |
||||
|
||||
/** Link from X to B **/ |
||||
double weightXB = dist( images[lX].at<Tp>(pA), |
||||
images[lX].at<Tp>(pB), |
||||
images[lB].at<Tp>(pA), |
||||
images[lB].at<Tp>(pB) ); |
||||
graph.addEdges(X, pB.y*width + pB.x, weightXB, weightXB); |
||||
} |
||||
} |
||||
|
||||
template <typename Tp> double Photomontage <Tp>:: |
||||
singleExpansion(const cv::Mat &x_i, const int alpha) |
||||
{ |
||||
int actualEdges = (height - 1)*width + height*(width - 1); |
||||
GCGraph <double> graph(actualEdges + height*width, 2*actualEdges); |
||||
|
||||
/** Terminal links **/ |
||||
for (int i = 0; i < height; ++i) |
||||
{ |
||||
const uchar *maskAlphaRow = masks[alpha].ptr <uchar>(i); |
||||
const int *labelRow = (const int *) x_i.ptr <int>(i); |
||||
|
||||
for (int j = 0; j < width; ++j) |
||||
graph.addTermWeights( graph.addVtx(), |
||||
maskAlphaRow[j] ? 0 : GCInfinity, |
||||
masks[ labelRow[j] ].at<uchar>(i, j) ? 0 : GCInfinity ); |
||||
} |
||||
|
||||
/** Neighbor links **/ |
||||
for (int i = 0; i < height - 1; ++i) |
||||
{ |
||||
const int *currentRow = (const int *) x_i.ptr <int>(i); |
||||
const int *nextRow = (const int *) x_i.ptr <int>(i + 1); |
||||
|
||||
for (int j = 0; j < width - 1; ++j) |
||||
{ |
||||
setWeights( graph, cv::Point(i, j), cv::Point(i, j + 1), currentRow[j], currentRow[j + 1], alpha ); |
||||
setWeights( graph, cv::Point(i, j), cv::Point(i + 1, j), currentRow[j], nextRow[j], alpha ); |
||||
} |
||||
|
||||
setWeights( graph, cv::Point(i, width - 1), cv::Point(i + 1, width - 1), |
||||
currentRow[width - 1], nextRow[width - 1], alpha ); |
||||
} |
||||
|
||||
const int *currentRow = (const int *) x_i.ptr <int>(height - 1); |
||||
for (int i = 0; i < width - 1; ++i) |
||||
setWeights( graph, cv::Point(height - 1, i), cv::Point(height - 1, i + 1), |
||||
currentRow[i], currentRow[i + 1], alpha ); |
||||
|
||||
/** Max-flow computation **/ |
||||
double result = graph.maxFlow(); |
||||
|
||||
/** Writing results **/ |
||||
labelings[alpha].create( height, width, CV_32SC1 ); |
||||
for (int i = 0; i < height; ++i) |
||||
{ |
||||
const int *inRow = (const int *) x_i.ptr <int>(i); |
||||
int *outRow = (int *) labelings[alpha].ptr <int>(i); |
||||
|
||||
for (int j = 0; j < width; ++j) |
||||
outRow[j] = graph.inSourceSegment(i*width + j) ? inRow[j] : alpha; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
template <typename Tp> void Photomontage <Tp>:: |
||||
gradientDescent(const cv::Mat &x_0, cv::Mat x_n) |
||||
{ |
||||
double optValue = std::numeric_limits<double>::max(); |
||||
x_0.copyTo(x_n); |
||||
|
||||
for (int num = -1; /**/; num = -1) |
||||
{ |
||||
for (int i = 0; i < lsize; ++i) |
||||
distances[i] = singleExpansion(x_n, i); |
||||
|
||||
int minIndex = min_idx(distances); |
||||
double minValue = distances[minIndex]; |
||||
|
||||
if (minValue < 0.98*optValue) |
||||
optValue = distances[num = minIndex]; |
||||
|
||||
if (num == -1) |
||||
break; |
||||
labelings[num].copyTo(x_n); |
||||
} |
||||
} |
||||
|
||||
template <typename Tp> void Photomontage <Tp>:: |
||||
assignLabeling(cv::Mat &img) |
||||
{ |
||||
if (multiscale == 0 || (height < EFFECTIVE_HEIGHT && width < EFFECTIVE_WIDTH)) |
||||
{ |
||||
img.create(height, width, CV_32SC1); |
||||
|
||||
img.setTo(0); |
||||
gradientDescent(img, img); |
||||
} |
||||
else |
||||
{ |
||||
int l = std::min( cvRound(height/600.0), cvRound(width/800.0) ); |
||||
img.create( cv::Size(width/l, height/l), CV_32SC1 ); |
||||
|
||||
... |
||||
img.setTo(0); |
||||
gradientDescent(img, img); |
||||
|
||||
resize(img, img, cv::Size(height, width), 0.0, 0.0, cv::INTER_NEAREST); |
||||
|
||||
... |
||||
} |
||||
} |
||||
|
||||
template <typename Tp> void Photomontage <Tp>:: |
||||
assignResImage(cv::Mat &img) |
||||
{ |
||||
cv::Mat optimalLabeling; |
||||
assignLabeling(optimalLabeling); |
||||
|
||||
img.create( height, width, type ); |
||||
|
||||
for (int i = 0; i < height; ++i) |
||||
for (int j = 0; j < width; ++j) |
||||
img.at<Tp>(i, j) = images[ optimalLabeling.at<int>(i, j) ].at<Tp>(i, j); |
||||
} |
||||
|
||||
template <typename Tp> Photomontage <Tp>:: |
||||
Photomontage(const std::vector <cv::Mat> &images, const std::vector <cv::Mat> &masks, const bool multiscale) |
||||
: |
||||
images(images), masks(masks), multiscale(multiscale), height(images[0].rows), width(images[0].cols), type(images[0].type()), |
||||
channels(images[0].channels()), lsize(images.size()), labelings(images.size()), distances(images.size()) |
||||
{ |
||||
CV_Assert(images[0].depth() != CV_8U && masks[0].depth() == CV_8U); |
||||
} |
||||
|
||||
#endif /* __PHOTOMONTAGE_HPP__ */ |
Loading…
Reference in new issue