From eadaab5fbb35aa4d9ccbea8668f3ebc30e63d6cd Mon Sep 17 00:00:00 2001 From: Pratham Kumar Date: Thu, 14 May 2026 13:26:21 +0530 Subject: [PATCH] Merge pull request #28664 from pratham-mcw:armpl_dft_opt Add ARMPL support for DFT Function #28664 - This PR introduces hal/armpl/ with implementation of 1D, 2D DFT and DCT routines using ARM Performance Libraries as a custom HAL replacement for OpenCV's DFT & DCT Function. - ArmPL MSI package is automatically downloaded and extracted via CMake when building on Windows ARM64, with a WITH_ARMPL option that defaults to ON for that platform. - Forward and inverse real DFT calls in dxt.cpp are routed through ArmPL when available, with scaling applied only when needed. - Test error thresholds in test_dxt.cpp are relaxed (from 1e-5 to 2e-4 for float ) to account for numerical differences between ArmPL and OpenCV's reference DFT results. **Performance Benchmarks :** image - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch --- CMakeLists.txt | 27 + cmake/OpenCVFindARMPL.cmake | 172 ++ cmake/OpenCVFindLibsPerf.cmake | 15 + .../table_of_content_introduction.markdown | 1 + .../windows_armpl_opencv.markdown | 169 ++ hal/armpl/CMakeLists.txt | 28 + hal/armpl/include/armpl_hal_core.hpp | 91 + hal/armpl/src/armpl_hal_core.cpp | 2642 +++++++++++++++++ modules/core/test/test_dxt.cpp | 32 +- 9 files changed, 3176 insertions(+), 1 deletion(-) create mode 100644 cmake/OpenCVFindARMPL.cmake create mode 100644 doc/tutorials/introduction/windows_armpl/windows_armpl_opencv.markdown create mode 100644 hal/armpl/CMakeLists.txt create mode 100644 hal/armpl/include/armpl_hal_core.hpp create mode 100644 hal/armpl/src/armpl_hal_core.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d49243093..a9321d07b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -284,6 +284,9 @@ OCV_OPTION(WITH_WAYLAND "Include Wayland support" OFF OCV_OPTION(WITH_IPP "Include Intel IPP support" (NOT MINGW AND NOT CV_DISABLE_OPTIMIZATION) VISIBLE_IF (X86_64 OR X86) AND NOT WINRT AND NOT IOS AND NOT XROS VERIFY HAVE_IPP) +OCV_OPTION(WITH_ARMPL "Include ARM Performance Libraries support (auto-download)" OFF + VISIBLE_IF (AARCH64 OR ARM64) AND NOT WINRT AND NOT IOS AND NOT XROS + VERIFY HAVE_ARMPL) OCV_OPTION(WITH_HALIDE "Include Halide support" OFF VISIBLE_IF TRUE VERIFY HAVE_HALIDE) @@ -975,6 +978,13 @@ if(HAVE_FASTCV) endif() endif() +if(HAVE_ARMPL) + ocv_debug_message(STATUS "Enable ARMPL acceleration") + if(NOT ";${OpenCV_HAL};" MATCHES ";armpl;") + set(OpenCV_HAL "armpl_hal;${OpenCV_HAL}") + endif() +endif() + if(HAVE_KLEIDICV) ocv_debug_message(STATUS "Enable KleidiCV acceleration") if(NOT ";${OpenCV_HAL};" MATCHES ";kleidicv;") @@ -1020,6 +1030,14 @@ foreach(hal ${OpenCV_HAL}) else() message(STATUS "FastCV: fastcv is not available, disabling fastcv...") endif() + elseif(hal STREQUAL "armpl_hal") + if((ARM OR AARCH64 OR ARM64) AND NOT WINRT AND NOT IOS AND NOT XROS) + add_subdirectory(hal/armpl) + ocv_hal_register(ARMPL_HAL_LIBRARIES ARMPL_HAL_HEADERS ARMPL_HAL_INCLUDE_DIRS) + list(APPEND OpenCV_USED_HAL "ARMPL (ver ${ARMPL_HAL_VERSION})") + else() + message(STATUS "ARMPL: ARM Performance Libraries not available on this platform, disabling armpl...") + endif() elseif(hal STREQUAL "kleidicv") add_subdirectory(hal/kleidicv) ocv_hal_register(KLEIDICV_HAL_LIBRARIES KLEIDICV_HAL_HEADERS KLEIDICV_HAL_INCLUDE_DIRS) @@ -1797,6 +1815,12 @@ if(WITH_IPP AND HAVE_IPP) endif() endif() +if(WITH_ARMPL AND HAVE_ARMPL) + status(" ARM Perf Lib:" "${ARMPL_VERSION_STR}") + status(" at:" "${ARMPL_ROOT_DIR}") + status(" variant:" "${ARMPL_LIB_NAME}") +endif() + if(WITH_VA OR HAVE_VA) status(" VA:" HAVE_VA THEN "YES" ELSE NO) endif() @@ -1885,6 +1909,9 @@ endif() if(WITH_FASTCV OR HAVE_FASTCV) status(" FastCV:" HAVE_FASTCV THEN "YES (${FASTCV_LIBRARY})" ELSE "NO") endif() +if(WITH_ARMPL OR HAVE_ARMPL) + status(" ARM Perf Lib:" HAVE_ARMPL THEN "YES (${ARMPL_LIBRARY})" ELSE "NO") +endif() status(" Custom HAL:" OpenCV_USED_HAL THEN "YES (${OpenCV_USED_HAL})" ELSE "NO") diff --git a/cmake/OpenCVFindARMPL.cmake b/cmake/OpenCVFindARMPL.cmake new file mode 100644 index 0000000000..508f43bedf --- /dev/null +++ b/cmake/OpenCVFindARMPL.cmake @@ -0,0 +1,172 @@ +if(NOT AARCH64 AND NOT ARM64 AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64") + return() +endif() + +if(NOT WITH_ARMPL) + return() +endif() + +set(ARMPL_ROOT_DIR "" CACHE PATH "Path to ARM Performance Libraries root directory") + +if(NOT ARMPL_ROOT_DIR) + if(DEFINED ENV{ARMPL_DIR}) + set(ARMPL_ROOT_DIR "$ENV{ARMPL_DIR}") + endif() +endif() + +find_path(ARMPL_INCLUDE_DIR + NAMES armpl.h + HINTS + "${ARMPL_ROOT_DIR}/include" + "${ARMPL_ROOT_DIR}/include_lp64" + PATHS + /opt/arm/armpl/include + /usr/include/armpl + ENV ARMPL_DIR + PATH_SUFFIXES include + NO_DEFAULT_PATH +) + +if(WITH_OPENMP AND OpenMP_CXX_FOUND) + set(ARMPL_USE_OPENMP TRUE) + set(ARMPL_LIB_CANDIDATES + armpl_lp64_mp + armpl_ilp64_mp + ) +else() + set(ARMPL_USE_OPENMP FALSE) + set(ARMPL_LIB_CANDIDATES + armpl_lp64 + armpl_ilp64 + ) +endif() + +set(ARMPL_LIB_FOUND FALSE) +set(ARMPL_LIB_NAME "") +set(ARMPL_LIB_FILE "") + +foreach(lib_candidate ${ARMPL_LIB_CANDIDATES}) + if(WIN32) + set(ARMPL_LIB_FILE_DLL "${ARMPL_ROOT_DIR}/lib/${lib_candidate}.dll.lib") + set(ARMPL_LIB_FILE_LIB "${ARMPL_ROOT_DIR}/lib/${lib_candidate}.lib") + if(EXISTS "${ARMPL_LIB_FILE_DLL}") + set(ARMPL_LIB_FILE "${ARMPL_LIB_FILE_DLL}") + set(ARMPL_LIB_NAME "${lib_candidate}") + set(ARMPL_LIB_FOUND TRUE) + break() + elseif(EXISTS "${ARMPL_LIB_FILE_LIB}") + set(ARMPL_LIB_FILE "${ARMPL_LIB_FILE_LIB}") + set(ARMPL_LIB_NAME "${lib_candidate}") + set(ARMPL_LIB_FOUND TRUE) + break() + endif() + else() + set(ARMPL_LIB_FILE "${ARMPL_ROOT_DIR}/lib/lib${lib_candidate}.a") + if(EXISTS "${ARMPL_LIB_FILE}") + set(ARMPL_LIB_NAME "${lib_candidate}") + set(ARMPL_LIB_FOUND TRUE) + break() + endif() + endif() +endforeach() + +if(NOT ARMPL_LIB_FOUND) + find_library(ARMPL_LIBRARY_FALLBACK + NAMES ${ARMPL_LIB_CANDIDATES} + HINTS "${ARMPL_ROOT_DIR}/lib" + PATHS + /opt/arm/armpl/lib + /usr/lib/armpl + ENV ARMPL_DIR + PATH_SUFFIXES lib + NO_DEFAULT_PATH + ) + if(ARMPL_LIBRARY_FALLBACK) + set(ARMPL_LIB_FILE "${ARMPL_LIBRARY_FALLBACK}") + get_filename_component(ARMPL_LIB_NAME "${ARMPL_LIBRARY_FALLBACK}" NAME_WE) + string(REGEX REPLACE "^lib" "" ARMPL_LIB_NAME "${ARMPL_LIB_NAME}") + set(ARMPL_LIB_FOUND TRUE) + endif() +endif() + +if(NOT ARMPL_INCLUDE_DIR OR NOT ARMPL_LIB_FOUND) + message(WARNING + "ARM Performance Libraries: NOT FOUND. " + "Please install ArmPL manually and set -DARMPL_ROOT_DIR=. " + "Download from: https://developer.arm.com/Tools%20and%20Software/Arm%20Performance%20Libraries" + ) + return() +endif() + +set(ARMPL_VERSION_STR "unknown") +if(EXISTS "${ARMPL_INCLUDE_DIR}/armpl.h") + file(STRINGS "${ARMPL_INCLUDE_DIR}/armpl.h" ARMPL_VERSION_MAJOR_LINE + REGEX "#define ARMPL_VERSION_MAJOR") + file(STRINGS "${ARMPL_INCLUDE_DIR}/armpl.h" ARMPL_VERSION_MINOR_LINE + REGEX "#define ARMPL_VERSION_MINOR") + if(ARMPL_VERSION_MAJOR_LINE AND ARMPL_VERSION_MINOR_LINE) + string(REGEX REPLACE ".*ARMPL_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" + ARMPL_VERSION_MAJOR "${ARMPL_VERSION_MAJOR_LINE}") + string(REGEX REPLACE ".*ARMPL_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" + ARMPL_VERSION_MINOR "${ARMPL_VERSION_MINOR_LINE}") + set(ARMPL_VERSION_STR "${ARMPL_VERSION_MAJOR}.${ARMPL_VERSION_MINOR}") + else() + file(STRINGS "${ARMPL_INCLUDE_DIR}/armpl.h" ARMPL_BUILD_LINE + REGEX "#define ARMPL_BUILD") + if(ARMPL_BUILD_LINE) + string(REGEX REPLACE ".*ARMPL_BUILD[ \t]+([0-9]+).*" "\\1" + ARMPL_VERSION_STR "${ARMPL_BUILD_LINE}") + else() + string(REGEX MATCH "armpl_([0-9]+\\.[0-9]+)" ARMPL_VERSION_MATCH "${ARMPL_ROOT_DIR}") + if(CMAKE_MATCH_1) + set(ARMPL_VERSION_STR "${CMAKE_MATCH_1}") + endif() + endif() + endif() +endif() + +if(ARMPL_USE_OPENMP) + message(STATUS "ArmPL: OpenMP enabled, using parallel version (${ARMPL_LIB_NAME})") +else() + message(WARNING + "ArmPL: OpenMP is not enabled. " + "Using serial version of ArmPL (${ARMPL_LIB_NAME}). " + "For better performance enable OpenMP with -DWITH_OPENMP=ON" + ) +endif() + +if(NOT TARGET armpl) + if(WIN32) + add_library(armpl SHARED IMPORTED) + find_file(ARMPL_DLL + NAMES "${ARMPL_LIB_NAME}.dll" + HINTS "${ARMPL_ROOT_DIR}/bin" + NO_DEFAULT_PATH + ) + set_target_properties(armpl PROPERTIES + IMPORTED_IMPLIB "${ARMPL_LIB_FILE}" + IMPORTED_LOCATION "${ARMPL_DLL}" + INTERFACE_INCLUDE_DIRECTORIES "${ARMPL_INCLUDE_DIR}" + ) + else() + add_library(armpl UNKNOWN IMPORTED) + set_target_properties(armpl PROPERTIES + IMPORTED_LOCATION "${ARMPL_LIB_FILE}" + INTERFACE_INCLUDE_DIRECTORIES "${ARMPL_INCLUDE_DIR}" + ) + endif() + if(ARMPL_USE_OPENMP) + set_target_properties(armpl PROPERTIES + INTERFACE_LINK_LIBRARIES OpenMP::OpenMP_CXX + ) + endif() +endif() + +set(ARMPL_LIBRARIES armpl CACHE INTERNAL "ArmPL libraries") +set(ARMPL_INCLUDE_DIRS "${ARMPL_INCLUDE_DIR}" CACHE INTERNAL "ArmPL include dirs") +set(ARMPL_INCLUDE_PATH "${ARMPL_INCLUDE_DIR}" CACHE INTERNAL "ArmPL include path") +set(ARMPL_LIBRARY "${ARMPL_LIB_FILE}" CACHE INTERNAL "ArmPL library path") +set(ARMPL_LIB_NAME "${ARMPL_LIB_NAME}" CACHE INTERNAL "ArmPL library variant") +set(ARMPL_VERSION_STR "${ARMPL_VERSION_STR}" CACHE INTERNAL "ArmPL version") +set(ARMPL_ROOT_DIR "${ARMPL_ROOT_DIR}" CACHE PATH "ArmPL root directory") +set(HAVE_ARMPL TRUE CACHE BOOL "ArmPL found and enabled" FORCE) diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake index 6976aeac1b..f3fe215c6f 100644 --- a/cmake/OpenCVFindLibsPerf.cmake +++ b/cmake/OpenCVFindLibsPerf.cmake @@ -38,6 +38,21 @@ if(WITH_IPP) endif() endif() +if(WITH_ARMPL) + include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindARMPL.cmake") + if(HAVE_ARMPL) + message(STATUS "Using ARM Performance Libraries") + ocv_include_directories(${ARMPL_INCLUDE_DIRS}) + list(APPEND OPENCV_LINKER_LIBS ${ARMPL_LIBRARIES}) + add_compile_definitions(HAVE_ARMPL) + if(WITH_OPENMP AND OpenMP_CXX_FOUND) + list(APPEND OPENCV_LINKER_LIBS OpenMP::OpenMP_CXX) + endif() + else() + message(STATUS "ARM Performance Libraries: Not found or not available") + endif() +endif() + # --- CUDA --- if(WITH_CUDA) if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE) diff --git a/doc/tutorials/introduction/table_of_content_introduction.markdown b/doc/tutorials/introduction/table_of_content_introduction.markdown index d67dd20cbc..3ca34a4f56 100644 --- a/doc/tutorials/introduction/table_of_content_introduction.markdown +++ b/doc/tutorials/introduction/table_of_content_introduction.markdown @@ -19,6 +19,7 @@ Introduction to OpenCV {#tutorial_table_of_content_introduction} - @subpage tutorial_windows_visual_studio_opencv - @subpage tutorial_windows_visual_studio_image_watch - @subpage tutorial_windows_msys2_vscode +- @subpage tutorial_windows_armpl ##### Java & Android - @subpage tutorial_java_dev_intro diff --git a/doc/tutorials/introduction/windows_armpl/windows_armpl_opencv.markdown b/doc/tutorials/introduction/windows_armpl/windows_armpl_opencv.markdown new file mode 100644 index 0000000000..9bcc975f36 --- /dev/null +++ b/doc/tutorials/introduction/windows_armpl/windows_armpl_opencv.markdown @@ -0,0 +1,169 @@ +Building OpenCV with ARM Performance Libraries (ARMPL) on Windows {#tutorial_windows_armpl} +================================================================== + +@prev_tutorial{tutorial_windows_install} +@next_tutorial{tutorial_linux_install} + +| | | +| -: | :- | + +@tableofcontents + +Introduction {#tutorial_windows_armpl_intro} +============ + +This tutorial explains how to build OpenCV on Windows (AArch64) with +[ARM Performance Libraries (ARMPL)](https://developer.arm.com/Tools%20and%20Software/Arm%20Performance%20Libraries) +as a math backend. ARMPL provides optimized BLAS and LAPACK routines for Arm-based hardware +and can significantly accelerate OpenCV operations such as DFT and DCT. + +Step 1: Download and Install ARM Performance Libraries {#tutorial_windows_armpl_download} +===================================================== + +1. Open a browser and go to the + [ARM Performance Libraries Downloads page](https://developer.arm.com/Tools%20and%20Software/Arm%20Performance%20Libraries#Downloads). + +2. Under **Windows / AArch64**, download the installer for your preferred toolchain: + + | File | Architecture | Size | + |------|--------------|------| + | `arm-performance-libraries_26.01_Windows.msi` | AArch64 | ~240 MiB | + +3. Run the downloaded `.msi` installer and follow the on-screen instructions. + The default installation directory is: + ``` + C:\Program Files\Arm Performance Libraries\armpl_26.01 + ``` + +Step 2: Configure System Environment Variables {#tutorial_windows_armpl_env} +============================================= + +OpenCV's CMake scripts (and the ARMPL runtime itself) need to find the library files at both +build time and run time. Add the following entries to the **System** `PATH` variable: + +1. Open **System Properties**, click **Advanced**, then **Environment Variables**. +2. Under **System variables**, select `Path` and click **Edit**. +3. Add the two paths below (adjust the version number if yours differs): + + ``` + C:\Program Files\Arm Performance Libraries\armpl_26.01\lib + C:\Program Files\Arm Performance Libraries\armpl_26.01\bin + ``` + +4. Click **OK** on every dialog to save. + +Step 3: Clone OpenCV {#tutorial_windows_armpl_clone} +==================== + +```bat +git clone https://github.com/opencv/opencv.git +cd opencv +``` + +If you also need the extra modules: + +```bat +git clone https://github.com/opencv/opencv_contrib.git +``` + +Step 4: Configure with CMake {#tutorial_windows_armpl_cmake} +============================ + +Create a build directory and run CMake with ARMPL support enabled. + +**Without OpenMP (single-threaded ARMPL):** + +```bat +mkdir build && cd build + +cmake -G "Visual Studio 17 2022" -A ARM64 ^ + -DWITH_ARMPL=ON ^ + -DARMPL_ROOT_DIR="C:\Program Files\Arm Performance Libraries\armpl_26.01" ^ + -DWITH_OPENMP=OFF ^ + .. +``` + +**With OpenMP (multi-threaded ARMPL):** + +ARMPL ships both serial and OpenMP-enabled library variants. To use the multi-threaded variant, +enable OpenMP in CMake: + +```bat +mkdir build && cd build + +cmake -G "Visual Studio 17 2022" -A ARM64 ^ + -DWITH_ARMPL=ON ^ + -DARMPL_ROOT_DIR="C:\Program Files\Arm Performance Libraries\armpl_26.01" ^ + -DWITH_OPENMP=ON ^ + .. +``` + +@note Enabling `WITH_OPENMP=ON` causes CMake to link against the `armpl_lp64_mp` (multi-threaded) +variant of ARMPL. Disabling it links against the serial `armpl_lp64` variant. Only one variant +should be enabled at a time to avoid symbol conflicts. + +Step 5: Build and Install {#tutorial_windows_armpl_build} +========================= + +Open the generated `.sln` file in Visual Studio and build the **Release** configuration, or +build from the command line: + +```bat +cmake --build . --config Release --parallel +cmake --install . --config Release +``` + +Step 6: Verify the Build {#tutorial_windows_armpl_verify} +========================= + +After a successful build, confirm that OpenCV detects ARMPL by running: + +```bat +opencv_version --verbose 2>&1 | findstr /i armpl +``` + +You should see a line similar to: + +``` + ARMPL: YES (armpl_26.01) +``` + +Alternatively, check the CMake configuration log for the line: + +``` +-- ARMPL support: YES +``` + +Troubleshooting {#tutorial_windows_armpl_troubleshoot} +=============== + +**CMake cannot find ARMPL:** + +Make sure `ARMPL_ROOT_DIR` points to the folder that contains both `include\` and `lib\` +sub-directories: + +``` +C:\Program Files\Arm Performance Libraries\armpl_26.01 + bin\ + include\ + lib\ +``` + +**Runtime error: DLL not found:** + +Ensure that both the `lib\` and `bin\` directories are on the system `PATH` and that +you opened a new Command Prompt after adding them (changes are not picked up by already-open +sessions). + +**Linker errors with OpenMP:** + +If you see duplicate symbol errors when `WITH_OPENMP=ON`, make sure you are not also linking +against the serial ARMPL library. Pass `-DWITH_OPENMP=ON` consistently and clean the build +directory before re-running CMake. + +See also {#tutorial_windows_armpl_seealso} +========= + +- @ref tutorial_windows_install - Generic Windows build guide +- [ARM Performance Libraries documentation](https://developer.arm.com/documentation/101004/) +- @ref tutorial_general_install - General installation guide diff --git a/hal/armpl/CMakeLists.txt b/hal/armpl/CMakeLists.txt new file mode 100644 index 0000000000..15f59eb353 --- /dev/null +++ b/hal/armpl/CMakeLists.txt @@ -0,0 +1,28 @@ +if(HAVE_ARMPL) + set(ARMPL_HAL_VERSION 0.0.1 CACHE INTERNAL "") + set(ARMPL_HAL_LIBRARIES "armpl_hal" CACHE INTERNAL "") + set(ARMPL_HAL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include" CACHE INTERNAL "") + set(ARMPL_HAL_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/include/armpl_hal_core.hpp" + CACHE INTERNAL "") + file(GLOB ARMPL_HAL_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") + add_library(armpl_hal STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL} ${ARMPL_HAL_FILES}) + target_include_directories(armpl_hal PRIVATE + ${CMAKE_SOURCE_DIR}/modules/core/include + ${CMAKE_BINARY_DIR} + ${ARMPL_HAL_INCLUDE_DIRS} + ${ARMPL_INCLUDE_PATH}) + target_link_libraries(armpl_hal PUBLIC ${ARMPL_LIBRARY}) + if(WITH_OPENMP AND OpenMP_CXX_FOUND) + target_link_libraries(armpl_hal PUBLIC OpenMP::OpenMP_CXX) + endif() + set_target_properties(armpl_hal PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH}) + if(NOT BUILD_SHARED_LIBS) + ocv_install_target(armpl_hal EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) + endif() + if(ENABLE_SOLUTION_FOLDERS) + set_target_properties(armpl_hal PROPERTIES FOLDER "3rdparty") + endif() +else() + message(STATUS "ArmPL is not available, disabling related HAL") +endif(HAVE_ARMPL) diff --git a/hal/armpl/include/armpl_hal_core.hpp b/hal/armpl/include/armpl_hal_core.hpp new file mode 100644 index 0000000000..d2d505cd51 --- /dev/null +++ b/hal/armpl/include/armpl_hal_core.hpp @@ -0,0 +1,91 @@ +#ifndef OPENCV_ARMPL_HAL_CORE_HPP +#define OPENCV_ARMPL_HAL_CORE_HPP + +#ifdef HAVE_ARMPL + +#include +#include +#include +#include + +#ifndef cvhalDFT +struct cvhalDFT; +#endif + +int armpl_hal_dftInit2D(cvhalDFT **context, int width, int height, + int depth, int src_channels, int dst_channels, + int flags, int nonzero_rows); + +int armpl_hal_dft2D(cvhalDFT *context, const unsigned char *src_data, + size_t src_step, unsigned char *dst_data, size_t dst_step); + +int armpl_hal_dftFree2D(cvhalDFT *context); + +#undef cv_hal_dftInit2D +#define cv_hal_dftInit2D armpl_hal_dftInit2D + +#undef cv_hal_dft2D +#define cv_hal_dft2D armpl_hal_dft2D + +#undef cv_hal_dftFree2D +#define cv_hal_dftFree2D armpl_hal_dftFree2D + +struct ArmplDFTSpec_C_32fc { + fftwf_plan plan; + int n; + bool isInverse; +}; + +struct ArmplDFTSpec_C_64fc { + fftw_plan plan; + int n; + bool isInverse; +}; + +struct ArmplDFTSpec_R_32f { + fftwf_plan plan; + int n; + bool isInverse; + double scale; +}; + +struct ArmplDFTSpec_R_64f { + fftw_plan plan; + int n; + bool isInverse; + double scale; +}; + +int armpl_hal_dftInit1D(cvhalDFT **context, int len, int count, + int depth, int flags, bool *needBuffer); + +int armpl_hal_dft1D(cvhalDFT *context, + const unsigned char *src, unsigned char *dst); + +int armpl_hal_dftFree1D(cvhalDFT *context); + +#undef cv_hal_dftInit1D +#define cv_hal_dftInit1D armpl_hal_dftInit1D + +#undef cv_hal_dft1D +#define cv_hal_dft1D armpl_hal_dft1D + +#undef cv_hal_dftFree1D +#define cv_hal_dftFree1D armpl_hal_dftFree1D + +int armpl_hal_dctInit2D(cvhalDFT **context, int width, int height, + int depth, int flags); +int armpl_hal_dct2D(cvhalDFT *context, const unsigned char *src_data, + size_t src_step, unsigned char *dst_data, size_t dst_step); +int armpl_hal_dctFree2D(cvhalDFT *context); + +#undef cv_hal_dctInit2D +#define cv_hal_dctInit2D armpl_hal_dctInit2D +#undef cv_hal_dct2D +#define cv_hal_dct2D armpl_hal_dct2D +#undef cv_hal_dctFree2D +#define cv_hal_dctFree2D armpl_hal_dctFree2D + +#endif // HAVE_ARMPL + +#endif // OPENCV_ARMPL_HAL_CORE_HPP diff --git a/hal/armpl/src/armpl_hal_core.cpp b/hal/armpl/src/armpl_hal_core.cpp new file mode 100644 index 0000000000..bb5ad02d5e --- /dev/null +++ b/hal/armpl/src/armpl_hal_core.cpp @@ -0,0 +1,2642 @@ +#ifdef HAVE_ARMPL + +#include "armpl_hal_core.hpp" + +#include +#include +#include +#include +enum ArmPLDFTMode +{ + ARMPL_DFT_C2C, + ARMPL_DFT_R2C, + ARMPL_DFT_C2C_ROW, + ARMPL_DFT_R_ROW, + ARMPL_DFT_1D_C2C_FWD, + ARMPL_DFT_1D_C2C_FWD_64, + ARMPL_DFT_C2R, + ARMPL_DFT_2D_C2R_INV, + ARMPL_DFT_1D_C2C_INV, + ARMPL_DFT_1D_C2C_INV_64, + ARMPL_DFT_1D_R2C_32, + ARMPL_DFT_1D_R2C_64, + ARMPL_DFT_1D_R2C_FWD, + ARMPL_DFT_1D_R2C_FWD_64, + ARMPL_DFT_1D_R2C_ROWS_32, + ARMPL_DFT_1D_R2C_ROWS_64, + ARMPL_DFT_1D_C2R_INV, + ARMPL_DFT_1D_C2R_INV_64, + ARMPL_DCT_2D, + ARMPL_DCT_2D_64, + ARMPL_DCT_ROW, + ARMPL_DCT_ROW_64, + ARMPL_DFT_C2C_D, + ARMPL_DFT_R2C_D, + ARMPL_DFT_C2R_D, + ARMPL_DFT_C2C_ROW_D, + ARMPL_DFT_R_ROW_D +}; + +struct ArmPLD_C2CDFTContext +{ + ArmPLDFTMode mode = ARMPL_DFT_C2C_D; + int width, height; + bool inv, no_scale; + double scale; + fftw_plan plan_fwd, plan_inv; +}; + +struct ArmPLD_R2CDFTContext +{ + ArmPLDFTMode mode = ARMPL_DFT_R2C_D; + int width, height; + bool col_wise, no_scale; + double scale; + fftw_plan plan; +}; + +struct ArmPLD_C2RDFTContext +{ + ArmPLDFTMode mode = ARMPL_DFT_C2R_D; + int width, height; + bool col_wise, no_scale; + double scale; + fftw_plan plan; +}; + +struct ArmPLD_C2CRowDFTContext +{ + ArmPLDFTMode mode = ARMPL_DFT_C2C_ROW_D; + int width, height; + bool inv, no_scale; + double scale; + fftw_plan plan_fwd, plan_inv; + fftw_complex *fftw_buf; +}; + +struct ArmPLD_RRowDFTContext +{ + ArmPLDFTMode mode = ARMPL_DFT_R_ROW_D; + int width, height; + bool inv, no_scale; + double scale; + fftw_plan plan_fwd, plan_inv; + double *fftw_in_r, *fftw_out_r; + fftw_complex *fftw_in_c, *fftw_out_c; +}; + +struct ArmPL1DR2CFwdContext { + ArmPLDFTMode mode; + int len; + fftwf_plan plan; + float scale; + bool no_scale; + bool complex_output; +}; + +struct ArmPL1DR2CFwdContext64 { + ArmPLDFTMode mode; + int len; + fftw_plan plan; + double scale; + bool no_scale; + bool complex_output; +}; + +struct ArmPL1DC2RInvContext { + ArmPLDFTMode mode; + int len; + fftwf_plan plan; + float scale; + bool no_scale; + bool complex_input; +}; + +struct ArmPL1DC2RInvContext64 { + ArmPLDFTMode mode; + int len; + fftw_plan plan; + double scale; + bool no_scale; + bool complex_input; +}; + +struct ArmPLDCT2DContext +{ + ArmPLDFTMode mode; + int width, height; + bool inv, no_scale; + fftwf_plan plan_fwd, plan_inv; + float scale_dc, scale_axis, scale_rest; + float *buf; + + ArmPLDCT2DContext() + : mode(ARMPL_DCT_2D), width(0), height(0), inv(false), no_scale(true), + plan_fwd(0), plan_inv(0), + scale_dc(1.f), scale_axis(1.f), scale_rest(1.f), buf(0) {} +}; + +struct ArmPLDCT2DContext64 +{ + ArmPLDFTMode mode; + int width, height; + bool inv, no_scale; + fftw_plan plan_fwd, plan_inv; + double scale_dc, scale_axis, scale_rest; + + ArmPLDCT2DContext64() + : mode(ARMPL_DCT_2D_64), width(0), height(0), inv(false), no_scale(true), + plan_fwd(0), plan_inv(0), + scale_dc(1.0), scale_axis(1.0), scale_rest(1.0) {} +}; + +struct ArmPLC2RDFTContext +{ + ArmPLDFTMode mode = ARMPL_DFT_C2R; + int width, height; + bool col_wise; + fftwf_plan plan; + float scale; + bool no_scale; +}; + +struct ArmPLDCTRowContext +{ + ArmPLDFTMode mode; + int width, height; + bool inv, no_scale; + fftwf_plan plan_fwd, plan_inv; + float scale_dc, scale_rest; + float *fftw_buf; + + ArmPLDCTRowContext() + : mode(ARMPL_DCT_ROW), width(0), height(0), inv(false), no_scale(true), + plan_fwd(0), plan_inv(0), + scale_dc(1.f), scale_rest(1.f), fftw_buf(0) {} +}; + +struct ArmPLDCTRowContext64 +{ + ArmPLDFTMode mode; + int width, height; + bool inv, no_scale; + fftw_plan plan_fwd, plan_inv; + double scale_dc, scale_rest; + double *fftw_buf; + + ArmPLDCTRowContext64() + : mode(ARMPL_DCT_ROW_64), width(0), height(0), inv(false), no_scale(true), + plan_fwd(0), plan_inv(0), + scale_dc(1.0), scale_rest(1.0), fftw_buf(0) {} +}; + +struct ArmPLC2CDFTContext +{ + ArmPLDFTMode mode; + int width, height; + bool inv, no_scale; + fftwf_plan plan_fwd, plan_inv; + float scale; + + ArmPLC2CDFTContext() + : mode(ARMPL_DFT_C2C), width(0), height(0), inv(false), no_scale(true), + plan_fwd(0), plan_inv(0), scale(1.f) {} +}; + +struct ArmPLR2CDFTContext +{ + ArmPLDFTMode mode; + int width, height; + bool col_wise, no_scale; + fftwf_plan plan; + float scale; + + ArmPLR2CDFTContext() + : mode(ARMPL_DFT_R2C), width(0), height(0), col_wise(false), no_scale(true), + plan(0), scale(1.f) {} +}; + +struct ArmPLC2CRowDFTContext +{ + ArmPLDFTMode mode; + int width, height; + bool inv, no_scale; + fftwf_plan plan_fwd, plan_inv; + float scale; + fftwf_complex *fftw_buf; + + ArmPLC2CRowDFTContext() + : mode(ARMPL_DFT_C2C_ROW), width(0), height(0), inv(false), no_scale(true), + plan_fwd(0), plan_inv(0), scale(1.f), fftw_buf(0) {} +}; + +struct ArmPLRRowDFTContext +{ + ArmPLDFTMode mode; + int width, height; + bool inv, no_scale; + fftwf_plan plan_fwd, plan_inv; + float scale; + float *fftw_in_r; + fftwf_complex *fftw_out_c; + fftwf_complex *fftw_in_c; + float *fftw_out_r; + + ArmPLRRowDFTContext() + : mode(ARMPL_DFT_R_ROW), width(0), height(0), inv(false), no_scale(true), + plan_fwd(0), plan_inv(0), scale(1.f), + fftw_in_r(0), fftw_out_c(0), fftw_in_c(0), fftw_out_r(0) {} +}; + +struct ArmPL1DC2CFwdContext +{ + ArmPLDFTMode mode; + int len; + bool no_scale; + fftwf_plan plan; + float scale; + + ArmPL1DC2CFwdContext() + : mode(ARMPL_DFT_1D_C2C_FWD), len(0), no_scale(true), + plan(0), scale(1.f) {} +}; + +struct ArmPL1DC2CFwdContext64 +{ + ArmPLDFTMode mode; + int len; + bool no_scale; + fftw_plan plan; + double scale; + + ArmPL1DC2CFwdContext64() + : mode(ARMPL_DFT_1D_C2C_FWD_64), len(0), no_scale(true), + plan(0), scale(1.0) {} +}; + +struct ArmPL1DR2CContext32 +{ + ArmPLDFTMode mode; + int len; + bool no_scale; + float scale; + fftwf_plan plan; + + ArmPL1DR2CContext32() + : mode(ARMPL_DFT_1D_R2C_32), len(0), no_scale(true), + scale(1.f), plan(0) {} +}; + +struct ArmPL1DR2CContext64 +{ + ArmPLDFTMode mode; + int len; + bool no_scale; + double scale; + fftw_plan plan; + + ArmPL1DR2CContext64() + : mode(ARMPL_DFT_1D_R2C_64), len(0), no_scale(true), + scale(1.0), plan(0) {} +}; + +struct ArmPL1DR2CRowsContext32 +{ + ArmPLDFTMode mode; + int len; + int count; + bool no_scale; + float scale; + fftwf_plan plan; + + ArmPL1DR2CRowsContext32() + : mode(ARMPL_DFT_1D_R2C_ROWS_32), len(0), count(0), no_scale(true), + scale(1.f), plan(0) {} +}; + +struct ArmPL1DR2CRowsContext64 +{ + ArmPLDFTMode mode; + int len; + int count; + bool no_scale; + double scale; + fftw_plan plan; + + ArmPL1DR2CRowsContext64() + : mode(ARMPL_DFT_1D_R2C_ROWS_64), len(0), count(0), no_scale(true), + scale(1.0), plan(0) {} +}; + +int armpl_hal_dftInit2D(cvhalDFT **context, + int width, int height, + int depth, + int src_channels, int dst_channels, + int flags, int nonzero_rows) +{ + if (nonzero_rows != 0) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const bool isInverse = (flags & CV_HAL_DFT_INVERSE) != 0; + const bool isScaled = (flags & CV_HAL_DFT_SCALE) != 0; + const bool isRowWise = (flags & CV_HAL_DFT_ROWS) != 0; + + if (depth == CV_32F) + { + if (!isRowWise && src_channels == 2 && dst_channels == 2) + { + const int norm_flag = !isScaled ? 8 : (isInverse ? 2 : 1); + float scale = 1.0f; + const float inv_total = 1.0f / (float)(width * height); + if (isInverse) { if (norm_flag == 1 || norm_flag == 2) scale = inv_total; } + else { if (norm_flag == 1) scale = inv_total; } + + const size_t total = (size_t)width * height; + fftwf_complex *tmp_in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * total); + fftwf_complex *tmp_out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * total); + if (!tmp_in || !tmp_out) + { + if (tmp_in) fftwf_free(tmp_in); + if (tmp_out) fftwf_free(tmp_out); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + fftwf_plan pf = fftwf_plan_dft_2d(height, width, tmp_in, tmp_out, FFTW_FORWARD, FFTW_ESTIMATE); + fftwf_plan pi = fftwf_plan_dft_2d(height, width, tmp_in, tmp_out, FFTW_BACKWARD, FFTW_ESTIMATE); + fftwf_free(tmp_in); + fftwf_free(tmp_out); + if (!pf || !pi) + { + if (pf) fftwf_destroy_plan(pf); + if (pi) fftwf_destroy_plan(pi); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + ArmPLC2CDFTContext *ctx = new ArmPLC2CDFTContext(); + ctx->width = width; ctx->height = height; + ctx->inv = isInverse; ctx->no_scale = (scale == 1.0f); + ctx->plan_fwd = pf; ctx->plan_inv = pi; ctx->scale = scale; + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + if (!isRowWise && src_channels == 1 && dst_channels == 1) + { + if (isInverse) + { + const bool col_wise = (width == 1); + float scale = 1.0f; + if (isScaled) + scale = col_wise ? (1.0f / height) : (1.0f / (float)(width * height)); + + fftwf_plan plan = 0; + if (col_wise) + { + fftwf_complex *dc = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (height/2 + 1)); + float *dr = (float*) fftwf_malloc(sizeof(float) * height); + if (!dc || !dr) { if (dc) fftwf_free(dc); if (dr) fftwf_free(dr); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + plan = fftwf_plan_dft_c2r_1d(height, dc, dr, FFTW_ESTIMATE); + fftwf_free(dc); + fftwf_free(dr); + } + else + { + fftwf_complex *dc = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (size_t)height * (width/2 + 1)); + float *dr = (float*) fftwf_malloc(sizeof(float) * (size_t)width * height); + if (!dc || !dr) { if (dc) fftwf_free(dc); if (dr) fftwf_free(dr); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + plan = fftwf_plan_dft_c2r_2d(height, width, dc, dr, FFTW_ESTIMATE); + fftwf_free(dc); + fftwf_free(dr); + } + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPLC2RDFTContext *ctx = new ArmPLC2RDFTContext(); + ctx->width = width; + ctx->height = height; + ctx->col_wise = col_wise; + ctx->plan = plan; + ctx->scale = scale; + ctx->no_scale = (scale == 1.0f); + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + + const bool col_wise = (width == 1); + float scale = 1.0f; + if (isScaled) + scale = col_wise ? (1.0f / height) : (1.0f / (float)(width * height)); + + fftwf_plan plan = 0; + if (col_wise) + { + float *dr = (float*) fftwf_malloc(sizeof(float) * height); + fftwf_complex *dc = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (height/2 + 1)); + if (!dr || !dc) { if (dr) fftwf_free(dr); if (dc) fftwf_free(dc); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + plan = fftwf_plan_dft_r2c_1d(height, dr, dc, FFTW_ESTIMATE); + fftwf_free(dr); fftwf_free(dc); + } + else + { + float *dr = (float*) fftwf_malloc(sizeof(float) * (size_t)width * height); + fftwf_complex *dc = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (size_t)height * (width/2 + 1)); + if (!dr || !dc) { if (dr) fftwf_free(dr); if (dc) fftwf_free(dc); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + plan = fftwf_plan_dft_r2c_2d(height, width, dr, dc, FFTW_ESTIMATE); + fftwf_free(dr); + fftwf_free(dc); + } + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPLR2CDFTContext *ctx = new ArmPLR2CDFTContext(); + ctx->width = width; ctx->height = height; + ctx->col_wise = col_wise; ctx->no_scale = (scale == 1.0f); + ctx->plan = plan; ctx->scale = scale; + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + if (isRowWise && src_channels == 2 && dst_channels == 2) + { + const int norm_flag = !isScaled ? 8 : (isInverse ? 2 : 1); + float scale = 1.0f; + const float inv_w = 1.0f / (float)width; + if (isInverse) { if (norm_flag == 1 || norm_flag == 2) scale = inv_w; } + else { if (norm_flag == 1) scale = inv_w; } + + fftwf_complex *fftw_buf = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * width); + if (!fftw_buf) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + fftwf_plan pf = fftwf_plan_dft_1d(width, fftw_buf, fftw_buf, FFTW_FORWARD, FFTW_ESTIMATE); + fftwf_plan pi = fftwf_plan_dft_1d(width, fftw_buf, fftw_buf, FFTW_BACKWARD, FFTW_ESTIMATE); + if (!pf || !pi) + { + if (pf) fftwf_destroy_plan(pf); + if (pi) fftwf_destroy_plan(pi); + fftwf_free(fftw_buf); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + ArmPLC2CRowDFTContext *ctx = new ArmPLC2CRowDFTContext(); + ctx->width = width; ctx->height = height; ctx->inv = isInverse; + ctx->plan_fwd = pf; ctx->plan_inv = pi; + ctx->scale = scale; ctx->no_scale = (scale == 1.0f); + ctx->fftw_buf = fftw_buf; + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + if (isRowWise && src_channels == 1 && dst_channels == 1) + { + float scale = 1.0f; + if (isScaled) scale = 1.0f / (float)width; + + float *fftw_in_r = (float*) fftwf_malloc(sizeof(float) * width); + fftwf_complex *fftw_out_c = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (width/2 + 1)); + fftwf_complex *fftw_in_c = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (width/2 + 1)); + float *fftw_out_r = (float*) fftwf_malloc(sizeof(float) * width); + if (!fftw_in_r || !fftw_out_c || !fftw_in_c || !fftw_out_r) + { + if (fftw_in_r) fftwf_free(fftw_in_r); + if (fftw_out_c) fftwf_free(fftw_out_c); + if (fftw_in_c) fftwf_free(fftw_in_c); + if (fftw_out_r) fftwf_free(fftw_out_r); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + fftwf_plan pf = fftwf_plan_dft_r2c_1d(width, fftw_in_r, fftw_out_c, FFTW_ESTIMATE); + fftwf_plan pi = fftwf_plan_dft_c2r_1d(width, fftw_in_c, fftw_out_r, FFTW_ESTIMATE); + if (!pf || !pi) + { + if (pf) fftwf_destroy_plan(pf); + if (pi) fftwf_destroy_plan(pi); + fftwf_free(fftw_in_r); fftwf_free(fftw_out_c); + fftwf_free(fftw_in_c); fftwf_free(fftw_out_r); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + ArmPLRRowDFTContext *ctx = new ArmPLRRowDFTContext(); + ctx->width = width; ctx->height = height; ctx->inv = isInverse; + ctx->plan_fwd = pf; ctx->plan_inv = pi; + ctx->scale = scale; ctx->no_scale = (scale == 1.0f); + ctx->fftw_in_r = fftw_in_r; ctx->fftw_out_c = fftw_out_c; + ctx->fftw_in_c = fftw_in_c; ctx->fftw_out_r = fftw_out_r; + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + if (depth == CV_64F) + { + if (!isRowWise && src_channels == 2 && dst_channels == 2) + { + const int norm_flag = !isScaled ? 8 : (isInverse ? 2 : 1); + double scale = 1.0; + const double inv_total = 1.0 / (double)(width * height); + if (isInverse) { if (norm_flag == 1 || norm_flag == 2) scale = inv_total; } + else { if (norm_flag == 1) scale = inv_total; } + + const size_t total = (size_t)width * height; + fftw_complex *tmp_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * total); + fftw_complex *tmp_out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * total); + if (!tmp_in || !tmp_out) + { + if (tmp_in) fftw_free(tmp_in); + if (tmp_out) fftw_free(tmp_out); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + fftw_plan pf = fftw_plan_dft_2d(height, width, tmp_in, tmp_out, FFTW_FORWARD, FFTW_ESTIMATE); + fftw_plan pi = fftw_plan_dft_2d(height, width, tmp_in, tmp_out, FFTW_BACKWARD, FFTW_ESTIMATE); + fftw_free(tmp_in); + fftw_free(tmp_out); + if (!pf || !pi) + { + if (pf) fftw_destroy_plan(pf); + if (pi) fftw_destroy_plan(pi); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + ArmPLD_C2CDFTContext *ctx = new ArmPLD_C2CDFTContext(); + ctx->width = width; ctx->height = height; + ctx->inv = isInverse; ctx->no_scale = (scale == 1.0); + ctx->plan_fwd = pf; ctx->plan_inv = pi; ctx->scale = scale; + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + if (!isRowWise && src_channels == 1 && dst_channels == 1) + { + if (isInverse) + { + const bool col_wise = (width == 1); + double scale = 1.0; + if (isScaled) + scale = col_wise ? (1.0 / height) : (1.0 / (double)(width * height)); + + fftw_plan plan = 0; + if (col_wise) + { + fftw_complex *dc = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (height/2 + 1)); + double *dr = (double*) fftw_malloc(sizeof(double) * height); + if (!dc || !dr) { if (dc) fftw_free(dc); if (dr) fftw_free(dr); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + plan = fftw_plan_dft_c2r_1d(height, dc, dr, FFTW_ESTIMATE); + fftw_free(dc); + fftw_free(dr); + } + else + { + fftw_complex *dc = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (size_t)height * (width/2 + 1)); + double *dr = (double*) fftw_malloc(sizeof(double) * (size_t)width * height); + if (!dc || !dr) { if (dc) fftw_free(dc); if (dr) fftw_free(dr); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + plan = fftw_plan_dft_c2r_2d(height, width, dc, dr, FFTW_ESTIMATE); + fftw_free(dc); + fftw_free(dr); + } + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPLD_C2RDFTContext *ctx = new ArmPLD_C2RDFTContext(); + ctx->width = width; + ctx->height = height; + ctx->col_wise = col_wise; + ctx->plan = plan; + ctx->scale = scale; + ctx->no_scale = (scale == 1.0); + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + + const bool col_wise = (width == 1); + double scale = 1.0; + if (isScaled) + scale = col_wise ? (1.0 / height) : (1.0 / (double)(width * height)); + + fftw_plan plan = 0; + if (col_wise) + { + double *dr = (double*) fftw_malloc(sizeof(double) * height); + fftw_complex *dc = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (height/2 + 1)); + if (!dr || !dc) { if (dr) fftw_free(dr); if (dc) fftw_free(dc); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + plan = fftw_plan_dft_r2c_1d(height, dr, dc, FFTW_ESTIMATE); + fftw_free(dr); fftw_free(dc); + } + else + { + double *dr = (double*) fftw_malloc(sizeof(double) * (size_t)width * height); + fftw_complex *dc = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (size_t)height * (width/2 + 1)); + if (!dr || !dc) { if (dr) fftw_free(dr); if (dc) fftw_free(dc); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + plan = fftw_plan_dft_r2c_2d(height, width, dr, dc, FFTW_ESTIMATE); + fftw_free(dr); + fftw_free(dc); + } + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPLD_R2CDFTContext *ctx = new ArmPLD_R2CDFTContext(); + ctx->width = width; ctx->height = height; + ctx->col_wise = col_wise; ctx->no_scale = (scale == 1.0); + ctx->plan = plan; ctx->scale = scale; + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + if (isRowWise && src_channels == 2 && dst_channels == 2) + { + const int norm_flag = !isScaled ? 8 : (isInverse ? 2 : 1); + double scale = 1.0; + const double inv_w = 1.0 / (double)width; + if (isInverse) { if (norm_flag == 1 || norm_flag == 2) scale = inv_w; } + else { if (norm_flag == 1) scale = inv_w; } + + fftw_complex *fftw_buf = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * width); + if (!fftw_buf) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + fftw_plan pf = fftw_plan_dft_1d(width, fftw_buf, fftw_buf, FFTW_FORWARD, FFTW_ESTIMATE); + fftw_plan pi = fftw_plan_dft_1d(width, fftw_buf, fftw_buf, FFTW_BACKWARD, FFTW_ESTIMATE); + if (!pf || !pi) + { + if (pf) fftw_destroy_plan(pf); + if (pi) fftw_destroy_plan(pi); + fftw_free(fftw_buf); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + ArmPLD_C2CRowDFTContext *ctx = new ArmPLD_C2CRowDFTContext(); + ctx->width = width; ctx->height = height; ctx->inv = isInverse; + ctx->plan_fwd = pf; ctx->plan_inv = pi; + ctx->scale = scale; ctx->no_scale = (scale == 1.0); + ctx->fftw_buf = fftw_buf; + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + if (isRowWise && src_channels == 1 && dst_channels == 1) + { + double scale = 1.0; + if (isScaled) scale = 1.0 / (double)width; + + double *fftw_in_r = (double*) fftw_malloc(sizeof(double) * width); + fftw_complex *fftw_out_c = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (width/2 + 1)); + fftw_complex *fftw_in_c = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (width/2 + 1)); + double *fftw_out_r = (double*) fftw_malloc(sizeof(double) * width); + if (!fftw_in_r || !fftw_out_c || !fftw_in_c || !fftw_out_r) + { + if (fftw_in_r) fftw_free(fftw_in_r); + if (fftw_out_c) fftw_free(fftw_out_c); + if (fftw_in_c) fftw_free(fftw_in_c); + if (fftw_out_r) fftw_free(fftw_out_r); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + fftw_plan pf = fftw_plan_dft_r2c_1d(width, fftw_in_r, fftw_out_c, FFTW_ESTIMATE); + fftw_plan pi = fftw_plan_dft_c2r_1d(width, fftw_in_c, fftw_out_r, FFTW_ESTIMATE); + if (!pf || !pi) + { + if (pf) fftw_destroy_plan(pf); + if (pi) fftw_destroy_plan(pi); + fftw_free(fftw_in_r); fftw_free(fftw_out_c); + fftw_free(fftw_in_c); fftw_free(fftw_out_r); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + ArmPLD_RRowDFTContext *ctx = new ArmPLD_RRowDFTContext(); + ctx->width = width; ctx->height = height; ctx->inv = isInverse; + ctx->plan_fwd = pf; ctx->plan_inv = pi; + ctx->scale = scale; ctx->no_scale = (scale == 1.0); + ctx->fftw_in_r = fftw_in_r; ctx->fftw_out_c = fftw_out_c; + ctx->fftw_in_c = fftw_in_c; ctx->fftw_out_r = fftw_out_r; + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +int armpl_hal_dft2D(cvhalDFT *context, + const unsigned char *src_data, size_t src_step, + unsigned char *dst_data, size_t dst_step) +{ + if (!context || !src_data || !dst_data) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const ArmPLDFTMode mode = *reinterpret_cast(context); + + if (mode == ARMPL_DFT_C2C) + { + ArmPLC2CDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan_fwd || !ctx->plan_inv) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const float sc = ctx->scale; + const bool no_scale = ctx->no_scale; + const size_t row_cb = (size_t)W * sizeof(fftwf_complex); + + fftwf_complex *in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (size_t)W * H); + fftwf_complex *out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (size_t)W * H); + if (!in || !out) { if (in) fftwf_free(in); if (out) fftwf_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + if (src_step == row_cb) + memcpy(in, src_data, (size_t)W * H * sizeof(fftwf_complex)); + else + { + for (int y = 0; y < H; y++) + { + const float *sr = reinterpret_cast(src_data + (size_t)y * src_step); + fftwf_complex *ir = in + (size_t)y * W; + int x = 0; +#ifdef CV_NEON + for (; x + 3 < W; x += 4) + { + vst1q_f32((float*)(ir+x), vld1q_f32(sr + x*2)); + vst1q_f32((float*)(ir+x+2), vld1q_f32(sr + (x+2)*2)); + } +#endif + for (; x < W; x++) { ir[x][0] = sr[x*2]; ir[x][1] = sr[x*2+1]; } + } + } + + fftwf_execute_dft(ctx->inv ? ctx->plan_inv : ctx->plan_fwd, in, out); + + if (no_scale) + { + if (dst_step == row_cb) + memcpy(dst_data, out, (size_t)W * H * sizeof(fftwf_complex)); + else + for (int y = 0; y < H; y++) + memcpy(dst_data + (size_t)y * dst_step, out + (size_t)y * W, row_cb); + } + else + { +#ifdef CV_NEON + const float32x4_t sv = vdupq_n_f32(sc); +#endif + for (int y = 0; y < H; y++) + { + float *dr = reinterpret_cast(dst_data + (size_t)y * dst_step); + const fftwf_complex *or_ = out + (size_t)y * W; + int x = 0; +#ifdef CV_NEON + for (; x + 3 < W; x += 4) + { + vst1q_f32(dr + x*2, vmulq_f32(vld1q_f32((const float*)(or_+x)), sv)); + vst1q_f32(dr + (x+2)*2, vmulq_f32(vld1q_f32((const float*)(or_+x+2)), sv)); + } +#endif + for (; x < W; x++) { dr[x*2] = or_[x][0]*sc; dr[x*2+1] = or_[x][1]*sc; } + } + } + + fftwf_free(in); + fftwf_free(out); + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_R2C) + { + ArmPLR2CDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const float sc = ctx->scale; + const bool no_scale = ctx->no_scale; + + if (ctx->col_wise) + { + float *in = (float*) fftwf_malloc(sizeof(float) * H); + fftwf_complex *out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (H/2 + 1)); + if (!in || !out) { if (in) fftwf_free(in); if (out) fftwf_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + for (int y = 0; y < H; y++) + in[y] = reinterpret_cast(src_data + (size_t)y * src_step)[0]; + fftwf_execute_dft_r2c(ctx->plan, in, out); + + const int pairs = (H - 1) / 2; + if (no_scale) + { + reinterpret_cast(dst_data)[0] = out[0][0]; + for (int k = 1; k <= pairs; k++) + { + reinterpret_cast(dst_data + (size_t)(2*k-1)*dst_step)[0] = out[k][0]; + reinterpret_cast(dst_data + (size_t)(2*k) *dst_step)[0] = out[k][1]; + } + if ((H & 1) == 0) + reinterpret_cast(dst_data + (size_t)(H-1)*dst_step)[0] = out[H/2][0]; + } + else + { + reinterpret_cast(dst_data)[0] = out[0][0] * sc; + for (int k = 1; k <= pairs; k++) + { + reinterpret_cast(dst_data + (size_t)(2*k-1)*dst_step)[0] = out[k][0] * sc; + reinterpret_cast(dst_data + (size_t)(2*k) *dst_step)[0] = out[k][1] * sc; + } + if ((H & 1) == 0) + reinterpret_cast(dst_data + (size_t)(H-1)*dst_step)[0] = out[H/2][0] * sc; + } + fftwf_free(in); + fftwf_free(out); + return CV_HAL_ERROR_OK; + } + + float *in = (float*) fftwf_malloc(sizeof(float) * (size_t)W * H); + fftwf_complex *out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (size_t)H * (W/2 + 1)); + if (!in || !out) { if (in) fftwf_free(in); if (out) fftwf_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + if (src_step == (size_t)W * sizeof(float)) + memcpy(in, src_data, (size_t)W * H * sizeof(float)); + else + for (int y = 0; y < H; y++) + memcpy(in + (size_t)y * W, + reinterpret_cast(src_data + (size_t)y * src_step), + (size_t)W * sizeof(float)); + fftwf_execute_dft_r2c(ctx->plan, in, out); + + const int half1 = W/2 + 1; + const int pairs = (W - 1) / 2; + const int even_W = (W & 1) == 0; + +#define PACK_BINS_F(dr_, fi_) \ + do { \ + float *_d = (dr_); int _fi = (fi_); \ + if (no_scale) { \ + for (int k = 1; k <= pairs; k++) { \ + _d[2*k-1] = out[_fi+k][0]; _d[2*k] = out[_fi+k][1]; \ + } \ + } else { \ + for (int k = 1; k <= pairs; k++) { \ + _d[2*k-1] = out[_fi+k][0]*sc; _d[2*k] = out[_fi+k][1]*sc; \ + } \ + } \ + } while(0) + + for (int y = 0; y < H; y++) + { + float *dr = reinterpret_cast(dst_data + (size_t)y * dst_step); + const int fi = y * half1; + + if (y == 0 || y == 1) + dr[0] = no_scale ? out[fi][0] : out[fi][0] * sc; + else if ((y & 1) == 0) + { + const int fi_c0 = (y / 2) * half1; + dr[0] = no_scale ? out[fi_c0][1] : out[fi_c0][1] * sc; + } + else + { + const int fi_c0 = ((y + 1) / 2) * half1; + dr[0] = no_scale ? out[fi_c0][0] : out[fi_c0][0] * sc; + } + + PACK_BINS_F(dr, fi); + + if (even_W) + { + if (y == 0 || y == 1) + dr[W - 1] = no_scale ? out[fi + W/2][0] : out[fi + W/2][0] * sc; + else if ((y & 1) == 0) + { + const int fi_c0 = (y / 2) * half1; + dr[W - 1] = no_scale ? out[fi_c0 + W/2][1] : out[fi_c0 + W/2][1] * sc; + } + else + { + const int fi_c0 = ((y + 1) / 2) * half1; + dr[W - 1] = no_scale ? out[fi_c0 + W/2][0] : out[fi_c0 + W/2][0] * sc; + } + } + } + +#undef PACK_BINS_F + + fftwf_free(in); + fftwf_free(out); + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_C2R) + { + ArmPLC2RDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const float sc = ctx->scale; + const bool no_scale = ctx->no_scale; + + if (ctx->col_wise) + { + fftwf_complex *in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (H/2 + 1)); + float *out = (float*) fftwf_malloc(sizeof(float) * H); + if (!in || !out) { if (in) fftwf_free(in); if (out) fftwf_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + in[0][0] = reinterpret_cast(src_data)[0]; + in[0][1] = 0.f; + + const int pairs = (H - 1) / 2; + for (int k = 1; k <= pairs; k++) + { + in[k][0] = reinterpret_cast(src_data + (size_t)(2*k-1)*src_step)[0]; + in[k][1] = reinterpret_cast(src_data + (size_t)(2*k) *src_step)[0]; + } + if ((H & 1) == 0) + { + in[H/2][0] = reinterpret_cast(src_data + (size_t)(H-1)*src_step)[0]; + in[H/2][1] = 0.f; + } + fftwf_execute_dft_c2r(ctx->plan, in, out); + if (no_scale) + for (int y = 0; y < H; y++) + reinterpret_cast(dst_data + (size_t)y * dst_step)[0] = out[y]; + else + for (int y = 0; y < H; y++) + reinterpret_cast(dst_data + (size_t)y * dst_step)[0] = out[y] * sc; + + fftwf_free(in); + fftwf_free(out); + return CV_HAL_ERROR_OK; + } + + const int half1 = W/2 + 1; + const int pairs = (W - 1) / 2; + const int even_W = (W & 1) == 0; + + fftwf_complex *in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (size_t)H * half1); + float *out = (float*) fftwf_malloc(sizeof(float) * (size_t)W * H); + if (!in || !out) { if (in) fftwf_free(in); if (out) fftwf_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + memset(in, 0, sizeof(fftwf_complex) * (size_t)H * half1); + + { + in[0][0] = reinterpret_cast(src_data)[0]; + in[0][1] = 0.f; + + for (int y = 1; y <= (H-1)/2; y++) + { + float re = reinterpret_cast(src_data + (size_t)(2*y - 1)*src_step)[0]; + float im = reinterpret_cast(src_data + (size_t)(2*y )*src_step)[0]; + in[y * half1][0] = re; in[y * half1][1] = im; + in[(H - y) * half1][0] = re; in[(H - y) * half1][1] = -im; + } + + if ((H & 1) == 0) + { + in[(H/2) * half1][0] = reinterpret_cast(src_data + (size_t)(H-1)*src_step)[0]; + in[(H/2) * half1][1] = 0.f; + } + } + + if (even_W) + { + const int kny = W / 2; + in[kny][0] = reinterpret_cast(src_data)[W-1]; + in[kny][1] = 0.f; + + for (int y = 1; y <= (H-1)/2; y++) + { + float re = reinterpret_cast(src_data + (size_t)(2*y - 1)*src_step)[W-1]; + float im = reinterpret_cast(src_data + (size_t)(2*y )*src_step)[W-1]; + in[y * half1 + kny][0] = re; in[y * half1 + kny][1] = im; + in[(H - y) * half1 + kny][0] = re; in[(H - y) * half1 + kny][1] = -im; + } + + if ((H & 1) == 0) + { + in[(H/2) * half1 + kny][0] = reinterpret_cast(src_data + (size_t)(H-1)*src_step)[W-1]; + in[(H/2) * half1 + kny][1] = 0.f; + } + } + + for (int y = 0; y < H; y++) + { + const float *sr = reinterpret_cast(src_data + (size_t)y * src_step); + const int fi = y * half1; + for (int k = 1; k <= pairs; k++) + { + in[fi + k][0] = sr[2*k - 1]; + in[fi + k][1] = sr[2*k]; + } + } + + fftwf_execute_dft_c2r(ctx->plan, in, out); + fftwf_free(in); + + for (int y = 0; y < H; y++) + { + float *dr = reinterpret_cast(dst_data + (size_t)y * dst_step); + const float *row = out + (size_t)y * W; + if (no_scale) + memcpy(dr, row, (size_t)W * sizeof(float)); + else + { + int x = 0; +#ifdef CV_NEON + const float32x4_t sv = vdupq_n_f32(sc); + for (; x + 3 < W; x += 4) + vst1q_f32(dr + x, vmulq_f32(vld1q_f32(row + x), sv)); +#endif + for (; x < W; x++) dr[x] = row[x] * sc; + } + } + + fftwf_free(out); + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_C2C_ROW) + { + ArmPLC2CRowDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan_fwd || !ctx->plan_inv) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const float sc = ctx->scale; + const bool no_scale = ctx->no_scale; + const size_t rb = (size_t)W * sizeof(fftwf_complex); + fftwf_complex *buf = ctx->fftw_buf; + + if (!ctx->inv) + { + for (int i = 0; i < H; i++) + { + const unsigned char *sb = src_data + (size_t)i * src_step; + unsigned char *db = dst_data + (size_t)i * dst_step; + if (sb != db) memcpy(db, sb, rb); + fftwf_execute_dft(ctx->plan_fwd, + reinterpret_cast(db), + reinterpret_cast(db)); + if (!no_scale) + { + float *f = reinterpret_cast(db); + int j = 0; +#ifdef CV_NEON + const float32x4_t sv = vdupq_n_f32(sc); + for (; j + 7 < W*2; j += 8) + { + vst1q_f32(f+j, vmulq_f32(vld1q_f32(f+j), sv)); + vst1q_f32(f+j+4, vmulq_f32(vld1q_f32(f+j+4), sv)); + } +#endif + for (; j < W*2; j++) f[j] *= sc; + } + } + } + else + { + for (int i = 0; i < H; i++) + { + const unsigned char *sb = src_data + (size_t)i * src_step; + unsigned char *db = dst_data + (size_t)i * dst_step; + memcpy(buf, sb, rb); + fftwf_execute(ctx->plan_inv); + if (no_scale) + memcpy(db, buf, rb); + else + { + float *df = reinterpret_cast(db); + const float *bf = reinterpret_cast(buf); + int j = 0; +#ifdef CV_NEON + const float32x4_t sv = vdupq_n_f32(sc); + for (; j + 7 < W*2; j += 8) + { + vst1q_f32(df+j, vmulq_f32(vld1q_f32(bf+j), sv)); + vst1q_f32(df+j+4, vmulq_f32(vld1q_f32(bf+j+4), sv)); + } +#endif + for (; j < W*2; j++) df[j] = bf[j]*sc; + } + } + } + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_R_ROW) + { + ArmPLRRowDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan_fwd || !ctx->plan_inv) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const float sc = ctx->scale; + const bool no_scale = ctx->no_scale; + + if (!ctx->inv) + { + float *fin = ctx->fftw_in_r; + fftwf_complex *fout = ctx->fftw_out_c; + const int ncf = (W - 1) / 2; + const bool hnyq = (W & 1) == 0; + + for (int i = 0; i < H; i++) + { + const float *sr = reinterpret_cast(src_data + (size_t)i * src_step); + float *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + + memcpy(fin, sr, (size_t)W * sizeof(float)); + fftwf_execute(ctx->plan_fwd); + + if (no_scale) + { + dr[0] = fout[0][0]; + int j = 1; + for (; j + 3 <= ncf; j += 4) + { + dr[j*2-1] = fout[j][0]; dr[j*2] = fout[j][1]; + dr[(j+1)*2-1] = fout[j+1][0]; dr[(j+1)*2] = fout[j+1][1]; + dr[(j+2)*2-1] = fout[j+2][0]; dr[(j+2)*2] = fout[j+2][1]; + dr[(j+3)*2-1] = fout[j+3][0]; dr[(j+3)*2] = fout[j+3][1]; + } + for (; j <= ncf; j++) { dr[j*2-1] = fout[j][0]; dr[j*2] = fout[j][1]; } + if (hnyq) dr[W-1] = fout[W/2][0]; + } + else + { + dr[0] = fout[0][0] * sc; + int j = 1; + for (; j + 3 <= ncf; j += 4) + { + dr[j*2-1] = fout[j][0]*sc; dr[j*2] = fout[j][1]*sc; + dr[(j+1)*2-1] = fout[j+1][0]*sc; dr[(j+1)*2] = fout[j+1][1]*sc; + dr[(j+2)*2-1] = fout[j+2][0]*sc; dr[(j+2)*2] = fout[j+2][1]*sc; + dr[(j+3)*2-1] = fout[j+3][0]*sc; dr[(j+3)*2] = fout[j+3][1]*sc; + } + for (; j <= ncf; j++) { dr[j*2-1] = fout[j][0]*sc; dr[j*2] = fout[j][1]*sc; } + if (hnyq) dr[W-1] = fout[W/2][0] * sc; + } + } + } + else + { + fftwf_complex *fin = ctx->fftw_in_c; + float *fout = ctx->fftw_out_r; + const bool hnyq = (W & 1) == 0; + + for (int i = 0; i < H; i++) + { + const float *sr = reinterpret_cast(src_data + (size_t)i * src_step); + float *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + + fin[0][0] = sr[0]; fin[0][1] = 0.f; + + if (hnyq) + { + int j = 1, end = W/2; + for (; j + 3 < end; j += 4) + { + fin[j][0] = sr[j*2-1]; fin[j][1] = sr[j*2]; + fin[j+1][0] = sr[(j+1)*2-1]; fin[j+1][1] = sr[(j+1)*2]; + fin[j+2][0] = sr[(j+2)*2-1]; fin[j+2][1] = sr[(j+2)*2]; + fin[j+3][0] = sr[(j+3)*2-1]; fin[j+3][1] = sr[(j+3)*2]; + } + for (; j < end; j++) { fin[j][0] = sr[j*2-1]; fin[j][1] = sr[j*2]; } + fin[W/2][0] = sr[W-1]; fin[W/2][1] = 0.f; + } + else + { + int j = 1, end = W/2 + 1; + for (; j + 3 < end; j += 4) + { + fin[j][0] = sr[j*2-1]; fin[j][1] = sr[j*2]; + fin[j+1][0] = sr[(j+1)*2-1]; fin[j+1][1] = sr[(j+1)*2]; + fin[j+2][0] = sr[(j+2)*2-1]; fin[j+2][1] = sr[(j+2)*2]; + fin[j+3][0] = sr[(j+3)*2-1]; fin[j+3][1] = sr[(j+3)*2]; + } + for (; j < end; j++) { fin[j][0] = sr[j*2-1]; fin[j][1] = sr[j*2]; } + } + + fftwf_execute(ctx->plan_inv); + + if (no_scale) + memcpy(dr, fout, (size_t)W * sizeof(float)); + else + { + int j = 0; +#ifdef CV_NEON + const float32x4_t sv = vdupq_n_f32(sc); + for (; j + 3 < W; j += 4) + vst1q_f32(dr+j, vmulq_f32(vld1q_f32(fout+j), sv)); +#endif + for (; j < W; j++) dr[j] = fout[j] * sc; + } + } + } + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_C2C_D) + { + ArmPLD_C2CDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan_fwd || !ctx->plan_inv) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const double sc = ctx->scale; + const bool no_scale = ctx->no_scale; + const size_t row_cb = (size_t)W * sizeof(fftw_complex); + + fftw_complex *in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (size_t)W * H); + fftw_complex *out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (size_t)W * H); + if (!in || !out) { if (in) fftw_free(in); if (out) fftw_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + if (src_step == row_cb) + memcpy(in, src_data, (size_t)W * H * sizeof(fftw_complex)); + else + { + for (int y = 0; y < H; y++) + { + const double *sr = reinterpret_cast(src_data + (size_t)y * src_step); + fftw_complex *ir = in + (size_t)y * W; + for (int x = 0; x < W; x++) { ir[x][0] = sr[x*2]; ir[x][1] = sr[x*2+1]; } + } + } + + fftw_execute_dft(ctx->inv ? ctx->plan_inv : ctx->plan_fwd, in, out); + + if (no_scale) + { + if (dst_step == row_cb) + memcpy(dst_data, out, (size_t)W * H * sizeof(fftw_complex)); + else + for (int y = 0; y < H; y++) + memcpy(dst_data + (size_t)y * dst_step, out + (size_t)y * W, row_cb); + } + else + { + for (int y = 0; y < H; y++) + { + double *dr = reinterpret_cast(dst_data + (size_t)y * dst_step); + const fftw_complex *or_ = out + (size_t)y * W; + for (int x = 0; x < W; x++) { dr[x*2] = or_[x][0]*sc; dr[x*2+1] = or_[x][1]*sc; } + } + } + + fftw_free(in); + fftw_free(out); + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_R2C_D) + { + ArmPLD_R2CDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const double sc = ctx->scale; + const bool no_scale = ctx->no_scale; + + if (ctx->col_wise) + { + double *in = (double*) fftw_malloc(sizeof(double) * H); + fftw_complex *out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (H/2 + 1)); + if (!in || !out) { if (in) fftw_free(in); if (out) fftw_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + for (int y = 0; y < H; y++) + in[y] = reinterpret_cast(src_data + (size_t)y * src_step)[0]; + fftw_execute_dft_r2c(ctx->plan, in, out); + + const int pairs = (H - 1) / 2; + if (no_scale) + { + reinterpret_cast(dst_data)[0] = out[0][0]; + for (int k = 1; k <= pairs; k++) + { + reinterpret_cast(dst_data + (size_t)(2*k-1)*dst_step)[0] = out[k][0]; + reinterpret_cast(dst_data + (size_t)(2*k) *dst_step)[0] = out[k][1]; + } + if ((H & 1) == 0) + reinterpret_cast(dst_data + (size_t)(H-1)*dst_step)[0] = out[H/2][0]; + } + else + { + reinterpret_cast(dst_data)[0] = out[0][0] * sc; + for (int k = 1; k <= pairs; k++) + { + reinterpret_cast(dst_data + (size_t)(2*k-1)*dst_step)[0] = out[k][0] * sc; + reinterpret_cast(dst_data + (size_t)(2*k) *dst_step)[0] = out[k][1] * sc; + } + if ((H & 1) == 0) + reinterpret_cast(dst_data + (size_t)(H-1)*dst_step)[0] = out[H/2][0] * sc; + } + fftw_free(in); + fftw_free(out); + return CV_HAL_ERROR_OK; + } + + double *in = (double*) fftw_malloc(sizeof(double) * (size_t)W * H); + fftw_complex *out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (size_t)H * (W/2 + 1)); + if (!in || !out) { if (in) fftw_free(in); if (out) fftw_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + if (src_step == (size_t)W * sizeof(double)) + memcpy(in, src_data, (size_t)W * H * sizeof(double)); + else + for (int y = 0; y < H; y++) + memcpy(in + (size_t)y * W, + reinterpret_cast(src_data + (size_t)y * src_step), + (size_t)W * sizeof(double)); + fftw_execute_dft_r2c(ctx->plan, in, out); + + const int half1 = W/2 + 1; + const int pairs = (W - 1) / 2; + const int even_W = (W & 1) == 0; + +#define PACK_BINS_D(dr_, fi_) \ + do { \ + double *_d = (dr_); int _fi = (fi_); \ + if (no_scale) { \ + for (int k = 1; k <= pairs; k++) { \ + _d[2*k-1] = out[_fi+k][0]; _d[2*k] = out[_fi+k][1]; \ + } \ + } else { \ + for (int k = 1; k <= pairs; k++) { \ + _d[2*k-1] = out[_fi+k][0]*sc; _d[2*k] = out[_fi+k][1]*sc; \ + } \ + } \ + } while(0) + + for (int y = 0; y < H; y++) + { + double *dr = reinterpret_cast(dst_data + (size_t)y * dst_step); + const int fi = y * half1; + + if (y == 0 || y == 1) + dr[0] = no_scale ? out[fi][0] : out[fi][0] * sc; + else if ((y & 1) == 0) + { + const int fi_c0 = (y / 2) * half1; + dr[0] = no_scale ? out[fi_c0][1] : out[fi_c0][1] * sc; + } + else + { + const int fi_c0 = ((y + 1) / 2) * half1; + dr[0] = no_scale ? out[fi_c0][0] : out[fi_c0][0] * sc; + } + + PACK_BINS_D(dr, fi); + + if (even_W) + { + if (y == 0 || y == 1) + dr[W - 1] = no_scale ? out[fi + W/2][0] : out[fi + W/2][0] * sc; + else if ((y & 1) == 0) + { + const int fi_c0 = (y / 2) * half1; + dr[W - 1] = no_scale ? out[fi_c0 + W/2][1] : out[fi_c0 + W/2][1] * sc; + } + else + { + const int fi_c0 = ((y + 1) / 2) * half1; + dr[W - 1] = no_scale ? out[fi_c0 + W/2][0] : out[fi_c0 + W/2][0] * sc; + } + } + } + +#undef PACK_BINS_D + + fftw_free(in); + fftw_free(out); + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_C2R_D) + { + ArmPLD_C2RDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const double sc = ctx->scale; + const bool no_scale = ctx->no_scale; + + if (ctx->col_wise) + { + fftw_complex *in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (H/2 + 1)); + double *out = (double*) fftw_malloc(sizeof(double) * H); + if (!in || !out) { if (in) fftw_free(in); if (out) fftw_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + in[0][0] = reinterpret_cast(src_data)[0]; + in[0][1] = 0.0; + + const int pairs = (H - 1) / 2; + for (int k = 1; k <= pairs; k++) + { + in[k][0] = reinterpret_cast(src_data + (size_t)(2*k-1)*src_step)[0]; + in[k][1] = reinterpret_cast(src_data + (size_t)(2*k) *src_step)[0]; + } + if ((H & 1) == 0) + { + in[H/2][0] = reinterpret_cast(src_data + (size_t)(H-1)*src_step)[0]; + in[H/2][1] = 0.0; + } + fftw_execute_dft_c2r(ctx->plan, in, out); + if (no_scale) + for (int y = 0; y < H; y++) + reinterpret_cast(dst_data + (size_t)y * dst_step)[0] = out[y]; + else + for (int y = 0; y < H; y++) + reinterpret_cast(dst_data + (size_t)y * dst_step)[0] = out[y] * sc; + + fftw_free(in); + fftw_free(out); + return CV_HAL_ERROR_OK; + } + + const int half1 = W/2 + 1; + const int pairs = (W - 1) / 2; + const int even_W = (W & 1) == 0; + + fftw_complex *in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (size_t)H * half1); + double *out = (double*) fftw_malloc(sizeof(double) * (size_t)W * H); + if (!in || !out) { if (in) fftw_free(in); if (out) fftw_free(out); return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + memset(in, 0, sizeof(fftw_complex) * (size_t)H * half1); + + { + in[0][0] = reinterpret_cast(src_data)[0]; + in[0][1] = 0.0; + + for (int y = 1; y <= (H-1)/2; y++) + { + double re = reinterpret_cast(src_data + (size_t)(2*y - 1)*src_step)[0]; + double im = reinterpret_cast(src_data + (size_t)(2*y )*src_step)[0]; + in[y * half1][0] = re; in[y * half1][1] = im; + in[(H - y) * half1][0] = re; in[(H - y) * half1][1] = -im; + } + + if ((H & 1) == 0) + { + in[(H/2) * half1][0] = reinterpret_cast(src_data + (size_t)(H-1)*src_step)[0]; + in[(H/2) * half1][1] = 0.0; + } + } + + if (even_W) + { + const int kny = W / 2; + in[kny][0] = reinterpret_cast(src_data)[W-1]; + in[kny][1] = 0.0; + + for (int y = 1; y <= (H-1)/2; y++) + { + double re = reinterpret_cast(src_data + (size_t)(2*y - 1)*src_step)[W-1]; + double im = reinterpret_cast(src_data + (size_t)(2*y )*src_step)[W-1]; + in[y * half1 + kny][0] = re; in[y * half1 + kny][1] = im; + in[(H - y) * half1 + kny][0] = re; in[(H - y) * half1 + kny][1] = -im; + } + + if ((H & 1) == 0) + { + in[(H/2) * half1 + kny][0] = reinterpret_cast(src_data + (size_t)(H-1)*src_step)[W-1]; + in[(H/2) * half1 + kny][1] = 0.0; + } + } + + for (int y = 0; y < H; y++) + { + const double *sr = reinterpret_cast(src_data + (size_t)y * src_step); + const int fi = y * half1; + for (int k = 1; k <= pairs; k++) + { + in[fi + k][0] = sr[2*k - 1]; + in[fi + k][1] = sr[2*k]; + } + } + + fftw_execute_dft_c2r(ctx->plan, in, out); + fftw_free(in); + + for (int y = 0; y < H; y++) + { + double *dr = reinterpret_cast(dst_data + (size_t)y * dst_step); + const double *row = out + (size_t)y * W; + if (no_scale) + memcpy(dr, row, (size_t)W * sizeof(double)); + else + for (int x = 0; x < W; x++) dr[x] = row[x] * sc; + } + + fftw_free(out); + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_C2C_ROW_D) + { + ArmPLD_C2CRowDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan_fwd || !ctx->plan_inv) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const double sc = ctx->scale; + const bool no_scale = ctx->no_scale; + const size_t rb = (size_t)W * sizeof(fftw_complex); + fftw_complex *buf = ctx->fftw_buf; + + if (!ctx->inv) + { + for (int i = 0; i < H; i++) + { + const unsigned char *sb = src_data + (size_t)i * src_step; + unsigned char *db = dst_data + (size_t)i * dst_step; + if (sb != db) memcpy(db, sb, rb); + fftw_execute_dft(ctx->plan_fwd, + reinterpret_cast(db), + reinterpret_cast(db)); + if (!no_scale) + { + double *f = reinterpret_cast(db); + for (int j = 0; j < W*2; j++) f[j] *= sc; + } + } + } + else + { + for (int i = 0; i < H; i++) + { + const unsigned char *sb = src_data + (size_t)i * src_step; + unsigned char *db = dst_data + (size_t)i * dst_step; + memcpy(buf, sb, rb); + fftw_execute(ctx->plan_inv); + if (no_scale) + memcpy(db, buf, rb); + else + { + double *df = reinterpret_cast(db); + const double *bf = reinterpret_cast(buf); + for (int j = 0; j < W*2; j++) df[j] = bf[j] * sc; + } + } + } + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_R_ROW_D) + { + ArmPLD_RRowDFTContext *ctx = reinterpret_cast(context); + if (!ctx->plan_fwd || !ctx->plan_inv) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int W = ctx->width; + const int H = ctx->height; + const double sc = ctx->scale; + const bool no_scale = ctx->no_scale; + + if (!ctx->inv) + { + double *fin = ctx->fftw_in_r; + fftw_complex *fout = ctx->fftw_out_c; + const int ncf = (W - 1) / 2; + const bool hnyq = (W & 1) == 0; + + for (int i = 0; i < H; i++) + { + const double *sr = reinterpret_cast(src_data + (size_t)i * src_step); + double *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + + memcpy(fin, sr, (size_t)W * sizeof(double)); + fftw_execute(ctx->plan_fwd); + + if (no_scale) + { + dr[0] = fout[0][0]; + int j = 1; + for (; j + 3 <= ncf; j += 4) + { + dr[j*2-1] = fout[j][0]; dr[j*2] = fout[j][1]; + dr[(j+1)*2-1] = fout[j+1][0]; dr[(j+1)*2] = fout[j+1][1]; + dr[(j+2)*2-1] = fout[j+2][0]; dr[(j+2)*2] = fout[j+2][1]; + dr[(j+3)*2-1] = fout[j+3][0]; dr[(j+3)*2] = fout[j+3][1]; + } + for (; j <= ncf; j++) { dr[j*2-1] = fout[j][0]; dr[j*2] = fout[j][1]; } + if (hnyq) dr[W-1] = fout[W/2][0]; + } + else + { + dr[0] = fout[0][0] * sc; + int j = 1; + for (; j + 3 <= ncf; j += 4) + { + dr[j*2-1] = fout[j][0]*sc; dr[j*2] = fout[j][1]*sc; + dr[(j+1)*2-1] = fout[j+1][0]*sc; dr[(j+1)*2] = fout[j+1][1]*sc; + dr[(j+2)*2-1] = fout[j+2][0]*sc; dr[(j+2)*2] = fout[j+2][1]*sc; + dr[(j+3)*2-1] = fout[j+3][0]*sc; dr[(j+3)*2] = fout[j+3][1]*sc; + } + for (; j <= ncf; j++) { dr[j*2-1] = fout[j][0]*sc; dr[j*2] = fout[j][1]*sc; } + if (hnyq) dr[W-1] = fout[W/2][0] * sc; + } + } + } + else + { + fftw_complex *fin = ctx->fftw_in_c; + double *fout = ctx->fftw_out_r; + const bool hnyq = (W & 1) == 0; + + for (int i = 0; i < H; i++) + { + const double *sr = reinterpret_cast(src_data + (size_t)i * src_step); + double *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + + fin[0][0] = sr[0]; fin[0][1] = 0.0; + + if (hnyq) + { + int j = 1, end = W/2; + for (; j + 3 < end; j += 4) + { + fin[j][0] = sr[j*2-1]; fin[j][1] = sr[j*2]; + fin[j+1][0] = sr[(j+1)*2-1]; fin[j+1][1] = sr[(j+1)*2]; + fin[j+2][0] = sr[(j+2)*2-1]; fin[j+2][1] = sr[(j+2)*2]; + fin[j+3][0] = sr[(j+3)*2-1]; fin[j+3][1] = sr[(j+3)*2]; + } + for (; j < end; j++) { fin[j][0] = sr[j*2-1]; fin[j][1] = sr[j*2]; } + fin[W/2][0] = sr[W-1]; fin[W/2][1] = 0.0; + } + else + { + int j = 1, end = W/2 + 1; + for (; j + 3 < end; j += 4) + { + fin[j][0] = sr[j*2-1]; fin[j][1] = sr[j*2]; + fin[j+1][0] = sr[(j+1)*2-1]; fin[j+1][1] = sr[(j+1)*2]; + fin[j+2][0] = sr[(j+2)*2-1]; fin[j+2][1] = sr[(j+2)*2]; + fin[j+3][0] = sr[(j+3)*2-1]; fin[j+3][1] = sr[(j+3)*2]; + } + for (; j < end; j++) { fin[j][0] = sr[j*2-1]; fin[j][1] = sr[j*2]; } + } + + fftw_execute(ctx->plan_inv); + + if (no_scale) + memcpy(dr, fout, (size_t)W * sizeof(double)); + else + for (int j = 0; j < W; j++) dr[j] = fout[j] * sc; + } + } + return CV_HAL_ERROR_OK; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +int armpl_hal_dftFree2D(cvhalDFT *context) +{ + if (!context) return CV_HAL_ERROR_OK; + + const ArmPLDFTMode mode = *reinterpret_cast(context); + if (mode == ARMPL_DFT_C2C) + { + ArmPLC2CDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan_fwd) fftwf_destroy_plan(ctx->plan_fwd); + if (ctx->plan_inv) fftwf_destroy_plan(ctx->plan_inv); + delete ctx; + } + else if (mode == ARMPL_DFT_R2C) + { + ArmPLR2CDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan) fftwf_destroy_plan(ctx->plan); + delete ctx; + } + else if (mode == ARMPL_DFT_C2R) + { + ArmPLC2RDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan) fftwf_destroy_plan(ctx->plan); + delete ctx; + } + else if (mode == ARMPL_DFT_C2C_ROW) + { + ArmPLC2CRowDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan_fwd) fftwf_destroy_plan(ctx->plan_fwd); + if (ctx->plan_inv) fftwf_destroy_plan(ctx->plan_inv); + if (ctx->fftw_buf) fftwf_free(ctx->fftw_buf); + delete ctx; + } + else if (mode == ARMPL_DFT_R_ROW) + { + ArmPLRRowDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan_fwd) fftwf_destroy_plan(ctx->plan_fwd); + if (ctx->plan_inv) fftwf_destroy_plan(ctx->plan_inv); + if (ctx->fftw_in_r) fftwf_free(ctx->fftw_in_r); + if (ctx->fftw_out_c) fftwf_free(ctx->fftw_out_c); + if (ctx->fftw_in_c) fftwf_free(ctx->fftw_in_c); + if (ctx->fftw_out_r) fftwf_free(ctx->fftw_out_r); + delete ctx; + } + else if (mode == ARMPL_DFT_C2C_D) + { + ArmPLD_C2CDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan_fwd) fftw_destroy_plan(ctx->plan_fwd); + if (ctx->plan_inv) fftw_destroy_plan(ctx->plan_inv); + delete ctx; + } + else if (mode == ARMPL_DFT_R2C_D) + { + ArmPLD_R2CDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan) fftw_destroy_plan(ctx->plan); + delete ctx; + } + else if (mode == ARMPL_DFT_C2R_D) + { + ArmPLD_C2RDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan) fftw_destroy_plan(ctx->plan); + delete ctx; + } + else if (mode == ARMPL_DFT_C2C_ROW_D) + { + ArmPLD_C2CRowDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan_fwd) fftw_destroy_plan(ctx->plan_fwd); + if (ctx->plan_inv) fftw_destroy_plan(ctx->plan_inv); + if (ctx->fftw_buf) fftw_free(ctx->fftw_buf); + delete ctx; + } + else if (mode == ARMPL_DFT_R_ROW_D) + { + ArmPLD_RRowDFTContext *ctx = reinterpret_cast(context); + if (ctx->plan_fwd) fftw_destroy_plan(ctx->plan_fwd); + if (ctx->plan_inv) fftw_destroy_plan(ctx->plan_inv); + if (ctx->fftw_in_r) fftw_free(ctx->fftw_in_r); + if (ctx->fftw_out_c) fftw_free(ctx->fftw_out_c); + if (ctx->fftw_in_c) fftw_free(ctx->fftw_in_c); + if (ctx->fftw_out_r) fftw_free(ctx->fftw_out_r); + delete ctx; + } + + return CV_HAL_ERROR_OK; +} + +int armpl_hal_dftInit1D(cvhalDFT **context, int len, int count, + int depth, int flags, bool *needBuffer) +{ + const bool isInverse = (flags & CV_HAL_DFT_INVERSE) != 0; + const bool isScaled = (flags & CV_HAL_DFT_SCALE) != 0; + const bool isRows = (flags & CV_HAL_DFT_ROWS) != 0; + const bool isRealOut = (flags & CV_HAL_DFT_REAL_OUTPUT) != 0; + const bool isComplexOut = (flags & CV_HAL_DFT_COMPLEX_OUTPUT) != 0; + const bool isTwoStage = (flags & CV_HAL_DFT_TWO_STAGE) != 0; + const bool isStageCol = (flags & CV_HAL_DFT_STAGE_COLS) != 0; + + const bool isRealTransform = isRealOut; + + if (isRealTransform && !isInverse && !isStageCol) + { + double scale_d = 1.0; + if (isScaled && !isTwoStage) + { + int rowCount = count; + if (isRows) rowCount = 1; + scale_d = 1.0 / (double)(len * rowCount); + } + if (depth == CV_32F) + { + float* tmp_in = (float*)fftwf_malloc(sizeof(float) * len); + fftwf_complex* tmp_out = (fftwf_complex*)fftwf_malloc( + sizeof(fftwf_complex) * (len / 2 + 1)); + if (!tmp_in || !tmp_out) + { + if (tmp_in) fftwf_free(tmp_in); + if (tmp_out) fftwf_free(tmp_out); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + fftwf_plan plan = fftwf_plan_dft_r2c_1d(len, tmp_in, tmp_out, FFTW_ESTIMATE); + fftwf_free(tmp_in); + fftwf_free(tmp_out); + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPL1DR2CFwdContext *ctx = new ArmPL1DR2CFwdContext(); + ctx->mode = ARMPL_DFT_1D_R2C_FWD; + ctx->len = len; + ctx->plan = plan; + ctx->scale = (float)scale_d; + ctx->no_scale = (scale_d == 1.0); + ctx->complex_output = isComplexOut; + *context = reinterpret_cast(ctx); + } + else // CV_64F + { + double* tmp_in = (double*)fftw_malloc(sizeof(double) * len); + fftw_complex* tmp_out = (fftw_complex*)fftw_malloc( + sizeof(fftw_complex) * (len / 2 + 1)); + if (!tmp_in || !tmp_out) + { + if (tmp_in) fftw_free(tmp_in); + if (tmp_out) fftw_free(tmp_out); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + fftw_plan plan = fftw_plan_dft_r2c_1d(len, tmp_in, tmp_out, FFTW_ESTIMATE); + fftw_free(tmp_in); + fftw_free(tmp_out); + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPL1DR2CFwdContext64 *ctx = new ArmPL1DR2CFwdContext64(); + ctx->mode = ARMPL_DFT_1D_R2C_FWD_64; + ctx->len = len; + ctx->plan = plan; + ctx->scale = scale_d; + ctx->no_scale = (scale_d == 1.0); + ctx->complex_output = isComplexOut; + *context = reinterpret_cast(ctx); + } + + if (needBuffer) *needBuffer = false; + return CV_HAL_ERROR_OK; + } + if (isRealTransform && isInverse && !isStageCol) + { + double scale_d = 1.0; + if (isScaled && !isTwoStage) + { + int rowCount = count; + if (isRows) rowCount = 1; + scale_d = 1.0 / (double)(len * rowCount); + } + + if (depth == CV_32F) + { + float* tmp_in = (float*)fftwf_malloc(sizeof(float) * len); + fftwf_complex* tmp_out = (fftwf_complex*)fftwf_malloc( + sizeof(fftwf_complex) * (len / 2 + 1)); + if (!tmp_in || !tmp_out) + { + if (tmp_in) fftwf_free(tmp_in); + if (tmp_out) fftwf_free(tmp_out); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + fftwf_plan plan = fftwf_plan_dft_c2r_1d(len, tmp_out, tmp_in, FFTW_ESTIMATE); + fftwf_free(tmp_in); + fftwf_free(tmp_out); + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPL1DC2RInvContext *ctx = new ArmPL1DC2RInvContext(); + ctx->mode = ARMPL_DFT_1D_C2R_INV; + ctx->len = len; + ctx->plan = plan; + ctx->scale = (float)scale_d; + ctx->no_scale = (scale_d == 1.0); + ctx->complex_input = isComplexOut; + *context = reinterpret_cast(ctx); + } + else // CV_64F + { + double* tmp_in = (double*)fftw_malloc(sizeof(double) * len); + fftw_complex* tmp_out = (fftw_complex*)fftw_malloc( + sizeof(fftw_complex) * (len / 2 + 1)); + if (!tmp_in || !tmp_out) + { + if (tmp_in) fftw_free(tmp_in); + if (tmp_out) fftw_free(tmp_out); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + fftw_plan plan = fftw_plan_dft_c2r_1d(len, tmp_out, tmp_in, FFTW_ESTIMATE); + fftw_free(tmp_in); + fftw_free(tmp_out); + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPL1DC2RInvContext64 *ctx = new ArmPL1DC2RInvContext64(); + ctx->mode = ARMPL_DFT_1D_C2R_INV_64; + ctx->len = len; + ctx->plan = plan; + ctx->scale = scale_d; + ctx->no_scale = (scale_d == 1.0); + ctx->complex_input = isComplexOut; + *context = reinterpret_cast(ctx); + } + + if (needBuffer) *needBuffer = false; + return CV_HAL_ERROR_OK; + } + + if (isScaled && !isRows && isRealTransform) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const double scale_d = isScaled ? (1.0 / (double)len) : 1.0; + + const int fftw_dir = isInverse ? FFTW_BACKWARD : FFTW_FORWARD; + + if (depth == CV_32F) + { + fftwf_complex *tmp_in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * len); + fftwf_complex *tmp_out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * len); + if (!tmp_in || !tmp_out) + { + if (tmp_in) fftwf_free(tmp_in); + if (tmp_out) fftwf_free(tmp_out); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + fftwf_plan plan = fftwf_plan_dft_1d(len, tmp_in, tmp_out, fftw_dir, FFTW_ESTIMATE); + fftwf_free(tmp_in); + fftwf_free(tmp_out); + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPL1DC2CFwdContext *ctx = new ArmPL1DC2CFwdContext(); + ctx->mode = isInverse ? ARMPL_DFT_1D_C2C_INV : ARMPL_DFT_1D_C2C_FWD; + ctx->len = len; + ctx->plan = plan; + ctx->scale = (float)scale_d; + ctx->no_scale = (scale_d == 1.0); + *context = reinterpret_cast(ctx); + } + else // CV_64F + { + fftw_complex *tmp_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * len); + fftw_complex *tmp_out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * len); + if (!tmp_in || !tmp_out) + { + if (tmp_in) fftw_free(tmp_in); + if (tmp_out) fftw_free(tmp_out); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + fftw_plan plan = fftw_plan_dft_1d(len, tmp_in, tmp_out, fftw_dir, FFTW_ESTIMATE); + fftw_free(tmp_in); + fftw_free(tmp_out); + if (!plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + ArmPL1DC2CFwdContext64 *ctx = new ArmPL1DC2CFwdContext64(); + ctx->mode = isInverse ? ARMPL_DFT_1D_C2C_INV_64 : ARMPL_DFT_1D_C2C_FWD_64; + ctx->len = len; + ctx->plan = plan; + ctx->scale = scale_d; + ctx->no_scale = (scale_d == 1.0); + *context = reinterpret_cast(ctx); + } + + if (needBuffer) *needBuffer = false; + return CV_HAL_ERROR_OK; +} + +int armpl_hal_dft1D(cvhalDFT *context, + const unsigned char *src, unsigned char *dst) +{ + if (!context || !src || !dst) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const ArmPLDFTMode mode = *reinterpret_cast(context); + + if (mode == ARMPL_DFT_1D_R2C_FWD) + { + ArmPL1DR2CFwdContext *ctx = reinterpret_cast(context); + if (!ctx->plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int n = ctx->len; + const bool complex_output = ctx->complex_output; + const bool no_scale = ctx->no_scale; + const float sc = ctx->scale; + + const float* src_f = reinterpret_cast(src); + float* dst_f = reinterpret_cast(dst); + + fftwf_complex* tmp_out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (n / 2 + 1)); + if (!tmp_out) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + fftwf_execute_dft_r2c(ctx->plan, const_cast(src_f), tmp_out); + + float* dst_pack = dst_f + (complex_output ? 1 : 0); + dst_pack[0] = tmp_out[0][0]; + + const int num_complex = (n - 1) / 2; + int dst_idx = 1; + for (int i = 1; i <= num_complex; i++) + { + dst_pack[dst_idx++] = tmp_out[i][0]; + dst_pack[dst_idx++] = tmp_out[i][1]; + } + if ((n & 1) == 0) + dst_pack[n - 1] = tmp_out[n / 2][0]; + + fftwf_free(tmp_out); + + if (!no_scale) + { + for (int i = 0; i < n; i++) + dst_pack[i] *= sc; + } + + if (complex_output) + { + dst_f[0] = dst_pack[0]; + dst_pack[0] = 0.f; + if ((n & 1) == 0) + dst_pack[n] = 0.f; + } + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_1D_R2C_FWD_64) + { + ArmPL1DR2CFwdContext64 *ctx = reinterpret_cast(context); + if (!ctx->plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int n = ctx->len; + const bool complex_output = ctx->complex_output; + const bool no_scale = ctx->no_scale; + const double sc = ctx->scale; + + const double* src_d = reinterpret_cast(src); + double* dst_d = reinterpret_cast(dst); + + fftw_complex* tmp_out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (n / 2 + 1)); + if (!tmp_out) return CV_HAL_ERROR_NOT_IMPLEMENTED; + fftw_execute_dft_r2c(ctx->plan, const_cast(src_d), tmp_out); + + double* dst_pack = dst_d + (complex_output ? 1 : 0); + dst_pack[0] = tmp_out[0][0]; + + const int num_complex = (n - 1) / 2; + int dst_idx = 1; + for (int i = 1; i <= num_complex; i++) + { + dst_pack[dst_idx++] = tmp_out[i][0]; + dst_pack[dst_idx++] = tmp_out[i][1]; + } + if ((n & 1) == 0) + dst_pack[n - 1] = tmp_out[n / 2][0]; + + fftw_free(tmp_out); + + if (!no_scale) + { + for (int i = 0; i < n; i++) + dst_pack[i] *= sc; + } + + if (complex_output) + { + dst_d[0] = dst_pack[0]; + dst_pack[0] = 0.0; + if ((n & 1) == 0) + dst_pack[n] = 0.0; + } + + return CV_HAL_ERROR_OK; + } + if (mode == ARMPL_DFT_1D_C2R_INV) + { + ArmPL1DC2RInvContext *ctx = reinterpret_cast(context); + if (!ctx->plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int n = ctx->len; + const bool complex_input = ctx->complex_input; + const bool no_scale = ctx->no_scale; + const float sc = ctx->scale; + + const float* src_f = reinterpret_cast(src); + float* dst_f = reinterpret_cast(dst); + + float save_s1 = 0.f; + if (complex_input) + { + save_s1 = src_f[1]; + const_cast(src_f)[1] = src_f[0]; + src_f++; + } + + fftwf_complex* tmp = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (n / 2 + 1)); + if (!tmp) + { + if (complex_input) + const_cast(src_f - 1)[1] = save_s1; + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + tmp[0][0] = src_f[0]; + tmp[0][1] = 0.f; + const int num_complex = (n - 1) / 2; + int src_idx = 1; + for (int i = 1; i <= num_complex; i++) + { + tmp[i][0] = src_f[src_idx++]; + tmp[i][1] = src_f[src_idx++]; + } + if ((n & 1) == 0) + { + tmp[n / 2][0] = src_f[n - 1]; + tmp[n / 2][1] = 0.f; + } + + fftwf_execute_dft_c2r(ctx->plan, tmp, dst_f); + fftwf_free(tmp); + + if (complex_input) + const_cast(src_f - 1)[1] = save_s1; + + if (!no_scale) + { + for (int i = 0; i < n; i++) + dst_f[i] *= sc; + } + + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_1D_C2R_INV_64) + { + ArmPL1DC2RInvContext64 *ctx = reinterpret_cast(context); + if (!ctx->plan) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int n = ctx->len; + const bool complex_input = ctx->complex_input; + const bool no_scale = ctx->no_scale; + const double sc = ctx->scale; + + const double* src_d = reinterpret_cast(src); + double* dst_d = reinterpret_cast(dst); + + double save_s1 = 0.0; + if (complex_input) + { + save_s1 = src_d[1]; + const_cast(src_d)[1] = src_d[0]; + src_d++; + } + + fftw_complex* tmp = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (n / 2 + 1)); + if (!tmp) + { + if (complex_input) + const_cast(src_d - 1)[1] = save_s1; + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + tmp[0][0] = src_d[0]; + tmp[0][1] = 0.0; + const int num_complex = (n - 1) / 2; + int src_idx = 1; + for (int i = 1; i <= num_complex; i++) + { + tmp[i][0] = src_d[src_idx++]; + tmp[i][1] = src_d[src_idx++]; + } + if ((n & 1) == 0) + { + tmp[n / 2][0] = src_d[n - 1]; + tmp[n / 2][1] = 0.0; + } + + fftw_execute_dft_c2r(ctx->plan, tmp, dst_d); + fftw_free(tmp); + + if (complex_input) + const_cast(src_d - 1)[1] = save_s1; + + if (!no_scale) + { + for (int i = 0; i < n; i++) + dst_d[i] *= sc; + } + + return CV_HAL_ERROR_OK; + } + if (mode == ARMPL_DFT_1D_C2C_FWD || mode == ARMPL_DFT_1D_C2C_INV) + { + ArmPL1DC2CFwdContext *ctx = reinterpret_cast(context); + if (!ctx->plan) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int len = ctx->len; + const float sc = ctx->scale; + const bool no_scale = ctx->no_scale; + fftwf_execute_dft( + ctx->plan, + reinterpret_cast(const_cast(src)), + reinterpret_cast(dst)); + if (!no_scale) + { + float *df = reinterpret_cast(dst); + int i = 0; + for (; i + 3 < len; i += 4) + { + df[i*2] *= sc; df[i*2+1] *= sc; + df[(i+1)*2] *= sc; df[(i+1)*2+1] *= sc; + df[(i+2)*2] *= sc; df[(i+2)*2+1] *= sc; + df[(i+3)*2] *= sc; df[(i+3)*2+1] *= sc; + } + for (; i < len; i++) { df[i*2] *= sc; df[i*2+1] *= sc; } + } + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DFT_1D_C2C_FWD_64 || mode == ARMPL_DFT_1D_C2C_INV_64) + { + ArmPL1DC2CFwdContext64 *ctx = reinterpret_cast(context); + if (!ctx->plan) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const int len = ctx->len; + const double sc = ctx->scale; + const bool no_scale = ctx->no_scale; + fftw_execute_dft( + ctx->plan, + reinterpret_cast(const_cast(src)), + reinterpret_cast(dst)); + + if (!no_scale) + { + double *df = reinterpret_cast(dst); + int i = 0; + for (; i + 3 < len; i += 4) + { + df[i*2] *= sc; df[i*2+1] *= sc; + df[(i+1)*2] *= sc; df[(i+1)*2+1] *= sc; + df[(i+2)*2] *= sc; df[(i+2)*2+1] *= sc; + df[(i+3)*2] *= sc; df[(i+3)*2+1] *= sc; + } + for (; i < len; i++) { df[i*2] *= sc; df[i*2+1] *= sc; } + } + return CV_HAL_ERROR_OK; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +int armpl_hal_dftFree1D(cvhalDFT *context) +{ + if (!context) + return CV_HAL_ERROR_OK; + + const ArmPLDFTMode mode = *reinterpret_cast(context); + + if (mode == ARMPL_DFT_1D_R2C_FWD) + { + ArmPL1DR2CFwdContext *ctx = reinterpret_cast(context); + if (ctx->plan) fftwf_destroy_plan(ctx->plan); + delete ctx; + return CV_HAL_ERROR_OK; + } + if (mode == ARMPL_DFT_1D_R2C_FWD_64) + { + ArmPL1DR2CFwdContext64 *ctx = reinterpret_cast(context); + if (ctx->plan) fftw_destroy_plan(ctx->plan); + delete ctx; + return CV_HAL_ERROR_OK; + } + if (mode == ARMPL_DFT_1D_C2R_INV) + { + ArmPL1DC2RInvContext *ctx = reinterpret_cast(context); + if (ctx->plan) fftwf_destroy_plan(ctx->plan); + delete ctx; + return CV_HAL_ERROR_OK; + } + if (mode == ARMPL_DFT_1D_C2R_INV_64) + { + ArmPL1DC2RInvContext64 *ctx = reinterpret_cast(context); + if (ctx->plan) fftw_destroy_plan(ctx->plan); + delete ctx; + return CV_HAL_ERROR_OK; + } + if (mode == ARMPL_DFT_1D_C2C_FWD || mode == ARMPL_DFT_1D_C2C_INV) + { + ArmPL1DC2CFwdContext *ctx = reinterpret_cast(context); + if (ctx->plan) fftwf_destroy_plan(ctx->plan); + delete ctx; + } + else if (mode == ARMPL_DFT_1D_C2C_FWD_64 || mode == ARMPL_DFT_1D_C2C_INV_64) + { + ArmPL1DC2CFwdContext64 *ctx = reinterpret_cast(context); + if (ctx->plan) fftw_destroy_plan(ctx->plan); + delete ctx; + } + + return CV_HAL_ERROR_OK; +} + +class DctHalRowInvoker : public cv::ParallelLoopBody +{ +public: + DctHalRowInvoker(const uchar *_src, size_t _src_step, + uchar *_dst, size_t _dst_step, + int _width, fftwf_plan _plan, bool *_ok) + : src(_src), src_step(_src_step), + dst(_dst), dst_step(_dst_step), + width(_width), plan(_plan), ok(_ok) + { *ok = true; } + + virtual void operator()(const cv::Range& range) const CV_OVERRIDE + { + if (!*ok) return; + cv::AutoBuffer temp_src(width); + cv::AutoBuffer temp_dst(width); + for (int i = range.start; i < range.end; ++i) + { + const float *sr = reinterpret_cast(src + (size_t)i * src_step); + float *dr = reinterpret_cast(dst + (size_t)i * dst_step); + memcpy(temp_src.data(), sr, (size_t)width * sizeof(float)); + fftwf_execute_r2r(plan, temp_src.data(), temp_dst.data()); + memcpy(dr, temp_dst.data(), (size_t)width * sizeof(float)); + } + } + +private: + const uchar *src; + size_t src_step; + uchar *dst; + size_t dst_step; + int width; + fftwf_plan plan; + bool *ok; +}; + +class DctHalColInvoker : public cv::ParallelLoopBody +{ +public: + DctHalColInvoker(const uchar *_src, size_t _src_step, + uchar *_dst, size_t _dst_step, + int _height, fftwf_plan _plan, bool *_ok) + : src(_src), src_step(_src_step), + dst(_dst), dst_step(_dst_step), + height(_height), plan(_plan), ok(_ok) + { *ok = true; } + + virtual void operator()(const cv::Range& range) const CV_OVERRIDE + { + if (!*ok) return; + cv::AutoBuffer temp_src(height); + cv::AutoBuffer temp_dst(height); + for (int j = range.start; j < range.end; ++j) + { + for (int i = 0; i < height; ++i) + { + const float *sr = reinterpret_cast(src + (size_t)i * src_step); + temp_src[i] = sr[j]; + } + fftwf_execute_r2r(plan, temp_src.data(), temp_dst.data()); + for (int i = 0; i < height; ++i) + { + float *dr = reinterpret_cast(dst + (size_t)i * dst_step); + dr[j] = temp_dst[i]; + } + } + } + +private: + const uchar *src; + size_t src_step; + uchar *dst; + size_t dst_step; + int height; + fftwf_plan plan; + bool *ok; +}; + +int armpl_hal_dctInit2D(cvhalDFT **context, + int width, int height, + int depth, int flags) +{ + const bool isInverse = (flags & CV_HAL_DFT_INVERSE) != 0; + const bool isRowWise = (flags & CV_HAL_DFT_ROWS) != 0; + + if (depth != CV_32F) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const fftw_r2r_kind kind = isInverse ? FFTW_REDFT01 + : FFTW_REDFT10; + + if (!isRowWise) + { + float *row_buf = (float*)fftwf_malloc(sizeof(float) * (size_t)width * height); + if (!row_buf) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + float *tmp_r = (float*)fftwf_malloc(sizeof(float) * width); + float *tmp_c = (float*)fftwf_malloc(sizeof(float) * height); + if (!tmp_r || !tmp_c) + { + fftwf_free(row_buf); + if (tmp_r) fftwf_free(tmp_r); + if (tmp_c) fftwf_free(tmp_c); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + fftwf_plan prow = fftwf_plan_r2r_1d(width, tmp_r, tmp_r, kind, FFTW_MEASURE); + fftwf_plan pcol = fftwf_plan_r2r_1d(height, tmp_c, tmp_c, kind, FFTW_MEASURE); + fftwf_free(tmp_r); + fftwf_free(tmp_c); + + if (!prow || !pcol) + { + if (prow) fftwf_destroy_plan(prow); + if (pcol) fftwf_destroy_plan(pcol); + fftwf_free(row_buf); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + ArmPLDCT2DContext *ctx = new ArmPLDCT2DContext(); + ctx->width = width; + ctx->height = height; + ctx->inv = isInverse; + ctx->plan_fwd = prow; + ctx->plan_inv = pcol; + ctx->buf = row_buf; + + const float w = (float)width; + const float h = (float)height; + const float inv_sqrt2 = 1.0f / std::sqrt(2.0f); + const float base = 1.0f / (2.0f * std::sqrt(w * h)); + + ctx->scale_dc = base * inv_sqrt2 * inv_sqrt2; + ctx->scale_axis = base * inv_sqrt2; + ctx->scale_rest = base; + + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; + } + + float *fftw_buf = (float*)fftwf_malloc(sizeof(float) * width); + if (!fftw_buf) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + fftwf_plan pf = fftwf_plan_r2r_1d(width, fftw_buf, fftw_buf, kind, FFTW_MEASURE); + if (!pf) + { + fftwf_free(fftw_buf); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + ArmPLDCTRowContext *ctx = new ArmPLDCTRowContext(); + ctx->width = width; + ctx->height = height; + ctx->inv = isInverse; + ctx->plan_fwd = pf; + ctx->fftw_buf = fftw_buf; + + const float w = (float)width; + const float inv_sqrt2 = 1.0f / std::sqrt(2.0f); + const float base = 1.0f / std::sqrt(2.0f * w); + ctx->scale_dc = base * inv_sqrt2; + ctx->scale_rest = base; + + *context = reinterpret_cast(ctx); + return CV_HAL_ERROR_OK; +} + +int armpl_hal_dct2D(cvhalDFT *context, + const unsigned char *src_data, size_t src_step, + unsigned char *dst_data, size_t dst_step) +{ + if (!context || !src_data || !dst_data) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + const ArmPLDFTMode mode = *reinterpret_cast(context); + + if (mode == ARMPL_DCT_2D) + { + ArmPLDCT2DContext *ctx = reinterpret_cast(context); + const int W = ctx->width; + const int H = ctx->height; + float *buf = ctx->buf; + + const float sc_dc = ctx->scale_dc; + const float sc_axis = ctx->scale_axis; + const float sc_rest = ctx->scale_rest; + + if (!ctx->inv) + { + bool ok_row = true; + cv::parallel_for_(cv::Range(0, H), + DctHalRowInvoker(src_data, src_step, + reinterpret_cast(buf), + (size_t)W * sizeof(float), + W, ctx->plan_fwd, &ok_row), + H / (double)(1 << 4)); + if (!ok_row) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + bool ok_col = true; + cv::parallel_for_(cv::Range(0, W), + DctHalColInvoker(reinterpret_cast(buf), + (size_t)W * sizeof(float), + dst_data, dst_step, + H, ctx->plan_inv, &ok_col), + W / (double)(1 << 4)); + if (!ok_col) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + for (int i = 0; i < H; ++i) + { + float *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + const float sc_row = (i == 0) ? sc_axis : sc_rest; + dr[0] *= (i == 0) ? sc_dc : sc_axis; + for (int j = 1; j < W; ++j) + dr[j] *= sc_row; + } + return CV_HAL_ERROR_OK; + } + + const float inv_sc_dc = 1.0f / sc_dc; + const float inv_sc_axis = 1.0f / sc_axis; + const float inv_sc_rest = 1.0f / sc_rest; + const float postscale = 1.0f / (4.0f * static_cast(W) * static_cast(H)); + + for (int i = 0; i < H; ++i) + { + const float *sr = reinterpret_cast(src_data + (size_t)i * src_step); + float *br = buf + (size_t)i * W; + const float row_inv_sc = (i == 0) ? inv_sc_axis : inv_sc_rest; + br[0] = sr[0] * ((i == 0) ? inv_sc_dc : inv_sc_axis); + for (int j = 1; j < W; ++j) + br[j] = sr[j] * row_inv_sc; + } + + bool ok_col = true; + cv::parallel_for_(cv::Range(0, W), + DctHalColInvoker(reinterpret_cast(buf), + (size_t)W * sizeof(float), + dst_data, dst_step, + H, ctx->plan_inv, &ok_col), + W / (double)(1 << 4)); + if (!ok_col) return CV_HAL_ERROR_NOT_IMPLEMENTED; + bool ok_row = true; + cv::parallel_for_(cv::Range(0, H), + DctHalRowInvoker(dst_data, dst_step, + dst_data, dst_step, + W, ctx->plan_fwd, &ok_row), + H / (double)(1 << 4)); + if (!ok_row) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + for (int i = 0; i < H; ++i) + { + float *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + for (int j = 0; j < W; ++j) + dr[j] *= postscale; + } + return CV_HAL_ERROR_OK; + } + + if (mode == ARMPL_DCT_ROW) + { + ArmPLDCTRowContext *ctx = reinterpret_cast(context); + const int W = ctx->width; + const int H = ctx->height; + const float sc_dc = ctx->scale_dc; + const float sc_rest = ctx->scale_rest; + + if (!ctx->inv) + { + bool ok_row = true; + cv::parallel_for_( + cv::Range(0, H), + DctHalRowInvoker(src_data, src_step, + dst_data, dst_step, + W, ctx->plan_fwd, &ok_row), + H / (double)(1 << 4)); + if (!ok_row) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + for (int i = 0; i < H; ++i) + { + float *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + dr[0] *= sc_dc; + for (int j = 1; j < W; ++j) + dr[j] *= sc_rest; + } + return CV_HAL_ERROR_OK; + } + + const float inv_sc_dc = 1.0f / sc_dc; + const float inv_sc_rest = 1.0f / sc_rest; + const float postscale = 1.0f / (2.0f * static_cast(W)); + + for (int i = 0; i < H; ++i) + { + const float *sr = reinterpret_cast(src_data + (size_t)i * src_step); + float *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + dr[0] = sr[0] * inv_sc_dc; + for (int j = 1; j < W; ++j) + dr[j] = sr[j] * inv_sc_rest; + } + + bool ok_row = true; + cv::parallel_for_( + cv::Range(0, H), + DctHalRowInvoker(dst_data, dst_step, + dst_data, dst_step, + W, ctx->plan_fwd, &ok_row), + H / (double)(1 << 4)); + if (!ok_row) return CV_HAL_ERROR_NOT_IMPLEMENTED; + + for (int i = 0; i < H; ++i) + { + float *dr = reinterpret_cast(dst_data + (size_t)i * dst_step); + for (int j = 0; j < W; ++j) + dr[j] *= postscale; + } + return CV_HAL_ERROR_OK; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +int armpl_hal_dctFree2D(cvhalDFT *context) +{ + if (!context) return CV_HAL_ERROR_OK; + + const ArmPLDFTMode mode = *reinterpret_cast(context); + + if (mode == ARMPL_DCT_2D) + { + ArmPLDCT2DContext *ctx = reinterpret_cast(context); + if (ctx->plan_fwd) fftwf_destroy_plan(ctx->plan_fwd); + if (ctx->plan_inv) fftwf_destroy_plan(ctx->plan_inv); + if (ctx->buf) fftwf_free(ctx->buf); + delete ctx; + } + else if (mode == ARMPL_DCT_ROW) + { + ArmPLDCTRowContext *ctx = reinterpret_cast(context); + if (ctx->plan_fwd) fftwf_destroy_plan(ctx->plan_fwd); + if (ctx->fftw_buf) fftwf_free(ctx->fftw_buf); + delete ctx; + } + + return CV_HAL_ERROR_OK; +} + +#endif // HAVE_ARMPL diff --git a/modules/core/test/test_dxt.cpp b/modules/core/test/test_dxt.cpp index b2305fef9a..405712ad49 100644 --- a/modules/core/test/test_dxt.cpp +++ b/modules/core/test/test_dxt.cpp @@ -678,13 +678,26 @@ public: protected: void run_func(); void prepare_to_validation( int test_case_idx ); + double get_success_error_level( int test_case_idx, int i, int j ); }; - CxCore_DFTTest::CxCore_DFTTest() : CxCore_DXTBaseTest( true, true, false ) { } +double CxCore_DFTTest::get_success_error_level( int test_case_idx, int i, int j ) +{ + CV_Assert(i == OUTPUT); + CV_Assert(j == 0); + + int depth = CV_MAT_DEPTH(cvGetElemType(test_array[i][j])); + + // NOTE: non-default threshold intorduced for ARMPL integration + if (depth == CV_32F) + return 1.5e-4; + + return CxCore_DXTBaseTest::get_success_error_level(test_case_idx, i, j); +} void CxCore_DFTTest::run_func() { @@ -743,6 +756,9 @@ public: protected: void run_func(); void prepare_to_validation( int test_case_idx ); +#if defined(HAVE_ARMPL) + double get_success_error_level( int test_case_idx, int i, int j ) CV_OVERRIDE; +#endif }; @@ -750,6 +766,20 @@ CxCore_DCTTest::CxCore_DCTTest() : CxCore_DXTBaseTest( false, false, false ) { } +#if defined(HAVE_ARMPL) +double CxCore_DCTTest::get_success_error_level(int, int i, int j) +{ + CV_Assert(i == OUTPUT); + CV_Assert(j == 0); + + int depth = CV_MAT_DEPTH(cvGetElemType(test_array[i][j])); + + if (depth == CV_32F) + return 1.67e-5; + + return 1e-12; +} +#endif void CxCore_DCTTest::run_func() {