From 690e96707cd6d8bb2ef2dadc7530c13b93c60da4 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sun, 17 Mar 2024 15:35:30 +0800 Subject: [PATCH] Modernize the code (part 1) This is the first batch of changes to update the code in preparation for multi-type image code changes. --- src/edge_detection.cpp | 35 +++-- src/edge_detection.h | 45 ++++-- src/image_buffer.h | 155 ++++++++++--------- src/image_function_simd.cpp | 10 +- src/math/hough_transform.cpp | 27 ++-- src/math/hough_transform.h | 6 +- src/math/math_base.h | 62 ++++---- src/memory/memory_allocator.h | 36 +++-- test/unit_tests/unit_test_edge_detection.cpp | 6 +- test/unit_tests/unit_test_file.cpp | 6 +- 10 files changed, 210 insertions(+), 178 deletions(-) diff --git a/src/edge_detection.cpp b/src/edge_detection.cpp index a07627ab..523e0f92 100644 --- a/src/edge_detection.cpp +++ b/src/edge_detection.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -228,11 +228,11 @@ namespace getDerivatives( data, first, second ); getEdgePoints( negative, data, first, second, edgeParameter ); removeSimilarPoints( negative ); - if ( ( forwardDirection && edgeParameter.edge == EdgeParameter::FIRST ) || ( !forwardDirection && edgeParameter.edge == EdgeParameter::LAST ) ) { + if ( ( forwardDirection && edgeParameter.edge == EdgeParameter::EdgeType::FIRST ) || ( !forwardDirection && edgeParameter.edge == EdgeParameter::EdgeType::LAST ) ) { leaveFirstElement( positive ); leaveLastElement( negative ); } - else if ( ( forwardDirection && edgeParameter.edge == EdgeParameter::LAST ) || ( !forwardDirection && edgeParameter.edge == EdgeParameter::FIRST ) ) { + else if ( ( forwardDirection && edgeParameter.edge == EdgeParameter::EdgeType::LAST ) || ( !forwardDirection && edgeParameter.edge == EdgeParameter::EdgeType::FIRST ) ) { leaveLastElement( positive ); leaveFirstElement( negative ); } @@ -246,7 +246,8 @@ namespace Image_Function::ValidateImageParameters( image, x, y, width, height ); edgeParameter.verify(); - const bool horizontalEdgeDetectionBase = ( edgeParameter.direction == EdgeParameter::LEFT_TO_RIGHT || edgeParameter.direction == EdgeParameter::RIGHT_TO_LEFT ); + const bool horizontalEdgeDetectionBase + = ( edgeParameter.direction == EdgeParameter::DirectionType::LEFT_TO_RIGHT || edgeParameter.direction == EdgeParameter::DirectionType::RIGHT_TO_LEFT ); if ( ( horizontalEdgeDetectionBase && ( width < 4u ) ) || ( !horizontalEdgeDetectionBase && ( height < 4u ) ) ) return; @@ -279,22 +280,22 @@ namespace std::vector<_Type> edgePositive; std::vector<_Type> edgeNegative; findEdgePoints( edgePositive, edgeNegative, data, firstDerivative, secondDerivative, edgeParameter, - ( edgeParameter.direction == EdgeParameter::LEFT_TO_RIGHT ) ); + ( edgeParameter.direction == EdgeParameter::DirectionType::LEFT_TO_RIGHT ) ); const _Type yPosition = static_cast<_Type>( y + rowId + ( edgeParameter.groupFactor - 1 ) / 2.0 ); - if ( edgeParameter.direction == EdgeParameter::LEFT_TO_RIGHT ) { - if ( edgeParameter.gradient == EdgeParameter::POSITIVE || edgeParameter.gradient == EdgeParameter::ANY ) + if ( edgeParameter.direction == EdgeParameter::DirectionType::LEFT_TO_RIGHT ) { + if ( edgeParameter.gradient == EdgeParameter::GradientType::POSITIVE || edgeParameter.gradient == EdgeParameter::GradientType::ANY ) createPositiveXEdge( edgePositive, positiveEdgePoint, static_cast<_Type>( x ), yPosition ); - if ( edgeParameter.gradient == EdgeParameter::NEGATIVE || edgeParameter.gradient == EdgeParameter::ANY ) + if ( edgeParameter.gradient == EdgeParameter::GradientType::NEGATIVE || edgeParameter.gradient == EdgeParameter::GradientType::ANY ) createNegativeXEdge( edgeNegative, negativeEdgePoint, static_cast<_Type>( x + width - 1 ), yPosition ); } else { - if ( edgeParameter.gradient == EdgeParameter::POSITIVE || edgeParameter.gradient == EdgeParameter::ANY ) + if ( edgeParameter.gradient == EdgeParameter::GradientType::POSITIVE || edgeParameter.gradient == EdgeParameter::GradientType::ANY ) createNegativeXEdge( edgeNegative, positiveEdgePoint, static_cast<_Type>( x + width - 1 ), yPosition ); - if ( edgeParameter.gradient == EdgeParameter::NEGATIVE || edgeParameter.gradient == EdgeParameter::ANY ) + if ( edgeParameter.gradient == EdgeParameter::GradientType::NEGATIVE || edgeParameter.gradient == EdgeParameter::GradientType::ANY ) createPositiveXEdge( edgePositive, negativeEdgePoint, static_cast<_Type>( x ), yPosition ); } } @@ -324,22 +325,22 @@ namespace std::vector<_Type> edgePositive; std::vector<_Type> edgeNegative; findEdgePoints( edgePositive, edgeNegative, data, firstDerivative, secondDerivative, edgeParameter, - ( edgeParameter.direction == EdgeParameter::TOP_TO_BOTTOM ) ); + ( edgeParameter.direction == EdgeParameter::DirectionType::TOP_TO_BOTTOM ) ); const _Type xPosition = static_cast<_Type>( x + rowId + ( edgeParameter.groupFactor - 1 ) / 2.0 ); - if ( edgeParameter.direction == EdgeParameter::TOP_TO_BOTTOM ) { - if ( edgeParameter.gradient == EdgeParameter::POSITIVE || edgeParameter.gradient == EdgeParameter::ANY ) + if ( edgeParameter.direction == EdgeParameter::DirectionType::TOP_TO_BOTTOM ) { + if ( edgeParameter.gradient == EdgeParameter::GradientType::POSITIVE || edgeParameter.gradient == EdgeParameter::GradientType::ANY ) createPositiveYEdge( edgePositive, positiveEdgePoint, xPosition, static_cast<_Type>( y ) ); - if ( edgeParameter.gradient == EdgeParameter::NEGATIVE || edgeParameter.gradient == EdgeParameter::ANY ) + if ( edgeParameter.gradient == EdgeParameter::GradientType::NEGATIVE || edgeParameter.gradient == EdgeParameter::GradientType::ANY ) createNegativeYEdge( edgeNegative, negativeEdgePoint, xPosition, static_cast<_Type>( y + height - 1 ) ); } else { - if ( edgeParameter.gradient == EdgeParameter::POSITIVE || edgeParameter.gradient == EdgeParameter::ANY ) + if ( edgeParameter.gradient == EdgeParameter::GradientType::POSITIVE || edgeParameter.gradient == EdgeParameter::GradientType::ANY ) createNegativeYEdge( edgeNegative, positiveEdgePoint, xPosition, static_cast<_Type>( y + height - 1 ) ); - if ( edgeParameter.gradient == EdgeParameter::NEGATIVE || edgeParameter.gradient == EdgeParameter::ANY ) + if ( edgeParameter.gradient == EdgeParameter::GradientType::NEGATIVE || edgeParameter.gradient == EdgeParameter::GradientType::ANY ) createPositiveYEdge( edgePositive, negativeEdgePoint, xPosition, static_cast<_Type>( y ) ); } } @@ -347,7 +348,7 @@ namespace } } -EdgeParameter::EdgeParameter( directionType _direction, gradientType _gradient, edgeType _edge, uint32_t _groupFactor, uint32_t _skipFactor, +EdgeParameter::EdgeParameter( DirectionType _direction, GradientType _gradient, EdgeType _edge, uint32_t _groupFactor, uint32_t _skipFactor, uint32_t _contrastCheckLeftSideOffset, uint32_t _contrastCheckRightSideOffset, uint8_t _minimumContrast ) : direction( _direction ) , gradient( _gradient ) diff --git a/src/edge_detection.h b/src/edge_detection.h index cc80fb39..b75a1d16 100644 --- a/src/edge_detection.h +++ b/src/edge_detection.h @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -27,46 +27,57 @@ struct EdgeParameter { // Direction of scanning for edges - enum directionType + enum class DirectionType : uint8_t { - LEFT_TO_RIGHT = 0, + LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP }; // Type of edge to detect based on gradient: positive means that pixel intensity increases while for negative it decreases. Any: positive and negative - enum gradientType + enum class GradientType : uint8_t { - POSITIVE = 4, + POSITIVE, NEGATIVE, ANY }; // Type of edge to find per scanning row. First means first edge point in a row, last - last edge point. Set all to catch all edge points in a row - enum edgeType + enum class EdgeType : uint8_t { - FIRST = 7, + FIRST, LAST, ALL }; - EdgeParameter( directionType _direction = LEFT_TO_RIGHT, gradientType _gradient = ANY, edgeType _edge = ALL, uint32_t _groupFactor = 1u, uint32_t _skipFactor = 1u, - uint32_t _contrastCheckLeftSideOffset = 0u, uint32_t _contrastCheckRightSideOffset = 0u, uint8_t _minimumContrast = 10 ); + EdgeParameter( DirectionType _direction = DirectionType::LEFT_TO_RIGHT, GradientType _gradient = GradientType::ANY, EdgeType _edge = EdgeType::ALL, + uint32_t _groupFactor = 1u, uint32_t _skipFactor = 1u, uint32_t _contrastCheckLeftSideOffset = 0u, uint32_t _contrastCheckRightSideOffset = 0u, + uint8_t _minimumContrast = 10 ); + + DirectionType direction; + + GradientType gradient; + + EdgeType edge; + + // Grouping per row or column (depending on direction) works as a median filter. Default is 1 - no grouping. + uint32_t groupFactor; + + // Skip specific number of rows or columns to do not find edge points on all rows/columns. Default is 1 - no skipping. + uint32_t skipFactor; - directionType direction; - gradientType gradient; - edgeType edge; - uint32_t groupFactor; // grouping per row or column (depending on direction) works as a median filter. Default is 1 - no grouping - uint32_t skipFactor; // skip specific number of rows or columns to do not find edge points on all rows/columns. Default is 1 - no skipping // Specify a number of pixels from each side of potential edge point to get pixel intensity needed for contrast verification // Such offsets are useful for very smooth edge when pixel intensity increases very slowly per pixel // Default values are 0 uint32_t contrastCheckLeftSideOffset; uint32_t contrastCheckRightSideOffset; - uint8_t minimumContrast; // minimun contrast needed to detect edge - void verify() const; // self-verification that all parameters are correct + // Minimun contrast needed to detect edge. + uint8_t minimumContrast; + + // Self-verification that all parameters are correct. + void verify() const; }; template @@ -115,4 +126,4 @@ class EdgeDetectionBase std::vector> negativeEdgePoint; }; -typedef EdgeDetectionBase EdgeDetection; +using EdgeDetection = EdgeDetectionBase; diff --git a/src/image_buffer.h b/src/image_buffer.h index 70beaf12..b1bac927 100644 --- a/src/image_buffer.h +++ b/src/image_buffer.h @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -23,8 +23,10 @@ #include "memory/cpu_memory.h" #include "penguinv_exception.h" #include +#include #include #include +#include #include namespace penguinV @@ -33,15 +35,7 @@ namespace penguinV class ImageTemplate { public: - explicit ImageTemplate( uint32_t width_ = 0u, uint32_t height_ = 0u, uint8_t colorCount_ = 1u, uint8_t alignment_ = 1u ) - : _width( 0 ) // width of image - , _height( 0 ) // height of image - , _colorCount( 1 ) // number of colors per pixel - , _alignment( 1 ) // some formats require that row size must be a multiple of some value (alignment) - // for example for Bitmap it must be a multiple of 4 - , _rowSize( 0 ) // size of single row on image, usually it is equal to width - , _data( nullptr ) // an array what store image information (pixel data) - , _type( 0 ) // special attribute to specify different types of images based on technology it is used for + explicit ImageTemplate( const uint32_t width_ = 0u, const uint32_t height_ = 0u, const uint8_t colorCount_ = 1u, const uint8_t alignment_ = 1u ) { _setType(); @@ -51,20 +45,12 @@ namespace penguinV } ImageTemplate( const ImageTemplate & image ) - : _data( nullptr ) - , _type( image._type ) + : _deviceType( image._deviceType ) { copy( image ); } ImageTemplate( ImageTemplate && image ) - : _width( 0 ) - , _height( 0 ) - , _colorCount( 1 ) - , _alignment( 1 ) - , _rowSize( 0 ) - , _data( nullptr ) - , _type( 0 ) { swap( image ); } @@ -85,8 +71,8 @@ namespace penguinV bool operator==( const ImageTemplate & image ) const { - return _data == image._data && _width == image._width && _height == image._height && _colorCount == image._colorCount && _alignment == image._alignment - && _type == image._type; + return _data == image._data && _width == image._width && _height == image._height && _colorChannelCount == image._colorChannelCount + && _alignment == image._alignment && _deviceType == image._deviceType; } virtual ~ImageTemplate() @@ -103,8 +89,9 @@ namespace penguinV _height = height_; _rowSize = width() * colorCount(); - if ( _rowSize % alignment() != 0 ) + if ( _rowSize % alignment() != 0 ) { _rowSize = ( _rowSize / alignment() + 1 ) * alignment(); + } _data = _allocate( static_cast( _height ) * static_cast( _rowSize ) ); } @@ -134,22 +121,24 @@ namespace penguinV void assign( TColorDepth * data_, uint32_t width_, uint32_t height_, uint8_t colorCount_, uint8_t alignment_ ) { - if ( data_ == nullptr || width_ == 0 || height_ == 0 || colorCount_ == 0 || alignment_ == 0 ) + if ( data_ == nullptr || width_ == 0 || height_ == 0 || colorCount_ == 0 || alignment_ == 0 ) { throw penguinVException( "Invalid image assignment parameters" ); + } clear(); _width = width_; _height = height_; - _colorCount = colorCount_; + _colorChannelCount = colorCount_; _alignment = alignment_; _data = data_; _rowSize = width() * colorCount(); - if ( _rowSize % alignment() != 0 ) + if ( _rowSize % alignment() != 0 ) { _rowSize = ( _rowSize / alignment() + 1 ) * alignment(); + } } bool empty() const @@ -174,14 +163,14 @@ namespace penguinV uint8_t colorCount() const { - return _colorCount; + return _colorChannelCount; } void setColorCount( uint8_t colorCount_ ) { - if ( colorCount_ > 0 && _colorCount != colorCount_ ) { + if ( colorCount_ > 0 && _colorChannelCount != colorCount_ ) { clear(); - _colorCount = colorCount_; + _colorChannelCount = colorCount_; } } @@ -200,8 +189,9 @@ namespace penguinV void fill( TColorDepth value ) { - if ( empty() ) + if ( empty() ) { return; + } _set( data(), value, sizeof( TColorDepth ) * height() * rowSize() ); } @@ -211,25 +201,26 @@ namespace penguinV std::swap( _width, image._width ); std::swap( _height, image._height ); - std::swap( _colorCount, image._colorCount ); + std::swap( _colorChannelCount, image._colorChannelCount ); std::swap( _rowSize, image._rowSize ); std::swap( _alignment, image._alignment ); std::swap( _data, image._data ); - std::swap( _type, image._type ); + std::swap( _deviceType, image._deviceType ); } void copy( const ImageTemplate & image ) { - if ( _type != image._type ) + if ( _deviceType != image._deviceType ) { throw penguinVException( "Cannot copy image of one type to another type." ); + } clear(); _width = image._width; _height = image._height; - _colorCount = image._colorCount; + _colorChannelCount = image._colorChannelCount; _rowSize = image._rowSize; _alignment = image._alignment; @@ -244,15 +235,17 @@ namespace penguinV { if ( colorCount_ > 0 && alignment_ > 0 ) { uint32_t rowSize_ = width_ * colorCount_; - if ( rowSize_ % alignment_ != 0 ) + if ( rowSize_ % alignment_ != 0 ) { rowSize_ = ( rowSize_ / alignment_ + 1 ) * alignment_; + } - if ( rowSize_ * height_ != _rowSize * _height ) + if ( rowSize_ * height_ != _rowSize * _height ) { return false; + } _width = width_; _height = height_; - _colorCount = colorCount_; + _colorChannelCount = colorCount_; _alignment = alignment_; _rowSize = rowSize_; @@ -264,13 +257,13 @@ namespace penguinV uint8_t type() const { - return _type; + return _deviceType; } ImageTemplate generate( uint32_t width_ = 0u, uint32_t height_ = 0u, uint8_t colorCount_ = 1u, uint8_t alignment_ = 1u ) const { ImageTemplate image; - image._type = _type; + image._deviceType = _deviceType; image.setColorCount( colorCount_ ); image.setAlignment( alignment_ ); @@ -280,37 +273,37 @@ namespace penguinV } protected: - typedef TColorDepth * ( *AllocateFunction )( size_t size ); - typedef void ( *DeallocateFunction )( TColorDepth * data ); - typedef void ( *CopyFunction )( TColorDepth * out, TColorDepth * in, size_t size ); - typedef void ( *SetFunction )( TColorDepth * data, TColorDepth value, size_t size ); + using AllocateFunction = std::function; + using DeallocateFunction = std::function; + using CopyFunction = std::function; + using SetFunction = std::function; void _setType( uint8_t type = 0u, AllocateFunction allocateFunction = _allocateMemory, DeallocateFunction deallocateFunction = _deallocateMemory, CopyFunction copyFunction = _copyMemory, SetFunction setFunction = _setMemory ) { - _type = type; - FunctionFacade::instance().initialize( _type, allocateFunction, deallocateFunction, copyFunction, setFunction ); + _deviceType = type; + FunctionFacade::instance().initialize( _deviceType, allocateFunction, deallocateFunction, copyFunction, setFunction ); } private: TColorDepth * _allocate( size_t size ) const { - return FunctionFacade::instance().allocate( _type )( size ); + return FunctionFacade::instance().allocate( _deviceType )( size ); } void _deallocate( TColorDepth * data ) const { - FunctionFacade::instance().deallocate( _type )( data ); + FunctionFacade::instance().deallocate( _deviceType )( data ); } void _copy( TColorDepth * out, TColorDepth * in, size_t size ) const { - FunctionFacade::instance().copy( _type )( out, in, size ); + FunctionFacade::instance().copy( _deviceType )( out, in, size ); } void _set( TColorDepth * data, TColorDepth value, size_t size ) const { - FunctionFacade::instance().set( _type )( data, value, size ); + FunctionFacade::instance().set( _deviceType )( data, value, size ); } static TColorDepth * _allocateMemory( size_t size ) @@ -333,16 +326,28 @@ namespace penguinV std::fill( data, data + size / sizeof( TColorDepth ), value ); } - uint32_t _width; - uint32_t _height; + // Width of image. + uint32_t _width{ 0 }; - uint8_t _colorCount; - uint8_t _alignment; - uint32_t _rowSize; + // Height of image. + uint32_t _height{ 0 }; - TColorDepth * _data; + // Number of colors per pixel / number of color channels present. + uint8_t _colorChannelCount{ 1 }; - uint8_t _type; + // Some image formats require that row size must be a multiple of some value (alignment). + // For example Bitmap's image alignment must be a multiple of 4. + uint8_t _alignment{ 1 }; + + // Size of single row on image, usually it is equal to width if alignment is 1. + uint32_t _rowSize{ 0 }; + + // Image data. + TColorDepth * _data{ nullptr }; + + // Special attribute to specify different types of images based on technology it is used for. + // For example, CPU, CUDA, OpenCL and others. + uint8_t _deviceType{ 0 }; class FunctionFacade { @@ -384,44 +389,40 @@ namespace penguinV } private: - FunctionFacade() - { - _allocate.resize( 256, nullptr ); - _deallocate.resize( 256, nullptr ); - _copy.resize( 256, nullptr ); - _set.resize( 256, nullptr ); - } + FunctionFacade() = default; FunctionFacade & operator=( const FunctionFacade & ) { return ( *this ); } + FunctionFacade( const FunctionFacade & ) {} template - TFunction _getFunction( const std::vector & data, uint8_t index ) const + TFunction _getFunction( const std::array & data, uint8_t index ) const { - if ( data[index] == nullptr ) + if ( data[index] == nullptr ) { throw penguinVException( "A function is not defined for this type of image" ); + } return data[index]; } - std::vector _allocate; - std::vector _deallocate; - std::vector _copy; - std::vector _set; + std::array _allocate{ nullptr }; + std::array _deallocate{ nullptr }; + std::array _copy{ nullptr }; + std::array _set{ nullptr }; }; }; - typedef ImageTemplate Image; - typedef ImageTemplate Image16Bit; + using Image = ImageTemplate; + using Image16Bit = ImageTemplate; - const static uint8_t GRAY_SCALE = 1u; - const static uint8_t RGB = 3u; - const static uint8_t RGBA = 4u; - const static uint8_t RED_CHANNEL = 0u; - const static uint8_t GREEN_CHANNEL = 1u; - const static uint8_t BLUE_CHANNEL = 2u; - const static uint8_t ALPHA_CHANNEL = 3u; + static const uint8_t GRAY_SCALE{ 1u }; + static const uint8_t RGB{ 3u }; + static const uint8_t RGBA{ 4u }; + static const uint8_t RED_CHANNEL{ 0u} ; + static const uint8_t GREEN_CHANNEL{ 1u }; + static const uint8_t BLUE_CHANNEL{ 2u }; + static const uint8_t ALPHA_CHANNEL{ 3u }; } diff --git a/src/image_function_simd.cpp b/src/image_function_simd.cpp index 5cb4eeba..d4a8764a 100644 --- a/src/image_function_simd.cpp +++ b/src/image_function_simd.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -80,7 +80,7 @@ namespace avx512 const uint32_t simdSize = 64u; #ifdef PENGUINV_AVX512_SKL_SET - typedef __m512i simd; + using simd = __m512i; void AbsoluteDifference( uint32_t rowSizeIn1, uint32_t rowSizeIn2, uint32_t rowSizeOut, const uint8_t * in1Y, const uint8_t * in2Y, uint8_t * outY, const uint8_t * outYEnd, uint32_t simdWidth, uint32_t totalSimdWidth, uint32_t nonSimdWidth ) @@ -538,7 +538,7 @@ namespace avx const uint32_t simdSize = 32u; #ifdef PENGUINV_AVX_SET - typedef __m256i simd; + using simd = __m256i; // We are not sure that input data is aligned by 32 bytes so we use loadu() functions instead of load() @@ -1155,7 +1155,7 @@ namespace sse const uint32_t simdSize = 16u; #ifdef PENGUINV_SSE_SET - typedef __m128i simd; + using simd = __m128i; // We are not sure that input data is aligned by 16 bytes so we use loadu() functions instead of load() @@ -1826,7 +1826,7 @@ namespace neon const uint32_t simdSize = 16u; #ifdef PENGUINV_NEON_SET - typedef uint8x16_t simd; + using simd = uint8x16_t; void AbsoluteDifference( uint32_t rowSizeIn1, uint32_t rowSizeIn2, uint32_t rowSizeOut, const uint8_t * in1Y, const uint8_t * in2Y, uint8_t * outY, const uint8_t * outYEnd, uint32_t, uint32_t totalSimdWidth, uint32_t nonSimdWidth ) diff --git a/src/math/hough_transform.cpp b/src/math/hough_transform.cpp index 1227c443..19047bcc 100644 --- a/src/math/hough_transform.cpp +++ b/src/math/hough_transform.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -32,24 +32,28 @@ namespace namespace { template - bool runHoughTransform( const std::vector> & input, _Type initialAngle, _Type angleTolerance, _Type angleStep, _Type lineTolerance, + bool runHoughTransform( const std::vector> & input, const _Type initialAngle, _Type angleTolerance, _Type angleStep, _Type lineTolerance, std::vector> & outOnLine, std::vector> & outOffLine ) { // validate input data if ( input.size() < 2u ) return false; - if ( angleStep < minimumAngleStep ) + if ( angleStep < minimumAngleStep ) { angleStep = minimumAngleStep; + } - if ( angleTolerance < minimumAngleStep ) + if ( angleTolerance < minimumAngleStep ) { angleTolerance = minimumAngleStep; + } - if ( angleTolerance < angleStep ) + if ( angleTolerance < angleStep ) { angleTolerance = angleStep; + } - if ( lineTolerance < minimumLineTolerance ) + if ( lineTolerance < minimumLineTolerance ) { lineTolerance = minimumLineTolerance; + } // find a range of search const int angleStepPerSide = static_cast( ( angleTolerance / angleStep ) + 0.5 ); @@ -68,17 +72,18 @@ namespace const _Type cosVal = std::cos( angleVal ); const _Type sinVal = std::sin( angleVal ); - // find and sort distances + // Find and sort distances. _Type * distanceVal = distanceToLine.data(); const PointBase2D<_Type> * point = input.data(); const PointBase2D<_Type> * pointEnd = point + inputPointCount; - for ( ; point != pointEnd; ++point, ++distanceVal ) + for ( ; point != pointEnd; ++point, ++distanceVal ) { ( *distanceVal ) = point->x * sinVal + point->y * cosVal; + } std::sort( distanceToLine.begin(), distanceToLine.end() ); - // find maximum number of points + // Find maximum number of points. size_t initialPointId = 0u; size_t onLinePointCount = 1u; @@ -137,13 +142,13 @@ namespace namespace Image_Function { - bool HoughTransform( const std::vector> & input, double initialAngle, double angleTolerance, double angleStep, double lineTolerance, + bool HoughTransform( const std::vector> & input, const double initialAngle, double angleTolerance, double angleStep, double lineTolerance, std::vector> & outOnLine, std::vector> & outOffLine ) { return runHoughTransform( input, initialAngle, angleTolerance, angleStep, lineTolerance, outOnLine, outOffLine ); } - bool HoughTransform( const std::vector> & input, float initialAngle, float angleTolerance, float angleStep, float lineTolerance, + bool HoughTransform( const std::vector> & input, const float initialAngle, float angleTolerance, float angleStep, float lineTolerance, std::vector> & outOnLine, std::vector> & outOffLine ) { return runHoughTransform( input, initialAngle, angleTolerance, angleStep, lineTolerance, outOnLine, outOffLine ); diff --git a/src/math/hough_transform.h b/src/math/hough_transform.h index af04b637..64b0b500 100644 --- a/src/math/hough_transform.h +++ b/src/math/hough_transform.h @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -25,9 +25,9 @@ namespace Image_Function { - bool HoughTransform( const std::vector> & input, double initialAngle, double angleTolerance, double angleStep, double lineTolerance, + bool HoughTransform( const std::vector> & input, const double initialAngle, double angleTolerance, double angleStep, double lineTolerance, std::vector> & outOnLine, std::vector> & outOffLine ); - bool HoughTransform( const std::vector> & input, float initialAngle, float angleTolerance, float angleStep, float lineTolerance, + bool HoughTransform( const std::vector> & input, const float initialAngle, float angleTolerance, float angleStep, float lineTolerance, std::vector> & outOnLine, std::vector> & outOffLine ); } diff --git a/src/math/math_base.h b/src/math/math_base.h index 40de21a4..eb06fdea 100644 --- a/src/math/math_base.h +++ b/src/math/math_base.h @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -62,15 +62,14 @@ namespace pvmath template struct PointBase2D { - PointBase2D() - : x( 0 ) - , y( 0 ) - {} + PointBase2D() = default; - PointBase2D( _Type _x, _Type _y ) + PointBase2D( const _Type _x, const _Type _y ) : x( _x ) , y( _y ) - {} + { + // Do nothing. + } bool operator==( const PointBase2D & point ) const { @@ -111,8 +110,8 @@ struct PointBase2D return PointBase2D( value * x, value * y ); } - _Type x; - _Type y; + _Type x{ 0 }; + _Type y{ 0 }; }; template @@ -124,15 +123,14 @@ PointBase2D<_Type> operator*( const T & value, const PointBase2D<_Type> & point template struct PointBase3D : public PointBase2D<_Type> { - PointBase3D() - : PointBase2D<_Type>() - , z( 0 ) - {} + PointBase3D() = default; - PointBase3D( _Type _x, _Type _y, _Type _z ) + PointBase3D( const _Type _x, const _Type _y, const _Type _z ) : PointBase2D<_Type>( _x, _y ) , z( _z ) - {} + { + // Do nothing. + } bool operator==( const PointBase3D & point ) const { @@ -163,32 +161,36 @@ struct PointBase3D : public PointBase2D<_Type> return PointBase3D( PointBase2D<_Type>::x - point.x, PointBase2D<_Type>::y - point.y, z - point.z ); } - _Type z; + _Type z{ 0 }; }; template class LineBase2D { public: - LineBase2D( const PointBase2D<_Type> & point1 = PointBase2D<_Type>(), const PointBase2D<_Type> & point2 = PointBase2D<_Type>() ) - : _position( point1 ) + LineBase2D() = default; + + LineBase2D( const PointBase2D<_Type> & start, const PointBase2D<_Type> & end ) + : _position( start ) { - if ( point1 == point2 ) { + if ( start == end ) { _direction = PointBase2D<_Type>( 1, 0 ); // we could raise an exception here instead } else { - const _Type xDiff = point2.x - point1.x; - const _Type yDiff = point2.y - point1.y; + const _Type xDiff = end.x - start.x; + const _Type yDiff = end.y - start.y; const _Type length = std::sqrt( xDiff * xDiff + yDiff * yDiff ); // here we might need more specific code for non-double cases _direction = PointBase2D<_Type>( xDiff / length, yDiff / length ); } } // Angle is in radians - LineBase2D( const PointBase2D<_Type> & position_, _Type angle_ ) + LineBase2D( const PointBase2D<_Type> & position_, const _Type angle_ ) : _position( position_ ) , _direction( std::cos( angle_ ), std::sin( angle_ ) ) - {} + { + // Do nothing. + } bool operator==( const LineBase2D & line ) const { @@ -219,11 +221,12 @@ class LineBase2D bool intersection( const LineBase2D & line, PointBase2D<_Type> & point ) const { - // based on Graphics Gems III, Faster Line Segment Intersection, p. 199-202 + // It is based on Graphics Gems III, Faster Line Segment Intersection, p. 199-202 // http://www.realtimerendering.com/resources/GraphicsGems/gems.html#gemsiii const _Type denominator = _direction.y * line._direction.x - _direction.x * line._direction.y; - if ( pvmath::isEqual<_Type>( denominator, 0, 10 ) ) + if ( pvmath::isEqual<_Type>( denominator, 0, 10 ) ) { return false; // they are parallel + } const PointBase2D<_Type> offset = _position - line._position; const _Type na = ( line._direction.y * offset.x - line._direction.x * offset.y ) / denominator; @@ -244,8 +247,9 @@ class LineBase2D _Type distance( const PointBase2D<_Type> & point ) const { - // Line equation in the Cartesian coordinate system is + // Line equation in the Cartesian coordinate system is: // y = a * x + b or A * x + B * y + C = 0 + // // A distance from a point to a line can be calculated as: // |A * x0 + B * y0 + C| / sqrt(A * A + B * B) const _Type distanceToLine = _direction.y * ( point.x - _position.x ) + _direction.x * ( _position.y - point.y ); @@ -317,6 +321,6 @@ class LineBase2D PointBase2D<_Type> _direction; }; -typedef PointBase2D Point2d; -typedef PointBase3D Point3d; -typedef LineBase2D Line2d; +using Point2d = PointBase2D ; +using Point3d = PointBase3D ; +using Line2d = LineBase2D ; diff --git a/src/memory/memory_allocator.h b/src/memory/memory_allocator.h index 565c9bbb..df2c8515 100644 --- a/src/memory/memory_allocator.h +++ b/src/memory/memory_allocator.h @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -29,9 +29,7 @@ class BaseMemoryAllocator { public: - BaseMemoryAllocator() - : _size( 0 ) - {} + BaseMemoryAllocator() = default; virtual ~BaseMemoryAllocator() {} @@ -39,11 +37,13 @@ class BaseMemoryAllocator // Do not reallocate memory if some objects in your source code are allocated through this allocator. void reserve( size_t size ) { - if ( size == 0 ) + if ( size == 0 ) { throw std::logic_error( "Memory size cannot be 0" ); + } - if ( size == _size ) + if ( size == _size ) { return; + } _allocate( size ); @@ -58,8 +58,9 @@ class BaseMemoryAllocator --levelCount; } - if ( usedSize == 0 ) + if ( usedSize == 0 ) { _freeChunk.resize( levelCount + 1u ); + } _freeChunk[levelCount].insert( usedSize ); @@ -77,7 +78,7 @@ class BaseMemoryAllocator _size = 0; } - // returns a level (power of 2) needed for a required size + // Returns a level (power of 2) needed for a required size. static uint8_t _getAllocationLevel( size_t initialSize ) { size_t size = 1; @@ -91,7 +92,7 @@ class BaseMemoryAllocator return level; } - // splits the preallocated memory by levels + // Splits the preallocated memory by levels. bool _split( uint8_t from ) { bool levelFound = false; @@ -105,8 +106,9 @@ class BaseMemoryAllocator } } - if ( !levelFound ) + if ( !levelFound ) { return false; + } if ( startLevel > from ) { size_t memorySize = static_cast( 1 ) << ( startLevel - 1 ); @@ -157,10 +159,16 @@ class BaseMemoryAllocator } } - size_t _size; // a size of memory allocated chunk - std::vector> _freeChunk; // free memory in preallocated memory + // A size of memory allocated chunk. + size_t _size{ 0 }; + + // Free memory in preallocated memory. + std::vector> _freeChunk; private: - virtual void _allocate( size_t size ) = 0; // true memory allocation - virtual void _deallocate() = 0; // true memory deallocation + // True memory allocation method. Implementation details are in child classes. + virtual void _allocate( size_t size ) = 0; + + // True memory deallocation method. Implementation details are in child classes. + virtual void _deallocate() = 0; }; diff --git a/test/unit_tests/unit_test_edge_detection.cpp b/test/unit_tests/unit_test_edge_detection.cpp index 20778279..e083b103 100644 --- a/test/unit_tests/unit_test_edge_detection.cpp +++ b/test/unit_tests/unit_test_edge_detection.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -45,7 +45,7 @@ namespace edge_detection Unit_Test::fillImage( image, roiX, roiY, roiWidth, roiHeight, Unit_Test::randomValue( 64, 256 ) ); EdgeDetectionBase<_Type> edgeDetection; - edgeDetection.find( image, EdgeParameter( EdgeParameter::LEFT_TO_RIGHT ) ); + edgeDetection.find( image, EdgeParameter( EdgeParameter::DirectionType::LEFT_TO_RIGHT ) ); const std::vector> & positive = edgeDetection.positiveEdge(); const std::vector> & negative = edgeDetection.negativeEdge(); @@ -87,7 +87,7 @@ namespace edge_detection Unit_Test::fillImage( image, roiX, roiY, roiWidth, roiHeight, Unit_Test::randomValue( 64, 256 ) ); EdgeDetectionBase<_Type> edgeDetection; - edgeDetection.find( image, EdgeParameter( EdgeParameter::TOP_TO_BOTTOM ) ); + edgeDetection.find( image, EdgeParameter( EdgeParameter::DirectionType::TOP_TO_BOTTOM ) ); const std::vector> & positive = edgeDetection.positiveEdge(); const std::vector> & negative = edgeDetection.negativeEdge(); diff --git a/test/unit_tests/unit_test_file.cpp b/test/unit_tests/unit_test_file.cpp index 1c1e8a3d..eab5ecc8 100644 --- a/test/unit_tests/unit_test_file.cpp +++ b/test/unit_tests/unit_test_file.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * penguinV: https://github.com/ihhub/penguinV * - * Copyright (C) 2017 - 2022 * + * Copyright (C) 2017 - 2024 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -148,14 +148,16 @@ void addTests_File( UnitTestFramework & framework ) framework.add( file_operation::WhiteGrayScaleImageBitmap, "File: Save and load white gray-scale bitmap image" ); framework.add( file_operation::BlackGrayScaleImageBitmap, "File: Save and load black gray-scale bitmap image" ); framework.add( file_operation::RandomRGBImageBitmap, "File: Save and load random RGB bitmap image" ); + framework.add( file_operation::RawRGBImage, "File: Save and load raw RGB image" ); + #if defined( PENGUINV_ENABLED_PNG_SUPPORT ) framework.add( file_operation::WhiteGrayScaleImagePng, "File: Save and load white gray-scale png image" ); framework.add( file_operation::BlackGrayScaleImagePng, "File: Save and load black gray-scale png image" ); framework.add( file_operation::RandomRGBImagePng, "File: Save and load random RGB png image" ); #endif + #if defined( PENGUINV_ENABLED_JPEG_SUPPORT ) framework.add( file_operation::WhiteGrayScaleImageJpeg, "File: Save and load white gray-scale jpeg image" ); framework.add( file_operation::BlackGrayScaleImageJpeg, "File: Save and load black gray-scale jpeg image" ); #endif - framework.add( file_operation::RawRGBImage, "File: Save and load raw RGB image" ); }