Skip to content

Commit

Permalink
add option to perform additional polishing pass with 3x3 patches
Browse files Browse the repository at this point in the history
  • Loading branch information
jamriska committed Oct 3, 2018
1 parent 9f59b13 commit 5e483f1
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 84 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -28,6 +28,7 @@ ebsynth -style <style.png> -guide <source.png> <target.png> -output <output.png>
-pyramidlevels <number>
-searchvoteiters <number>
-patchmatchiters <number>
-extrapass3x3
-backend [cpu|cuda]
```

Expand Down
2 changes: 2 additions & 0 deletions include/ebsynth.h
Expand Up @@ -63,6 +63,8 @@ void ebsynthRun(int ebsynthBackend, // use BACKEND_CUDA for maxim

int* stopThresholdPerLevel, // stop improving pixel when its change since last iteration falls under this threshold

int extraPass3x3, // perform additional polishing pass with 3x3 patches at the finest level, use 0 to disable

void* outputNnfData, // (width * height * 2) ints, scan-line order; pass NULL to ignore
void* outputImageData // (width * height * numStyleChannels) bytes, scan-line order
);
Expand Down
13 changes: 12 additions & 1 deletion src/ebsynth.cpp
Expand Up @@ -30,10 +30,11 @@ void ebsynthRun(int ebsynthBackend,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
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;
void (*backendDispatch)(int,int,int,int,void*,void*,int,int,void*,void*,float*,float*,float,int,int,int,int*,int*,int*,int,void*,void*) = 0;

if (ebsynthBackend==EBSYNTH_BACKEND_CPU ) { backendDispatch = ebsynthRunCpu; }
else if (ebsynthBackend==EBSYNTH_BACKEND_CUDA) { backendDispatch = ebsynthRunCuda; }
Expand All @@ -60,6 +61,7 @@ void ebsynthRun(int ebsynthBackend,
numSearchVoteItersPerLevel,
numPatchMatchItersPerLevel,
stopThresholdPerLevel,
extraPass3x3,
outputNnfData,
outputImageData);
}
Expand Down Expand Up @@ -256,6 +258,7 @@ int main(int argc,char** argv)
printf(" -searchvoteiters <number>\n");
printf(" -patchmatchiters <number>\n");
printf(" -stopthreshold <value>\n");
printf(" -extrapass3x3\n");
printf(" -backend [cpu|cuda]\n");
printf("\n");
return 1;
Expand Down Expand Up @@ -290,6 +293,7 @@ int main(int argc,char** argv)
int numSearchVoteIters = 6;
int numPatchMatchIters = 4;
int stopThreshold = 5;
int extraPass3x3 = 0;
int backend = ebsynthBackendAvailable(EBSYNTH_BACKEND_CUDA) ? EBSYNTH_BACKEND_CUDA : EBSYNTH_BACKEND_CPU;

{
Expand Down Expand Up @@ -369,6 +373,11 @@ int main(int argc,char** argv)

argi++;
}
else if (argi<args.size() && args[argi]=="-extrapass3x3")
{
extraPass3x3 = 1;
argi++;
}
else
{
printf("error: unrecognized option '%s'\n",args[argi].c_str());
Expand Down Expand Up @@ -510,6 +519,7 @@ int main(int argc,char** argv)
printf("searchvoteiters: %d\n",numSearchVoteIters);
printf("patchmatchiters: %d\n",numPatchMatchIters);
printf("stopthreshold: %d\n",stopThreshold);
printf("extrapass3x3: %s\n",extraPass3x3!=0?"yes":"no");
printf("backend: %s\n",backendToString(backend).c_str());

ebsynthRun(backend,
Expand All @@ -532,6 +542,7 @@ int main(int argc,char** argv)
numSearchVoteItersPerLevel.data(),
numPatchMatchItersPerLevel.data(),
stopThresholdPerLevel.data(),
extraPass3x3,
NULL,
output.data());

Expand Down
98 changes: 56 additions & 42 deletions src/ebsynth_cpu.cpp
Expand Up @@ -681,6 +681,7 @@ void ebsynthCpu(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData)
{
Expand Down Expand Up @@ -741,39 +742,37 @@ void ebsynthCpu(int numStyleChannels,

for (int level=0;level<pyramid.size();level++)
{
const V2i levelSourceSize = V2i(pyramid[level].sourceWidth,pyramid[level].sourceHeight);
const V2i levelTargetSize = V2i(pyramid[level].targetWidth,pyramid[level].targetHeight);

pyramid[level].targetStyle = Array2<Vec<NS,unsigned char>>(levelTargetSize);
pyramid[level].targetStyle2 = Array2<Vec<NS,unsigned char>>(levelTargetSize);
//pyramid[level].mask = Array2<unsigned char>(levelTargetSize);
//pyramid[level].mask2 = Array2<unsigned char>(levelTargetSize);
pyramid[level].NNF = Array2<Vec<2,int>>(levelTargetSize);
//pyramid[level].NNF2 = Array2<Vec<2,int>>(levelTargetSize);
pyramid[level].Omega = Array2<int>(levelSourceSize);
pyramid[level].E = Array2<float>(levelTargetSize);

if (level<levelCount-1)
if (!inExtraPass)
{
pyramid[level].sourceStyle = Array2<Vec<NS,unsigned char>>(levelSourceSize);
pyramid[level].sourceGuide = Array2<Vec<NG,unsigned char>>(levelSourceSize);
pyramid[level].targetGuide = Array2<Vec<NG,unsigned char>>(levelTargetSize);
const V2i levelSourceSize = V2i(pyramid[level].sourceWidth,pyramid[level].sourceHeight);
const V2i levelTargetSize = V2i(pyramid[level].targetWidth,pyramid[level].targetHeight);

pyramid[level].targetStyle = Array2<Vec<NS,unsigned char>>(levelTargetSize);
pyramid[level].targetStyle2 = Array2<Vec<NS,unsigned char>>(levelTargetSize);
//pyramid[level].mask = Array2<unsigned char>(levelTargetSize);
//pyramid[level].mask2 = Array2<unsigned char>(levelTargetSize);
pyramid[level].NNF = Array2<Vec<2,int>>(levelTargetSize);
//pyramid[level].NNF2 = Array2<Vec<2,int>>(levelTargetSize);
pyramid[level].Omega = Array2<int>(levelSourceSize);
pyramid[level].E = Array2<float>(levelTargetSize);

if (level<levelCount-1)
{
pyramid[level].sourceStyle = Array2<Vec<NS,unsigned char>>(levelSourceSize);
pyramid[level].sourceGuide = Array2<Vec<NG,unsigned char>>(levelSourceSize);
pyramid[level].targetGuide = Array2<Vec<NG,unsigned char>>(levelTargetSize);

resampleCPU(pyramid[level].sourceStyle,pyramid[levelCount-1].sourceStyle);
resampleCPU(pyramid[level].sourceGuide,pyramid[levelCount-1].sourceGuide);
resampleCPU(pyramid[level].targetGuide,pyramid[levelCount-1].targetGuide);
resampleCPU(pyramid[level].sourceStyle,pyramid[levelCount-1].sourceStyle);
resampleCPU(pyramid[level].sourceGuide,pyramid[levelCount-1].sourceGuide);
resampleCPU(pyramid[level].targetGuide,pyramid[levelCount-1].targetGuide);

if (targetModulationData)
{
resampleCPU(pyramid[level].targetModulation,pyramid[levelCount-1].targetModulation);
pyramid[level].targetModulation = Array2<Vec<NG,unsigned char>>(levelTargetSize);
if (targetModulationData)
{
resampleCPU(pyramid[level].targetModulation,pyramid[levelCount-1].targetModulation);
pyramid[level].targetModulation = Array2<Vec<NG,unsigned char>>(levelTargetSize);
}
}
}

/////////////////////////////////////////////////////////////////////////////

if (!inExtraPass)
{
A2V2i cpu_NNF;
if (level>0)
{
Expand Down Expand Up @@ -956,23 +955,36 @@ void ebsynthCpu(int numStyleChannels,
}
}

if (level==levelCount-1)
{
if (level==levelCount-1 && (extraPass3x3==0 || (extraPass3x3!=0 && inExtraPass)))
{
if (outputNnfData!=NULL) { copy(&outputNnfData,pyramid[level].NNF); }
copy(&outputImageData,pyramid[level].targetStyle);
}

pyramid[level].sourceStyle = Array2<Vec<NS,unsigned char>>();
pyramid[level].sourceGuide = Array2<Vec<NG,unsigned char>>();
pyramid[level].targetGuide = Array2<Vec<NG,unsigned char>>();
pyramid[level].targetStyle = Array2<Vec<NS,unsigned char>>();
pyramid[level].targetStyle2 = Array2<Vec<NS,unsigned char>>();
//pyramid[level].mask = Array2<unsigned char>();
//pyramid[level].mask2 = Array2<unsigned char>();
//pyramid[level].NNF2 = Array2<Vec<2,int>>();
pyramid[level].Omega = Array2<int>();
pyramid[level].E = Array2<float>();
if (targetModulationData) { pyramid[level].targetModulation = Array2<Vec<NG,unsigned char>>(); }
if ((level<levelCount-1) ||
(extraPass3x3==0) ||
(extraPass3x3!=0 && inExtraPass))
{
pyramid[level].sourceStyle = Array2<Vec<NS,unsigned char>>();
pyramid[level].sourceGuide = Array2<Vec<NG,unsigned char>>();
pyramid[level].targetGuide = Array2<Vec<NG,unsigned char>>();
pyramid[level].targetStyle = Array2<Vec<NS,unsigned char>>();
pyramid[level].targetStyle2 = Array2<Vec<NS,unsigned char>>();
//pyramid[level].mask = Array2<unsigned char>();
//pyramid[level].mask2 = Array2<unsigned char>();
//pyramid[level].NNF2 = Array2<Vec<2,int>>();
pyramid[level].Omega = Array2<int>();
pyramid[level].E = Array2<float>();
if (targetModulationData) { pyramid[level].targetModulation = Array2<Vec<NG,unsigned char>>(); }
}

if (level==levelCount-1 && (extraPass3x3!=0) && !inExtraPass)
{
inExtraPass = true;
level--;
patchSize = 3;
uniformityWeight = 0;
}
}

pyramid[levelCount-1].NNF = Array2<Vec<2,int>>();
Expand All @@ -997,10 +1009,11 @@ void ebsynthRunCpu(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData)
{
void (*const dispatchEbsynth[EBSYNTH_MAX_GUIDE_CHANNELS][EBSYNTH_MAX_STYLE_CHANNELS])(int,int,int,int,void*,void*,int,int,void*,void*,float*,float*,float,int,int,int,int*,int*,int*,void*,void*) =
void (*const dispatchEbsynth[EBSYNTH_MAX_GUIDE_CHANNELS][EBSYNTH_MAX_STYLE_CHANNELS])(int,int,int,int,void*,void*,int,int,void*,void*,float*,float*,float,int,int,int,int*,int*,int*,int,void*,void*) =
{
{ ebsynthCpu<1, 1>, ebsynthCpu<2, 1>, ebsynthCpu<3, 1>, ebsynthCpu<4, 1>, ebsynthCpu<5, 1>, ebsynthCpu<6, 1>, ebsynthCpu<7, 1>, ebsynthCpu<8, 1> },
{ ebsynthCpu<1, 2>, ebsynthCpu<2, 2>, ebsynthCpu<3, 2>, ebsynthCpu<4, 2>, ebsynthCpu<5, 2>, ebsynthCpu<6, 2>, ebsynthCpu<7, 2>, ebsynthCpu<8, 2> },
Expand Down Expand Up @@ -1050,6 +1063,7 @@ void ebsynthRunCpu(int numStyleChannels,
numSearchVoteItersPerLevel,
numPatchMatchItersPerLevel,
stopThresholdPerLevel,
extraPass3x3,
outputNnfData,
outputImageData);
}
Expand Down
1 change: 1 addition & 0 deletions src/ebsynth_cpu.h
Expand Up @@ -24,6 +24,7 @@ void ebsynthRunCpu(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData);

Expand Down
96 changes: 55 additions & 41 deletions src/ebsynth_cuda.cu
Expand Up @@ -764,6 +764,7 @@ void ebsynthCuda(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData)
{
Expand Down Expand Up @@ -826,39 +827,37 @@ void ebsynthCuda(int numStyleChannels,

for (int level=0;level<pyramid.size();level++)
{
const V2i levelSourceSize = V2i(pyramid[level].sourceWidth,pyramid[level].sourceHeight);
const V2i levelTargetSize = V2i(pyramid[level].targetWidth,pyramid[level].targetHeight);

pyramid[level].targetStyle = TexArray2<NS,unsigned char>(levelTargetSize);
pyramid[level].targetStyle2 = TexArray2<NS,unsigned char>(levelTargetSize);
pyramid[level].mask = TexArray2<1,unsigned char>(levelTargetSize);
pyramid[level].mask2 = TexArray2<1,unsigned char>(levelTargetSize);
pyramid[level].NNF = TexArray2<2,int>(levelTargetSize);
pyramid[level].NNF2 = TexArray2<2,int>(levelTargetSize);
pyramid[level].Omega = MemArray2<int>(levelSourceSize);
pyramid[level].E = TexArray2<1,float>(levelTargetSize);

if (level<levelCount-1)
if (!inExtraPass)
{
pyramid[level].sourceStyle = TexArray2<NS,unsigned char>(levelSourceSize);
pyramid[level].sourceGuide = TexArray2<NG,unsigned char>(levelSourceSize);
pyramid[level].targetGuide = TexArray2<NG,unsigned char>(levelTargetSize);
const V2i levelSourceSize = V2i(pyramid[level].sourceWidth,pyramid[level].sourceHeight);
const V2i levelTargetSize = V2i(pyramid[level].targetWidth,pyramid[level].targetHeight);

pyramid[level].targetStyle = TexArray2<NS,unsigned char>(levelTargetSize);
pyramid[level].targetStyle2 = TexArray2<NS,unsigned char>(levelTargetSize);
pyramid[level].mask = TexArray2<1,unsigned char>(levelTargetSize);
pyramid[level].mask2 = TexArray2<1,unsigned char>(levelTargetSize);
pyramid[level].NNF = TexArray2<2,int>(levelTargetSize);
pyramid[level].NNF2 = TexArray2<2,int>(levelTargetSize);
pyramid[level].Omega = MemArray2<int>(levelSourceSize);
pyramid[level].E = TexArray2<1,float>(levelTargetSize);

if (level<levelCount-1)
{
pyramid[level].sourceStyle = TexArray2<NS,unsigned char>(levelSourceSize);
pyramid[level].sourceGuide = TexArray2<NG,unsigned char>(levelSourceSize);
pyramid[level].targetGuide = TexArray2<NG,unsigned char>(levelTargetSize);

resampleGPU(pyramid[level].sourceStyle,pyramid[levelCount-1].sourceStyle);
resampleGPU(pyramid[level].sourceGuide,pyramid[levelCount-1].sourceGuide);
resampleGPU(pyramid[level].targetGuide,pyramid[levelCount-1].targetGuide);
resampleGPU(pyramid[level].sourceStyle,pyramid[levelCount-1].sourceStyle);
resampleGPU(pyramid[level].sourceGuide,pyramid[levelCount-1].sourceGuide);
resampleGPU(pyramid[level].targetGuide,pyramid[levelCount-1].targetGuide);

if (targetModulationData)
{
resampleGPU(pyramid[level].targetModulation,pyramid[levelCount-1].targetModulation);
pyramid[level].targetModulation = TexArray2<NG,unsigned char>(levelTargetSize);
if (targetModulationData)
{
resampleGPU(pyramid[level].targetModulation,pyramid[levelCount-1].targetModulation);
pyramid[level].targetModulation = TexArray2<NG,unsigned char>(levelTargetSize);
}
}
}

/////////////////////////////////////////////////////////////////////////////

if (!inExtraPass)
{
A2V2i cpu_NNF;
if (level>0)
{
Expand Down Expand Up @@ -1064,23 +1063,36 @@ void ebsynthCuda(int numStyleChannels,
}
}

if (level==levelCount-1)
if (level==levelCount-1 && (extraPass3x3==0 || (extraPass3x3!=0 && inExtraPass)))
{
if (outputNnfData!=NULL) { copy(&outputNnfData,pyramid[level].NNF); }
copy(&outputImageData,pyramid[level].targetStyle);
}

pyramid[level].sourceStyle.destroy();
pyramid[level].sourceGuide.destroy();
pyramid[level].targetGuide.destroy();
pyramid[level].targetStyle.destroy();
pyramid[level].targetStyle2.destroy();
pyramid[level].mask.destroy();
pyramid[level].mask2.destroy();
pyramid[level].NNF2.destroy();
pyramid[level].Omega.destroy();
pyramid[level].E.destroy();
if (targetModulationData) { pyramid[level].targetModulation.destroy(); }
if ((level<levelCount-1) ||
(extraPass3x3==0) ||
(extraPass3x3!=0 && inExtraPass))
{
pyramid[level].sourceStyle.destroy();
pyramid[level].sourceGuide.destroy();
pyramid[level].targetGuide.destroy();
pyramid[level].targetStyle.destroy();
pyramid[level].targetStyle2.destroy();
pyramid[level].mask.destroy();
pyramid[level].mask2.destroy();
pyramid[level].NNF2.destroy();
pyramid[level].Omega.destroy();
pyramid[level].E.destroy();
if (targetModulationData) { pyramid[level].targetModulation.destroy(); }
}

if (level==levelCount-1 && (extraPass3x3!=0) && !inExtraPass)
{
inExtraPass = true;
level--;
patchSize = 3;
uniformityWeight = 0;
}
}

pyramid[levelCount-1].NNF.destroy();
Expand All @@ -1107,10 +1119,11 @@ void ebsynthRunCuda(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData)
{
void (*const dispatchEbsynth[EBSYNTH_MAX_GUIDE_CHANNELS][EBSYNTH_MAX_STYLE_CHANNELS])(int,int,int,int,void*,void*,int,int,void*,void*,float*,float*,float,int,int,int,int*,int*,int*,void*,void*) =
void (*const dispatchEbsynth[EBSYNTH_MAX_GUIDE_CHANNELS][EBSYNTH_MAX_STYLE_CHANNELS])(int,int,int,int,void*,void*,int,int,void*,void*,float*,float*,float,int,int,int,int*,int*,int*,int,void*,void*) =
{
{ ebsynthCuda<1, 1>, ebsynthCuda<2, 1>, ebsynthCuda<3, 1>, ebsynthCuda<4, 1>, ebsynthCuda<5, 1>, ebsynthCuda<6, 1>, ebsynthCuda<7, 1>, ebsynthCuda<8, 1> },
{ ebsynthCuda<1, 2>, ebsynthCuda<2, 2>, ebsynthCuda<3, 2>, ebsynthCuda<4, 2>, ebsynthCuda<5, 2>, ebsynthCuda<6, 2>, ebsynthCuda<7, 2>, ebsynthCuda<8, 2> },
Expand Down Expand Up @@ -1160,6 +1173,7 @@ void ebsynthRunCuda(int numStyleChannels,
numSearchVoteItersPerLevel,
numPatchMatchItersPerLevel,
stopThresholdPerLevel,
extraPass3x3,
outputNnfData,
outputImageData);
}
Expand Down
1 change: 1 addition & 0 deletions src/ebsynth_cuda.h
Expand Up @@ -24,6 +24,7 @@ void ebsynthRunCuda(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData);

Expand Down
1 change: 1 addition & 0 deletions src/ebsynth_nocuda.cpp
Expand Up @@ -21,6 +21,7 @@ void ebsynthRunCuda(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData)
{
Expand Down

0 comments on commit 5e483f1

Please sign in to comment.