/*
Reference:
Texture synthesis by non-parametric sampling.pdf
http://en.wikipedia.org/wiki/Texture_synthesis
Potential applications: A successful texture synthesis
algorithm's application is abroad, including occlusion fill-in,
loosy image andvideo compression,
foreground removal, etc.
*/
//**********************************************************************
// 用EL99算法合成纹理,速度比较慢,效果还不错,适用于大多数纹理的合成
//**********************************************************************
void CTextureView::El_99()
{
srand((unsigned)time(NULL));
//隋机选择3X3种子
int rx=2+rand()%(m_sSrc.cx-4);
int ry=2+rand()%(m_sSrc.cy-4);
BOOL up,down,left,right;
up=down=left=right=FALSE;
int dx,dy;
CTextureDoc* pDoc = GetDocument();
dx=pDoc->width;dy=pDoc->height;
COLORREF *result=new COLORREF[dx*dy];
memset(result,0,dx*dy*sizeof(COLORREF));
//将种子插于到要合成的图象中
for(int i=0;i<5;i++)
for(int j=0;j<5;j++) result[(dy/2-2+i)*dx+dx/2-2+j]=m_cSrc[(ry-2+i)*m_sSrc.cx+rx-2+j];
//开始合成
int cx,cy;
cx=dx/2;cy=dy/2; //保存起始中心位置
int r,k=pDoc->window;
r=2;//当前已合成部分的半径,对合成后的块边界上的点进行合成
while(!(up && down && left && right))
{
if(!up)
{
int tx,ty;
ty=cy-r-1;tx=cx-r;
tx=(tx<0)?0:tx;
while(tx<=cx+r && tx<dx)
{
COLORREF *wp=new COLORREF[k*k];
memset(wp,0,k*k*sizeof(COLORREF));
for(i=0;i<k;i++)
{
if(ty-(k/2)+i<0 || ty-(k/2)+i>dy-1) continue;
for(int j=0;j<k;j++)
{
if(tx-(k/2)+j<0 || tx-(k/2)+j>dx-1) continue;
wp[i*k+j]=result[(ty-(k/2)+i)*dx+tx-(k/2)+j];
}
}
result[ty*dx+tx]=NextPixel(m_cSrc,m_sSrc,wp,k/2);
tx++;
delete[] wp;
}
}
if(!down)
{
int tx,ty;
ty=cy+r+1;tx=cx-r;
tx=(tx<0)?0:tx;
while(tx<=cx+r && tx<dx)
{
COLORREF *wp=new COLORREF[k*k];
memset(wp,0,k*k*sizeof(COLORREF));
for(i=0;i<k;i++)
{
if(ty-(k/2)+i<0 || ty-(k/2)+i>dy-1) continue;
for(int j=0;j<k;j++)
{
if(tx-(k/2)+j<0 || tx-(k/2)+j>dx-1) continue;
wp[i*k+j]=result[(ty-(k/2)+i)*dx+tx-(k/2)+j];
}
}
result[ty*dx+tx]=NextPixel(m_cSrc,m_sSrc,wp,k/2);
tx++;
delete[] wp;
}
}
if(!left)
{
int tx,ty;
ty=cy-r-1;tx=cx-r-1;
ty=(ty<0)?0:ty;
while(ty<=cy+r+1 && ty<dy)
{
COLORREF *wp=new COLORREF[k*k];
memset(wp,0,k*k*sizeof(COLORREF));
for(i=0;i<k;i++)
{
if(ty-(k/2)+i<0 || ty-(k/2)+i>dy-1) continue;
for(int j=0;j<k;j++)
{
if(tx-(k/2)+j<0 || tx-(k/2)+j>dx-1) continue;
wp[i*k+j]=result[(ty-(k/2)+i)*dx+tx-(k/2)+j];
}
}
result[ty*dx+tx]=NextPixel(m_cSrc,m_sSrc,wp,k/2);
ty++;
delete[] wp;
}
}
if(!right)
{
int tx,ty;
ty=cy-r-1;tx=cx+r+1;
ty=(ty<0)?0:ty;
while(ty<=cy+r+1 && ty<dy)
{
COLORREF *wp=new COLORREF[k*k];
memset(wp,0,k*k*sizeof(COLORREF));
for(i=0;i<k;i++)
{
if(ty-(k/2)+i<0 || ty-(k/2)+i>dy-1) continue;
for(int j=0;j<k;j++)
{
if(tx-(k/2)+j<0 || tx-(k/2)+j>dx-1) continue;
wp[i*k+j]=result[(ty-(k/2)+i)*dx+tx-(k/2)+j];
}
}
result[ty*dx+tx]=NextPixel(m_cSrc,m_sSrc,wp,k/2);
ty++;
delete[] wp;
}
}
r++;
if(cy-r-1<0) up=TRUE;
if(cy+r+1>=dy) down=TRUE;
if(cx-r-1<0) left=TRUE;
if(cx+r+1>=dx) right=TRUE;
double total=((2*r+1)*(2*r+1))*100.0/(dx*dy);
CString str;
str.Format("%g%% Completed!\t r=%d",total,r);
CMainFrame* pMfm = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
pMfm->SetStatusStr(str);
}
SaveToBMP("el99_result.bmp", result, dx, dy);
m_str="el99_result.bmp";finish=TRUE;
delete[] result;
}
//***********************************************************
// 用样本图象匹配待合成象素的邻域,以找到一个合适的匹配点
//***********************************************************
COLORREF CTextureView::NextPixel(COLORREF *sample, CSize size, COLORREF *p, int k)
{
if(sample==NULL || p==NULL) return -1;
int cx=size.cx;
int cy=size.cy;
COLORREF *tmp=new COLORREF[cx*cy*sizeof(COLORREF)];// 用来保存匹配点颜色
//COLORREF *tmp=new COLORREF[40];
int ok_num=0,count=0;
double w=8.0;//阈值
repeat:
for(int i=k;i<(cy-k);i++)
{
for(int j=k;j<(cx-k);j++)
{
count=0;
double dif=0.0;
for(int m=0;m<2*k+1;m++)
{
for(int n=0;n<2*k+1;n++)
{
COLORREF pc=(COLORREF)p[m*(2*k+1)+n];
if (pc==0) continue;
COLORREF sc=(COLORREF)sample[(i-k+m)*cx+j-k+n];
int difr=GetRValue(sc)-GetRValue(pc);
int difg=GetGValue(sc)-GetGValue(pc);
int difb=GetBValue(sc)-GetBValue(pc);
dif+=sqrt(difr*difr+difg*difg+difg*difg+0.0);
//dif+=abs(difr)+abs(difg)+abs(difg)+0.0;
//在此需要考虑是否与高斯内核相乘,即:dp=dssD*G
/* 5*5
1 2 3 2 1
2 5 6 5 2
3 6 8 6 3
2 5 6 5 2
1 2 3 2 1
*/
count++;
}
}
if(count!=0) dif/=count;
if(dif<w)
{
tmp[ok_num++]=sample[i*cx+j];
}
}
}
if(ok_num==0)//如果所设阈值过低,则修改阈值,重新匹配
{
w*=1.5;
goto repeat;
}
srand((unsigned)time(NULL));
COLORREF res=tmp[rand()%ok_num];//隋机选择结果
delete[] tmp;
return res;
}