00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00040 #include "InpaintOperator.hpp"
00041
00042 #include <cmath>
00043 #include <iostream>
00044
00045 using namespace Millie;
00046
00047 static float absolue(float a);
00048
00049 inline float absolue(float a)
00050 {
00051 if(a<=0)
00052 return -a;
00053 else
00054 return a;
00055 }
00056
00057
00058
00059
00060 void InpaintOperator::compute(Image & out, const Image & c, Image& mask)
00061 {
00062 int width = c.getWidth();
00063 int height = c.getHeight();
00064
00065 if(out.getNumComponents() != c.getNumComponents())
00066 throw Millie::IllegalArgument("InpaintOperator::compute");
00067
00068 if(mask.getHeight() != c.getHeight() || mask.getWidth() != c.getWidth())
00069 throw Millie::IllegalArgument("InpaintOperator::compute");
00070
00071
00072
00073
00074 static const int n = 8;
00075 static const int dx [n] =
00076 {
00077 -1,0,1,1,1,0,-1,-1
00078 };
00079 static const int dy [n] =
00080 {
00081 -1,-1,-1,0,1,1,1,0
00082 };
00083
00084
00085 out = c;
00086
00087 std::vector<int> contourInt1;
00088 std::vector<int> contourInt2;
00089
00090 for(int canal = 0; canal < c.getNumComponents(); canal++)
00091 {
00092
00093 while(true)
00094 {
00095
00096
00097 contourInt1.clear();
00098 contourInt2.clear();
00099
00100
00101
00102 for (int y = 0; y < height; y++)
00103 {
00104 for (int x = 0; x < width; x++)
00105 {
00106 if (absolue(mask.getPixel(x,y, canal))<0.01)
00107 continue;
00108 for (int i = 0; i < n; i++)
00109 {
00110 int xk = x + dx[i];
00111 int yk = y + dy[i];
00112 if (xk<0 || xk>=width)
00113 continue;
00114 if (yk<0 || yk>=height)
00115 continue;
00116 if (mask.getPixel(xk,yk, canal)>0.1)
00117 continue;
00118 contourInt1.push_back(x);
00119 contourInt2.push_back(y);
00120 break;
00121 }
00122 }
00123 }
00124
00125
00126 if (contourInt1.empty())
00127 break;
00128
00129
00130 for(unsigned int j=0;j<contourInt1.size();j++)
00131 {
00132 int x = contourInt1[j];
00133 int y = contourInt2[j];
00134
00135 mask.setPixel(x,y,canal, 0.0f);
00136
00137
00138 float value=0.0f;
00139 float wsum=0.0f;
00140 float w = 0.0f;
00141
00142
00143 for (int i = 0; i < n; i++)
00144 {
00145 int xk = x + dx[i];
00146 int yk = y + dy[i];
00147 if (xk<0 || xk>=width)
00148 continue;
00149 if (yk<0 || yk>=height)
00150 continue;
00151 if (mask.getPixel(xk,yk, canal)>0.1f)
00152 continue;
00153
00154
00155 float norme = 0;
00156 float angle = 0;
00157
00158 InpaintOperator::gradient(c, xk, yk, canal, &norme, &angle);
00159
00160 angle+= M_PI /2.0f;
00161
00162
00163
00164
00165
00166 float pscal;
00167 pscal = cos(angle)*(static_cast<float>(dx[i])) + (-sin(angle))*(static_cast<float>(dy[i]));
00168 pscal/=sqrt(static_cast<float> (dx[i]*dx[i]+dy[i]*dy[i]));
00169
00170
00171
00172 w = norme*(absolue(pscal)-1)+1;
00173
00174 value += w*c.getPixel(xk,yk, canal);
00175 wsum += w;
00176 }
00177
00178 if (wsum<=0)
00179 {
00180 std::cout<<"d "<<wsum<<std::endl;
00181 continue;
00182 }
00183 value/=wsum;
00184
00185 out.setPixel(x,y, canal, static_cast<int>(value));
00186
00187
00188 }
00189
00190 }
00191
00192 }
00193
00194 }
00195
00196
00197
00198
00199 void InpaintOperator::gradient(const Image& c, int x, int y, int canal, float * norme, float * angle)
00200 {
00201 int width = c.getWidth();
00202 int height = c.getHeight();
00203
00204 const float cst1 = (0.25f*(2-sqrt(2.0f)));
00205 const float cst2 = (0.5f*(sqrt(2.0f)-1.0f));
00206
00207 int px = x-1;
00208 int nx = x+1;
00209 int py = y-1;
00210 int ny = y+1;
00211 if (px<0)
00212 px=0;
00213 if (nx>=width)
00214 nx=width-1;
00215 if (py<0)
00216 py=0;
00217 if (ny>=height)
00218 ny=height-1;
00219
00220 float Ipp=c.getPixel(px,py, canal);
00221 float Ipc=c.getPixel(px,y, canal) ;
00222 float Ipn=c.getPixel(px,ny, canal);
00223 float Icp=c.getPixel(x,py, canal);
00224 float Icn=c.getPixel(x,ny, canal);
00225 float Inp=c.getPixel(nx,py, canal);
00226 float Inc=c.getPixel(nx,y, canal) ;
00227 float Inn=c.getPixel(nx,ny, canal);
00228
00229 float IppInn = cst1*(Inn-Ipp);
00230 float IpnInp = cst1*(Ipn-Inp);
00231 float gradx = (IppInn-IpnInp-cst2*Ipc+cst2*Inc);
00232 float grady = (IppInn+IpnInp-cst2*Icp+cst2*Icn);
00233
00234 *norme = sqrt( gradx*gradx + grady*grady );
00235
00236 *angle = 0.0f;
00237 if (*norme>0.01f)
00238 {
00239 *angle = acos(gradx/ *norme);
00240 if (grady>0.01f)
00241 *angle = 2.0f*M_PI - *angle;
00242 }
00243
00244 *norme/=255.0f;
00245
00246 }
00247
00248
00249