Merge pull request #26556 from asmorkalov:FastcvHAL_1stPost

Added Fastcv HAL changes in the 3rdparty folder.
Code Changes includes HAL code , Fastcv libs and Headers

Change-Id: I2f0ddb1f57515c82ae86ba8c2a82965b1a9626ec

Requires binaries from https://github.com/opencv/opencv_3rdparty/pull/86.
Related patch to opencv_contrib: https://github.com/opencv/opencv_contrib/pull/3811

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [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
- [ ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
pull/20569/merge
Alexander Smorkalov 3 days ago committed by GitHub
parent 96dab6ba71
commit 5f1b05af0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 34
      3rdparty/fastcv/CMakeLists.txt
  2. 43
      3rdparty/fastcv/fastcv.cmake
  3. 155
      3rdparty/fastcv/include/fastcv_hal_core.hpp
  4. 151
      3rdparty/fastcv/include/fastcv_hal_imgproc.hpp
  5. 83
      3rdparty/fastcv/include/fastcv_hal_utils.hpp
  6. 334
      3rdparty/fastcv/src/fastcv_hal_core.cpp
  7. 318
      3rdparty/fastcv/src/fastcv_hal_imgproc.cpp
  8. 56
      3rdparty/fastcv/src/fastcv_hal_utils.cpp
  9. 20
      CMakeLists.txt
  10. 20
      cmake/OpenCVFindLibsPerf.cmake

@ -0,0 +1,34 @@
if(HAVE_FASTCV)
set(FASTCV_HAL_VERSION 0.0.1 CACHE INTERNAL "")
set(FASTCV_HAL_LIBRARIES "fastcv_hal" CACHE INTERNAL "")
set(FASTCV_HAL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include" CACHE INTERNAL "")
set(FASTCV_HAL_HEADERS
"${CMAKE_CURRENT_SOURCE_DIR}/include/fastcv_hal_core.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/fastcv_hal_imgproc.hpp"
CACHE INTERNAL "")
file(GLOB FASTCV_HAL_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(fastcv_hal STATIC ${FASTCV_HAL_FILES})
target_include_directories(fastcv_hal PRIVATE
${CMAKE_SOURCE_DIR}/modules/core/include
${CMAKE_SOURCE_DIR}/modules/imgproc/include
${FASTCV_HAL_INCLUDE_DIRS} ${FastCV_INCLUDE_PATH})
target_link_libraries(fastcv_hal PUBLIC ${FASTCV_LIBRARY})
set_target_properties(fastcv_hal PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH})
if(NOT BUILD_SHARED_LIBS)
ocv_install_target(fastcv_hal EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
endif()
ocv_install_3rdparty_licenses(FastCV "${OpenCV_BINARY_DIR}/3rdparty/fastcv/LICENSE")
if(ENABLE_SOLUTION_FOLDERS)
set_target_properties(fastcv_hal PROPERTIES FOLDER "3rdparty")
endif()
else()
message(STATUS "FastCV is not available, disabling related HAL")
endif(HAVE_FASTCV)

@ -0,0 +1,43 @@
function(download_fastcv root_dir)
# Commit SHA in the opencv_3rdparty repo
set(FASTCV_COMMIT "b8f0d48fa9dbebb0237d3e0abd206f9930c89db6")
# Define actual FastCV versions
if(ANDROID)
if(AARCH64)
message(STATUS "Download FastCV for Android aarch64")
set(FCV_PACKAGE_NAME "fastcv_android_aarch64_2024_10_24.tgz")
set(FCV_PACKAGE_HASH "14486af00dc0282dac591dc9ccdd957e")
else()
message(STATUS "Download FastCV for Android armv7")
set(FCV_PACKAGE_NAME "fastcv_android_arm32_2024_10_24.tgz")
set(FCV_PACKAGE_HASH "b5afadd5a5b55f8f6c2e7361f225fa21")
endif()
elseif(UNIX AND NOT APPLE AND NOT IOS AND NOT XROS)
if(AARCH64)
set(FCV_PACKAGE_NAME "fastcv_linux_aarch64_2024_10_24.tgz")
set(FCV_PACKAGE_HASH "d15c7b77f2d3577ba46bd94e6cf15230")
else()
message("FastCV: fastcv lib for 32-bit Linux is not supported for now!")
endif()
endif(ANDROID)
# Download Package
set(OPENCV_FASTCV_URL "https://raw.githubusercontent.com/opencv/opencv_3rdparty/${FASTCV_COMMIT}/fastcv/")
ocv_download( FILENAME ${FCV_PACKAGE_NAME}
HASH ${FCV_PACKAGE_HASH}
URL ${OPENCV_FASTCV_URL}
DESTINATION_DIR ${root_dir}
ID FASTCV
STATUS res
UNPACK
RELATIVE_URL)
if(res)
set(HAVE_FASTCV TRUE CACHE BOOL "FastCV status")
else()
message(WARNING "FastCV: package download failed!")
endif()
endfunction()

@ -0,0 +1,155 @@
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef OPENCV_FASTCV_HAL_CORE_HPP_INCLUDED
#define OPENCV_FASTCV_HAL_CORE_HPP_INCLUDED
#include <opencv2/core/base.hpp>
#undef cv_hal_lut
#define cv_hal_lut fastcv_hal_lut
#undef cv_hal_normHammingDiff8u
#define cv_hal_normHammingDiff8u fastcv_hal_normHammingDiff8u
#undef cv_hal_mul8u16u
#define cv_hal_mul8u16u fastcv_hal_mul8u16u
#undef cv_hal_sub8u32f
#define cv_hal_sub8u32f fastcv_hal_sub8u32f
#undef cv_hal_transpose2d
#define cv_hal_transpose2d fastcv_hal_transpose2d
#undef cv_hal_meanStdDev
#define cv_hal_meanStdDev fastcv_hal_meanStdDev
#undef cv_hal_flip
#define cv_hal_flip fastcv_hal_flip
#undef cv_hal_rotate90
#define cv_hal_rotate90 fastcv_hal_rotate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief look-up table transform of an array.
/// @param src_data Source image data
/// @param src_step Source image step
/// @param src_type Source image type
/// @param lut_data Pointer to lookup table
/// @param lut_channel_size Size of each channel in bytes
/// @param lut_channels Number of channels in lookup table
/// @param dst_data Destination data
/// @param dst_step Destination step
/// @param width Width of images
/// @param height Height of images
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_lut(
const uchar* src_data,
size_t src_step,
size_t src_type,
const uchar* lut_data,
size_t lut_channel_size,
size_t lut_channels,
uchar* dst_data,
size_t dst_step,
int width,
int height);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Hamming distance between two vectors
/// @param a pointer to first vector data
/// @param b pointer to second vector data
/// @param n length of vectors
/// @param cellSize how many bits of the vectors will be added and treated as a single bit, can be 1 (standard Hamming distance), 2 or 4
/// @param result pointer to result output
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_normHammingDiff8u(const uchar* a, const uchar* b, int n, int cellSize, int* result);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_mul8u16u(
const uchar * src1_data,
size_t src1_step,
const uchar * src2_data,
size_t src2_step,
ushort * dst_data,
size_t dst_step,
int width,
int height,
double scale);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_sub8u32f(
const uchar *src1_data,
size_t src1_step,
const uchar *src2_data,
size_t src2_step,
float *dst_data,
size_t dst_step,
int width,
int height);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_transpose2d(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int src_width,
int src_height,
int element_size);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_meanStdDev(
const uchar * src_data,
size_t src_step,
int width,
int height,
int src_type,
double * mean_val,
double * stddev_val,
uchar * mask,
size_t mask_step);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Flips a 2D array around vertical, horizontal, or both axes
/// @param src_type source and destination image type
/// @param src_data source image data
/// @param src_step source image step
/// @param src_width source and destination image width
/// @param src_height source and destination image height
/// @param dst_data destination image data
/// @param dst_step destination image step
/// @param flip_mode 0 flips around x-axis, 1 around y-axis, -1 both
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_flip(
int src_type,
const uchar* src_data,
size_t src_step,
int src_width,
int src_height,
uchar* dst_data,
size_t dst_step,
int flip_mode);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Rotates a 2D array in multiples of 90 degrees.
/// @param src_type source and destination image type
/// @param src_data source image data
/// @param src_step source image step
/// @param src_width source image width
/// @If angle has value [180] it is also destination image width
/// If angle has values [90, 270] it is also destination image height
/// @param src_height source and destination image height (destination image width for angles [90, 270])
/// If angle has value [180] it is also destination image height
/// If angle has values [90, 270] it is also destination image width
/// @param dst_data destination image data
/// @param dst_step destination image step
/// @param angle clockwise angle for rotation in degrees from set [90, 180, 270]
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_rotate(
int src_type,
const uchar* src_data,
size_t src_step,
int src_width,
int src_height,
uchar* dst_data,
size_t dst_step,
int angle);
#endif

@ -0,0 +1,151 @@
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef OPENCV_FASTCV_HAL_IMGPROC_HPP_INCLUDED
#define OPENCV_FASTCV_HAL_IMGPROC_HPP_INCLUDED
#include <opencv2/core/base.hpp>
#undef cv_hal_medianBlur
#define cv_hal_medianBlur fastcv_hal_medianBlur
#undef cv_hal_sobel
#define cv_hal_sobel fastcv_hal_sobel
#undef cv_hal_boxFilter
#define cv_hal_boxFilter fastcv_hal_boxFilter
#undef cv_hal_adaptiveThreshold
#define cv_hal_adaptiveThreshold fastcv_hal_adaptiveThreshold
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Calculate medianBlur filter
/// @param src_data Source image data
/// @param src_step Source image step
/// @param dst_data Destination image data
/// @param dst_step Destination image step
/// @param width Source image width
/// @param height Source image height
/// @param depth Depths of source and destination image
/// @param cn Number of channels
/// @param ksize Size of kernel
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_medianBlur(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
int depth,
int cn,
int ksize);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Computes Sobel derivatives
///
/// @param src_data Source image data
/// @param src_step Source image step
/// @param dst_data Destination image data
/// @param dst_step Destination image step
/// @param width Source image width
/// @param height Source image height
/// @param src_depth Depth of source image
/// @param dst_depth Depths of destination image
/// @param cn Number of channels
/// @param margin_left Left margins for source image
/// @param margin_top Top margins for source image
/// @param margin_right Right margins for source image
/// @param margin_bottom Bottom margins for source image
/// @param dx orders of the derivative x
/// @param dy orders of the derivative y
/// @param ksize Size of kernel
/// @param scale Scale factor for the computed derivative values
/// @param delta Delta value that is added to the results prior to storing them in dst
/// @param border_type Border type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_sobel(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
int src_depth,
int dst_depth,
int cn,
int margin_left,
int margin_top,
int margin_right,
int margin_bottom,
int dx,
int dy,
int ksize,
double scale,
double delta,
int border_type);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Canny edge detector
/// @param src_data Source image data
/// @param src_step Source image step
/// @param dst_data Destination image data
/// @param dst_step Destination image step
/// @param width Source image width
/// @param height Source image height
/// @param cn Number of channels
/// @param lowThreshold low thresholds value
/// @param highThreshold high thresholds value
/// @param ksize Kernel size for Sobel operator.
/// @param L2gradient Flag, indicating use L2 or L1 norma.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_canny(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
int cn,
double lowThreshold,
double highThreshold,
int ksize,
bool L2gradient);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_boxFilter(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
int src_depth,
int dst_depth,
int cn,
int margin_left,
int margin_top,
int margin_right,
int margin_bottom,
size_t ksize_width,
size_t ksize_height,
int anchor_x,
int anchor_y,
bool normalize,
int border_type);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fastcv_hal_adaptiveThreshold(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
double maxValue,
int adaptiveMethod,
int thresholdType,
int blockSize,
double C);
#endif

@ -0,0 +1,83 @@
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef OPENCV_FASTCV_HAL_UTILS_HPP_INCLUDED
#define OPENCV_FASTCV_HAL_UTILS_HPP_INCLUDED
#include "fastcv.h"
#include <opencv2/core/utils/logger.hpp>
#define INITIALIZATION_CHECK \
{ \
if (!FastCvContext::getContext().isInitialized) \
{ \
return CV_HAL_ERROR_UNKNOWN; \
} \
}
#define CV_HAL_RETURN(status, func) \
{ \
if( status == FASTCV_SUCCESS ) \
{ \
CV_LOG_DEBUG(NULL, "FastCV HAL for "<<#func<<" run successfully!"); \
return CV_HAL_ERROR_OK; \
} \
else if(status == FASTCV_EBADPARAM || status == FASTCV_EUNALIGNPARAM || \
status == FASTCV_EUNSUPPORTED || status == FASTCV_EHWQDSP || \
status == FASTCV_EHWGPU) \
{ \
CV_LOG_DEBUG(NULL, "FastCV status:"<<getFastCVErrorString(status) \
<<"Switching to default OpenCV solution!"); \
return CV_HAL_ERROR_NOT_IMPLEMENTED; \
} \
else \
{ \
CV_LOG_ERROR(NULL,"FastCV error:"<<getFastCVErrorString(status)); \
return CV_HAL_ERROR_UNKNOWN; \
} \
}
#define CV_HAL_RETURN_NOT_IMPLEMENTED(reason) \
{ \
CV_LOG_DEBUG(NULL,"Switching to default OpenCV\nInfo: "<<reason); \
return CV_HAL_ERROR_NOT_IMPLEMENTED; \
}
#define FCV_KernelSize_SHIFT 3
#define FCV_MAKETYPE(ksize,depth) ((ksize<<FCV_KernelSize_SHIFT) + depth)
const char* getFastCVErrorString(int status);
const char* borderToString(int border);
const char* interpolationToString(int interpolation);
struct FastCvContext
{
public:
// initialize at first call
// Defines a static local variable context. Variable is created only once.
static FastCvContext& getContext()
{
static FastCvContext context;
return context;
}
FastCvContext()
{
if (fcvSetOperationMode(FASTCV_OP_CPU_PERFORMANCE) != 0)
{
CV_LOG_WARNING(NULL, "Failed to switch FastCV operation mode");
isInitialized = false;
}
else
{
CV_LOG_INFO(NULL, "FastCV Operation Mode Switched");
isInitialized = true;
}
}
bool isInitialized;
};
#endif

@ -0,0 +1,334 @@
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "fastcv_hal_core.hpp"
#include "fastcv_hal_utils.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/core/base.hpp>
class ParallelTableLookup : public cv::ParallelLoopBody
{
public:
ParallelTableLookup(const uchar* src_data_, int width_, size_t src_step_, const uchar* lut_data_, uchar* dst_data_, size_t dst_step_) :
cv::ParallelLoopBody(), src_data(src_data_), width(width_), src_step(src_step_), lut_data(lut_data_), dst_data(dst_data_), dst_step(dst_step_)
{
}
virtual void operator()(const cv::Range& range) const CV_OVERRIDE
{
fcvStatus status = FASTCV_SUCCESS;
for (int y = range.start; y < range.end; y++) {
status = fcvTableLookupu8((uint8_t*)src_data + y * src_step, width, 1, src_step, (uint8_t*)lut_data, (uint8_t*)dst_data + y * dst_step, dst_step);
if(status != FASTCV_SUCCESS)
CV_LOG_ERROR(NULL,"FastCV error:"<<getFastCVErrorString(status));
}
}
private:
const uchar* src_data;
int width;
size_t src_step;
const uchar* lut_data;
uchar* dst_data;
size_t dst_step;
};
int fastcv_hal_lut(
const uchar* src_data,
size_t src_step,
size_t src_type,
const uchar* lut_data,
size_t lut_channel_size,
size_t lut_channels,
uchar* dst_data,
size_t dst_step,
int width,
int height)
{
if((width*height)<=(320*240))
CV_HAL_RETURN_NOT_IMPLEMENTED("Switching to default OpenCV solution!");
INITIALIZATION_CHECK;
fcvStatus status;
if (src_type == CV_8UC1 && lut_channels == 1 && lut_channel_size == 1)
{
cv::parallel_for_(cv::Range(0, height),
ParallelTableLookup(src_data, width, src_step, lut_data, dst_data, dst_step));
status = FASTCV_SUCCESS;
CV_HAL_RETURN(status, hal_lut);
}
else
{
CV_HAL_RETURN_NOT_IMPLEMENTED("Multi-channel input is not supported");
}
}
int fastcv_hal_normHammingDiff8u(
const uchar* a,
const uchar* b,
int n,
int cellSize,
int* result)
{
fcvStatus status;
if (cellSize != 1)
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("NORM_HAMMING2 cellSize:%d is not supported", cellSize));
INITIALIZATION_CHECK;
uint32_t dist = 0;
dist = fcvHammingDistanceu8((uint8_t*)a, (uint8_t*)b, n);
*result = dist;
status = FASTCV_SUCCESS;
CV_HAL_RETURN(status, hal_normHammingDiff8u);
}
int fastcv_hal_mul8u16u(
const uchar* src1_data,
size_t src1_step,
const uchar* src2_data,
size_t src2_step,
ushort* dst_data,
size_t dst_step,
int width,
int height,
double scale)
{
if(scale != 1.0)
CV_HAL_RETURN_NOT_IMPLEMENTED("Scale factor not supported");
INITIALIZATION_CHECK;
fcvStatus status = FASTCV_SUCCESS;
if (src1_step < (size_t)width && src2_step < (size_t)width)
{
src1_step = width*sizeof(uchar);
src2_step = width*sizeof(uchar);
dst_step = width*sizeof(ushort);
}
status = fcvElementMultiplyu8u16_v2(src1_data, width, height, src1_step,
src2_data, src2_step, dst_data, dst_step);
CV_HAL_RETURN(status,hal_multiply);
}
int fastcv_hal_sub8u32f(
const uchar* src1_data,
size_t src1_step,
const uchar* src2_data,
size_t src2_step,
float* dst_data,
size_t dst_step,
int width,
int height)
{
INITIALIZATION_CHECK;
fcvStatus status = FASTCV_SUCCESS;
if (src1_step < (size_t)width && src2_step < (size_t)width)
{
src1_step = width*sizeof(uchar);
src2_step = width*sizeof(uchar);
dst_step = width*sizeof(float);
}
status = fcvImageDiffu8f32_v2(src1_data, src2_data, width, height, src1_step,
src2_step, dst_data, dst_step);
CV_HAL_RETURN(status,hal_subtract);
}
int fastcv_hal_transpose2d(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int src_width,
int src_height,
int element_size)
{
INITIALIZATION_CHECK;
if (src_data == dst_data)
CV_HAL_RETURN_NOT_IMPLEMENTED("In-place not supported");
fcvStatus status = FASTCV_SUCCESS;
switch (element_size)
{
case 1:
status = fcvTransposeu8_v2(src_data, src_width, src_height, src_step,
dst_data, dst_step);
break;
case 2:
status = fcvTransposeu16_v2((const uint16_t*)src_data, src_width, src_height,
src_step, (uint16_t*)dst_data, dst_step);
break;
case 4:
status = fcvTransposef32_v2((const float32_t*)src_data, src_width, src_height,
src_step, (float32_t*)dst_data, dst_step);
break;
default:
CV_HAL_RETURN_NOT_IMPLEMENTED("srcType not supported");
}
CV_HAL_RETURN(status,hal_transpose);
}
int fastcv_hal_meanStdDev(
const uchar* src_data,
size_t src_step,
int width,
int height,
int src_type,
double* mean_val,
double* stddev_val,
uchar* mask,
size_t mask_step)
{
INITIALIZATION_CHECK;
CV_UNUSED(mask_step);
if(src_type != CV_8UC1)
{
CV_HAL_RETURN_NOT_IMPLEMENTED("src type not supported");
}
else if(mask != nullptr)
{
CV_HAL_RETURN_NOT_IMPLEMENTED("mask not supported");
}
else if(mean_val == nullptr && stddev_val == nullptr)
{
CV_HAL_RETURN_NOT_IMPLEMENTED("null ptr for mean and stddev");
}
float32_t mean, variance;
fcvStatus status = fcvImageIntensityStats_v2(src_data, src_step, 0, 0, width, height,
&mean, &variance, FASTCV_BIASED_VARIANCE_ESTIMATOR);
if(mean_val != nullptr)
*mean_val = mean;
if(stddev_val != nullptr)
*stddev_val = std::sqrt(variance);
CV_HAL_RETURN(status,hal_meanStdDev);
}
int fastcv_hal_flip(
int src_type,
const uchar* src_data,
size_t src_step,
int src_width,
int src_height,
uchar* dst_data,
size_t dst_step,
int flip_mode)
{
INITIALIZATION_CHECK;
if(src_type!=CV_8UC1 && src_type!=CV_16UC1 && src_type!=CV_8UC3)
CV_HAL_RETURN_NOT_IMPLEMENTED("Data type is not supported, Switching to default OpenCV solution!");
if((src_width*src_height)<=(640*480))
CV_HAL_RETURN_NOT_IMPLEMENTED("Switching to default OpenCV solution!");
fcvStatus status = FASTCV_SUCCESS;;
fcvFlipDir dir;
switch (flip_mode)
{
//Flip around X-Axis: Vertical Flip or FLIP_ROWS
case 0:
CV_HAL_RETURN_NOT_IMPLEMENTED("Switching to default OpenCV solution due to low perf!");
dir = FASTCV_FLIP_VERT;
break;
//Flip around Y-Axis: Horizontal Flip or FLIP_COLS
case 1:
dir = FASTCV_FLIP_HORIZ;
break;
//Flip around both X and Y-Axis or FLIP_BOTH
case -1:
dir = FASTCV_FLIP_BOTH;
break;
default:
CV_HAL_RETURN_NOT_IMPLEMENTED("Invalid flip_mode, Switching to default OpenCV solution!");
}
if(src_type==CV_8UC1)
fcvFlipu8(src_data, src_width, src_height, src_step, dst_data, dst_step, dir);
else if(src_type==CV_16UC1)
fcvFlipu16((uint16_t*)src_data, src_width, src_height, src_step, (uint16_t*)dst_data, dst_step, dir);
else if(src_type==CV_8UC3)
status = fcvFlipRGB888u8((uint8_t*)src_data, src_width, src_height, src_step, (uint8_t*)dst_data, dst_step, dir);
else
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("Data type:%d is not supported, Switching to default OpenCV solution!", src_type));
CV_HAL_RETURN(status, hal_flip);
}
int fastcv_hal_rotate(
int src_type,
const uchar* src_data,
size_t src_step,
int src_width,
int src_height,
uchar* dst_data,
size_t dst_step,
int angle)
{
if((src_width*src_height)<(120*80))
CV_HAL_RETURN_NOT_IMPLEMENTED("Switching to default OpenCV solution for lower resolution!");
fcvStatus status;
fcvRotateDegree degree;
if (src_type != CV_8UC1 && src_type != CV_8UC2)
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("src_type:%d is not supported", src_type));
INITIALIZATION_CHECK;
switch (angle)
{
case 90:
degree = FASTCV_ROTATE_90;
break;
case 180:
degree = FASTCV_ROTATE_180;
break;
case 270:
degree = FASTCV_ROTATE_270;
break;
default:
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("Rotation angle:%d is not supported", angle));
}
switch(src_type)
{
case CV_8UC1:
status = fcvRotateImageu8(src_data, src_width, src_height, src_step, dst_data, dst_step, degree);
break;
case CV_8UC2:
status = fcvRotateImageInterleavedu8((uint8_t*)src_data, src_width, src_height, src_step, (uint8_t*)dst_data,
dst_step, degree);
break;
default:
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("src_type:%d is not supported", src_type));
}
CV_HAL_RETURN(status, hal_rotate);
}

