Skip to content

Commit

Permalink
Add parameter sigma_v
Browse files Browse the repository at this point in the history
  • Loading branch information
HolyWu committed Feb 5, 2019
1 parent b48f29b commit 6a424f8
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 48 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ Ported from AviSynth plugin http://bengal.missouri.edu/~kes25c/
Usage
=====

tcanny.TCanny(clip clip[, float[] sigma=1.5, float t_h=8.0, float t_l=1.0, int mode=0, int op=1, float gmmax=50.0, int opt=0, int[] planes=[0, 1, 2]])
tcanny.TCanny(clip clip[, float[] sigma=1.5, float[] sigma_v=sigma, float t_h=8.0, float t_l=1.0, int mode=0, int op=1, float gmmax=50.0, int opt=0, int[] planes=[0, 1, 2]])

* clip: Clip to process. Any planar format with either integer sample type of 8-16 bit depth or float sample type of 32 bit depth is supported.

* sigma: Standard deviation of gaussian blur. If a single `sigma` is specified, it will be used for all planes. If two `sigma` are given then the second value will be used for the third plane as well. The value used internally will be adjusted according to the subsampling of the second and third plane in each direction.
* sigma: Standard deviation of horizontal gaussian blur. If a single `sigma` is specified, it will be used for all planes. If two `sigma` are given then the second value will be used for the third plane as well.

* sigma_v: Standard deviation of vertical gaussian blur.

* t_h: High gradient magnitude threshold for hysteresis.

Expand Down Expand Up @@ -43,7 +45,7 @@ Usage

---

tcanny.TCannyCL(clip clip[, float[] sigma=1.5, float t_h=8.0, float t_l=1.0, int mode=0, int op=1, float gmmax=50.0, int device=-1, bint list_device=False, bint info=False, int[] planes=[0, 1, 2]])
tcanny.TCannyCL(clip clip[, float[] sigma=1.5, float[] sigma_v=sigma, float t_h=8.0, float t_l=1.0, int mode=0, int op=1, float gmmax=50.0, int device=-1, bint list_device=False, bint info=False, int[] planes=[0, 1, 2]])

* device: Sets target OpenCL device. Use `list_device` to get the index of the available devices. By default the default device is selected.

