PICCANTE  0.4
The hottest HDR imaging library!
poisson_image_editing.hpp
Go to the documentation of this file.
1 /*
2 
3 PICCANTE
4 The hottest HDR imaging library!
5 http://vcg.isti.cnr.it/piccante
6 
7 Copyright (C) 2014
8 Visual Computing Laboratory - ISTI CNR
9 http://vcg.isti.cnr.it
10 First author: Francesco Banterle
11 
12 This Source Code Form is subject to the terms of the Mozilla Public
13 License, v. 2.0. If a copy of the MPL was not distributed with this
14 file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 
16 */
17 
18 #ifndef PIC_ALGORITHMS_POISSON_IMAGE_EDITING_HPP
19 #define PIC_ALGORITHMS_POISSON_IMAGE_EDITING_HPP
20 
21 #include <vector>
22 
23 #include "../base.hpp"
24 #include "../image.hpp"
25 #include "../util/std_util.hpp"
26 #include "../filtering/filter_laplacian.hpp"
27 
28 #ifndef PIC_DISABLE_EIGEN
29 
30 #ifndef PIC_EIGEN_NOT_BUNDLED
31  #include "../externals/Eigen/Sparse"
32  #include "../externals/Eigen/src/SparseCore/SparseMatrix.h"
33 #else
34  #include <Eigen/Sparse>
35  #include <Eigen/src/SparseCore/SparseMatrix.h>
36 #endif
37 
38 #endif
39 
40 namespace pic {
41 
42 #ifndef PIC_DISABLE_EIGEN
43 
51 PIC_INLINE Image *computePoissonImageEditing(Image *source, Image *target, bool *mask, Image *ret = NULL)
52 {
53  if((source == NULL) || (target == NULL) || (mask == NULL)) {
54  return NULL;
55  }
56 
57  //allocate the output
58  if(ret == NULL) {
59  ret = target->clone();
60  }
61 
62  int width = target->width;
63  int height = target->height;
64 
65  #ifdef PIC_DEBUG
66  printf("Init matrix...");
67  #endif
68 
69  Image *lap_source = FilterLaplacian::execute(source, NULL);
70 
71  std::vector< Eigen::Triplet< double > > tL;
72 
73  //indices pass
74  int *index = new int[width * height];
75  int count = 0;
76  for(int i = 0; i < height; i++) {
77  int tmpI = i * width;
78 
79  for(int j = 0; j < width; j++) {
80  int indI = tmpI + j;
81 
82  if(mask[indI]) {
83  index[indI] = count;
84  count++;
85  } else {
86  index[indI] = 0;
87  }
88  }
89  }
90 
91  //matrix A pass
92  count = 0;
93  for(int i = 0; i < height; i++) {
94  int tmpI = i * width;
95 
96  for(int j = 0; j < width; j++) {
97  int indI = tmpI + j;
98 
99  if(mask[indI]) {
100  if((j + 1) < (width - 1)) {
101  if(mask[indI + 1]) {
102  tL.push_back(Eigen::Triplet< double > (count, index[indI + 1], -1.0));
103  }
104  }
105 
106  if((j - 1) > -1) {
107  if(mask[indI - 1]) {
108  tL.push_back(Eigen::Triplet< double > (count, index[indI - 1], -1.0));
109  }
110  }
111 
112  if((i + 1) < (height - 1)) {
113  if(mask[indI + width]) {
114  tL.push_back(Eigen::Triplet< double > (count, index[indI + width], -1.0));
115  }
116  }
117 
118  if((i - 1) > -1) {
119  if(mask[indI - width]) {
120  tL.push_back(Eigen::Triplet< double > (count, index[indI - width], -1.0));
121  }
122  }
123 
124  tL.push_back(Eigen::Triplet< double > (count, count , 4.0));
125 
126  count++;
127  }
128  }
129  }
130 
131  int tot = count;
132  Eigen::SparseMatrix<double> A = Eigen::SparseMatrix<double>(tot, tot);
133  A.setFromTriplets(tL.begin(), tL.end());
134 
135  #ifdef PIC_DEBUG
136  printf("Ok\n");
137  #endif
138 
139  //solve the linear system for each color channel
140  Eigen::SimplicialCholesky<Eigen::SparseMatrix<double> > solver(A);
141 
142  for(int k=0; k< target->channels; k++) {
143 
144  Eigen::VectorXd b, x;
145  b = Eigen::VectorXd::Zero(tot);
146 
147  //assign values to b
148  int count = 0;
149  for(int i = 0; i < height; i++) {
150  int tmpI = i * width;
151 
152  for(int j = 0; j < width; j++) {
153  int indI = (tmpI + j);
154 
155  if(mask[indI]) {
156 
157  b[count] = -(*lap_source)(j, i)[k];
158 
159  if((j + 1) < (width - 1)) {
160  if(!mask[indI + 1]) {
161  b[count] += (*target)(j + 1, i)[k];
162  }
163  }
164 
165  if((j - 1) > -1) {
166  if(!mask[indI - 1]) {
167  b[count] += (*target)(j - 1, i)[k];
168  }
169  }
170 
171  if((i + 1) < (height - 1)) {
172  if(!mask[indI + width]) {
173  b[count] += (*target)(j, i + 1)[k];
174  }
175  }
176 
177  if((i - 1) > -1) {
178  if(!mask[indI - width]) {
179  b[count] += (*target)(j, i - 1)[k];
180  }
181  }
182 
183  count++;
184  }
185  }
186  }
187 
188  x = solver.solve(b);
189 
190  if(solver.info() != Eigen::Success) {
191  #ifdef PIC_DEBUG
192  printf("SOLVER FAILED!\n");
193  #endif
194 
195  return NULL;
196  }
197 
198  #ifdef PIC_DEBUG
199  printf("SOLVER SUCCESS!\n");
200  #endif
201 
202  count = 0;
203  for(int i = 0; i < height; i++) {
204  int tmpI = i * width;
205 
206  for(int j = 0; j < width; j++) {
207  int indI = (tmpI + j);
208 
209  if(mask[indI]) {
210  float val = float(x(count));
211  (*ret)(j, i)[k] = val > 0.0f ? val : 0.0f;
212  count++;
213  }
214  }
215  }
216  }
217 
218  delete_s(lap_source);
219  delete_vec_s(index);
220 
221  return ret;
222 }
223 #endif
224 
225 } // end namespace pic
226 
227 #endif /* PIC_ALGORITHMS_POISSON_IMAGE_EDITING_HPP */
228 
int channels
Definition: image.hpp:80
T * delete_s(T *data)
delete_s
Definition: std_util.hpp:123
T * delete_vec_s(T *data)
delete_vec_s
Definition: std_util.hpp:138
static Image * execute(Image *imgIn, Image *imgOut)
execute
Definition: filter_laplacian.hpp:79
#define PIC_INLINE
Definition: base.hpp:33
The Image class stores an image as buffer of float.
Definition: image.hpp:60
Image * clone() const
Clone creates a deep copy of the calling instance.
PIC_INLINE Image * computePoissonImageEditing(Image *source, Image *target, bool *mask, Image *ret=NULL)
computePoissonImageEditing
Definition: poisson_image_editing.hpp:51
Definition: bilateral_separation.hpp:25
int width
Definition: image.hpp:80
int height
Definition: image.hpp:80