@ -0,0 +1,318 @@
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "fastcv_hal_imgproc.hpp"
#include "fastcv_hal_utils.hpp"
#include <opencv2/core/base.hpp>
#include <opencv2/imgproc.hpp>
int fastcv_hal_medianBlur(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
int depth,
int cn,
int ksize)
{
// Do not support inplace case
if (src_data == dst_data)
CV_HAL_RETURN_NOT_IMPLEMENTED("Inplace is not supported");
// The input image width and height should greater than kernel size
if ((height <= ksize) || (width <= ksize))
CV_HAL_RETURN_NOT_IMPLEMENTED("Input image size should be larger than kernel size");
// The input channel should be 1
if (cn != 1)
CV_HAL_RETURN_NOT_IMPLEMENTED("Multi-channels is not supported");
INITIALIZATION_CHECK;
fcvStatus status;
int fcvFuncType = FCV_MAKETYPE(ksize,depth);
switch (fcvFuncType)
{
case FCV_MAKETYPE(3,CV_8U):
{
status = fcvFilterMedian3x3u8_v3(src_data, width, height, src_step, dst_data, dst_step,
fcvBorderType::FASTCV_BORDER_REPLICATE, 0);
break;
}
default:
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("Ksize:%d, depth:%s is not supported", ksize, cv::depthToString(depth)));
}
CV_HAL_RETURN(status, hal_medianBlur);
}
int fastcv_hal_sobel(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
int src_depth,
int dst_depth,
int cn,
int margin_left,
int margin_top,
int margin_right,
int margin_bottom,
int dx,
int dy,
int ksize,
double scale,
double delta,
int border_type)
{
if(scale != 1.0f || delta != 0.0f)
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("Scale:%f, delta:%f is not supported", scale, delta));
// Do not support inplace case
if (src_data == dst_data)
CV_HAL_RETURN_NOT_IMPLEMENTED("Inplace is not supported");
// The input image width and height should greater than kernel size
if ((height <= ksize) || (width <= ksize))
CV_HAL_RETURN_NOT_IMPLEMENTED("Input image size should be larger than kernel size");
// The input channel should be 1
if (cn != 1)
CV_HAL_RETURN_NOT_IMPLEMENTED("Multi-channels is not supported");
// Do not support for ROI case
if((margin_left!=0) || (margin_top != 0) || (margin_right != 0) || (margin_bottom !=0))
CV_HAL_RETURN_NOT_IMPLEMENTED("ROI is not supported");
// 1. When ksize <= 0, OpenCV will use Scharr Derivatives
// 2. When ksize == 1, OpenCV will use 3×1 or 1×3 kernel(no Gaussian smoothing is done)
// FastCV doesn't support above two situation
if (ksize <= 1)
CV_HAL_RETURN_NOT_IMPLEMENTED("Scharr derivatives or non square kernel are not supported");
// Only support the result type is CV_16S
if (dst_depth != CV_16S)
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("Dst depth:%s is not supported", cv::depthToString(dst_depth)));
INITIALIZATION_CHECK;
// Only support one direction derivatives and the order is 1.(dx=1 && dy=0)||(dx=0 && dy=1)
int16_t *dxBuffer, *dyBuffer;
if ((dx == 1) && (dy == 0))
{
dxBuffer = (int16_t*)dst_data;
dyBuffer = NULL;
}
else if ((dx == 0) && (dy == 1))
{
dxBuffer = NULL;
dyBuffer = (int16_t*)dst_data;
}
else
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("Dx:%d Dy:%d is not supported",dx, dy));
fcvStatus status;
fcvBorderType fcvBorder;
switch (border_type)
{
// For constant border, there are no border value, OpenCV default value is 0
case cv::BorderTypes::BORDER_CONSTANT:
{
fcvBorder = fcvBorderType::FASTCV_BORDER_CONSTANT;
break;
}
case cv::BorderTypes::BORDER_REPLICATE:
{
fcvBorder = fcvBorderType::FASTCV_BORDER_REPLICATE;
break;
}
default:
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("Border type:%s is not supported", borderToString(border_type)));
}
int fcvFuncType = FCV_MAKETYPE(ksize,src_depth);
switch (fcvFuncType)
{
case FCV_MAKETYPE(3,CV_8U):
{
status = fcvFilterSobel3x3u8s16(src_data, width, height, src_step, dxBuffer, dyBuffer, dst_step, fcvBorder, 0);
break;
}
case FCV_MAKETYPE(5,CV_8U):
{
status = fcvFilterSobel5x5u8s16(src_data, width, height, src_step, dxBuffer, dyBuffer, dst_step, fcvBorder, 0);
break;
}
case FCV_MAKETYPE(7,CV_8U):
{
status = fcvFilterSobel7x7u8s16(src_data, width, height, src_step, dxBuffer, dyBuffer, dst_step, fcvBorder, 0);
break;
}
default:
CV_HAL_RETURN_NOT_IMPLEMENTED(cv::format("Ksize:%d, src_depth:%s, border type:%s is not supported",
ksize, cv::depthToString(src_depth), borderToString(border_type)));
}
CV_HAL_RETURN(status, hal_sobel);
}
int fastcv_hal_boxFilter(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
int src_depth,
int dst_depth,
int cn,
int margin_left,
int margin_top,
int margin_right,
int margin_bottom,
size_t ksize_width,
size_t ksize_height,
int anchor_x,
int anchor_y,
bool normalize,
int border_type)
{
if((width*height) < (320*240))
{
CV_HAL_RETURN_NOT_IMPLEMENTED("input size not supported");
}
else if(src_data == dst_data)
{
CV_HAL_RETURN_NOT_IMPLEMENTED("in-place processing not supported");
}
else if(src_depth != CV_8U || cn != 1)
{
CV_HAL_RETURN_NOT_IMPLEMENTED("src type not supported");
}
else if(dst_depth != src_depth)
{
CV_HAL_RETURN_NOT_IMPLEMENTED("same src and dst type supported");
}
else if(ksize_width != ksize_height ||
(ksize_width != 3 && ksize_width != 5))
{
CV_HAL_RETURN_NOT_IMPLEMENTED("kernel size not supported");
}
else if(anchor_x != -1 || anchor_y != -1 ||
margin_left != 0 || margin_top != 0 ||
margin_right != 0 || margin_bottom != 0)
{
CV_HAL_RETURN_NOT_IMPLEMENTED("ROI not supported");
}
INITIALIZATION_CHECK;
fcvBorderType bdr;
uint8_t bdrVal = 0;
switch(border_type)
{
case cv::BORDER_REPLICATE:
bdr = FASTCV_BORDER_REPLICATE;
break;
case cv::BORDER_REFLECT:
bdr = FASTCV_BORDER_REFLECT;
break;
case cv::BORDER_REFLECT101: // cv::BORDER_REFLECT_101, BORDER_DEFAULT
bdr = FASTCV_BORDER_REFLECT_V2;
break;
default:
CV_HAL_RETURN_NOT_IMPLEMENTED("border type not supported");
}
fcvStatus status = FASTCV_SUCCESS;
if(ksize_width == 3)
{
status = fcvBoxFilter3x3u8_v3(src_data, width, height, src_step,
dst_data, dst_step, normalize, bdr, bdrVal);
}
else if(ksize_width == 5)
{
status = fcvBoxFilter5x5u8_v2(src_data, width, height, src_step,
dst_data, dst_step, normalize, bdr, bdrVal);
}
CV_HAL_RETURN(status,hal_boxFilter);
}
int fastcv_hal_adaptiveThreshold(
const uchar* src_data,
size_t src_step,
uchar* dst_data,
size_t dst_step,
int width,
int height,
double maxValue,
int adaptiveMethod,
int thresholdType,
int blockSize,
double C)
{
if((width*height) < (320*240))
{
CV_HAL_RETURN_NOT_IMPLEMENTED("input size not supported");
}
else if (src_data == dst_data)
{
CV_HAL_RETURN_NOT_IMPLEMENTED("In place processing not supported");
}
int value = (thresholdType == cv::THRESH_BINARY) ? cvCeil(C) : cvFloor(C);
if ((maxValue < 1) || (maxValue > 255))
{
CV_HAL_RETURN_NOT_IMPLEMENTED("max value 1-255 supported");
}
INITIALIZATION_CHECK;
uchar maxVal = cv::saturate_cast<uchar>(maxValue);
fcvThreshType threshType = (thresholdType == cv::THRESH_BINARY) ? FCV_THRESH_BINARY : FCV_THRESH_BINARY_INV;
fcvStatus status = FASTCV_SUCCESS;
if(adaptiveMethod == cv::ADAPTIVE_THRESH_GAUSSIAN_C)
{
if(blockSize == 3)
status = fcvAdaptiveThresholdGaussian3x3u8_v2(src_data, width, height, src_step, maxVal, threshType, value, dst_data, dst_step);
else if(blockSize == 5)
status = fcvAdaptiveThresholdGaussian5x5u8_v2(src_data, width, height, src_step, maxVal, threshType, value, dst_data, dst_step);
else
{
CV_HAL_RETURN_NOT_IMPLEMENTED("block size not supported");
}
}
else if(adaptiveMethod == cv::ADAPTIVE_THRESH_MEAN_C)
{
if(blockSize == 3)
status = fcvAdaptiveThresholdMean3x3u8_v2(src_data, width, height, src_step, maxVal, threshType, value, dst_data, dst_step);
else if(blockSize == 5)
status = fcvAdaptiveThresholdMean5x5u8_v2(src_data, width, height, src_step, maxVal, threshType, value, dst_data, dst_step);
else
{
CV_HAL_RETURN_NOT_IMPLEMENTED("block size not supported");
}
}
else
{
CV_HAL_RETURN_NOT_IMPLEMENTED("adaptive method not supported");
}
CV_HAL_RETURN(status,hal_adaptiveThreshold);
}

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "fastcv_hal_utils.hpp"
const char* getFastCVErrorString(int status)
{
switch(status)
{
case FASTCV_SUCCESS: return "Successful";
case FASTCV_EFAIL: return "General failure";
case FASTCV_EUNALIGNPARAM: return "Unaligned pointer parameter";
case FASTCV_EBADPARAM: return "Bad parameters";
case FASTCV_EINVALSTATE: return "Called at invalid state";
case FASTCV_ENORES: return "Insufficient resources, memory, thread, etc";
case FASTCV_EUNSUPPORTED: return "Unsupported feature";
case FASTCV_EHWQDSP: return "Hardware QDSP failed to respond";
case FASTCV_EHWGPU: return "Hardware GPU failed to respond";
default: return "Unknown FastCV Error";
}
}
const char* borderToString(int border)
{
switch (border)
{
case 0: return "BORDER_CONSTANT";
case 1: return "BORDER_REPLICATE";
case 2: return "BORDER_REFLECT";
case 3: return "BORDER_WRAP";
case 4: return "BORDER_REFLECT_101";
case 5: return "BORDER_TRANSPARENT";
default: return "Unknown border type";
}
}
const char* interpolationToString(int interpolation)
{
switch (interpolation)
{
case 0: return "INTER_NEAREST";
case 1: return "INTER_LINEAR";
case 2: return "INTER_CUBIC";
case 3: return "INTER_AREA";
case 4: return "INTER_LANCZOS4";
case 5: return "INTER_LINEAR_EXACT";
case 6: return "INTER_NEAREST_EXACT";
case 7: return "INTER_MAX";
case 8: return "WARP_FILL_OUTLIERS";
case 16: return "WARP_INVERSE_MAP";
case 32: return "WARP_RELATIVE_MAP";
default: return "Unknown interpolation type";
}
}

