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
+
0 commit comments