Skip to content

Commit

Permalink
ENH: Enforce computational requirements for SobelOperator
Browse files Browse the repository at this point in the history
* Sobel Direction 1 coefficients (G_y) convolved with Neighborhood of 1's
  should equal 0

         G_y           *      N
  [ +1.   +2.   +1. ]    [ 1  1  1]
  [  0.    0.    0. ]  * [ 1  1  1]    =>   0
  [ -1.   -2.   -1. ]    [ 1  1  1]

If the SobelOperator is templated over a pixel type
that is not signed, the G_y coefficients above are
typecast to the internal pixel type, this removing
the sign, or introducing wrap errors.

Test code:
    double d = -1.;
    unsigned char c = d;
    std::cout << +c << std::endl;

On intel computers:
    prints 255
On apple silicon computers:
    print 0

NOTE: The sobel coeficients are not properly applied
      during the inner product for unsigned data types.

Turn on concept checking for the SobelOperator to enforce
signed neighborhood processing.
  • Loading branch information
hjmjohnson committed Mar 7, 2023
1 parent 1a6f2ce commit 03c8176
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 1 deletion.
6 changes: 6 additions & 0 deletions Modules/Core/Common/include/itkSobelOperator.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ class ITK_TEMPLATE_EXPORT SobelOperator : public NeighborhoodOperator<TPixel, VD
// virtual void CreateToRadius(const unsigned long);

protected:
#ifdef ITK_USE_CONCEPT_CHECKING
// Begin concept checking
itkConceptMacro(SignedOutputPixelType, (Concept::Signed<typename NumericTraits<TPixel>::ValueType>));
// End concept checking
#endif

/** Type alias support for coefficient vector type.*/
using typename Superclass::CoefficientVector;

Expand Down
5 changes: 4 additions & 1 deletion Modules/Core/Common/include/itkSobelOperator.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ SobelOperator<TPixel, VDimension, TAllocator>::Fill(const CoefficientVector & co
for (int x = -1; x <= 1; ++x)
{
const int pos = center + y * this->GetStride(1) + x * this->GetStride(0);
//
// Note, The following line copies the double precision
// coefficients of SobelOperator to the pixel type
// of the neighborhood operator which may not support
// negative numbers, or floating point numbers.
this->operator[](pos) = static_cast<TPixel>(coeff[coeff_index]);

++coeff_index;
Expand Down

0 comments on commit 03c8176

Please sign in to comment.