@ -233,6 +233,8 @@ OCV_OPTION(WITH_NDSRVP "Use Andes RVP extension" (NOT CV_DISABLE_OPTIMIZATION)
VISIBLE_IF RISCV)
OCV_OPTION(WITH_HAL_RVV "Use HAL RVV optimizations" (NOT CV_DISABLE_OPTIMIZATION)
VISIBLE_IF RISCV)
OCV_OPTION(WITH_FASTCV "Use Qualcomm FastCV acceleration library for ARM platform" OFF
VISIBLE_IF ((ARM OR AARCH64) AND (ANDROID OR (UNIX AND NOT APPLE AND NOT IOS AND NOT XROS))))
OCV_OPTION(WITH_CPUFEATURES "Use cpufeatures Android library" ON
VISIBLE_IF ANDROID
VERIFY HAVE_CPUFEATURES)
@ -935,6 +937,13 @@ if(HAVE_OPENVX)
endif()
endif()
if(HAVE_FASTCV)
ocv_debug_message(STATUS "Enable FastCV acceleration")
if(NOT ";${OpenCV_HAL};" MATCHES ";fastcv;")
set(OpenCV_HAL "fastcv;${OpenCV_HAL}")
endif()
endif()
if(HAVE_KLEIDICV)
ocv_debug_message(STATUS "Enable KleidiCV acceleration")
if(NOT ";${OpenCV_HAL};" MATCHES ";kleidicv;")
@ -972,6 +981,14 @@ foreach(hal ${OpenCV_HAL})
else()
message(STATUS "Carotene: NEON is not available, disabling carotene...")
endif()
elseif(hal STREQUAL "fastcv")
if((ARM OR AARCH64) AND (ANDROID OR (UNIX AND NOT APPLE AND NOT IOS AND NOT XROS)))
add_subdirectory(3rdparty/fastcv)
ocv_hal_register(FASTCV_HAL_LIBRARIES FASTCV_HAL_HEADERS FASTCV_HAL_INCLUDE_DIRS)
list(APPEND OpenCV_USED_HAL "fastcv (ver ${FASTCV_HAL_VERSION})")
else()
message(STATUS "FastCV: fastcv is not available, disabling fastcv...")
endif()
elseif(hal STREQUAL "kleidicv")
add_subdirectory(3rdparty/kleidicv)
ocv_hal_register(KLEIDICV_HAL_LIBRARIES KLEIDICV_HAL_HEADERS KLEIDICV_HAL_INCLUDE_DIRS)
@ -1793,6 +1810,9 @@ endif()
if(WITH_OPENVX OR HAVE_OPENVX)
status(" OpenVX:" HAVE_OPENVX THEN "YES (${OPENVX_LIBRARIES})" ELSE "NO")
endif()
if(WITH_FASTCV OR HAVE_FASTCV)
status(" FastCV:" HAVE_FASTCV THEN "YES (${FASTCV_LIBRARY})" ELSE "NO")
endif()
status(" Custom HAL:" OpenCV_USED_HAL THEN "YES (${OpenCV_USED_HAL})" ELSE "NO")

