Skip to content

Commit 6b4b44c

Browse files
complete the first version
0 parents  commit 6b4b44c

8 files changed

+1171
-0
lines changed

clone.cpp

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#include "clone.h"
2+
#include "poisson_solver.h"
3+
#include <opencv2/opencv.hpp>
4+
#include <iostream>
5+
#include <Eigen/Sparse>
6+
#include <Eigen/Dense>
7+
8+
bool findOverlap(cv::InputArray background,
9+
cv::InputArray foreground,
10+
int offsetX, int offsetY,
11+
cv::Rect &rBackground,
12+
cv::Rect &rForeground)
13+
{
14+
cv::Mat bg = background.getMat();
15+
cv::Mat fg = foreground.getMat();
16+
17+
18+
rBackground = cv::Rect(0, 0, bg.cols, bg.rows) &
19+
cv::Rect(offsetX, offsetY, fg.cols, fg.rows);
20+
21+
22+
// Compensate for negative offsets. If offset < 0, offset in foreground is positive.
23+
rForeground = cv::Rect(std::max<int>(-offsetX, 0),
24+
std::max<int>(-offsetY, 0),
25+
rBackground.width,
26+
rBackground.height);
27+
28+
29+
return rForeground.area() > 0;
30+
31+
}
32+
33+
void computeMixedGradientVectorField(cv::InputArray background,
34+
cv::InputArray foreground,
35+
cv::OutputArray vx_,
36+
cv::OutputArray vy_)
37+
{
38+
cv::Mat bg = background.getMat();
39+
cv::Mat fg = foreground.getMat();
40+
41+
const int channels = bg.channels();
42+
43+
vx_.create(bg.size(), CV_MAKETYPE(CV_32F, channels));
44+
vy_.create(bg.size(), CV_MAKETYPE(CV_32F, channels));
45+
46+
cv::Mat vx = vx_.getMat();
47+
cv::Mat vy = vy_.getMat();
48+
49+
cv::Mat kernelx = (cv::Mat_<float>(1, 3) << -0.5, 0, 0.5);
50+
cv::Mat kernely = (cv::Mat_<float>(3, 1) << -0.5, 0, 0.5);
51+
52+
cv::Mat vxf, vyf, vxb, vyb;
53+
cv::filter2D(fg, vxf, CV_32F, kernelx, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
54+
cv::filter2D(fg, vyf, CV_32F, kernely, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
55+
cv::filter2D(bg, vxb, CV_32F, kernelx, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
56+
cv::filter2D(bg, vyb, CV_32F, kernely, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
57+
58+
59+
for(int id = 0; id <= (vx.rows * vx.cols * channels - channels); ++id)
60+
{
61+
const cv::Vec2f g[2] = {
62+
cv::Vec2f(vxf.ptr<float>()[id], vyf.ptr<float>()[id]),
63+
cv::Vec2f(vxb.ptr<float>()[id], vyb.ptr<float>()[id])
64+
};
65+
66+
int which = (g[0].dot(g[0]) > g[1].dot(g[1])) ? 0 : 1;
67+
68+
vx.ptr<float>()[id] = g[which][0];
69+
vy.ptr<float>()[id] = g[which][1];
70+
}
71+
}
72+
73+
void computeWeightedGradientVectorField(cv::InputArray background,
74+
cv::InputArray foreground,
75+
cv::OutputArray vx,
76+
cv::OutputArray vy,
77+
float weightForeground)
78+
{
79+
80+
cv::Mat bg = background.getMat();
81+
cv::Mat fg = foreground.getMat();
82+
83+
cv::Mat kernelx = (cv::Mat_<float>(1, 3) << -0.5, 0, 0.5);
84+
cv::Mat kernely = (cv::Mat_<float>(3, 1) << -0.5, 0, 0.5);
85+
86+
cv::Mat vxf, vyf, vxb, vyb;
87+
cv::filter2D(fg, vxf, CV_32F, kernelx, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
88+
cv::filter2D(fg, vyf, CV_32F, kernely, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
89+
cv::filter2D(bg, vxb, CV_32F, kernelx, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
90+
cv::filter2D(bg, vyb, CV_32F, kernely, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
91+
92+
cv::addWeighted(vxf, weightForeground, vxb, 1.f - weightForeground, 0, vx);
93+
cv::addWeighted(vyf, weightForeground, vyb, 1.f - weightForeground, 0, vy);
94+
}
95+
96+
97+
void seamlessClone(cv::InputArray background,
98+
cv::InputArray foreground,
99+
cv::InputArray foregroundMask,
100+
int offsetX,
101+
int offsetY,
102+
cv::OutputArray destination,
103+
CloneType type)
104+
{
105+
106+
// Copy original background as we only solve for the overlapping area of the translated foreground mask.
107+
background.getMat().copyTo(destination);
108+
109+
// Find overlapping region. We will only perform on this region
110+
cv::Rect rbg, rfg;
111+
if (!findOverlap(background, foreground, offsetX, offsetY, rbg, rfg))
112+
return;
113+
114+
cv::Mat fore, back;
115+
cv::Mat lap = (cv::Mat_<float>(3, 3) << 0.0, -1, 0.0, -1, 4, -1, 0.0, -1, 0.0);
116+
cv::filter2D(foreground.getMat()(rfg), fore, CV_32F, lap, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
117+
cv::filter2D(background.getMat()(rbg), back, CV_32F, lap, cv::Point(-1,-1), 0, cv::BORDER_REPLICATE);
118+
cv::Mat f = fore;
119+
120+
cv::Mat boundaryMask(rfg.size(), CV_8UC1);
121+
cv::threshold(foregroundMask.getMat()(rfg), boundaryMask, UNKNOWN, DIRICHLET_BD, cv::THRESH_BINARY_INV);
122+
cv::rectangle(boundaryMask, cv::Rect(0, 0, boundaryMask.cols, boundaryMask.rows), DIRICHLET_BD, 1);
123+
124+
cv::Mat boundaryValues(rfg.size(), CV_MAKETYPE(CV_32F, background.channels()));
125+
background.getMat()(rbg).convertTo(boundaryValues, CV_32F);
126+
127+
cv::Mat foreValues(rfg.size(), CV_MAKETYPE(CV_32F, foreground.channels()));
128+
foreground.getMat()(rfg).convertTo(foreValues, CV_32F);
129+
/*
130+
cv::Mat image = boundaryMask;
131+
int nr=image.rows;
132+
int nc=image.cols;
133+
if(image.isContinuous())
134+
{
135+
nr=1;
136+
nc=nc*image.rows*image.channels();
137+
}
138+
for(int i=0;i<nr;i++)
139+
{
140+
const uchar* inData=image.ptr<uchar>(i);
141+
for(int j=0;j<nc;j++)
142+
{
143+
std::cout<<int(*inData++)<<std::endl;
144+
145+
}
146+
}
147+
*/
148+
149+
150+
151+
// Solve Poisson equation
152+
cv::Mat result;
153+
/*
154+
solvePoissonEquations(f,
155+
boundaryMask,
156+
boundaryValues,
157+
result);
158+
*/
159+
solvePoissonEquationsFast(foreValues,
160+
boundaryMask,
161+
boundaryValues,
162+
result);
163+
164+
// Copy result to destination image.
165+
result.convertTo(destination.getMat()(rbg), CV_8U);
166+
167+
}
168+
169+

clone.h

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#ifndef POISSON_CLONE_H
2+
#define POISSON_CLONE_H
3+
4+
#include "constant.h"
5+
#include <opencv2/core/core.hpp>
6+
7+
/**
8+
9+
Determine the area of overlap.
10+
11+
Computes the areas of overlap for background and foreground when foreground
12+
is layed over background given a translational offset.
13+
14+
*/
15+
bool findOverlap(cv::InputArray background,
16+
cv::InputArray foreground,
17+
int offsetX, int offsetY,
18+
cv::Rect &rBackground,
19+
cv::Rect &rForeground);
20+
21+
/**
22+
23+
Compute Poisson guidance vector field by mixing gradients from background and foreground.
24+
25+
*/
26+
void computeMixedGradientVectorField(cv::InputArray background,
27+
cv::InputArray foreground,
28+
cv::OutputArray vx,
29+
cv::OutputArray vy);
30+
31+
/**
32+
33+
Compute Poisson guidance vector field by averaging background and foreground gradients.
34+
35+
*/
36+
void computeWeightedGradientVectorField(cv::InputArray background,
37+
cv::InputArray foreground,
38+
cv::OutputArray vx,
39+
cv::OutputArray vy,
40+
float weightForeground);
41+
42+
/**
43+
44+
Solve multi-channel Poisson equations.
45+
46+
*/
47+
void solvePoissonEquations(cv::InputArray background,
48+
cv::InputArray foreground,
49+
cv::InputArray foregroundMask,
50+
cv::InputArray vx,
51+
cv::InputArray vy,
52+
cv::OutputArray destination);
53+
54+
55+
enum CloneType {
56+
CLONE_FOREGROUND_GRADIENTS,
57+
CLONE_AVERAGED_GRADIENTS,
58+
CLONE_MIXED_GRADIENTS
59+
};
60+
61+
62+
void seamlessClone(cv::InputArray background,
63+
cv::InputArray foreground,
64+
cv::InputArray foregroundMask,
65+
int offsetX,
66+
int offsetY,
67+
cv::OutputArray destination,
68+
CloneType type);
69+
70+
71+
#endif

constant.h

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef CONSTANT_H
2+
#define CONSTANT_H
3+
4+
const unsigned char UNKNOWN = 0;
5+
const unsigned char DIRICHLET_BD = 1;
6+
const unsigned char NEUMANN_BD = 2;
7+
8+
9+
#endif

makefile

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
seamless_clone: seamless_cloning.o clone.o poisson_solver.o
2+
g++ -I /usr/local/include/eigen3 $$(pkg-config --cflags --libs opencv) seamless_cloning.o clone.o poisson_solver.o -O2 -o seamless_clone
3+
4+
seamless_cloning.o: seamless_cloning.cpp clone.h
5+
g++ -I /usr/local/include/eigen3 $$(pkg-config --cflags --libs opencv) -c seamless_cloning.cpp
6+
7+
clone.o: clone.cpp clone.h poisson_solver.h
8+
g++ -I /usr/local/include/eigen3 $$(pkg-config --cflags --libs opencv) -c clone.cpp
9+
10+
poisson_solver.o: poisson_solver.cpp poisson_solver.h
11+
g++ -I /usr/local/include/eigen3 $$(pkg-config --cflags --libs opencv) -c poisson_solver.cpp
12+
13+
clean:
14+
rm *.o

0 commit comments

Comments
 (0)