// This software is in the public domain. Where that dedication is not // recognized, you are granted a perpetual, irrevocable license to copy // and modify this file as you see fit. #include "ebsynth.h" #include "ebsynth_cpu.h" #include "ebsynth_cuda.h" #include #include EBSYNTH_API void ebsynthRun(int ebsynthBackend, int numStyleChannels, int numGuideChannels, int sourceWidth, int sourceHeight, void* sourceStyleData, void* sourceGuideData, int targetWidth, int targetHeight, void* targetGuideData, void* targetModulationData, float* styleWeights, float* guideWeights, float uniformityWeight, int patchSize, int voteMode, int numPyramidLevels, int* numSearchVoteItersPerLevel, int* numPatchMatchItersPerLevel, int* stopThresholdPerLevel, void* outputNnfData, void* outputImageData) { void (*backendDispatch)(int,int,int,int,void*,void*,int,int,void*,void*,float*,float*,float,int,int,int,int*,int*,int*,void*,void*) = 0; if (ebsynthBackend==EBSYNTH_BACKEND_CPU ) { backendDispatch = ebsynthRunCpu; } else if (ebsynthBackend==EBSYNTH_BACKEND_CUDA) { backendDispatch = ebsynthRunCuda; } else if (ebsynthBackend==EBSYNTH_BACKEND_AUTO) { backendDispatch = ebsynthBackendAvailableCuda() ? ebsynthRunCuda : ebsynthRunCpu; } if (backendDispatch!=0) { backendDispatch(numStyleChannels, numGuideChannels, sourceWidth, sourceHeight, sourceStyleData, sourceGuideData, targetWidth, targetHeight, targetGuideData, targetModulationData, styleWeights, guideWeights, uniformityWeight, patchSize, voteMode, numPyramidLevels, numSearchVoteItersPerLevel, numPatchMatchItersPerLevel, stopThresholdPerLevel, outputNnfData, outputImageData); } } EBSYNTH_API int ebsynthBackendAvailable(int ebsynthBackend) { if (ebsynthBackend==EBSYNTH_BACKEND_CPU ) { return ebsynthBackendAvailableCpu(); } else if (ebsynthBackend==EBSYNTH_BACKEND_CUDA) { return ebsynthBackendAvailableCuda(); } else if (ebsynthBackend==EBSYNTH_BACKEND_AUTO) { return ebsynthBackendAvailableCpu() || ebsynthBackendAvailableCuda(); } return 0; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include "jzq.h" template bool tryToParseArg(const std::vector& args,int* inout_argi,const char* name,bool* out_fail,FUNC handler) { int& argi = *inout_argi; bool& fail = *out_fail; if (argi<0 || argi>=args.size()) { fail = true; return false; } if (args[argi]==name) { argi++; fail = !handler(); return true; } fail = false; return false; } bool tryToParseIntArg(const std::vector& args,int* inout_argi,const char* name,int* out_value,bool* out_fail) { return tryToParseArg(args,inout_argi,name,out_fail,[&] { int& argi = *inout_argi; if (argi& args,int* inout_argi,const char* name,float* out_value,bool* out_fail) { return tryToParseArg(args,inout_argi,name,out_fail,[&] { int& argi = *inout_argi; if (argi& args,int* inout_argi,const char* name,std::string* out_value,bool* out_fail) { return tryToParseArg(args,inout_argi,name,out_fail,[&] { int& argi = *inout_argi; if (argi& args,int* inout_argi,const char* name,std::pair* out_value,bool* out_fail) { return tryToParseArg(args,inout_argi,name,out_fail,[&] { int& argi = *inout_argi; if ((argi+1)\n"); printf(" -guide \n"); printf(" -output \n"); printf(" -weight \n"); printf(" -uniformity \n"); printf(" -patchsize \n"); printf(" -pyramidlevels \n"); printf(" -searchvoteiters \n"); printf(" -patchmatchiters \n"); printf(" -stopthreshold \n"); printf(" -backend [cpu|cuda]\n"); printf("\n"); return 1; } std::string styleFileName; float styleWeight = NAN; std::string outputFileName = "output.png"; struct Guide { std::string sourceFileName; std::string targetFileName; float weight; int sourceWidth; int sourceHeight; unsigned char* sourceData; int targetWidth; int targetHeight; unsigned char* targetData; int numChannels; }; std::vector guides; float uniformityWeight = 3500; int patchSize = 5; int numPyramidLevels = -1; int numSearchVoteIters = 6; int numPatchMatchIters = 4; int stopThreshold = 5; int backend = ebsynthBackendAvailable(EBSYNTH_BACKEND_CUDA) ? EBSYNTH_BACKEND_CUDA : EBSYNTH_BACKEND_CPU; { std::vector args(argc); for(int i=0;i guidePair; std::string backendName; if (tryToParseStringArg(args,&argi,"-style",&styleFileName,&fail)) { styleWeight = NAN; precedingStyleOrGuideWeight = &styleWeight; argi++; } else if (tryToParseStringPairArg(args,&argi,"-guide",&guidePair,&fail)) { Guide guide; guide.sourceFileName = guidePair.first; guide.targetFileName = guidePair.second; guide.weight = NAN; guides.push_back(guide); precedingStyleOrGuideWeight = &guides[guides.size()-1].weight; argi++; } else if (tryToParseStringArg(args,&argi,"-output",&outputFileName,&fail)) { argi++; } else if (tryToParseFloatArg(args,&argi,"-weight",&weight,&fail)) { if (precedingStyleOrGuideWeight!=0) { *precedingStyleOrGuideWeight = weight; } else { printf("error: at least one -style or -guide option must precede the -weight option!\n"); return 1; } argi++; } else if (tryToParseFloatArg(args,&argi,"-uniformity",&uniformityWeight,&fail)) { argi++; } else if (tryToParseIntArg(args,&argi,"-patchsize",&patchSize,&fail)) { if (patchSize<3) { printf("error: patchsize is too small!\n"); return 1; } if (patchSize%2==0) { printf("error: patchsize must be an odd number!\n"); return 1; } argi++; } else if (tryToParseIntArg(args,&argi,"-pyramidlevels",&numPyramidLevels,&fail)) { if (numPyramidLevels<1) { printf("error: bad argument for -pyramidlevels!\n"); return 1; } argi++; } else if (tryToParseIntArg(args,&argi,"-searchvoteiters",&numSearchVoteIters,&fail)) { if (numSearchVoteIters<0) { printf("error: bad argument for -searchvoteiters!\n"); return 1; } argi++; } else if (tryToParseIntArg(args,&argi,"-patchmatchiters",&numPatchMatchIters,&fail)) { if (numPatchMatchIters<0) { printf("error: bad argument for -patchmatchiters!\n"); return 1; } argi++; } else if (tryToParseIntArg(args,&argi,"-stopthreshold",&stopThreshold,&fail)) { if (stopThreshold<0) { printf("error: bad argument for -stopthreshold!\n"); return 1; } argi++; } else if (tryToParseStringArg(args,&argi,"-backend",&backendName,&fail)) { if (backendName=="cpu" ) { backend = EBSYNTH_BACKEND_CPU; } else if (backendName=="cuda") { backend = EBSYNTH_BACKEND_CUDA; } else { printf("error: unrecognized backend '%s'\n",backendName.c_str()); return 1; } if (!ebsynthBackendAvailable(backend)) { printf("error: the %s backend is not available!\n",backendToString(backend).c_str()); return 1; } argi++; } else { printf("error: unrecognized option '%s'\n",args[argi].c_str()); fail = true; } } if (fail) { return 1; } } const int numGuides = guides.size(); int sourceWidth = 0; int sourceHeight = 0; unsigned char* sourceStyleData = tryLoad(styleFileName,&sourceWidth,&sourceHeight); const int numStyleChannelsTotal = evalNumChannels(sourceStyleData,sourceWidth*sourceHeight); std::vector sourceStyle(sourceWidth*sourceHeight*numStyleChannelsTotal); for(int xy=0;xy0) { sourceStyle[xy*numStyleChannelsTotal+0] = sourceStyleData[xy*4+0]; } if (numStyleChannelsTotal==2) { sourceStyle[xy*numStyleChannelsTotal+1] = sourceStyleData[xy*4+3]; } else if (numStyleChannelsTotal>1) { sourceStyle[xy*numStyleChannelsTotal+1] = sourceStyleData[xy*4+1]; } if (numStyleChannelsTotal>2) { sourceStyle[xy*numStyleChannelsTotal+2] = sourceStyleData[xy*4+2]; } if (numStyleChannelsTotal>3) { sourceStyle[xy*numStyleChannelsTotal+3] = sourceStyleData[xy*4+3]; } } int targetWidth = 0; int targetHeight = 0; int numGuideChannelsTotal = 0; for(int i=0;i0 && (guide.targetWidth!=targetWidth || guide.targetHeight!=targetHeight)) { printf("error: target guide '%s' doesn't match the resolution of '%s'\n",guide.targetFileName.c_str(),guides[0].targetFileName.c_str()); return 1; } else if (i==0) { targetWidth = guide.targetWidth; targetHeight = guide.targetHeight; } guide.numChannels = std::max(evalNumChannels(guide.sourceData,sourceWidth*sourceHeight), evalNumChannels(guide.targetData,targetWidth*targetHeight)); numGuideChannelsTotal += guide.numChannels; } if (numStyleChannelsTotal>EBSYNTH_MAX_STYLE_CHANNELS) { printf("error: too many style channels (%d), maximum number is %d\n",numStyleChannelsTotal,EBSYNTH_MAX_STYLE_CHANNELS); return 1; } if (numGuideChannelsTotal>EBSYNTH_MAX_GUIDE_CHANNELS) { printf("error: too many guide channels (%d), maximum number is %d\n",numGuideChannelsTotal,EBSYNTH_MAX_GUIDE_CHANNELS); return 1; } std::vector sourceGuides(sourceWidth*sourceHeight*numGuideChannelsTotal); for(int xy=0;xy0) { sourceGuides[xy*numGuideChannelsTotal+c+0] = guides[i].sourceData[xy*4+0]; } if (numChannels==2) { sourceGuides[xy*numGuideChannelsTotal+c+1] = guides[i].sourceData[xy*4+3]; } else if (numChannels>1) { sourceGuides[xy*numGuideChannelsTotal+c+1] = guides[i].sourceData[xy*4+1]; } if (numChannels>2) { sourceGuides[xy*numGuideChannelsTotal+c+2] = guides[i].sourceData[xy*4+2]; } if (numChannels>3) { sourceGuides[xy*numGuideChannelsTotal+c+3] = guides[i].sourceData[xy*4+3]; } c += numChannels; } } std::vector targetGuides(targetWidth*targetHeight*numGuideChannelsTotal); for(int xy=0;xy0) { targetGuides[xy*numGuideChannelsTotal+c+0] = guides[i].targetData[xy*4+0]; } if (numChannels==2) { targetGuides[xy*numGuideChannelsTotal+c+1] = guides[i].targetData[xy*4+3]; } else if (numChannels>1) { targetGuides[xy*numGuideChannelsTotal+c+1] = guides[i].targetData[xy*4+1]; } if (numChannels>2) { targetGuides[xy*numGuideChannelsTotal+c+2] = guides[i].targetData[xy*4+2]; } if (numChannels>3) { targetGuides[xy*numGuideChannelsTotal+c+3] = guides[i].targetData[xy*4+3]; } c += numChannels; } } std::vector styleWeights(numStyleChannelsTotal); if (isnan(styleWeight)) { styleWeight = 1.0f; } for(int i=0;i guideWeights(numGuideChannelsTotal); { int c = 0; for(int i=0;i=0;level--) { if (min(pyramidLevelSize(std::min(V2i(sourceWidth,sourceHeight),V2i(targetWidth,targetHeight)),level)) >= (2*patchSize+1)) { maxPyramidLevels = level+1; break; } } if (numPyramidLevels==-1) { numPyramidLevels = maxPyramidLevels; } numPyramidLevels = std::min(numPyramidLevels,maxPyramidLevels); std::vector numSearchVoteItersPerLevel(numPyramidLevels); std::vector numPatchMatchItersPerLevel(numPyramidLevels); std::vector stopThresholdPerLevel(numPyramidLevels); for(int i=0;i output(targetWidth*targetHeight*numStyleChannelsTotal); printf("uniformity: %.0f\n",uniformityWeight); printf("patchsize: %d\n",patchSize); printf("pyramidlevels: %d\n",numPyramidLevels); printf("searchvoteiters: %d\n",numSearchVoteIters); printf("patchmatchiters: %d\n",numPatchMatchIters); printf("stopthreshold: %d\n",stopThreshold); printf("backend: %s\n",backendToString(backend).c_str()); ebsynthRun(backend, numStyleChannelsTotal, numGuideChannelsTotal, sourceWidth, sourceHeight, sourceStyle.data(), sourceGuides.data(), targetWidth, targetHeight, targetGuides.data(), NULL, styleWeights.data(), guideWeights.data(), uniformityWeight, patchSize, EBSYNTH_VOTEMODE_PLAIN, numPyramidLevels, numSearchVoteItersPerLevel.data(), numPatchMatchItersPerLevel.data(), stopThresholdPerLevel.data(), NULL, output.data()); stbi_write_png(outputFileName.c_str(),targetWidth,targetHeight,numStyleChannelsTotal,output.data(),numStyleChannelsTotal*targetWidth); printf("result was written to %s\n",outputFileName.c_str()); stbi_image_free(sourceStyleData); for(int i=0;i