@ -176,3 +176,23 @@ if(WITH_KLEIDICV)
endif()
endif()
endif(WITH_KLEIDICV)
# --- FastCV ---
if(WITH_FASTCV)
if((EXISTS ${FastCV_INCLUDE_PATH}) AND (EXISTS ${FastCV_LIB_PATH}))
set(HAVE_FASTCV TRUE CACHE BOOL "FastCV status")
else()
include("${OpenCV_SOURCE_DIR}/3rdparty/fastcv/fastcv.cmake")
set(FCV_ROOT_DIR "${OpenCV_BINARY_DIR}/3rdparty/fastcv")
download_fastcv(${FCV_ROOT_DIR})
if (HAVE_FASTCV)
set(FastCV_INCLUDE_PATH "${FCV_ROOT_DIR}/inc" CACHE PATH "FastCV includes directory")
set(FastCV_LIB_PATH "${FCV_ROOT_DIR}/libs" CACHE PATH "FastCV library directory")
else()
set(HAVE_FASTCV FALSE CACHE BOOL "FastCV status")
endif()
if (HAVE_FASTCV)
set(FASTCV_LIBRARY "${FastCV_LIB_PATH}/libfastcvopt.so" CACHE PATH "FastCV library")
endif()
endif()
endif(WITH_FASTCV)

Loading…
Cancel
Save