efros_freeman  0.1
blending.c
Go to the documentation of this file.
1 /*
2  Copyright (c) 2016 Lara Raad <lara.raad@cmla.ens-cachan.fr>,
3  Bruno Galerne <bruno.galerne@parisdescartes.fr>
4 
5  Quilting is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Affero General Public License as
7  published by the Free Software Foundation, either version 3 of the
8  License, or (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <math.h>
22 #include <assert.h>
23 #include <float.h>
24 
25 #include "blending.h"
26 #include "io_png.h"
27 
28 #define min(a,b) (a<=b)?(a):(b)
29 #define max(a,b) (a>b)?(a):(b)
30 #define abs(a) (a<0)?-(a):(a)
31 
32 /**
33 * This method blends new block in the output image with the corresponding
34 * "new edges" defined by the boudary mask. The new block will be composed of
35 * the synthesized part in the top and/or left part of the minimal error
36 * cut and of the new block from the source image in the rest, with a mix of
37 * both in the transition zone if the smoothed option is set to 1.
38 * @author Lara Raad
39 * @param boundary_mask boundary_mask is the mask used to redefine
40 * the ragged edges of the patches
41 * @param out_im The synthesized texture
42 * @param src_im The input texture sample
43 * @param patch_src Corner position of the patch to copy from
44 * the input texture sample
45 * @param temp Corner position of the location were to add the
46 * new patch in the output image
47 * @param ps The size of the patches
48 * @param ps The overlap size
49 * @date 24/06/2014
50 */
51 int blend_patch(Image boundary_mask, Image *out_im, Image src_im,
52  Corner patch_src, Corner temp, int ps, int os)
53 {
54  int pos_o, pos_s, pos_m, ii, jj, kk, inc_o, inc_s, x, y;
55 
56  int smooth = 1;
57 
58  x = temp.x;
59  y = temp.y;
60  inc_s = src_im.w*src_im.h;
61  inc_o = out_im->w*out_im->h;
62 
63  if (smooth && os!= 1)
64  smooth_mask(&boundary_mask,ps,os,temp);
65 
66  for(ii=0; ii<ps; ii++)
67  {
68  for(jj=0; jj<ps; jj++)
69  {
70  pos_m = ii*boundary_mask.w + jj;
71  for(kk=0; kk<3; kk++)
72  {
73  pos_o = (ii+x)*out_im->w + (jj+y) + kk*inc_o;
74  pos_s = (ii+patch_src.x)*src_im.w + (jj+patch_src.y) + kk*inc_s;
75  out_im->img[pos_o] =
76  out_im->img[pos_o]*(boundary_mask.img[pos_m]) +
77  src_im.img[pos_s]*(1-(boundary_mask.img[pos_m]));
78  }
79  }
80  }
81 
82  return 0;
83 }
84 
85 /**
86 * This method smoothes the boudary mask using a Gaussian kernel.
87 * The transition between the old part and the new part is smoother.
88 * @author Lara Raad
89 * @param boundary_mask boundary_mask is the mask used to redefine
90 * the ragged edges of the patches
91 * @param ps The patch size
92 * @param os The overlap size
93 * @param temp Corner position of the location were to add
94 * the new patch in the output image
95 * @date 07/07/2014
96 */
97 int smooth_mask(Image *boundary_mask, int ps, int os, Corner temp)
98 {
99  int ii;
100  int kernel_size = 3;
101  float kernel[kernel_size];
102  int center = kernel_size - 1;
103  float var = 0.8;//gaussian kernel's variance
104 
105  //* Create Gaussian kernel *//
106  for(ii=0; ii<kernel_size; ii++)
107  {
108  kernel[ii] = expf(-(ii*ii)/(2*var));
109  }
110 
111  //* Filtering the boundary mask*//
112  int X1[2]; int Y1[2]; int X2[2]; int Y2[2];
113  if (temp.x>0 && temp.y>0)//L-shape overlap
114  {
115  X1[0] = 0; X1[1] = os; Y1[0] = 0; Y1[1] = ps;
116  X2[0] = os; X2[1] = ps; Y2[0] = 0; Y2[1] = os;
117  filter_mask(X1,Y1,X2,Y2,ps,boundary_mask,kernel,center);
118  }
119  else if (temp.x==0 && temp.y>0)//vertival overlap
120  {
121  X1[0] = 0; X1[1] = os; Y1[0] = 0; Y1[1] = os;
122  X2[0] = os; X2[1] = ps; Y2[0] = 0; Y2[1] = os;
123  filter_mask(X1,Y1,X2,Y2,ps,boundary_mask,kernel,center);
124  }
125  else if (temp.x>0 && temp.y==0)//horizontal overlap
126  {
127  X1[0] = 0; X1[1] = os; Y1[0] = 0; Y1[1] = os;
128  X2[0] = 0; X2[1] = os; Y2[0] = os; Y2[1] = ps;
129  filter_mask(X1,Y1,X2,Y2,ps,boundary_mask,kernel,center);
130  }
131 
132  return 0;
133 }
134 
135 
136 /**
137 * This method partially filters an image. We pass X1, X2, X3 and X4
138 * to mark out the area we wish to filter. It is done in two steps to
139 * to contemplate the L-shaped case. With X1 and Y1 we filter a first area.
140 * With X2 ans Y2 we filter a second area. X1 and X2 have the coordinates
141 * in x that mark out the first and second area vertically. And Y1 and Y2
142 * the coordinates in y that mark out the first and second area horizontally.
143 * @author Lara Raad
144 * @param X1 2-d vector with the x-coordinates that mark out
145 * horizontally the first area
146 * @param Y1 2-d vector with the y-coordinates that mark out
147 * horizontally the first area
148 * @param X2 2-d vector with the x-coordinates that mark out
149 * horizontally the second area
150 * @param Y2 2-d vector with the y-coordinates that mark out
151 * horizontally the second area
152 * @param ps The patch size
153 * @param boundary_mask Mask to filter
154 * @param kernel The kernel used to filter the mask
155 * @param center The kernel's center
156 * @date 07/07/2014
157 */
158 int filter_mask(int X1[],int Y1[], int X2[], int Y2[], int ps,
159  Image *boundary_mask, float kernel[], int center)
160 {
161  int left, right, top, bottom, ii, jj, kk, ll, pos, pos_aux, pos_blend;
162  float tot_weight;
163  Image aux_mask;
164 
165  //* Initialize auxiliar mask *//
166  initialize_image(&aux_mask, ps, ps, 1);
167 
168  for(ii=0; ii<X1[1]; ii++)
169  {
170  for(jj=0; jj<Y1[1]; jj++)
171  {
172  left = max(0, jj-center); right = min(Y1[1]-1, jj+center);
173  top = max(0, ii-center); bottom = min(X1[1]-1, ii+center);
174  pos_aux = ii*aux_mask.w + jj;
175  tot_weight = 0;
176  for(kk=top; kk<=bottom; kk++)
177  {
178  for(ll=left; ll<=right; ll++)
179  {
180  pos_blend = kk*boundary_mask->w + ll;
181  aux_mask.img[pos_aux] +=
182  boundary_mask->img[pos_blend]*
183  kernel[abs(ii-kk)]*kernel[abs(jj-ll)];
184  tot_weight += kernel[abs(ii-kk)]*kernel[abs(jj-ll)];
185  }
186  }
187  aux_mask.img[pos_aux] /= tot_weight;
188  }
189  }
190 
191  for(ii=X2[0]; ii<X2[1]; ii++)
192  {
193  for(jj=Y2[0]; jj<Y2[1]; jj++)
194  {
195  left = max(Y2[0], jj-center); right = min(Y2[1]-1, jj+center);
196  top = max(X2[0], ii-center); bottom = min(X2[1]-1, ii+center);
197  pos_aux = ii*aux_mask.w + jj;
198  tot_weight = 0;
199  for(kk=top; kk<=bottom; kk++)
200  {
201  for(ll=left; ll<=right; ll++)
202  {
203  pos_blend = kk*boundary_mask->w + ll;
204  aux_mask.img[pos_aux] +=
205  boundary_mask->img[pos_blend]*
206  kernel[abs(ii-kk)]*kernel[abs(jj-ll)];
207  tot_weight += kernel[abs(ii-kk)]*kernel[abs(jj-ll)];
208  }
209  }
210  aux_mask.img[pos_aux] /= tot_weight;
211  }
212  }
213 
214  //* Updating values of smoothed mask *//
215  for(ii=0; ii<X1[1]; ii++)
216  {
217  for(jj=0; jj<Y1[1]; jj++)
218  {
219  pos = ii*aux_mask.w + jj;
220  boundary_mask->img[pos] = aux_mask.img[pos];
221  }
222  }
223  for(ii=X2[0]; ii<X2[1]; ii++)
224  {
225  for(jj=Y2[0]; jj<Y2[1]; jj++)
226  {
227  pos = ii*aux_mask.w + jj;
228  boundary_mask->img[pos] = aux_mask.img[pos];
229  }
230  }
231 
232  //* free memory *//
233  free(aux_mask.img);
234 
235  return 0;
236 }