Skip to content

Commit e0cc55e

Browse files
authored
Create half Gaussian kernel (#206)
Expose internally MakeHalfGaussian and update CreateGauss to optionally only generate half of a Gaussian kernel
1 parent d5e2be4 commit e0cc55e

8 files changed

Lines changed: 62 additions & 17 deletions

File tree

changelogs/diplib_next.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ date: 2020-00-00
3838
The low-level functions `dip::SymmetricEigenDecomposition2()` and `dip::SymmetricEigenDecomposition3()` add
3939
the same argument, but as an enum rather than a string.
4040

41+
- `dip::CreateGauss()` has a new argument, `extent`, which defaults to `"full"`. When set to `"half"`, the output
42+
is the first half (in 1D) or quadrant (in 2D) of the Gaussian kernel.
43+
4144
### Changed functionality
4245

4346
- All functions that compute a percentile (`dip::Percentile()`, `dip::PercentilePosition()`,

dipimage/derivative.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
%
3737
% DIPlib:
3838
% This function calls the DIPlib function <a href="https://diplib.org/diplib-docs/linear.html#dip-Derivative-Image-CL-Image-L-UnsignedArray--FloatArray--String-CL-StringArray-CL-dfloat-">dip::Derivative</a> (which calls <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussFIR-Image-CL-Image-L-FloatArray--UnsignedArray--StringArray-CL-dfloat-">dip::GaussFIR</a>,
39-
% <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussIIR-Image-CL-Image-L-FloatArray--UnsignedArray--StringArray-CL-UnsignedArray--String-CL-dfloat-">dip::GaussIIR</a>, <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussFT-Image-CL-Image-L-FloatArray--UnsignedArray--dfloat--String-CL-String-CL-StringArray-CL">dip::GaussFT</a> and <a href="https://diplib.org/diplib-docs/linear.html#dip-FiniteDifference-Image-CL-Image-L-UnsignedArray--String-CL-StringArray-CL-BooleanArray-">dip::FiniteDifference</a>) and <a href="https://diplib.org/diplib-docs/generation_test.html#dip-CreateGauss-Image-L-FloatArray-CL-UnsignedArray--dfloat--UnsignedArray-">dip::CreateGauss</a>.
39+
% <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussIIR-Image-CL-Image-L-FloatArray--UnsignedArray--StringArray-CL-UnsignedArray--String-CL-dfloat-">dip::GaussIIR</a>, <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussFT-Image-CL-Image-L-FloatArray--UnsignedArray--dfloat--String-CL-String-CL-StringArray-CL">dip::GaussFT</a> and <a href="https://diplib.org/diplib-docs/linear.html#dip-FiniteDifference-Image-CL-Image-L-UnsignedArray--String-CL-StringArray-CL-BooleanArray-">dip::FiniteDifference</a>) and <a href="https://diplib.org/diplib-docs/generation_test.html#dip-CreateGauss-Image-L-FloatArray-CL-UnsignedArray--dfloat--UnsignedArray--String-CL">dip::CreateGauss</a>.
4040

4141
% (c)2017-2018, Cris Luengo.
4242
% Based on original DIPlib code: (c)1995-2014, Delft University of Technology.

dipimage/gaussf.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
%
3333
% DIPlib:
3434
% This function calls the DIPlib function <a href="https://diplib.org/diplib-docs/linear.html#dip-Derivative-Image-CL-Image-L-UnsignedArray--FloatArray--String-CL-StringArray-CL-dfloat-">dip::Derivative</a> (which calls <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussFIR-Image-CL-Image-L-FloatArray--UnsignedArray--StringArray-CL-dfloat-">dip::GaussFIR</a>,
35-
% <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussIIR-Image-CL-Image-L-FloatArray--UnsignedArray--StringArray-CL-UnsignedArray--String-CL-dfloat-">dip::GaussIIR</a> and <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussFT-Image-CL-Image-L-FloatArray--UnsignedArray--dfloat--String-CL-String-CL-StringArray-CL">dip::GaussFT</a>) and <a href="https://diplib.org/diplib-docs/generation_test.html#dip-CreateGauss-Image-L-FloatArray-CL-UnsignedArray--dfloat--UnsignedArray-">dip::CreateGauss</a>.
35+
% <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussIIR-Image-CL-Image-L-FloatArray--UnsignedArray--StringArray-CL-UnsignedArray--String-CL-dfloat-">dip::GaussIIR</a> and <a href="https://diplib.org/diplib-docs/linear.html#dip-GaussFT-Image-CL-Image-L-FloatArray--UnsignedArray--dfloat--String-CL-String-CL-StringArray-CL">dip::GaussFT</a>) and <a href="https://diplib.org/diplib-docs/generation_test.html#dip-CreateGauss-Image-L-FloatArray-CL-UnsignedArray--dfloat--UnsignedArray--String-CL">dip::CreateGauss</a>.
3636

3737
% (c)2017-2018, Cris Luengo.
3838
% Based on original DIPlib code: (c)1995-2014, Delft University of Technology.

include/diplib/generation.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,19 @@ DIP_NODISCARD inline Image CreateDelta( UnsignedArray const& sizes, String const
628628
return out;
629629
}
630630

631+
// Create a half Gaussian, used by MakeGaussian in linear/gauss.cpp (where it is defined)
632+
// Not documented because not a public function. We suggest you use `CreateGauss()` instead.
633+
// Length will be given by truncation and sigma, but limited to meaningful values.
634+
//
635+
// !!! warning
636+
// The second half of the gaussian will need to be scaled by -1.0 for odd derivative order (ex 1, 3, ...)
637+
// Defined in src/linear/gauss.cpp
638+
DIP_EXPORT std::vector< dfloat > MakeHalfGaussian(
639+
dfloat sigma,
640+
dip::uint derivativeOrder = 0,
641+
dfloat truncation = 3.0,
642+
DataType dt = DT_DFLOAT // if not DT_DFLOAT, assumed to be DT_SFLOAT
643+
);
631644

632645
// Create 1D Gaussian, used in linear/gauss.cpp (where it is defined) and in nonlinear/bilateral.cpp
633646
// Not documented because not a public function. We suggest you use `CreateGauss()` instead.
@@ -654,6 +667,10 @@ DIP_EXPORT std::vector< dfloat > MakeGaussian(
654667
/// By setting `exponents` to a positive value for each dimension, the created kernel will be multiplied by
655668
/// the coordinates to the power of `exponents`.
656669
///
670+
/// `extent` defaults to `"full"`. Set it to `"half"` to generate only the first half (along each dimension)
671+
/// of the kernel.
672+
/// The second half of the gaussian will need to be scaled by -1.0 for odd derivative order (ex 1, 3, ...)
673+
///
657674
/// !!! warning
658675
/// Convolving an image with the result of this function is much less efficient than calling \ref Gauss.
659676
// Defined in src/linear/gauss.cpp
@@ -662,16 +679,18 @@ DIP_EXPORT void CreateGauss(
662679
FloatArray const& sigmas,
663680
UnsignedArray derivativeOrder = { 0 },
664681
dfloat truncation = 3.0,
665-
UnsignedArray exponents = { 0 }
682+
UnsignedArray exponents = { 0 },
683+
String const& extent = "full"
666684
);
667685
DIP_NODISCARD inline Image CreateGauss(
668686
FloatArray const& sigmas,
669687
UnsignedArray derivativeOrder = { 0 },
670688
dfloat truncation = 3.0,
671-
UnsignedArray exponents = { 0 }
689+
UnsignedArray exponents = { 0 },
690+
String const& extent = "full"
672691
) {
673692
Image out;
674-
CreateGauss( out, sigmas, std::move( derivativeOrder ), truncation, std::move( exponents ));
693+
CreateGauss( out, sigmas, std::move( derivativeOrder ), truncation, std::move( exponents ), extent );
675694
return out;
676695
}
677696

pydip/src/documentation_strings.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ constexpr char const* dip·viewer·Manager·createWindow·WindowPtr· = "Create
147147
constexpr char const* dip·viewer·Manager·activeWindows = "Returns the number of managed windows.";
148148
constexpr char const* dip·viewer·Manager·destroyWindows = "Destroys all windows.";
149149
constexpr char const* dip·viewer·Manager·processEvents = "Processes event queue.";
150+
constexpr char const* dip·viewer·Manager·screenSize·C = "Returns the size of the screen in pixels.";
150151
constexpr char const* dip·viewer·Manager·swapBuffers·Window·P = "Swap display buffers.";
151152
constexpr char const* dip·viewer·Manager·setWindowTitle·Window·P·char·CP = "Sets a Window's title.";
152153
constexpr char const* dip·viewer·Manager·refreshWindow·Window·P = "Refresh a Window's contents.";
@@ -1970,7 +1971,7 @@ constexpr char const* dip·GaussianLineClip·Image·CL·Image·L·Image·Pixel·
19701971
constexpr char const* dip·FillDelta·Image·L·String·CL = "Fills an image with a delta function.";
19711972
constexpr char const* dip·CreateDelta·Image·L·UnsignedArray·CL·String·CL = "Creates a delta function image.";
19721973
constexpr char const* dip·CreateDelta·UnsignedArray·CL·String·CL = "Overload for the function above, which takes image sizes instead of an image.";
1973-
constexpr char const* dip·CreateGauss·Image·L·FloatArray·CL·UnsignedArray··dfloat··UnsignedArray· = "Creates a Gaussian kernel.";
1974+
constexpr char const* dip·CreateGauss·Image·L·FloatArray·CL·UnsignedArray··dfloat··UnsignedArray··String·CL = "Creates a Gaussian kernel.";
19741975
constexpr char const* dip·CreateGabor·Image·L·FloatArray·CL·FloatArray·CL·dfloat· = "Creates a Gabor kernel.";
19751976
constexpr char const* dip·FTEllipsoid·Image·L·FloatArray··dfloat· = "Generates the Fourier transform of an ellipsoid.";
19761977
constexpr char const* dip·FTEllipsoid·UnsignedArray·CL·FloatArray··dfloat· = "Overload for the function above, which takes image sizes instead of an image.";

pydip/src/documentation_urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
('dip.viewer.Manager.activeWindows', 'dip-viewer-Manager.html#dip-viewer-Manager-activeWindows'),
149149
('dip.viewer.Manager.destroyWindows', 'dip-viewer-Manager.html#dip-viewer-Manager-destroyWindows'),
150150
('dip.viewer.Manager.processEvents', 'dip-viewer-Manager.html#dip-viewer-Manager-processEvents'),
151+
('dip.viewer.Manager.screenSize', 'dip-viewer-Manager.html#dip-viewer-Manager-screenSize-C'),
151152
('dip.viewer.Manager.swapBuffers', 'dip-viewer-Manager.html#dip-viewer-Manager-swapBuffers-Window-P'),
152153
('dip.viewer.Manager.setWindowTitle', 'dip-viewer-Manager.html#dip-viewer-Manager-setWindowTitle-Window-P-char-CP'),
153154
('dip.viewer.Manager.refreshWindow', 'dip-viewer-Manager.html#dip-viewer-Manager-refreshWindow-Window-P'),
@@ -2012,7 +2013,7 @@
20122013
('dip.FillDelta', 'generation_test.html#dip-FillDelta-Image-L-String-CL'),
20132014
('dip.CreateDelta', 'generation_test.html#dip-CreateDelta-Image-L-UnsignedArray-CL-String-CL'),
20142015
('dip.CreateDelta', 'generation_test.html#dip-CreateDelta-UnsignedArray-CL-String-CL'),
2015-
('dip.CreateGauss', 'generation_test.html#dip-CreateGauss-Image-L-FloatArray-CL-UnsignedArray--dfloat--UnsignedArray-'),
2016+
('dip.CreateGauss', 'generation_test.html#dip-CreateGauss-Image-L-FloatArray-CL-UnsignedArray--dfloat--UnsignedArray--String-CL'),
20162017
('dip.CreateGabor', 'generation_test.html#dip-CreateGabor-Image-L-FloatArray-CL-FloatArray-CL-dfloat-'),
20172018
('dip.FTEllipsoid', 'generation_test.html#dip-FTEllipsoid-Image-L-FloatArray--dfloat-'),
20182019
('dip.FTEllipsoid', 'generation_test.html#dip-FTEllipsoid-UnsignedArray-CL-FloatArray--dfloat-'),

pydip/src/generation.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ void init_generation( py::module& m ) {
105105
"sizes"_a, "origin"_a = "", doc_strings::dip·CreateDelta·UnsignedArray·CL·String·CL );
106106
m.def( "CreateDelta", py::overload_cast< dip::Image&, dip::UnsignedArray const&, dip::String const& >( &dip::CreateDelta ),
107107
py::kw_only(), "out"_a, "sizes"_a, "origin"_a = "", doc_strings::dip·CreateDelta·Image·L·UnsignedArray·CL·String·CL );
108-
m.def( "CreateGauss", py::overload_cast< dip::FloatArray const&, dip::UnsignedArray, dip::dfloat, dip::UnsignedArray >( &dip::CreateGauss ),
109-
"sigmas"_a, "order"_a = dip::UnsignedArray{ 0 }, "truncation"_a = 3.0, "exponents"_a = dip::UnsignedArray{ 0 }, doc_strings::dip·CreateGauss·Image·L·FloatArray·CL·UnsignedArray··dfloat··UnsignedArray· );
110-
m.def( "CreateGauss", py::overload_cast< dip::Image&, dip::FloatArray const&, dip::UnsignedArray, dip::dfloat, dip::UnsignedArray >( &dip::CreateGauss ),
111-
py::kw_only(), "out"_a, "sigmas"_a, "order"_a = dip::UnsignedArray{ 0 }, "truncation"_a = 3.0, "exponents"_a = dip::UnsignedArray{ 0 }, doc_strings::dip·CreateGauss·Image·L·FloatArray·CL·UnsignedArray··dfloat··UnsignedArray· );
108+
m.def( "CreateGauss", py::overload_cast< dip::FloatArray const&, dip::UnsignedArray, dip::dfloat, dip::UnsignedArray, dip::String const& >( &dip::CreateGauss ),
109+
"sigmas"_a, "order"_a = dip::UnsignedArray{ 0 }, "truncation"_a = 3.0, "exponents"_a = dip::UnsignedArray{ 0 }, "extent"_a = "full", doc_strings::dip·CreateGauss·Image·L·FloatArray·CL·UnsignedArray··dfloat··UnsignedArray··String·CL );
110+
m.def( "CreateGauss", py::overload_cast< dip::Image&, dip::FloatArray const&, dip::UnsignedArray, dip::dfloat, dip::UnsignedArray, dip::String const& >( &dip::CreateGauss ),
111+
py::kw_only(), "out"_a, "sigmas"_a, "order"_a = dip::UnsignedArray{ 0 }, "truncation"_a = 3.0, "exponents"_a = dip::UnsignedArray{ 0 }, "extent"_a = "full", doc_strings::dip·CreateGauss·Image·L·FloatArray·CL·UnsignedArray··dfloat··UnsignedArray··String·CL );
112112
m.def( "CreateGabor", py::overload_cast< dip::FloatArray const&, dip::FloatArray const&, dip::dfloat >( &dip::CreateGabor ),
113113
"sigmas"_a, "frequencies"_a, "truncation"_a = 3.0, doc_strings::dip·CreateGabor·Image·L·FloatArray·CL·FloatArray·CL·dfloat· );
114114
m.def( "CreateGabor", py::overload_cast< dip::Image&, dip::FloatArray const&, dip::FloatArray const&, dip::dfloat >( &dip::CreateGabor ),

src/linear/gauss.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ inline dip::uint HalfGaussianSize(
5050
return clamp_cast< dip::uint >( std::ceil( truncation * sigma ));
5151
}
5252

53-
// Creates a half Gaussian kernel, with the x=0 at the right end (last element) of the output array.
54-
std::vector< dfloat > MakeHalfGaussian(
53+
std::vector< dfloat > MakeHalfGaussianInternal(
5554
dfloat sigma,
5655
dip::uint derivativeOrder,
5756
dfloat truncation,
@@ -148,6 +147,23 @@ std::vector< dfloat > MakeHalfGaussian(
148147

149148
} // namespace
150149

150+
// Creates a half Gaussian kernel, with the x=0 at the right end (last element) of the output array.
151+
std::vector< dfloat > MakeHalfGaussian(
152+
dfloat sigma,
153+
dip::uint derivativeOrder,
154+
dfloat truncation,
155+
DataType dt
156+
) {
157+
// Handle sigma == 0.0
158+
if( sigma == 0.0 ) {
159+
return { 1.0 };
160+
}
161+
// Create half Gaussian
162+
std::vector< dfloat > gaussian;
163+
DIP_STACK_TRACE_THIS( gaussian = MakeHalfGaussianInternal( sigma, derivativeOrder, truncation, dt ));
164+
return gaussian;
165+
}
166+
151167
// Create 1D full Gaussian
152168
std::vector< dfloat > MakeGaussian(
153169
dfloat sigma,
@@ -161,7 +177,7 @@ std::vector< dfloat > MakeGaussian(
161177
}
162178
// Create half Gaussian
163179
std::vector< dfloat > gaussian;
164-
DIP_STACK_TRACE_THIS( gaussian = MakeHalfGaussian( sigma, derivativeOrder, truncation, dt ));
180+
DIP_STACK_TRACE_THIS( gaussian = MakeHalfGaussianInternal( sigma, derivativeOrder, truncation, dt ));
165181
dip::uint halfFilterSize = gaussian.size() - 1;
166182
// Complete the Gaussian
167183
gaussian.resize( halfFilterSize * 2 + 1 );
@@ -177,22 +193,27 @@ void CreateGauss(
177193
FloatArray const& sigmas,
178194
UnsignedArray orders,
179195
dfloat truncation,
180-
UnsignedArray exponents
196+
UnsignedArray exponents,
197+
String const& extent
181198
) {
182199
// Verify dimensionality
183200
dip::uint nDims = sigmas.size();
184201
DIP_STACK_TRACE_THIS( ArrayUseParameter( orders, nDims, dip::uint( 0 )));
185202
DIP_STACK_TRACE_THIS( ArrayUseParameter( exponents, nDims, dip::uint( 0 )));
186203

204+
bool full{};
205+
DIP_STACK_TRACE_THIS( full = BooleanFromString( extent, "full", "half" ));
206+
187207
// Create 1D gaussian for each dimension
188208
std::vector< std::vector< dfloat >> gaussians( nDims );
189209
UnsignedArray outSizes( nDims );
190210
UnsignedArray centers( nDims );
211+
191212
for( dip::uint ii = 0; ii < nDims; ++ii ) {
192-
DIP_STACK_TRACE_THIS( gaussians[ ii ] = MakeGaussian( sigmas[ ii ], orders[ ii ], truncation, DT_DFLOAT ));
213+
DIP_STACK_TRACE_THIS( gaussians[ ii ] = full ? MakeGaussian( sigmas[ ii ], orders[ ii ], truncation, DT_DFLOAT ) : MakeHalfGaussian( sigmas[ ii ], orders[ ii ], truncation, DT_DFLOAT ));
193214
dip::uint gaussianLength = gaussians[ ii ].size();
194215
outSizes[ ii ] = gaussianLength;
195-
centers[ ii ] = ( gaussianLength - 1 ) / 2;
216+
centers[ ii ] = full ? ( gaussianLength - 1 ) / 2 : gaussianLength - 1;
196217
}
197218

198219
// Create output image

0 commit comments

Comments
 (0)