// ------------------------------------------------------------------------ // 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 http://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 #include #include using namespace std ; // Require the ANN library // download and install it from // http://www.cs.umd.edu/~mount/ANN/ #include "ann.h" #pragma comment (lib,"ann.lib") template 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::iterator fit = Elements_tmp.begin() ; for( int i=0;iannkSearch( // 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::iterator fit=Elements_tmp.begin();fit != Elements_tmp.end();fit++ ) delete[] *fit ; Elements_tmp.clear() ; if( pAnnTree ) delete pAnnTree ; pAnnTree = 0 ; for(list::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 data ; list Elements_tmp ; list 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"<> 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 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;iyheight;++iy ) for( int ix=0;ixwidth;++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 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)"<raster[i]=(unsigned char)(rand()%256); TextureSynthesis(imgsource,imgtarget,2); imgtarget->SaveImagePPM("texturesynthesis-output.ppm"); char line[256]; cout<<"Press Return key"<