topical media & game development
basic-visual-08-textureperpixel.c
? /
basic-visual-08-textureperpixel.c
// ------------------------------------------------------------------------
// This program is complementary material for the book:
//
// Frank Nielsen
//
// Visual Computing: Geometry, Graphics, and Vision
//
// ISBN: 1-58450-427-7
//
// Charles River Media, Inc.
//
//
// All programs are available at www.charlesriver.com/visualcomputing/
//
// You may use this program for ACADEMIC and PERSONAL purposes ONLY.
//
//
// The use of this program in a commercial product requires EXPLICITLY
// written permission from the author. The author is NOT responsible or
// liable for damage or loss that may be caused by the use of this program.
//
// Copyright (c) 2005. Frank Nielsen. All rights reserved.
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// File: textureperpixel.cpp
//
// Description: Texture Synthesis per Pixel (Wei & Levoy Algorithm)
// ------------------------------------------------------------------------
include <stdafx.h>
include <list>
include <vector>
include <fstream>
using namespace std ;
// Require the ANN library
// download and install it from
// www.cs.umd.edu/~mount/ANN/
#include <ann.h>
#pragma comment (lib,"ann.lib")
template <class COORD_TYPE=double,class INDEX_TYPE=unsigned int> class CAnnTree_Simple {
public:
CAnnTree_Simple():pAnnTree(0),dim(-1){}
~CAnnTree_Simple(){Clear();}
void Setup(int dim){ Clear(); this->dim = dim ; }
void AddElement(COORD_TYPE* Elem,INDEX_TYPE Index){
double* elm = new double[dim] ;
for( int i=0;i<dim;i++ ) elm[i] = (double)Elem[i] ;
Elements_tmp.push_back(elm) ;
data.push_back(Index) ;
}
void ConstructSearchStructure(){
int n_pts = Elements_tmp.size() ;
ANNpointArray data_pts = annAllocPts(n_pts, dim);
PAtoDestroy.push_back(data_pts) ;
list<double*>::iterator fit = Elements_tmp.begin() ;
for( int i=0;i<n_pts;i++,fit++ ){
ANNpoint p = data_pts[i] ;
memcpy(p,*fit,sizeof(double)*dim) ;
delete[] *fit ;
}
Elements_tmp.clear() ;
if( pAnnTree ) delete pAnnTree ;
pAnnTree = new ANNkd_tree(data_pts,n_pts,dim) ;
}
INDEX_TYPE FindMostSimilar( COORD_TYPE* Query,double error_bound = 0.001 ) throw(std::exception)
{
ANNpoint query_pt = annAllocPt(dim);
for( int i=0;i<dim;i++ ) query_pt[i] = Query[i] ;
if( data.empty() ) return 0 ;
ANNidx nn_idx ;
ANNdist dist ;
// search nearest neighbor
pAnnTree->annkSearch( // search
query_pt, // query point
1, // number of near neighbors
&nn_idx, // nearest neighbors (returned)
&dist, // distance (returned)
error_bound); // error bound
annDeallocPt(query_pt) ;
if( nn_idx < 0 || nn_idx >= data.size() )
throw std::exception("Couldn't find similar point.") ;
return data[nn_idx] ;
}
void Clear(){
dim = -1 ; data.clear() ;
for(list<double*>::iterator fit=Elements_tmp.begin();fit != Elements_tmp.end();fit++ ) delete[] *fit ;
Elements_tmp.clear() ;
if( pAnnTree ) delete pAnnTree ; pAnnTree = 0 ;
for(list<ANNpointArray>::iterator it = PAtoDestroy.begin() ;
it != PAtoDestroy.end() ; it++ ){
annDeallocPts(*it) ;
}
PAtoDestroy.clear() ;
}
int GetItemNum(){ return data.size() ; }
int GetDim(){return dim;}
protected:
int dim ;
vector<INDEX_TYPE> data ;
list<double*> Elements_tmp ;
list<ANNpointArray> PAtoDestroy ;
ANNkd_tree* pAnnTree ;
} ;
class CPoint {
public :
CPoint(int x=0,int y=0){ this->x = x ; this->y = y ; }
int x,y ;
} ;
define GETPIXELQUICK(img,x,y) &img->raster[((y)*img->width+(x))*3]
define GETPIXELLOOP(img,x,y) GETPIXELQUICK(img,(x+img->width)\%img->width,(y+img->height)\%img->height)
class Image{
public:
int width, height;
unsigned char * raster;
void SaveImagePPM(char * file)
{
ofstream OUT(file, ios::binary );
if (OUT){
OUT << "P6" << endl << width << ' ' << height << endl << 255 << endl;
OUT.write((char *)raster, 3*width*height);
OUT.close();}
}
// Load a PPM Image that does not contain comments.
Image(int w, int h)
{
width=w;height=h;
raster=new unsigned char [3*width*height];
}
Image(char *ifile)
{
char dummy1=0, dummy2=0; int maxc;
unsigned char * img;
ifstream IN(ifile, ios::binary);
IN.get(dummy1);IN.get(dummy2);
if ((dummy1!='P')&&(dummy2!='6')) {cerr<<"Not P6 PPM file"<<endl; }
IN >> width >> height;
IN >> maxc;
IN.get(dummy1);
raster=new unsigned char[3*width*height];
IN.read((char *)raster, 3*width*height);
IN.close();
}
};
void TextureSynthesis(Image* imgSrc, Image* imgDest, const int nsize_2)
{
const int nsize = nsize_2*2 + 1 ;
CAnnTree_Simple<unsigned char,CPoint> SearchTree ;
{
// Build search tree.
SearchTree.Setup( 3 * (nsize*nsize_2+nsize_2) ) ;
unsigned char* buf = new unsigned char[SearchTree.GetDim()] ;
for( int iy = nsize_2 ; iy < imgSrc->height ; ++iy ){
for( int ix = nsize_2 ; ix < imgSrc->width - nsize_2 ; ++ix ){
unsigned char* bp = buf ;
for( int diy=-nsize_2 ; diy<0 ; ++diy )
for( int dix=-nsize_2 ; dix<=nsize_2 ; ++dix,bp+=3 ){
memcpy( bp,GETPIXELQUICK(imgSrc, ix+dix,iy+diy ),3 ) ;
}
int diy=0 ;
for( int dix=-nsize_2 ; dix<0 ; ++dix,bp+=3 ){
memcpy( bp,GETPIXELQUICK(imgSrc, ix+dix,iy+diy ),3 ) ;
}
SearchTree.AddElement( buf,CPoint(ix,iy) ) ;
}
}
delete[] buf ;
SearchTree.ConstructSearchStructure() ;
}
// Fill main L-Shape
{
unsigned char* buf = new unsigned char[SearchTree.GetDim()] ;
for( int iy=0;iy<imgDest->height;++iy )
for( int ix=0;ix<imgDest->width;++ix )
{
unsigned char* tgt_pxl = GETPIXELQUICK(imgDest,ix,iy) ;
unsigned char* bp = buf ;
for( int diy=-nsize_2 ; diy<0 ; ++diy )
for( int dix=-nsize_2 ; dix<=nsize_2 ; ++dix,bp+=3 )
memcpy( bp,GETPIXELLOOP(imgDest, ix+dix,iy+diy ),3 ) ;
int diy=0 ;
for( int dix=-nsize_2 ; dix<0 ; ++dix,bp+=3 )
memcpy( bp,GETPIXELLOOP(imgDest, ix+dix,iy+diy ),3 );
CPoint& bestMatchLocation = SearchTree.FindMostSimilar( buf ) ;
memcpy( tgt_pxl,GETPIXELQUICK(imgSrc, bestMatchLocation.x,bestMatchLocation.y ) , 3 ) ;
}
delete[] buf ;
}
}
include <ctime>
int _tmain(int argc, _TCHAR* argv[])
{
Image *imgsource, *imgtarget;
int wo,ho;
imgsource=new Image("texturesynthesis-input.ppm");
wo=2*imgsource->width;
ho=2*imgsource->height;
cout<<"Visual Computing: Geometry, Graphics, and Vision (ISBN:1-58450-427-7)"<<endl;
cout<<"Demo program\n\n"<<endl;
cout<<"I am creating 4 times larger texture now... Wait a bit please."<<endl;
imgtarget=new Image(wo,ho);
srand(2005);
for(int i=0;i<3*wo*ho;i++) imgtarget->raster[i]=(unsigned char)(rand()%256);
TextureSynthesis(imgsource,imgtarget,2);
imgtarget->SaveImagePPM("texturesynthesis-output.ppm");
char line[256];
cout<<"Press Return key"<<endl;
gets(line);
return 0;
}
(C) Æliens
20/2/2008
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.