Expand Down
72 changes: 48 additions & 24 deletions TCanny/TCanny.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,24 +492,36 @@ static void VS_CC tcannyCreate(const VSMap *in, VSMap *out, void *userData, VSCo
if (d->vi->height < 2)
throw std::string{ "the clip's height must be greater than or equal to 2" };

const int numSigma = vsapi->propNumElements(in, "sigma");
if (numSigma > d->vi->format->numPlanes)
throw std::string{ "more sigma given than the number of planes" };
const int numSigmaH = vsapi->propNumElements(in, "sigma");
if (numSigmaH > d->vi->format->numPlanes)
throw std::string{ "more sigma given than there are planes" };

const int numSigmaV = vsapi->propNumElements(in, "sigma_v");
if (numSigmaV > d->vi->format->numPlanes)
throw std::string{ "more sigma_v given than there are planes" };

float sigmaH[3], sigmaV[3];

for (int i = 0; i < 3; i++) {
if (i < numSigma) {
sigmaH[i] = sigmaV[i] = static_cast<float>(vsapi->propGetFloat(in, "sigma", i, nullptr));
} else if (i == 0) {
sigmaH[0] = sigmaV[0] = 1.5f;
} else if (i == 1) {
if (i < numSigmaH)
sigmaH[i] = static_cast<float>(vsapi->propGetFloat(in, "sigma", i, nullptr));
else if (i == 0)
sigmaH[0] = 1.5f;
else if (i == 1)
sigmaH[1] = sigmaH[0] / (1 << d->vi->format->subSamplingW);
sigmaV[1] = sigmaV[0] / (1 << d->vi->format->subSamplingH);
} else {
else
sigmaH[2] = sigmaH[1];

if (i < numSigmaV)
sigmaV[i] = static_cast<float>(vsapi->propGetFloat(in, "sigma_v", i, nullptr));
else if (i < numSigmaH)
sigmaV[i] = sigmaH[i];
else if (i == 0)
sigmaV[0] = 1.5f;
else if (i == 1)
sigmaV[1] = sigmaV[0] / (1 << d->vi->format->subSamplingH);
else
sigmaV[2] = sigmaV[1];
}
}

d->t_h = static_cast<float>(vsapi->propGetFloat(in, "t_h", 0, &err));
Expand Down Expand Up @@ -552,6 +564,9 @@ static void VS_CC tcannyCreate(const VSMap *in, VSMap *out, void *userData, VSCo
for (int i = 0; i < 3; i++) {
if (sigmaH[i] < 0.f)
throw std::string{ "sigma must be greater than or equal to 0.0" };

if (sigmaV[i] < 0.f)
throw std::string{ "sigma_v must be greater than or equal to 0.0" };
}

if (d->t_l >= d->t_h)
Expand Down Expand Up @@ -600,21 +615,28 @@ static void VS_CC tcannyCreate(const VSMap *in, VSMap *out, void *userData, VSCo
}

for (int plane = 0; plane < d->vi->format->numPlanes; plane++) {
if (d->process[plane] && sigmaH[plane]) {
d->weightsH[plane] = gaussianWeights(sigmaH[plane], d->radiusH[plane]);
d->weightsV[plane] = gaussianWeights(sigmaV[plane], d->radiusV[plane]);
if (!d->weightsH[plane] || !d->weightsV[plane])
throw std::string{ "malloc failure (weights)" };

const int width = d->vi->width >> (plane ? d->vi->format->subSamplingW : 0);
const int height = d->vi->height >> (plane ? d->vi->format->subSamplingH : 0);
const std::string planeOrder{ plane == 0 ? "first" : (plane == 1 ? "second" : "third") };
if (d->process[plane]) {
if (sigmaH[plane]) {
d->weightsH[plane] = gaussianWeights(sigmaH[plane], d->radiusH[plane]);
if (!d->weightsH[plane])
throw std::string{ "malloc failure (weightsH)" };

const int width = d->vi->width >> (plane ? d->vi->format->subSamplingW : 0);
const std::string planeOrder{ plane == 0 ? "first" : (plane == 1 ? "second" : "third") };
if (width < d->radiusH[plane] + 1)
throw std::string{ "the " + planeOrder + " plane's width must be greater than or equal to " + std::to_string(d->radiusH[plane] + 1) + " for specified sigma" };
}

if (width < d->radiusH[plane] + 1)
throw std::string{ "the " + planeOrder + " plane's width must be greater than or equal to " + std::to_string(d->radiusH[plane] + 1) + " for specified sigma" };
if (sigmaV[plane]) {
d->weightsV[plane] = gaussianWeights(sigmaV[plane], d->radiusV[plane]);
if (!d->weightsV[plane])
throw std::string{ "malloc failure (weightsV)" };

if (height < d->radiusV[plane] + 1)
throw std::string{ "the " + planeOrder + " plane's height must be greater than or equal to " + std::to_string(d->radiusV[plane] + 1) + " for specified sigma" };
const int height = d->vi->height >> (plane ? d->vi->format->subSamplingH : 0);
const std::string planeOrder{ plane == 0 ? "first" : (plane == 1 ? "second" : "third") };
if (height < d->radiusV[plane] + 1)
throw std::string{ "the " + planeOrder + " plane's height must be greater than or equal to " + std::to_string(d->radiusV[plane] + 1) + " for specified sigma_v" };
}
}
}

Expand Down Expand Up @@ -643,6 +665,7 @@ VS_EXTERNAL_API(void) VapourSynthPluginInit(VSConfigPlugin configFunc, VSRegiste
registerFunc("TCanny",
"clip:clip;"
"sigma:float[]:opt;"
"sigma_v:float[]:opt;"
"t_h:float:opt;"
"t_l:float:opt;"
"mode:int:opt;"
Expand All @@ -656,6 +679,7 @@ VS_EXTERNAL_API(void) VapourSynthPluginInit(VSConfigPlugin configFunc, VSRegiste
registerFunc("TCannyCL",
"clip:clip;"
"sigma:float[]:opt;"
"sigma_v:float[]:opt;"
"t_h:float:opt;"
"t_l:float:opt;"
"mode:int:opt;"
Expand Down
66 changes: 45 additions & 21 deletions TCanny/TCannyCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ static const VSFrameRef *VS_CC tcannyclGetFrame(int n, int activationReason, voi
queue.enqueue_write_image(srcImage, origin, region, srcp, stride);

if (d->radiusV[plane]) {
gaussianBlurV.set_args(srcImage, gradientImage, d->weightsV[plane], d->radiusV[plane], d->offset[plane]);
gaussianBlurV.set_args(srcImage, d->radiusH[plane] ? gradientImage : blurImage, d->weightsV[plane], d->radiusV[plane], d->offset[plane]);
queue.enqueue_nd_range_kernel(gaussianBlurV, 2, nullptr, globalWorkSize, nullptr);
} else {
copyPlane.set_args(srcImage, d->radiusH[plane] ? gradientImage : blurImage, d->offset[plane]);
Expand Down Expand Up @@ -239,24 +239,36 @@ void VS_CC tcannyclCreate(const VSMap *in, VSMap *out, void *userData, VSCore *c
(d->vi->format->sampleType == stFloat && d->vi->format->bitsPerSample != 32))
throw std::string{ "only constant format 8-16 bit integer and 32 bit float input supported" };

const int numSigma = vsapi->propNumElements(in, "sigma");
if (numSigma > d->vi->format->numPlanes)
throw std::string{ "more sigma given than the number of planes" };
const int numSigmaH = vsapi->propNumElements(in, "sigma");
if (numSigmaH > d->vi->format->numPlanes)
throw std::string{ "more sigma given than there are planes" };

const int numSigmaV = vsapi->propNumElements(in, "sigma_v");
if (numSigmaV > d->vi->format->numPlanes)
throw std::string{ "more sigma_v given than there are planes" };

float sigmaH[3], sigmaV[3];

for (int i = 0; i < 3; i++) {
if (i < numSigma) {
sigmaH[i] = sigmaV[i] = static_cast<float>(vsapi->propGetFloat(in, "sigma", i, nullptr));
} else if (i == 0) {
sigmaH[0] = sigmaV[0] = 1.5f;
} else if (i == 1) {
if (i < numSigmaH)
sigmaH[i] = static_cast<float>(vsapi->propGetFloat(in, "sigma", i, nullptr));
else if (i == 0)
sigmaH[0] = 1.5f;
else if (i == 1)
sigmaH[1] = sigmaH[0] / (1 << d->vi->format->subSamplingW);
sigmaV[1] = sigmaV[0] / (1 << d->vi->format->subSamplingH);
} else {
else
sigmaH[2] = sigmaH[1];

if (i < numSigmaV)
sigmaV[i] = static_cast<float>(vsapi->propGetFloat(in, "sigma_v", i, nullptr));
else if (i < numSigmaH)
sigmaV[i] = sigmaH[i];
else if (i == 0)
sigmaV[0] = 1.5f;
else if (i == 1)
sigmaV[1] = sigmaV[0] / (1 << d->vi->format->subSamplingH);
else
sigmaV[2] = sigmaV[1];
}
}

float t_h = static_cast<float>(vsapi->propGetFloat(in, "t_h", 0, &err));
Expand Down Expand Up @@ -301,6 +313,9 @@ void VS_CC tcannyclCreate(const VSMap *in, VSMap *out, void *userData, VSCore *c
for (int i = 0; i < 3; i++) {
if (sigmaH[i] < 0.f)
throw std::string{ "sigma must be greater than or equal to 0.0" };

if (sigmaV[i] < 0.f)
throw std::string{ "sigma_v must be greater than or equal to 0.0" };
}

if (t_l >= t_h)
Expand Down Expand Up @@ -433,17 +448,26 @@ void VS_CC tcannyclCreate(const VSMap *in, VSMap *out, void *userData, VSCore *c
}

for (int plane = 0; plane < d->vi->format->numPlanes; plane++) {
if (d->process[plane] && sigmaH[plane]) {
float * weightsH = gaussianWeights(sigmaH[plane], d->radiusH[plane]);
float * weightsV = gaussianWeights(sigmaV[plane], d->radiusV[plane]);
if (!weightsH || !weightsV)
throw std::string{ "malloc failure (weights)" };
if (d->process[plane]) {
if (sigmaH[plane]) {
float * weightsH = gaussianWeights(sigmaH[plane], d->radiusH[plane]);
if (!weightsH)
throw std::string{ "malloc failure (weightsH)" };

d->weightsH[plane] = compute::buffer{ d->ctx, (d->radiusH[plane] * 2 + 1) * sizeof(cl_float), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR | CL_MEM_HOST_NO_ACCESS, weightsH };
d->weightsV[plane] = compute::buffer{ d->ctx, (d->radiusV[plane] * 2 + 1) * sizeof(cl_float), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR | CL_MEM_HOST_NO_ACCESS, weightsV };
d->weightsH[plane] = compute::buffer{ d->ctx, (d->radiusH[plane] * 2 + 1) * sizeof(cl_float), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR | CL_MEM_HOST_NO_ACCESS, weightsH };

delete[] weightsH;
delete[] weightsV;
delete[] weightsH;
}

if (sigmaV[plane]) {
float * weightsV = gaussianWeights(sigmaV[plane], d->radiusV[plane]);
if (!weightsV)
throw std::string{ "malloc failure (weightsV)" };

d->weightsV[plane] = compute::buffer{ d->ctx, (d->radiusV[plane] * 2 + 1) * sizeof(cl_float), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR | CL_MEM_HOST_NO_ACCESS, weightsV };

delete[] weightsV;
}
}
}

Expand Down

0 comments on commit 6a424f8

Please sign in to comment.