add option to perform additional polishing pass with 3x3 patches

This commit is contained in:
Ondrej Jamriska
2018-10-03 12:23:02 +02:00
parent 9f59b13cb7
commit 5e483f122c
8 changed files with 135 additions and 90 deletions

View File

@@ -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]
```

View File

@@ -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
);

View File

@@ -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; }
@@ -60,6 +61,7 @@ void ebsynthRun(int ebsynthBackend,
numSearchVoteItersPerLevel,
numPatchMatchItersPerLevel,
stopThresholdPerLevel,
extraPass3x3,
outputNnfData,
outputImageData);
}
@@ -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;
@@ -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;
{
@@ -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());
@@ -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,
@@ -532,6 +542,7 @@ int main(int argc,char** argv)
numSearchVoteItersPerLevel.data(),
numPatchMatchItersPerLevel.data(),
stopThresholdPerLevel.data(),
extraPass3x3,
NULL,
output.data());

View File

@@ -681,6 +681,7 @@ void ebsynthCpu(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData)
{
@@ -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)
{
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);
if (targetModulationData)
{
resampleCPU(pyramid[level].targetModulation,pyramid[levelCount-1].targetModulation);
pyramid[level].targetModulation = Array2<Vec<NG,unsigned char>>(levelTargetSize);
}
}
/////////////////////////////////////////////////////////////////////////////
if (!inExtraPass)
{
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);
if (targetModulationData)
{
resampleCPU(pyramid[level].targetModulation,pyramid[levelCount-1].targetModulation);
pyramid[level].targetModulation = Array2<Vec<NG,unsigned char>>(levelTargetSize);
}
}
A2V2i cpu_NNF;
if (level>0)
{
@@ -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>>();
@@ -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> },
@@ -1050,6 +1063,7 @@ void ebsynthRunCpu(int numStyleChannels,
numSearchVoteItersPerLevel,
numPatchMatchItersPerLevel,
stopThresholdPerLevel,
extraPass3x3,
outputNnfData,
outputImageData);
}

View File

@@ -24,6 +24,7 @@ void ebsynthRunCpu(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData);

View File

@@ -764,6 +764,7 @@ void ebsynthCuda(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData)
{
@@ -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)
{
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);
if (targetModulationData)
{
resampleGPU(pyramid[level].targetModulation,pyramid[levelCount-1].targetModulation);
pyramid[level].targetModulation = TexArray2<NG,unsigned char>(levelTargetSize);
}
}
/////////////////////////////////////////////////////////////////////////////
if (!inExtraPass)
{
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);
if (targetModulationData)
{
resampleGPU(pyramid[level].targetModulation,pyramid[levelCount-1].targetModulation);
pyramid[level].targetModulation = TexArray2<NG,unsigned char>(levelTargetSize);
}
}
A2V2i cpu_NNF;
if (level>0)
{
@@ -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();
@@ -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> },
@@ -1160,6 +1173,7 @@ void ebsynthRunCuda(int numStyleChannels,
numSearchVoteItersPerLevel,
numPatchMatchItersPerLevel,
stopThresholdPerLevel,
extraPass3x3,
outputNnfData,
outputImageData);
}

View File

@@ -24,6 +24,7 @@ void ebsynthRunCuda(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData);

View File

@@ -21,6 +21,7 @@ void ebsynthRunCuda(int numStyleChannels,
int* numSearchVoteItersPerLevel,
int* numPatchMatchItersPerLevel,
int* stopThresholdPerLevel,
int extraPass3x3,
void* outputNnfData,
void* outputImageData)
{