mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge branch 4.x
This commit is contained in:
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
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()
|
||||
|
||||
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)
|
||||
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
function(download_fastcv root_dir)
|
||||
|
||||
# Commit SHA in the opencv_3rdparty repo
|
||||
set(FASTCV_COMMIT "dc5d58018f3af915a8d209386d2c58c0501c0f2c")
|
||||
|
||||
# Define actual FastCV versions
|
||||
if(ANDROID)
|
||||
if(AARCH64)
|
||||
message(STATUS "Download FastCV for Android aarch64")
|
||||
set(FCV_PACKAGE_NAME "fastcv_android_aarch64_2024_12_11.tgz")
|
||||
set(FCV_PACKAGE_HASH "9dac41e86597305f846212dae31a4a88")
|
||||
else()
|
||||
message(STATUS "Download FastCV for Android armv7")
|
||||
set(FCV_PACKAGE_NAME "fastcv_android_arm32_2024_12_11.tgz")
|
||||
set(FCV_PACKAGE_HASH "fe2d30334180b17e3031eee92aac43b6")
|
||||
endif()
|
||||
elseif(UNIX AND NOT APPLE AND NOT IOS AND NOT XROS)
|
||||
if(AARCH64)
|
||||
set(FCV_PACKAGE_NAME "fastcv_linux_aarch64_2024_12_11.tgz")
|
||||
set(FCV_PACKAGE_HASH "7b33ad833e6f15ab6d4ec64fa3c17acd")
|
||||
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()
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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
|
||||
#undef cv_hal_addWeighted8u
|
||||
#define cv_hal_addWeighted8u fastcv_hal_addWeighted8u
|
||||
#undef cv_hal_mul8u
|
||||
#define cv_hal_mul8u fastcv_hal_mul8u
|
||||
#undef cv_hal_mul16s
|
||||
#define cv_hal_mul16s fastcv_hal_mul16s
|
||||
#undef cv_hal_mul32f
|
||||
#define cv_hal_mul32f fastcv_hal_mul32f
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief weighted sum of two arrays using formula: dst[i] = a * src1[i] + b * src2[i]
|
||||
/// @param src1_data first source image data
|
||||
/// @param src1_step first source image step
|
||||
/// @param src2_data second source image data
|
||||
/// @param src2_step second source image step
|
||||
/// @param dst_data destination image data
|
||||
/// @param dst_step destination image step
|
||||
/// @param width width of the images
|
||||
/// @param height height of the images
|
||||
/// @param scalars numbers a, b, and c
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_addWeighted8u(
|
||||
const uchar* src1_data,
|
||||
size_t src1_step,
|
||||
const uchar* src2_data,
|
||||
size_t src2_step,
|
||||
uchar* dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
const double scalars[3]);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_mul8u(
|
||||
const uchar *src1_data,
|
||||
size_t src1_step,
|
||||
const uchar *src2_data,
|
||||
size_t src2_step,
|
||||
uchar *dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
double scale);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_mul16s(
|
||||
const short *src1_data,
|
||||
size_t src1_step,
|
||||
const short *src2_data,
|
||||
size_t src2_step,
|
||||
short *dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
double scale);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_mul32f(
|
||||
const float *src1_data,
|
||||
size_t src1_step,
|
||||
const float *src2_data,
|
||||
size_t src2_step,
|
||||
float *dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
double scale);
|
||||
|
||||
#endif
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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
|
||||
#undef cv_hal_gaussianBlurBinomial
|
||||
#define cv_hal_gaussianBlurBinomial fastcv_hal_gaussianBlurBinomial
|
||||
#undef cv_hal_warpPerspective
|
||||
#define cv_hal_warpPerspective fastcv_hal_warpPerspective
|
||||
#undef cv_hal_pyrdown
|
||||
#define cv_hal_pyrdown fastcv_hal_pyrdown
|
||||
#undef cv_hal_cvtBGRtoHSV
|
||||
#define cv_hal_cvtBGRtoHSV fastcv_hal_cvtBGRtoHSV
|
||||
#undef cv_hal_cvtBGRtoYUVApprox
|
||||
#define cv_hal_cvtBGRtoYUVApprox fastcv_hal_cvtBGRtoYUVApprox
|
||||
#undef cv_hal_canny
|
||||
#define cv_hal_canny fastcv_hal_canny
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Blurs an image using a Gaussian 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 Depth of source and 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 ksize Kernel size
|
||||
/// @param border_type Border type
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_gaussianBlurBinomial(
|
||||
const uchar* src_data,
|
||||
size_t src_step,
|
||||
uchar* dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
int depth,
|
||||
int cn,
|
||||
size_t margin_left,
|
||||
size_t margin_top,
|
||||
size_t margin_right,
|
||||
size_t margin_bottom,
|
||||
size_t ksize,
|
||||
int border_type);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Applies a perspective transformation to an image.
|
||||
///
|
||||
/// @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
|
||||
/// @param src_height Source image height
|
||||
/// @param dst_data Destination image data
|
||||
/// @param dst_step Destination image step
|
||||
/// @param dst_width Destination image width
|
||||
/// @param dst_height Destination image height
|
||||
/// @param M 3x3 matrix with transform coefficients
|
||||
/// @param interpolation Interpolation mode (CV_HAL_INTER_NEAREST, ...)
|
||||
/// @param border_type Border processing mode (CV_HAL_BORDER_REFLECT, ...)
|
||||
/// @param border_value Values to use for CV_HAL_BORDER_CONSTANT mode
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_warpPerspective(
|
||||
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 dst_width,
|
||||
int dst_height,
|
||||
const double M[9],
|
||||
int interpolation,
|
||||
int border_type,
|
||||
const double border_value[4]);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_pyrdown(
|
||||
const uchar* src_data,
|
||||
size_t src_step,
|
||||
int src_width,
|
||||
int src_height,
|
||||
uchar* dst_data,
|
||||
size_t dst_step,
|
||||
int dst_width,
|
||||
int dst_height,
|
||||
int depth,
|
||||
int cn,
|
||||
int border_type);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_cvtBGRtoHSV(
|
||||
const uchar * src_data,
|
||||
size_t src_step,
|
||||
uchar * dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
int depth,
|
||||
int scn,
|
||||
bool swapBlue,
|
||||
bool isFullRange,
|
||||
bool isHSV);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fastcv_hal_cvtBGRtoYUVApprox(
|
||||
const uchar * src_data,
|
||||
size_t src_step,
|
||||
uchar * dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
int depth,
|
||||
int scn,
|
||||
bool swapBlue,
|
||||
bool isCbCr);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @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 hresholds value
|
||||
/// @param highThreshold high thresholds value
|
||||
/// @param ksize Kernel size for Sobel operator.
|
||||
/// @param L2gradient Flag, indicating use of 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);
|
||||
|
||||
#endif
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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)
|
||||
#define FCV_CMP_EQ(val1,val2) (fabs(val1 - val2) < FLT_EPSILON)
|
||||
|
||||
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
|
||||
+574
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
int fastcv_hal_addWeighted8u(
|
||||
const uchar* src1_data,
|
||||
size_t src1_step,
|
||||
const uchar* src2_data,
|
||||
size_t src2_step,
|
||||
uchar* dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
const double scalars[3])
|
||||
{
|
||||
if( (scalars[0] < -128.0f) || (scalars[0] >= 128.0f) ||
|
||||
(scalars[1] < -128.0f) || (scalars[1] >= 128.0f) ||
|
||||
(scalars[2] < -(1<<23))|| (scalars[2] >= 1<<23))
|
||||
CV_HAL_RETURN_NOT_IMPLEMENTED(
|
||||
cv::format("Alpha:%f,Beta:%f,Gamma:%f is not supported because it's too large or too small\n",
|
||||
scalars[0],scalars[1],scalars[2]));
|
||||
|
||||
INITIALIZATION_CHECK;
|
||||
|
||||
fcvStatus status = FASTCV_SUCCESS;
|
||||
|
||||
if (height == 1)
|
||||
{
|
||||
src1_step = width*sizeof(uchar);
|
||||
src2_step = width*sizeof(uchar);
|
||||
dst_step = width*sizeof(uchar);
|
||||
|
||||
cv::parallel_for_(cv::Range(0, width), [&](const cv::Range &range){
|
||||
int rangeWidth = range.end - range.start;
|
||||
const uint8_t *src1 = src1_data + range.start;
|
||||
const uint8_t *src2 = src2_data + range.start;
|
||||
uint8_t *dst = dst_data + range.start;
|
||||
fcvAddWeightedu8_v2(src1, rangeWidth, height, src1_step, src2, src2_step,
|
||||
scalars[0], scalars[1], scalars[2], dst, dst_step);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::parallel_for_(cv::Range(0, height), [&](const cv::Range &range){
|
||||
int rangeHeight = range.end - range.start;
|
||||
const uint8_t *src1 = src1_data + range.start * src1_step;
|
||||
const uint8_t *src2 = src2_data + range.start * src2_step;
|
||||
uint8_t *dst = dst_data + range.start * dst_step;
|
||||
fcvAddWeightedu8_v2(src1, width, rangeHeight, src1_step, src2, src2_step,
|
||||
scalars[0], scalars[1], scalars[2], dst, dst_step);
|
||||
});
|
||||
}
|
||||
|
||||
CV_HAL_RETURN(status, hal_addWeighted8u_v2);
|
||||
}
|
||||
|
||||
int fastcv_hal_mul8u(
|
||||
const uchar *src1_data,
|
||||
size_t src1_step,
|
||||
const uchar *src2_data,
|
||||
size_t src2_step,
|
||||
uchar *dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
double scale)
|
||||
{
|
||||
int8_t sF;
|
||||
|
||||
if(FCV_CMP_EQ(scale,1.0)) { sF = 0; }
|
||||
else if(scale > 1.0)
|
||||
{
|
||||
if(FCV_CMP_EQ(scale,2.0)) { sF = -1; }
|
||||
else if(FCV_CMP_EQ(scale,4.0)) { sF = -2; }
|
||||
else if(FCV_CMP_EQ(scale,8.0)) { sF = -3; }
|
||||
else if(FCV_CMP_EQ(scale,16.0)) { sF = -4; }
|
||||
else if(FCV_CMP_EQ(scale,32.0)) { sF = -5; }
|
||||
else if(FCV_CMP_EQ(scale,64.0)) { sF = -6; }
|
||||
else if(FCV_CMP_EQ(scale,128.0)) { sF = -7; }
|
||||
else if(FCV_CMP_EQ(scale,256.0)) { sF = -8; }
|
||||
else CV_HAL_RETURN_NOT_IMPLEMENTED("scale factor not supported");
|
||||
}
|
||||
else if(scale > 0 && scale < 1.0)
|
||||
{
|
||||
if(FCV_CMP_EQ(scale,1/2.0)) { sF = 1; }
|
||||
else if(FCV_CMP_EQ(scale,1/4.0)) { sF = 2; }
|
||||
else if(FCV_CMP_EQ(scale,1/8.0)) { sF = 3; }
|
||||
else if(FCV_CMP_EQ(scale,1/16.0)) { sF = 4; }
|
||||
else if(FCV_CMP_EQ(scale,1/32.0)) { sF = 5; }
|
||||
else if(FCV_CMP_EQ(scale,1/64.0)) { sF = 6; }
|
||||
else if(FCV_CMP_EQ(scale,1/128.0)) { sF = 7; }
|
||||
else if(FCV_CMP_EQ(scale,1/256.0)) { sF = 8; }
|
||||
else CV_HAL_RETURN_NOT_IMPLEMENTED("scale factor not supported");
|
||||
}
|
||||
else
|
||||
CV_HAL_RETURN_NOT_IMPLEMENTED("scale factor not supported");
|
||||
|
||||
INITIALIZATION_CHECK;
|
||||
|
||||
int nStripes = cv::getNumThreads();
|
||||
|
||||
if(height == 1)
|
||||
{
|
||||
cv::parallel_for_(cv::Range(0, width), [&](const cv::Range &range){
|
||||
int rangeWidth = range.end - range.start;
|
||||
const uchar* yS1 = src1_data + static_cast<size_t>(range.start);
|
||||
const uchar* yS2 = src2_data + static_cast<size_t>(range.start);
|
||||
uchar* yD = dst_data + static_cast<size_t>(range.start);
|
||||
fcvElementMultiplyu8(yS1, rangeWidth, 1, 0, yS2, 0, sF,
|
||||
FASTCV_CONVERT_POLICY_SATURATE, yD, 0);
|
||||
}, nStripes);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::parallel_for_(cv::Range(0, height), [&](const cv::Range &range){
|
||||
int rangeHeight = range.end - range.start;
|
||||
const uchar* yS1 = src1_data + static_cast<size_t>(range.start)*src1_step;
|
||||
const uchar* yS2 = src2_data + static_cast<size_t>(range.start)*src2_step;
|
||||
uchar* yD = dst_data + static_cast<size_t>(range.start)*dst_step;
|
||||
fcvElementMultiplyu8(yS1, width, rangeHeight, src1_step, yS2, src2_step,
|
||||
sF, FASTCV_CONVERT_POLICY_SATURATE, yD, dst_step);
|
||||
}, nStripes);
|
||||
}
|
||||
|
||||
fcvStatus status = FASTCV_SUCCESS;
|
||||
CV_HAL_RETURN(status, hal_mul8u);
|
||||
}
|
||||
|
||||
int fastcv_hal_mul16s(
|
||||
const short *src1_data,
|
||||
size_t src1_step,
|
||||
const short *src2_data,
|
||||
size_t src2_step,
|
||||
short *dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
double scale)
|
||||
{
|
||||
int8_t sF;
|
||||
|
||||
if(FCV_CMP_EQ(scale,1.0)) { sF = 0; }
|
||||
else if(scale > 1.0)
|
||||
{
|
||||
if(FCV_CMP_EQ(scale,2.0)) { sF = -1; }
|
||||
else if(FCV_CMP_EQ(scale,4.0)) { sF = -2; }
|
||||
else if(FCV_CMP_EQ(scale,8.0)) { sF = -3; }
|
||||
else if(FCV_CMP_EQ(scale,16.0)) { sF = -4; }
|
||||
else if(FCV_CMP_EQ(scale,32.0)) { sF = -5; }
|
||||
else if(FCV_CMP_EQ(scale,64.0)) { sF = -6; }
|
||||
else if(FCV_CMP_EQ(scale,128.0)) { sF = -7; }
|
||||
else if(FCV_CMP_EQ(scale,256.0)) { sF = -8; }
|
||||
else CV_HAL_RETURN_NOT_IMPLEMENTED("scale factor not supported");
|
||||
}
|
||||
else if(scale > 0 && scale < 1.0)
|
||||
{
|
||||
if(FCV_CMP_EQ(scale,1/2.0)) { sF = 1; }
|
||||
else if(FCV_CMP_EQ(scale,1/4.0)) { sF = 2; }
|
||||
else if(FCV_CMP_EQ(scale,1/8.0)) { sF = 3; }
|
||||
else if(FCV_CMP_EQ(scale,1/16.0)) { sF = 4; }
|
||||
else if(FCV_CMP_EQ(scale,1/32.0)) { sF = 5; }
|
||||
else if(FCV_CMP_EQ(scale,1/64.0)) { sF = 6; }
|
||||
else if(FCV_CMP_EQ(scale,1/128.0)) { sF = 7; }
|
||||
else if(FCV_CMP_EQ(scale,1/256.0)) { sF = 8; }
|
||||
else CV_HAL_RETURN_NOT_IMPLEMENTED("scale factor not supported");
|
||||
}
|
||||
else
|
||||
CV_HAL_RETURN_NOT_IMPLEMENTED("scale factor not supported");
|
||||
|
||||
INITIALIZATION_CHECK;
|
||||
|
||||
int nStripes = cv::getNumThreads();
|
||||
|
||||
if(height == 1)
|
||||
{
|
||||
cv::parallel_for_(cv::Range(0, width), [&](const cv::Range &range){
|
||||
int rangeWidth = range.end - range.start;
|
||||
const short* yS1 = src1_data + static_cast<size_t>(range.start);
|
||||
const short* yS2 = src2_data + static_cast<size_t>(range.start);
|
||||
short* yD = dst_data + static_cast<size_t>(range.start);
|
||||
fcvElementMultiplys16(yS1, rangeWidth, 1, 0, yS2, 0, sF,
|
||||
FASTCV_CONVERT_POLICY_SATURATE, yD, 0);
|
||||
}, nStripes);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::parallel_for_(cv::Range(0, height), [&](const cv::Range &range){
|
||||
int rangeHeight = range.end - range.start;
|
||||
const short* yS1 = src1_data + static_cast<size_t>(range.start) * (src1_step/sizeof(short));
|
||||
const short* yS2 = src2_data + static_cast<size_t>(range.start) * (src2_step/sizeof(short));
|
||||
short* yD = dst_data + static_cast<size_t>(range.start) * (dst_step/sizeof(short));
|
||||
fcvElementMultiplys16(yS1, width, rangeHeight, src1_step, yS2, src2_step,
|
||||
sF, FASTCV_CONVERT_POLICY_SATURATE, yD, dst_step);
|
||||
}, nStripes);
|
||||
}
|
||||
|
||||
fcvStatus status = FASTCV_SUCCESS;
|
||||
CV_HAL_RETURN(status, hal_mul16s);
|
||||
}
|
||||
|
||||
int fastcv_hal_mul32f(
|
||||
const float *src1_data,
|
||||
size_t src1_step,
|
||||
const float *src2_data,
|
||||
size_t src2_step,
|
||||
float *dst_data,
|
||||
size_t dst_step,
|
||||
int width,
|
||||
int height,
|
||||
double scale)
|
||||
{
|
||||
if(!FCV_CMP_EQ(scale,1.0))
|
||||
CV_HAL_RETURN_NOT_IMPLEMENTED("scale factor not supported");
|
||||
|
||||
INITIALIZATION_CHECK;
|
||||
|
||||
int nStripes = cv::getNumThreads();
|
||||
|
||||
if(height == 1)
|
||||
{
|
||||
cv::parallel_for_(cv::Range(0, width), [&](const cv::Range &range){
|
||||
int rangeWidth = range.end - range.start;
|
||||
const float* yS1 = src1_data + static_cast<size_t>(range.start);
|
||||
const float* yS2 = src2_data + static_cast<size_t>(range.start);
|
||||
float* yD = dst_data + static_cast<size_t>(range.start);
|
||||
fcvElementMultiplyf32(yS1, rangeWidth, 1, 0, yS2, 0, yD, 0);
|
||||
}, nStripes);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::parallel_for_(cv::Range(0, height), [&](const cv::Range &range){
|
||||
int rangeHeight = range.end - range.start;
|
||||
const float* yS1 = src1_data + static_cast<size_t>(range.start) * (src1_step/sizeof(float));
|
||||
const float* yS2 = src2_data + static_cast<size_t>(range.start) * (src2_step/sizeof(float));
|
||||
float* yD = dst_data + static_cast<size_t>(range.start) * (dst_step/sizeof(float));
|
||||
fcvElementMultiplyf32(yS1, width, rangeHeight, src1_step,
|
||||
yS2, src2_step, yD, dst_step);
|
||||
}, nStripes);
|
||||
}
|
||||
|
||||
fcvStatus status = FASTCV_SUCCESS;
|
||||
CV_HAL_RETURN(status, hal_mul32f);
|
||||
}
|
||||
+1050
File diff suppressed because it is too large
Load Diff
+56
@@ -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";
|
||||
}
|
||||
}
|
||||
Vendored
+1
@@ -21,6 +21,7 @@
|
||||
|
||||
#if defined(__riscv_v) && __riscv_v == 1000000
|
||||
#include "hal_rvv_1p0/merge.hpp" // core
|
||||
#include "hal_rvv_1p0/mean.hpp" // core
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#ifndef OPENCV_HAL_RVV_MEANSTDDEV_HPP_INCLUDED
|
||||
#define OPENCV_HAL_RVV_MEANSTDDEV_HPP_INCLUDED
|
||||
|
||||
#include <riscv_vector.h>
|
||||
|
||||
namespace cv { namespace cv_hal_rvv {
|
||||
|
||||
#undef cv_hal_meanStdDev
|
||||
#define cv_hal_meanStdDev cv::cv_hal_rvv::meanStdDev
|
||||
|
||||
inline int meanStdDev_8UC1(const uchar* src_data, size_t src_step, int width, int height,
|
||||
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step);
|
||||
inline int meanStdDev_8UC4(const uchar* src_data, size_t src_step, int width, int height,
|
||||
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step);
|
||||
inline int meanStdDev_32FC1(const uchar* src_data, size_t src_step, int width, int height,
|
||||
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step);
|
||||
|
||||
inline int 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) {
|
||||
switch (src_type)
|
||||
{
|
||||
case CV_8UC1:
|
||||
return meanStdDev_8UC1(src_data, src_step, width, height, mean_val, stddev_val, mask, mask_step);
|
||||
case CV_8UC4:
|
||||
return meanStdDev_8UC4(src_data, src_step, width, height, mean_val, stddev_val, mask, mask_step);
|
||||
case CV_32FC1:
|
||||
return meanStdDev_32FC1(src_data, src_step, width, height, mean_val, stddev_val, mask, mask_step);
|
||||
default:
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
inline int meanStdDev_8UC1(const uchar* src_data, size_t src_step, int width, int height,
|
||||
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step) {
|
||||
int nz = 0;
|
||||
int vlmax = __riscv_vsetvlmax_e64m8();
|
||||
vuint64m8_t vec_sum = __riscv_vmv_v_x_u64m8(0, vlmax);
|
||||
vuint64m8_t vec_sqsum = __riscv_vmv_v_x_u64m8(0, vlmax);
|
||||
if (mask) {
|
||||
for (int i = 0; i < height; ++i) {
|
||||
const uchar* src_row = src_data + i * src_step;
|
||||
const uchar* mask_row = mask + i * mask_step;
|
||||
int j = 0, vl;
|
||||
for ( ; j < width; j += vl) {
|
||||
vl = __riscv_vsetvl_e8m1(width - j);
|
||||
auto vec_pixel_u8 = __riscv_vle8_v_u8m1(src_row + j, vl);
|
||||
auto vmask_u8 = __riscv_vle8_v_u8m1(mask_row+j, vl);
|
||||
auto vec_pixel = __riscv_vzext_vf4(vec_pixel_u8, vl);
|
||||
auto vmask = __riscv_vmseq_vx_u8m1_b8(vmask_u8, 1, vl);
|
||||
vec_sum = __riscv_vwaddu_wv_u64m8_tumu(vmask, vec_sum, vec_sum, vec_pixel, vl);
|
||||
vec_sqsum = __riscv_vwmaccu_vv_u64m8_tumu(vmask, vec_sqsum, vec_pixel, vec_pixel, vl);
|
||||
nz += __riscv_vcpop_m_b8(vmask, vl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < height; i++) {
|
||||
const uchar* src_row = src_data + i * src_step;
|
||||
int j = 0, vl;
|
||||
for ( ; j < width; j += vl) {
|
||||
vl = __riscv_vsetvl_e8m1(width - j);
|
||||
auto vec_pixel_u8 = __riscv_vle8_v_u8m1(src_row + j, vl);
|
||||
auto vec_pixel = __riscv_vzext_vf4(vec_pixel_u8, vl);
|
||||
vec_sum = __riscv_vwaddu_wv_u64m8_tu(vec_sum, vec_sum, vec_pixel, vl);
|
||||
vec_sqsum = __riscv_vwmaccu_vv_u64m8_tu(vec_sqsum, vec_pixel, vec_pixel, vl);
|
||||
}
|
||||
}
|
||||
nz = height * width;
|
||||
}
|
||||
if (nz == 0) {
|
||||
if (mean_val) *mean_val = 0.0;
|
||||
if (stddev_val) *stddev_val = 0.0;
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
auto zero = __riscv_vmv_s_x_u64m1(0, vlmax);
|
||||
auto vec_red = __riscv_vmv_v_x_u64m1(0, vlmax);
|
||||
auto vec_reddev = __riscv_vmv_v_x_u64m1(0, vlmax);
|
||||
vec_red = __riscv_vredsum(vec_sum, zero, vlmax);
|
||||
vec_reddev = __riscv_vredsum(vec_sqsum, zero, vlmax);
|
||||
double sum = __riscv_vmv_x(vec_red);
|
||||
double mean = sum / nz;
|
||||
if (mean_val) {
|
||||
*mean_val = mean;
|
||||
}
|
||||
if (stddev_val) {
|
||||
double sqsum = __riscv_vmv_x(vec_reddev);
|
||||
double variance = std::max((sqsum / nz) - (mean * mean), 0.0);
|
||||
double stddev = std::sqrt(variance);
|
||||
*stddev_val = stddev;
|
||||
}
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
inline int meanStdDev_8UC4(const uchar* src_data, size_t src_step, int width, int height,
|
||||
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step) {
|
||||
int nz = 0;
|
||||
int vlmax = __riscv_vsetvlmax_e64m8();
|
||||
vuint64m8_t vec_sum = __riscv_vmv_v_x_u64m8(0, vlmax);
|
||||
vuint64m8_t vec_sqsum = __riscv_vmv_v_x_u64m8(0, vlmax);
|
||||
if (mask) {
|
||||
for (int i = 0; i < height; ++i) {
|
||||
const uchar* src_row = src_data + i * src_step;
|
||||
const uchar* mask_row = mask + i * mask_step;
|
||||
int j = 0, jm = 0, vl, vlm;
|
||||
for ( ; j < width*4; j += vl, jm += vlm) {
|
||||
vl = __riscv_vsetvl_e8m1(width*4 - j);
|
||||
vlm = __riscv_vsetvl_e8mf4(width - jm);
|
||||
auto vec_pixel_u8 = __riscv_vle8_v_u8m1(src_row + j, vl);
|
||||
auto vmask_u8mf4 = __riscv_vle8_v_u8mf4(mask_row + jm, vlm);
|
||||
auto vmask_u32 = __riscv_vzext_vf4(vmask_u8mf4, vlm);
|
||||
// 0 -> 0000; 1 -> 1111
|
||||
vmask_u32 = __riscv_vmul(vmask_u32, 0b00000001000000010000000100000001, vlm);
|
||||
auto vmask_u8 = __riscv_vreinterpret_u8m1(vmask_u32);
|
||||
auto vec_pixel = __riscv_vzext_vf4(vec_pixel_u8, vl);
|
||||
auto vmask = __riscv_vmseq_vx_u8m1_b8(vmask_u8, 1, vl);
|
||||
vec_sum = __riscv_vwaddu_wv_u64m8_tumu(vmask, vec_sum, vec_sum, vec_pixel, vl);
|
||||
vec_sqsum = __riscv_vwmaccu_vv_u64m8_tumu(vmask, vec_sqsum, vec_pixel, vec_pixel, vl);
|
||||
nz += __riscv_vcpop_m_b8(vmask, vl);
|
||||
}
|
||||
}
|
||||
nz /= 4;
|
||||
} else {
|
||||
for (int i = 0; i < height; i++) {
|
||||
const uchar* src_row = src_data + i * src_step;
|
||||
int j = 0, vl;
|
||||
for ( ; j < width*4; j += vl) {
|
||||
vl = __riscv_vsetvl_e8m1(width*4 - j);
|
||||
auto vec_pixel_u8 = __riscv_vle8_v_u8m1(src_row + j, vl);
|
||||
auto vec_pixel = __riscv_vzext_vf4(vec_pixel_u8, vl);
|
||||
vec_sum = __riscv_vwaddu_wv_u64m8_tu(vec_sum, vec_sum, vec_pixel, vl);
|
||||
vec_sqsum = __riscv_vwmaccu_vv_u64m8_tu(vec_sqsum, vec_pixel, vec_pixel, vl);
|
||||
}
|
||||
}
|
||||
nz = height * width;
|
||||
}
|
||||
if (nz == 0) {
|
||||
if (mean_val) *mean_val = 0.0;
|
||||
if (stddev_val) *stddev_val = 0.0;
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
uint64_t s[256], sq[256], sum[4] = {0}, sqsum[4] = {0};
|
||||
__riscv_vse64(s, vec_sum, vlmax);
|
||||
__riscv_vse64(sq, vec_sqsum, vlmax);
|
||||
for (int i = 0; i < vlmax; ++i)
|
||||
{
|
||||
sum[i % 4] += s[i];
|
||||
sqsum[i % 4] += sq[i];
|
||||
}
|
||||
if (mean_val) {
|
||||
mean_val[0] = (double)sum[0] / nz;
|
||||
mean_val[1] = (double)sum[1] / nz;
|
||||
mean_val[2] = (double)sum[2] / nz;
|
||||
mean_val[3] = (double)sum[3] / nz;
|
||||
}
|
||||
if (stddev_val) {
|
||||
stddev_val[0] = std::sqrt(std::max(((double)sqsum[0] / nz) - (mean_val[0] * mean_val[0]), 0.0));
|
||||
stddev_val[1] = std::sqrt(std::max(((double)sqsum[1] / nz) - (mean_val[1] * mean_val[1]), 0.0));
|
||||
stddev_val[2] = std::sqrt(std::max(((double)sqsum[2] / nz) - (mean_val[2] * mean_val[2]), 0.0));
|
||||
stddev_val[3] = std::sqrt(std::max(((double)sqsum[3] / nz) - (mean_val[3] * mean_val[3]), 0.0));
|
||||
}
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
inline int meanStdDev_32FC1(const uchar* src_data, size_t src_step, int width, int height,
|
||||
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step) {
|
||||
int nz = 0;
|
||||
int vlmax = __riscv_vsetvlmax_e64m4();
|
||||
vfloat64m4_t vec_sum = __riscv_vfmv_v_f_f64m4(0, vlmax);
|
||||
vfloat64m4_t vec_sqsum = __riscv_vfmv_v_f_f64m4(0, vlmax);
|
||||
src_step /= sizeof(float);
|
||||
if (mask) {
|
||||
for (int i = 0; i < height; ++i) {
|
||||
const float* src_row0 = reinterpret_cast<const float*>(src_data) + i * src_step;
|
||||
const uchar* mask_row = mask + i * mask_step;
|
||||
int j = 0, vl;
|
||||
for ( ; j < width; j += vl) {
|
||||
vl = __riscv_vsetvl_e32m2(width - j);
|
||||
auto vec_pixel = __riscv_vle32_v_f32m2(src_row0 + j, vl);
|
||||
auto vmask_u8 = __riscv_vle8_v_u8mf2(mask_row + j, vl);
|
||||
auto vmask_u32 = __riscv_vzext_vf4(vmask_u8, vl);
|
||||
auto vmask = __riscv_vmseq_vx_u32m2_b16(vmask_u32, 1, vl);
|
||||
vec_sum = __riscv_vfwadd_wv_f64m4_tumu(vmask, vec_sum, vec_sum, vec_pixel, vl);
|
||||
vec_sqsum = __riscv_vfwmacc_vv_f64m4_tumu(vmask, vec_sqsum, vec_pixel, vec_pixel, vl);
|
||||
nz += __riscv_vcpop_m_b16(vmask, vl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < height; i++) {
|
||||
const float* src_row0 = reinterpret_cast<const float*>(src_data) + i * src_step;
|
||||
int j = 0, vl;
|
||||
for ( ; j < width; j += vl) {
|
||||
vl = __riscv_vsetvl_e32m2(width - j);
|
||||
auto vec_pixel = __riscv_vle32_v_f32m2(src_row0 + j, vl);
|
||||
vec_sum = __riscv_vfwadd_wv_f64m4_tu(vec_sum, vec_sum, vec_pixel, vl);
|
||||
vec_sqsum = __riscv_vfwmacc_vv_f64m4_tu(vec_sqsum, vec_pixel, vec_pixel, vl);
|
||||
}
|
||||
}
|
||||
nz = height * width;
|
||||
}
|
||||
if (nz == 0) {
|
||||
if (mean_val) *mean_val = 0.0;
|
||||
if (stddev_val) *stddev_val = 0.0;
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
auto zero = __riscv_vfmv_v_f_f64m1(0, vlmax);
|
||||
auto vec_red = __riscv_vfmv_v_f_f64m1(0, vlmax);
|
||||
auto vec_reddev = __riscv_vfmv_v_f_f64m1(0, vlmax);
|
||||
vec_red = __riscv_vfredusum(vec_sum, zero, vlmax);
|
||||
vec_reddev = __riscv_vfredusum(vec_sqsum, zero, vlmax);
|
||||
double sum = __riscv_vfmv_f(vec_red);
|
||||
double mean = sum / nz;
|
||||
if (mean_val) {
|
||||
*mean_val = mean;
|
||||
}
|
||||
if (stddev_val) {
|
||||
double sqsum = __riscv_vfmv_f(vec_reddev);
|
||||
double variance = std::max((sqsum / nz) - (mean * mean), 0.0);
|
||||
double stddev = std::sqrt(variance);
|
||||
*stddev_val = stddev;
|
||||
}
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
+63
-32
@@ -20,9 +20,9 @@ namespace cv { namespace cv_hal_rvv {
|
||||
#if defined __GNUC__
|
||||
__attribute__((optimize("no-tree-vectorize")))
|
||||
#endif
|
||||
static int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
inline int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
int k = cn % 4 ? cn % 4 : 4;
|
||||
int i = 0, j;
|
||||
int i = 0;
|
||||
int vl = __riscv_vsetvlmax_e8m1();
|
||||
if( k == 1 )
|
||||
{
|
||||
@@ -30,7 +30,7 @@ static int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
for( ; i <= len - vl; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*2, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*cn, a, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
@@ -45,8 +45,8 @@ static int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
{
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
auto b = __riscv_vle8_v_u8m1(src1 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*2, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*2, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*cn, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*cn, b, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
@@ -65,9 +65,9 @@ static int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
auto b = __riscv_vle8_v_u8m1(src1 + i, vl);
|
||||
auto c = __riscv_vle8_v_u8m1(src2 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*3, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*3, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 2, sizeof(uchar)*3, c, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*cn, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*cn, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 2, sizeof(uchar)*cn, c, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
@@ -88,10 +88,10 @@ static int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
auto b = __riscv_vle8_v_u8m1(src1 + i, vl);
|
||||
auto c = __riscv_vle8_v_u8m1(src2 + i, vl);
|
||||
auto d = __riscv_vle8_v_u8m1(src3 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*4, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*4, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 2, sizeof(uchar)*4, c, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 3, sizeof(uchar)*4, d, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*cn, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*cn, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 2, sizeof(uchar)*cn, c, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 3, sizeof(uchar)*cn, d, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
@@ -110,10 +110,27 @@ static int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
for( ; k < cn; k += 4 )
|
||||
{
|
||||
const uchar *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3];
|
||||
for( i = 0, j = k; i < len; i++, j += cn )
|
||||
i = 0;
|
||||
for( ; i <= len - vl; i += vl)
|
||||
{
|
||||
dst[j] = src0[i]; dst[j+1] = src1[i];
|
||||
dst[j+2] = src2[i]; dst[j+3] = src3[i];
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
auto b = __riscv_vle8_v_u8m1(src1 + i, vl);
|
||||
auto c = __riscv_vle8_v_u8m1(src2 + i, vl);
|
||||
auto d = __riscv_vle8_v_u8m1(src3 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + k+i*cn, sizeof(uchar)*cn, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + k+i*cn + 1, sizeof(uchar)*cn, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + k+i*cn + 2, sizeof(uchar)*cn, c, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + k+i*cn + 3, sizeof(uchar)*cn, d, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++ )
|
||||
{
|
||||
dst[k+i*cn] = src0[i];
|
||||
dst[k+i*cn+1] = src1[i];
|
||||
dst[k+i*cn+2] = src2[i];
|
||||
dst[k+i*cn+3] = src3[i];
|
||||
}
|
||||
}
|
||||
return CV_HAL_ERROR_OK;
|
||||
@@ -122,9 +139,9 @@ static int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
#if defined __GNUC__
|
||||
__attribute__((optimize("no-tree-vectorize")))
|
||||
#endif
|
||||
static int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
inline int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
int k = cn % 4 ? cn % 4 : 4;
|
||||
int i = 0, j;
|
||||
int i = 0;
|
||||
int vl = __riscv_vsetvlmax_e16m1();
|
||||
if( k == 1 )
|
||||
{
|
||||
@@ -132,7 +149,7 @@ static int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
for( ; i <= len - vl; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*2, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*cn, a, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
@@ -147,8 +164,8 @@ static int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
{
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
auto b = __riscv_vle16_v_u16m1(src1 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*2, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*2, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*cn, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*cn, b, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
@@ -167,9 +184,9 @@ static int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
auto b = __riscv_vle16_v_u16m1(src1 + i, vl);
|
||||
auto c = __riscv_vle16_v_u16m1(src2 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*3, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*3, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 2, sizeof(ushort)*3, c, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*cn, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*cn, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 2, sizeof(ushort)*cn, c, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
@@ -190,10 +207,10 @@ static int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
auto b = __riscv_vle16_v_u16m1(src1 + i, vl);
|
||||
auto c = __riscv_vle16_v_u16m1(src2 + i, vl);
|
||||
auto d = __riscv_vle16_v_u16m1(src3 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*4, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*4, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 2, sizeof(ushort)*4, c, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 3, sizeof(ushort)*4, d, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*cn, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*cn, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 2, sizeof(ushort)*cn, c, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 3, sizeof(ushort)*cn, d, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
@@ -212,10 +229,24 @@ static int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
for( ; k < cn; k += 4 )
|
||||
{
|
||||
const uint16_t *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3];
|
||||
for( i = 0, j = k; i < len; i++, j += cn )
|
||||
i = 0;
|
||||
for( ; i <= len - vl; i += vl)
|
||||
{
|
||||
dst[j] = src0[i]; dst[j+1] = src1[i];
|
||||
dst[j+2] = src2[i]; dst[j+3] = src3[i];
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
auto b = __riscv_vle16_v_u16m1(src1 + i, vl);
|
||||
auto c = __riscv_vle16_v_u16m1(src2 + i, vl);
|
||||
auto d = __riscv_vle16_v_u16m1(src3 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + k+i*cn, sizeof(ushort)*cn, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + k+i*cn + 1, sizeof(ushort)*cn, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + k+i*cn + 2, sizeof(ushort)*cn, c, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + k+i*cn + 3, sizeof(ushort)*cn, d, vl);
|
||||
}
|
||||
for( ; i < len; i++ )
|
||||
{
|
||||
dst[k+i*cn] = src0[i];
|
||||
dst[k+i*cn+1] = src1[i];
|
||||
dst[k+i*cn+2] = src2[i];
|
||||
dst[k+i*cn+3] = src3[i];
|
||||
}
|
||||
}
|
||||
return CV_HAL_ERROR_OK;
|
||||
@@ -224,7 +255,7 @@ static int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
#if defined __GNUC__
|
||||
__attribute__((optimize("no-tree-vectorize")))
|
||||
#endif
|
||||
static int merge32s(const int** src, int* dst, int len, int cn ) {
|
||||
inline int merge32s(const int** src, int* dst, int len, int cn ) {
|
||||
int k = cn % 4 ? cn % 4 : 4;
|
||||
int i, j;
|
||||
if( k == 1 )
|
||||
@@ -294,7 +325,7 @@ static int merge32s(const int** src, int* dst, int len, int cn ) {
|
||||
#if defined __GNUC__
|
||||
__attribute__((optimize("no-tree-vectorize")))
|
||||
#endif
|
||||
static int merge64s(const int64** src, int64* dst, int len, int cn ) {
|
||||
inline int merge64s(const int64** src, int64* dst, int len, int cn ) {
|
||||
int k = cn % 4 ? cn % 4 : 4;
|
||||
int i, j;
|
||||
if( k == 1 )
|
||||
|
||||
Vendored
+5
-1
@@ -3,5 +3,9 @@ project(kleidicv_hal)
|
||||
if(HAVE_KLEIDICV)
|
||||
option(KLEIDICV_ENABLE_SME2 "" OFF) # not compatible with some CLang versions in NDK
|
||||
include("${KLEIDICV_SOURCE_PATH}/adapters/opencv/CMakeLists.txt")
|
||||
# HACK to suppress adapters/opencv/kleidicv_hal.cpp:343:12: warning: unused function 'from_opencv' [-Wunused-function]
|
||||
target_compile_options( kleidicv_hal PRIVATE
|
||||
$<TARGET_PROPERTY:kleidicv,COMPILE_OPTIONS>
|
||||
"-Wno-old-style-cast" "-Wno-unused-function"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -1,8 +1,8 @@
|
||||
function(download_kleidicv root_var)
|
||||
set(${root_var} "" PARENT_SCOPE)
|
||||
|
||||
ocv_update(KLEIDICV_SRC_COMMIT "0.2.0")
|
||||
ocv_update(KLEIDICV_SRC_HASH "dabe522e8f55ac342d07a787391dab80")
|
||||
ocv_update(KLEIDICV_SRC_COMMIT "0.3.0")
|
||||
ocv_update(KLEIDICV_SRC_HASH "51a77b0185c2bac2a968a2163869b1ed")
|
||||
|
||||
set(THE_ROOT "${OpenCV_BINARY_DIR}/3rdparty/kleidicv")
|
||||
ocv_download(FILENAME "kleidicv-${KLEIDICV_SRC_COMMIT}.tar.gz"
|
||||
|
||||
@@ -174,6 +174,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)
|
||||
@@ -242,6 +244,9 @@ OCV_OPTION(WITH_OPENJPEG "Include JPEG2K support (OpenJPEG)" ON
|
||||
OCV_OPTION(WITH_JPEG "Include JPEG support" ON
|
||||
VISIBLE_IF TRUE
|
||||
VERIFY HAVE_JPEG)
|
||||
OCV_OPTION(WITH_JPEGXL "Include JPEG XL support" OFF
|
||||
VISIBLE_IF TRUE
|
||||
VERIFY HAVE_JPEGXL)
|
||||
OCV_OPTION(WITH_WEBP "Include WebP support" ON
|
||||
VISIBLE_IF NOT WINRT
|
||||
VERIFY HAVE_WEBP)
|
||||
@@ -365,6 +370,9 @@ OCV_OPTION(WITH_ITT "Include Intel ITT support" ON
|
||||
OCV_OPTION(WITH_PROTOBUF "Enable libprotobuf" ON
|
||||
VISIBLE_IF TRUE
|
||||
VERIFY HAVE_PROTOBUF)
|
||||
OCV_OPTION(WITH_IMGCODEC_GIF "Include GIF support" OFF
|
||||
VISIBLE_IF TRUE
|
||||
VERIFY HAVE_IMGCODEC_GIF)
|
||||
OCV_OPTION(WITH_IMGCODEC_HDR "Include HDR support" ON
|
||||
VISIBLE_IF TRUE
|
||||
VERIFY HAVE_IMGCODEC_HDR)
|
||||
@@ -697,6 +705,13 @@ elseif(WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DEFINED OPENCV_ALGO_HINT_DEFAULT)
|
||||
if(NOT OPENCV_ALGO_HINT_DEFAULT STREQUAL "ALGO_HINT_ACCURATE" AND
|
||||
NOT OPENCV_ALGO_HINT_DEFAULT STREQUAL "ALGO_HINT_APPROX")
|
||||
message(FATAL_ERROR "OPENCV_ALGO_HINT_DEFAULT should be one of ALGO_HINT_ACCURATE or ALGO_HINT_APPROX.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(cmake/OpenCVPCHSupport.cmake)
|
||||
include(cmake/OpenCVModule.cmake)
|
||||
|
||||
@@ -861,6 +876,13 @@ if(NOT DEFINED OpenCV_HAL)
|
||||
set(OpenCV_HAL "OpenCV_HAL")
|
||||
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;")
|
||||
@@ -898,6 +920,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)
|
||||
@@ -1439,6 +1469,10 @@ if(WITH_TIFF OR HAVE_TIFF)
|
||||
status(" TIFF:" TIFF_FOUND THEN "${TIFF_LIBRARY} (ver ${TIFF_VERSION} / ${TIFF_VERSION_STRING})" ELSE "build (ver ${TIFF_VERSION} - ${TIFF_VERSION_STRING})")
|
||||
endif()
|
||||
|
||||
if(WITH_JPEGXL OR HAVE_JPEGXL)
|
||||
status(" JPEG XL:" JPEGXL_FOUND THEN "${JPEGXL_LIBRARY} (ver ${JPEGXL_VERSION})" ELSE "NO")
|
||||
endif()
|
||||
|
||||
if(HAVE_OPENJPEG)
|
||||
status(" JPEG 2000:" OpenJPEG_FOUND
|
||||
THEN "OpenJPEG (ver ${OPENJPEG_VERSION})"
|
||||
@@ -1466,6 +1500,10 @@ if(WITH_GDCM OR HAVE_GDCM)
|
||||
status(" GDCM:" HAVE_GDCM THEN "YES (${GDCM_VERSION})" ELSE "NO")
|
||||
endif()
|
||||
|
||||
if(WITH_IMGCODEC_GIF OR DEFINED HAVE_IMGCODEC_GIF)
|
||||
status(" GIF:" HAVE_IMGCODEC_GIF THEN "YES" ELSE "NO")
|
||||
endif()
|
||||
|
||||
if(WITH_IMGCODEC_HDR OR DEFINED HAVE_IMGCODEC_HDR)
|
||||
status(" HDR:" HAVE_IMGCODEC_HDR THEN "YES" ELSE "NO")
|
||||
endif()
|
||||
@@ -1712,6 +1750,10 @@ if(WITH_EIGEN OR HAVE_EIGEN)
|
||||
status(" Eigen:" HAVE_EIGEN THEN "YES (ver ${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION})" 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")
|
||||
|
||||
foreach(s ${CUSTOM_STATUS})
|
||||
|
||||
@@ -191,11 +191,6 @@ if(CV_GCC OR CV_CLANG OR CV_ICX)
|
||||
endif()
|
||||
add_extra_compiler_option(-fdiagnostics-show-option)
|
||||
|
||||
# The -Wno-long-long is required in 64bit systems when including system headers.
|
||||
if(X86_64)
|
||||
add_extra_compiler_option(-Wno-long-long)
|
||||
endif()
|
||||
|
||||
# We need pthread's, unless we have explicitly disabled multi-thread execution.
|
||||
if(NOT OPENCV_DISABLE_THREAD_SUPPORT
|
||||
AND (
|
||||
@@ -409,6 +404,14 @@ if(NOT OPENCV_SKIP_LINK_NO_UNDEFINED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# For 16k pages support with NDK prior 27
|
||||
# Details: https://developer.android.com/guide/practices/page-sizes?hl=en
|
||||
if(ANDROID AND ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES AND (ANDROID_ABI STREQUAL arm64-v8a OR ANDROID_ABI STREQUAL x86_64))
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||
endif()
|
||||
|
||||
# combine all "extra" options
|
||||
if(NOT OPENCV_SKIP_EXTRA_COMPILER_FLAGS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPENCV_EXTRA_FLAGS} ${OPENCV_EXTRA_C_FLAGS}")
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
# The script is taken from https://webkit.googlesource.com/WebKit/+/master/Source/cmake/FindJPEGXL.cmake
|
||||
|
||||
# Copyright (C) 2021 Sony Interactive Entertainment Inc.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
# THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#[=======================================================================[.rst:
|
||||
FindJPEGXL
|
||||
---------
|
||||
Find JPEGXL headers and libraries.
|
||||
Imported Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
``JPEGXL::jxl``
|
||||
The JPEGXL library, if found.
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
This will define the following variables in your project:
|
||||
``JPEGXL_FOUND``
|
||||
true if (the requested version of) JPEGXL is available.
|
||||
``JPEGXL_VERSION``
|
||||
the version of JPEGXL.
|
||||
``JPEGXL_LIBRARIES``
|
||||
the libraries to link against to use JPEGXL.
|
||||
``JPEGXL_INCLUDE_DIRS``
|
||||
where to find the JPEGXL headers.
|
||||
``JPEGXL_COMPILE_OPTIONS``
|
||||
this should be passed to target_compile_options(), if the
|
||||
target is not used for linking
|
||||
#]=======================================================================]
|
||||
|
||||
if(NOT OPENCV_SKIP_JPEGXL_FIND_PACKAGE)
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PkgConfig_FOUND)
|
||||
pkg_check_modules(PC_JPEGXL QUIET jxl)
|
||||
set(JPEGXL_COMPILE_OPTIONS ${PC_JPEGXL_CFLAGS_OTHER})
|
||||
set(JPEGXL_VERSION ${PC_JPEGXL_VERSION})
|
||||
endif ()
|
||||
find_path(JPEGXL_INCLUDE_DIR
|
||||
NAMES jxl/decode.h
|
||||
HINTS ${PC_JPEGXL_INCLUDEDIR} ${PC_JPEGXL_INCLUDE_DIRS} ${JPEGXL_INCLUDE_DIR}
|
||||
)
|
||||
find_library(JPEGXL_LIBRARY
|
||||
NAMES ${JPEGXL_NAMES} jxl
|
||||
HINTS ${PC_JPEGXL_LIBDIR} ${PC_JPEGXL_LIBRARY_DIRS}
|
||||
)
|
||||
find_library(JPEGXL_CMS_LIBRARY
|
||||
NAMES ${JPEGXL_NAMES} jxl_cms
|
||||
HINTS ${PC_JPEGXL_LIBDIR} ${PC_JPEGXL_LIBRARY_DIRS}
|
||||
)
|
||||
if (JPEGXL_LIBRARY AND JPEGXL_CMS_LIBRARY)
|
||||
set(JPEGXL_LIBRARY ${JPEGXL_LIBRARY} ${JPEGXL_CMS_LIBRARY})
|
||||
endif ()
|
||||
find_library(JPEGXL_CMS2_LIBRARY
|
||||
NAMES ${JPEGXL_NAMES} lcms2
|
||||
HINTS ${PC_JPEGXL_LIBDIR} ${PC_JPEGXL_LIBRARY_DIRS}
|
||||
)
|
||||
if (JPEGXL_LIBRARY AND JPEGXL_CMS2_LIBRARY)
|
||||
set(JPEGXL_LIBRARY ${JPEGXL_LIBRARY} ${JPEGXL_CMS2_LIBRARY})
|
||||
endif ()
|
||||
find_library(JPEGXL_THREADS_LIBRARY
|
||||
NAMES ${JPEGXL_NAMES} jxl_threads
|
||||
HINTS ${PC_JPEGXL_LIBDIR} ${PC_JPEGXL_LIBRARY_DIRS}
|
||||
)
|
||||
if (JPEGXL_LIBRARY AND JPEGXL_THREADS_LIBRARY)
|
||||
set(JPEGXL_LIBRARY ${JPEGXL_LIBRARY} ${JPEGXL_THREADS_LIBRARY})
|
||||
endif ()
|
||||
find_library(JPEGXL_BROTLICOMMON_LIBRARY
|
||||
NAMES ${JPEGXL_NAMES} brotlicommon
|
||||
HINTS ${PC_JPEGXL_LIBDIR} ${PC_JPEGXL_LIBRARY_DIRS}
|
||||
)
|
||||
find_library(JPEGXL_BROTLIDEC_LIBRARY
|
||||
NAMES ${JPEGXL_NAMES} brotlidec
|
||||
HINTS ${PC_JPEGXL_LIBDIR} ${PC_JPEGXL_LIBRARY_DIRS}
|
||||
)
|
||||
if (JPEGXL_LIBRARY AND JPEGXL_BROTLIDEC_LIBRARY)
|
||||
set(JPEGXL_LIBRARY ${JPEGXL_LIBRARY} ${JPEGXL_BROTLIDEC_LIBRARY})
|
||||
endif ()
|
||||
find_library(JPEGXL_BROTLIENC_LIBRARY
|
||||
NAMES ${JPEGXL_NAMES} brotlienc
|
||||
HINTS ${PC_JPEGXL_LIBDIR} ${PC_JPEGXL_LIBRARY_DIRS}
|
||||
)
|
||||
if (JPEGXL_LIBRARY AND JPEGXL_BROTLIENC_LIBRARY)
|
||||
set(JPEGXL_LIBRARY ${JPEGXL_LIBRARY} ${JPEGXL_BROTLIENC_LIBRARY})
|
||||
endif ()
|
||||
if (JPEGXL_LIBRARY AND JPEGXL_BROTLICOMMON_LIBRARY)
|
||||
set(JPEGXL_LIBRARY ${JPEGXL_LIBRARY} ${JPEGXL_BROTLICOMMON_LIBRARY})
|
||||
endif ()
|
||||
find_library(JPEGXL_HWY_LIBRARY
|
||||
NAMES ${JPEGXL_NAMES} hwy
|
||||
HINTS ${PC_JPEGXL_LIBDIR} ${PC_JPEGXL_LIBRARY_DIRS}
|
||||
)
|
||||
if (JPEGXL_LIBRARY AND JPEGXL_HWY_LIBRARY)
|
||||
set(JPEGXL_LIBRARY ${JPEGXL_LIBRARY} ${JPEGXL_HWY_LIBRARY})
|
||||
endif ()
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(JPEGXL
|
||||
FOUND_VAR JPEGXL_FOUND
|
||||
REQUIRED_VARS JPEGXL_LIBRARY JPEGXL_INCLUDE_DIR
|
||||
VERSION_VAR JPEGXL_VERSION
|
||||
)
|
||||
if (NOT EXISTS "${JPEGXL_INCLUDE_DIR}/jxl/version.h")
|
||||
# the library version older 0.6 is not supported (no version.h file there)
|
||||
set(JPEGXL_FOUND FALSE CACHE BOOL "libjxl found" FORCE)
|
||||
message(STATUS "Ignored incompatible version of libjxl")
|
||||
endif ()
|
||||
|
||||
if (JPEGXL_LIBRARY AND NOT TARGET JPEGXL::jxl)
|
||||
add_library(JPEGXL::jxl UNKNOWN IMPORTED GLOBAL)
|
||||
set_target_properties(JPEGXL::jxl PROPERTIES
|
||||
IMPORTED_LOCATION "${JPEGXL_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${JPEGXL_COMPILE_OPTIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${JPEGXL_INCLUDE_DIR}"
|
||||
)
|
||||
endif ()
|
||||
mark_as_advanced(JPEGXL_INCLUDE_DIR JPEGXL_LIBRARY)
|
||||
if (JPEGXL_FOUND)
|
||||
set(JPEGXL_LIBRARIES ${JPEGXL_LIBRARY})
|
||||
set(JPEGXL_INCLUDE_DIRS ${JPEGXL_INCLUDE_DIR})
|
||||
if (NOT JPEGXL_VERSION)
|
||||
file(READ "${JPEGXL_INCLUDE_DIR}/jxl/version.h" VERSION_HEADER_CONTENTS)
|
||||
string(REGEX MATCH "#define JPEGXL_MAJOR_VERSION ([0-9]+)" _ ${VERSION_HEADER_CONTENTS})
|
||||
set(JXL_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "#define JPEGXL_MINOR_VERSION ([0-9]+)" _ ${VERSION_HEADER_CONTENTS})
|
||||
set(JXL_VERSION_MINOR ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "#define JPEGXL_PATCH_VERSION ([0-9]+)" _ ${VERSION_HEADER_CONTENTS})
|
||||
set(JXL_VERSION_PATCH ${CMAKE_MATCH_1})
|
||||
set(JPEGXL_VERSION "${JXL_VERSION_MAJOR}.${JXL_VERSION_MINOR}.${JXL_VERSION_PATCH}")
|
||||
endif()
|
||||
endif ()
|
||||
endif()
|
||||
@@ -189,19 +189,45 @@ if(WITH_WEBP AND NOT WEBP_FOUND
|
||||
endif()
|
||||
|
||||
if(NOT WEBP_VERSION AND WEBP_INCLUDE_DIR)
|
||||
ocv_clear_vars(ENC_MAJ_VERSION ENC_MIN_VERSION ENC_REV_VERSION)
|
||||
if(EXISTS "${WEBP_INCLUDE_DIR}/enc/vp8enci.h")
|
||||
ocv_parse_header("${WEBP_INCLUDE_DIR}/enc/vp8enci.h" WEBP_VERSION_LINES ENC_MAJ_VERSION ENC_MIN_VERSION ENC_REV_VERSION)
|
||||
set(WEBP_VERSION "${ENC_MAJ_VERSION}.${ENC_MIN_VERSION}.${ENC_REV_VERSION}")
|
||||
elseif(EXISTS "${WEBP_INCLUDE_DIR}/webp/encode.h")
|
||||
if(EXISTS "${WEBP_INCLUDE_DIR}/webp/encode.h")
|
||||
file(STRINGS "${WEBP_INCLUDE_DIR}/webp/encode.h" WEBP_ENCODER_ABI_VERSION REGEX "#define[ \t]+WEBP_ENCODER_ABI_VERSION[ \t]+([x0-9a-f]+)" )
|
||||
if(WEBP_ENCODER_ABI_VERSION MATCHES "#define[ \t]+WEBP_ENCODER_ABI_VERSION[ \t]+([x0-9a-f]+)")
|
||||
set(WEBP_ENCODER_ABI_VERSION "${CMAKE_MATCH_1}")
|
||||
set(WEBP_VERSION "encoder: ${WEBP_ENCODER_ABI_VERSION}")
|
||||
else()
|
||||
unset(WEBP_ENCODER_ABI_VERSION)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(EXISTS "${WEBP_INCLUDE_DIR}/webp/decode.h")
|
||||
file(STRINGS "${WEBP_INCLUDE_DIR}/webp/decode.h" WEBP_DECODER_ABI_VERSION REGEX "#define[ \t]+WEBP_DECODER_ABI_VERSION[ \t]+([x0-9a-f]+)" )
|
||||
if(WEBP_DECODER_ABI_VERSION MATCHES "#define[ \t]+WEBP_DECODER_ABI_VERSION[ \t]+([x0-9a-f]+)")
|
||||
set(WEBP_DECODER_ABI_VERSION "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
unset(WEBP_DECODER_ABI_VERSION)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(EXISTS "${WEBP_INCLUDE_DIR}/webp/demux.h")
|
||||
file(STRINGS "${WEBP_INCLUDE_DIR}/webp/demux.h" WEBP_DEMUX_ABI_VERSION REGEX "#define[ \t]+WEBP_DEMUX_ABI_VERSION[ \t]+([x0-9a-f]+)" )
|
||||
if(WEBP_DEMUX_ABI_VERSION MATCHES "#define[ \t]+WEBP_DEMUX_ABI_VERSION[ \t]+([x0-9a-f]+)")
|
||||
set(WEBP_DEMUX_ABI_VERSION "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
unset(WEBP_DEMUX_ABI_VERSION)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(WEBP_VERSION "decoder: ${WEBP_DECODER_ABI_VERSION}, encoder: ${WEBP_ENCODER_ABI_VERSION}, demux: ${WEBP_DEMUX_ABI_VERSION}")
|
||||
endif()
|
||||
|
||||
# --- libjxl (optional) ---
|
||||
if(WITH_JPEGXL)
|
||||
ocv_clear_vars(HAVE_JPEGXL)
|
||||
ocv_clear_internal_cache_vars(JPEGXL_INCLUDE_PATHS JPEGXL_LIBRARIES JPEGXL_VERSION)
|
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindJPEGXL.cmake")
|
||||
if(JPEGXL_FOUND)
|
||||
set(HAVE_JPEGXL YES)
|
||||
message(STATUS "Found system JPEG-XL: ver ${JPEGXL_VERSION}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- libopenjp2 (optional, check before libjasper) ---
|
||||
@@ -364,6 +390,11 @@ if(WITH_GDCM)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_IMGCODEC_GIF)
|
||||
set(HAVE_IMGCODEC_GIF ON)
|
||||
elseif(DEFINED WITH_IMGCODEC_GIF)
|
||||
set(HAVE_IMGCODEC_GIF OFF)
|
||||
endif()
|
||||
if(WITH_IMGCODEC_HDR)
|
||||
set(HAVE_IMGCODEC_HDR ON)
|
||||
elseif(DEFINED WITH_IMGCODEC_HDR)
|
||||
|
||||
@@ -174,3 +174,27 @@ if(WITH_KLEIDICV)
|
||||
set(HAVE_KLEIDICV OFF)
|
||||
endif()
|
||||
endif(WITH_KLEIDICV)
|
||||
|
||||
# --- FastCV ---
|
||||
if(WITH_FASTCV)
|
||||
if((EXISTS ${FastCV_INCLUDE_PATH}) AND (EXISTS ${FastCV_LIB_PATH}))
|
||||
message(STATUS "Use external FastCV ${FastCV_INCLUDE_PATH}, ${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")
|
||||
ocv_install_3rdparty_licenses(FastCV "${OpenCV_BINARY_DIR}/3rdparty/fastcv/LICENSE")
|
||||
install(FILES "${FastCV_LIB_PATH}/libfastcvopt.so"
|
||||
DESTINATION "${OPENCV_LIB_INSTALL_PATH}" COMPONENT "bin")
|
||||
else()
|
||||
set(HAVE_FASTCV FALSE CACHE BOOL "FastCV status")
|
||||
endif()
|
||||
endif()
|
||||
if(HAVE_FASTCV)
|
||||
set(FASTCV_LIBRARY "${FastCV_LIB_PATH}/libfastcvopt.so" CACHE PATH "FastCV library")
|
||||
endif()
|
||||
endif(WITH_FASTCV)
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
# Look for the header file.
|
||||
|
||||
unset(WEBP_FOUND)
|
||||
|
||||
FIND_PATH(WEBP_INCLUDE_DIR NAMES webp/decode.h)
|
||||
|
||||
if(NOT WEBP_INCLUDE_DIR)
|
||||
@@ -21,13 +19,14 @@ else()
|
||||
|
||||
# Look for the library.
|
||||
FIND_LIBRARY(WEBP_LIBRARY NAMES webp)
|
||||
MARK_AS_ADVANCED(WEBP_LIBRARY)
|
||||
FIND_LIBRARY(WEBP_MUX_LIBRARY NAMES webpmux)
|
||||
FIND_LIBRARY(WEBP_DEMUX_LIBRARY NAMES webpdemux)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set WEBP_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WebP DEFAULT_MSG WEBP_LIBRARY WEBP_INCLUDE_DIR)
|
||||
|
||||
SET(WEBP_LIBRARIES ${WEBP_LIBRARY})
|
||||
SET(WEBP_LIBRARIES ${WEBP_LIBRARY} ${WEBP_MUX_LIBRARY} ${WEBP_DEMUX_LIBRARY})
|
||||
SET(WEBP_INCLUDE_DIRS ${WEBP_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# https://developer.android.com/studio/releases/gradle-plugin
|
||||
set(ANDROID_GRADLE_PLUGIN_VERSION "7.3.1" CACHE STRING "Android Gradle Plugin version")
|
||||
set(ANDROID_GRADLE_PLUGIN_VERSION "8.6.0" CACHE STRING "Android Gradle Plugin version")
|
||||
message(STATUS "Android Gradle Plugin version: ${ANDROID_GRADLE_PLUGIN_VERSION}")
|
||||
|
||||
set(KOTLIN_PLUGIN_VERSION "1.8.20" CACHE STRING "Kotlin Plugin version")
|
||||
@@ -13,16 +13,16 @@ else()
|
||||
set(KOTLIN_STD_LIB "" CACHE STRING "Kotlin Standard Library dependency")
|
||||
endif()
|
||||
|
||||
set(GRADLE_VERSION "7.6.3" CACHE STRING "Gradle version")
|
||||
set(GRADLE_VERSION "8.11.1" CACHE STRING "Gradle version")
|
||||
message(STATUS "Gradle version: ${GRADLE_VERSION}")
|
||||
|
||||
set(ANDROID_COMPILE_SDK_VERSION "31" CACHE STRING "Android compileSdkVersion")
|
||||
set(ANDROID_COMPILE_SDK_VERSION "34" CACHE STRING "Android compileSdkVersion")
|
||||
if(ANDROID_NATIVE_API_LEVEL GREATER 21)
|
||||
set(ANDROID_MIN_SDK_VERSION "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android minSdkVersion")
|
||||
else()
|
||||
set(ANDROID_MIN_SDK_VERSION "21" CACHE STRING "Android minSdkVersion")
|
||||
endif()
|
||||
set(ANDROID_TARGET_SDK_VERSION "31" CACHE STRING "Android minSdkVersion")
|
||||
set(ANDROID_TARGET_SDK_VERSION "34" CACHE STRING "Android targetSdkVersion")
|
||||
|
||||
set(ANDROID_BUILD_BASE_DIR "${OpenCV_BINARY_DIR}/opencv_android" CACHE INTERNAL "")
|
||||
set(ANDROID_TMP_INSTALL_BASE_DIR "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/install/opencv_android")
|
||||
@@ -35,11 +35,11 @@ include '${ANDROID_ABI}'
|
||||
")
|
||||
|
||||
set(ANDROID_INSTALL_ABI_FILTER "
|
||||
//reset()
|
||||
//include 'armeabi-v7a'
|
||||
//include 'arm64-v8a'
|
||||
//include 'x86'
|
||||
//include 'x86_64'
|
||||
reset()
|
||||
include 'armeabi-v7a'
|
||||
include 'arm64-v8a'
|
||||
include 'x86'
|
||||
include 'x86_64'
|
||||
")
|
||||
if(NOT INSTALL_CREATE_DISTRIB)
|
||||
set(ANDROID_INSTALL_ABI_FILTER "${ANDROID_BUILD_ABI_FILTER}")
|
||||
@@ -54,7 +54,9 @@ set(ANDROID_STRICT_BUILD_CONFIGURATION "true")
|
||||
configure_file("${OpenCV_SOURCE_DIR}/samples/android/build.gradle.in" "${ANDROID_BUILD_BASE_DIR}/build.gradle" @ONLY)
|
||||
|
||||
set(ANDROID_ABI_FILTER "${ANDROID_INSTALL_ABI_FILTER}")
|
||||
set(ANDROID_STRICT_BUILD_CONFIGURATION "false")
|
||||
# CI uses NDK 26d to overcome https://github.com/opencv/opencv/issues/26072
|
||||
# It's ahead of default configuration and we have to force version to get non-controversial parts of the package
|
||||
#set(ANDROID_STRICT_BUILD_CONFIGURATION "false")
|
||||
configure_file("${OpenCV_SOURCE_DIR}/samples/android/build.gradle.in" "${ANDROID_TMP_INSTALL_BASE_DIR}/${ANDROID_INSTALL_SAMPLES_DIR}/build.gradle" @ONLY)
|
||||
install(FILES "${ANDROID_TMP_INSTALL_BASE_DIR}/${ANDROID_INSTALL_SAMPLES_DIR}/build.gradle" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}" COMPONENT samples)
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
/* IJG JPEG codec */
|
||||
#cmakedefine HAVE_JPEG
|
||||
|
||||
/* JPEG XL codec */
|
||||
#cmakedefine HAVE_JPEGXL
|
||||
|
||||
/* GDCM DICOM codec */
|
||||
#cmakedefine HAVE_GDCM
|
||||
|
||||
|
||||
+5
-14
@@ -402,20 +402,11 @@
|
||||
publisher = {BMVA Press},
|
||||
url = {https://www.researchgate.net/profile/Robert_Fisher5/publication/2237785_A_Buyer's_Guide_to_Conic_Fitting/links/0fcfd50f59aeded518000000/A-Buyers-Guide-to-Conic-Fitting.pdf}
|
||||
}
|
||||
@article{fitzgibbon1999,
|
||||
abstract = {This work presents a new efficient method for fitting ellipses to scattered data. Previous algorithms either fitted general conics or were computationally expensive. By minimizing the algebraic distance subject to the constraint 4ac-b<sup>2</sup>=1, the new method incorporates the ellipticity constraint into the normalization factor. The proposed method combines several advantages: It is ellipse-specific, so that even bad data will always return an ellipse. It can be solved naturally by a generalized eigensystem. It is extremely robust, efficient, and easy to implement},
|
||||
author = {Fitzgibbon, Andrew and Pilu, Maurizio and Fisher, Robert B.},
|
||||
doi = {10.1109/34.765658},
|
||||
isbn = {0162-8828},
|
||||
issn = {01628828},
|
||||
journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence},
|
||||
number = {5},
|
||||
pages = {476--480},
|
||||
pmid = {708},
|
||||
title = {Direct least square fitting of ellipses},
|
||||
volume = {21},
|
||||
year = {1999},
|
||||
url = {https://pdfs.semanticscholar.org/090d/25f94cb021bdd3400a2f547f989a6a5e07ec.pdf}
|
||||
@inproceedings{oy1998NumericallySD,
|
||||
title = {Numerically Stable Direct Least Squares Fitting of Ellipses},
|
||||
author = {Radim Hal oy and Jan Flusser},
|
||||
year = {1998},
|
||||
url = {https://www.semanticscholar.org/paper/Numerically-Stable-Direct-Least-Squares-Fitting-of-oy-Flusser/9a8607575ba9c6016e9f3db5e52f5ed4d14d5dfd}
|
||||
}
|
||||
@article{Gallego2014ACF,
|
||||
title = {A Compact Formula for the Derivative of a 3-D Rotation in Exponential Coordinates},
|
||||
|
||||
@@ -36,7 +36,8 @@ Now let's create a function, draw which takes the corners in the chessboard (obt
|
||||
**cv.findChessboardCorners()**) and **axis points** to draw a 3D axis.
|
||||
@code{.py}
|
||||
def draw(img, corners, imgpts):
|
||||
corner = tuple(corners[0].ravel())
|
||||
corner = tuple(corners[0].ravel().astype("int32"))
|
||||
imgpts = imgpts.astype("int32")
|
||||
img = cv.line(img, corner, tuple(imgpts[0].ravel()), (255,0,0), 5)
|
||||
img = cv.line(img, corner, tuple(imgpts[1].ravel()), (0,255,0), 5)
|
||||
img = cv.line(img, corner, tuple(imgpts[2].ravel()), (0,0,255), 5)
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
Handling Animated Image Files {#tutorial_animations}
|
||||
===========================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Suleyman Turkmen (with help of ChatGPT) |
|
||||
| Compatibility | OpenCV >= 4.11 |
|
||||
|
||||
Goal
|
||||
----
|
||||
In this tutorial, you will learn how to:
|
||||
|
||||
- Use `cv::imreadanimation` to load frames from animated image files.
|
||||
- Understand the structure and parameters of the `cv::Animation` structure.
|
||||
- Display individual frames from an animation.
|
||||
- Use `cv::imwriteanimation` to write `cv::Animation` to a file.
|
||||
|
||||
Source Code
|
||||
-----------
|
||||
|
||||
@add_toggle_cpp
|
||||
- **Downloadable code**: Click
|
||||
[here](https://github.com/opencv/opencv/tree/4.x/samples/cpp/tutorial_code/imgcodecs/animations.cpp)
|
||||
|
||||
- **Code at a glance:**
|
||||
@include samples/cpp/tutorial_code/imgcodecs/animations.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
- **Downloadable code**: Click
|
||||
[here](https://github.com/opencv/opencv/tree/4.x/samples/python/tutorial_code/imgcodecs/animations.py)
|
||||
|
||||
- **Code at a glance:**
|
||||
@include samples/python/tutorial_code/imgcodecs/animations.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
## Initializing the Animation Structure
|
||||
|
||||
Initialize a `cv::Animation` structure to hold the frames from the animated image file.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/imgcodecs/animations.cpp init_animation
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/imgcodecs/animations.py init_animation
|
||||
@end_toggle
|
||||
|
||||
## Loading Frames
|
||||
|
||||
Use `cv::imreadanimation` to load frames from the specified file. Here, we load all frames from an animated WebP image.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/imgcodecs/animations.cpp read_animation
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/imgcodecs/animations.py read_animation
|
||||
@end_toggle
|
||||
|
||||
## Displaying Frames
|
||||
|
||||
Each frame in the `animation.frames` vector can be displayed as a standalone image. This loop iterates through each frame, displaying it in a window with a short delay to simulate the animation.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/imgcodecs/animations.cpp show_animation
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/imgcodecs/animations.py show_animation
|
||||
@end_toggle
|
||||
|
||||
## Saving Animation
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/imgcodecs/animations.cpp write_animation
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/imgcodecs/animations.py write_animation
|
||||
@end_toggle
|
||||
|
||||
## Summary
|
||||
|
||||
The `cv::imreadanimation` and `cv::imwriteanimation` functions make it easy to work with animated image files by loading frames into a `cv::Animation` structure, allowing frame-by-frame processing.
|
||||
With these functions, you can load, process, and save frames from animated image files like GIF, AVIF, APNG, and WebP.
|
||||
@@ -10,3 +10,4 @@ Application utils (highgui, imgcodecs, videoio modules) {#tutorial_table_of_cont
|
||||
- @subpage tutorial_orbbec_uvc
|
||||
- @subpage tutorial_intelperc
|
||||
- @subpage tutorial_wayland_ubuntu
|
||||
- @subpage tutorial_animations
|
||||
|
||||
@@ -83,7 +83,7 @@ Arranging the terms: \f$r = x \cos \theta + y \sin \theta\f$
|
||||
|
||||
### Standard and Probabilistic Hough Line Transform
|
||||
|
||||
OpenCV implements two kind of Hough Line Transforms:
|
||||
OpenCV implements three kind of Hough Line Transforms:
|
||||
|
||||
a. **The Standard Hough Transform**
|
||||
|
||||
@@ -97,6 +97,12 @@ b. **The Probabilistic Hough Line Transform**
|
||||
of the detected lines \f$(x_{0}, y_{0}, x_{1}, y_{1})\f$
|
||||
- In OpenCV it is implemented with the function **HoughLinesP()**
|
||||
|
||||
c. **The Weighted Hough Transform**
|
||||
|
||||
- Uses edge intensity instead binary 0 or 1 values in standard Hough transform.
|
||||
- In OpenCV it is implemented with the function **HoughLines()** with use_edgeval=true.
|
||||
- See the example in samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp.
|
||||
|
||||
### What does this program do?
|
||||
- Loads an image
|
||||
- Applies a *Standard Hough Line Transform* and a *Probabilistic Line Transform*.
|
||||
|
||||
@@ -217,7 +217,7 @@ Following options can be used to produce special builds with instrumentation or
|
||||
| `ENABLE_BUILD_HARDENING` | GCC, Clang, MSVC | Enable compiler options which reduce possibility of code exploitation. |
|
||||
| `ENABLE_LTO` | GCC, Clang, MSVC | Enable Link Time Optimization (LTO). |
|
||||
| `ENABLE_THIN_LTO` | Clang | Enable thin LTO which incorporates intermediate bitcode to binaries allowing consumers optimize their applications later. |
|
||||
| `OPENCV_ALGO_HINT_DEFAULT` | Any | Set default OpenCV implementation hint value: `ALGO_HINT_ACCURATE` or `ALGO_HINT_APROX`. Dangerous! The option changes behaviour globally and may affect accuracy of many algorithms. |
|
||||
| `OPENCV_ALGO_HINT_DEFAULT` | Any | Set default OpenCV implementation hint value: `ALGO_HINT_ACCURATE` or `ALGO_HINT_APPROX`. Dangerous! The option changes behaviour globally and may affect accuracy of many algorithms. |
|
||||
|
||||
@see [GCC instrumentation](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html)
|
||||
@see [Build hardening](https://en.wikipedia.org/wiki/Hardening_(computing))
|
||||
@@ -310,11 +310,12 @@ Following formats can be read by OpenCV without help of any third-party library:
|
||||
| [JPEG2000 with OpenJPEG](https://en.wikipedia.org/wiki/OpenJPEG) | `WITH_OPENJPEG` | _ON_ | `BUILD_OPENJPEG` |
|
||||
| [JPEG2000 with JasPer](https://en.wikipedia.org/wiki/JasPer) | `WITH_JASPER` | _ON_ (see note) | `BUILD_JASPER` |
|
||||
| [EXR](https://en.wikipedia.org/wiki/OpenEXR) | `WITH_OPENEXR` | _ON_ | `BUILD_OPENEXR` |
|
||||
| [JPEG XL](https://en.wikipedia.org/wiki/JPEG_XL) | `WITH_JPEGXL` | _ON_ | Not supported. (see note) |
|
||||
|
||||
All libraries required to read images in these formats are included into OpenCV and will be built automatically if not found at the configuration stage. Corresponding `BUILD_*` options will force building and using own libraries, they are enabled by default on some platforms, e.g. Windows.
|
||||
|
||||
@note OpenJPEG have higher priority than JasPer which is deprecated. In order to use JasPer, OpenJPEG must be disabled.
|
||||
|
||||
@note (JPEG XL) OpenCV doesn't contain libjxl source code, so `BUILD_JPEGXL` is not supported.
|
||||
|
||||
### GDAL integration
|
||||
|
||||
|
||||
@@ -9,41 +9,49 @@ Installation in MacOS {#tutorial_macos_install}
|
||||
| Original author | `@sajarindider` |
|
||||
| Compatibility | OpenCV >= 3.4 |
|
||||
|
||||
The following steps have been tested for MacOSX (Mavericks) but should work with other versions as well.
|
||||
The following steps have been tested for macOS (Mavericks) but should work with other versions as well.
|
||||
|
||||
Required Packages
|
||||
-----------------
|
||||
|
||||
- CMake 3.9 or higher
|
||||
- Git
|
||||
- Python 2.7 or later and Numpy 1.5 or later
|
||||
- Python 3.x and NumPy 1.5 or later
|
||||
|
||||
This tutorial will assume you have [Python](https://docs.python.org/3/using/mac.html),
|
||||
[Numpy](https://docs.scipy.org/doc/numpy-1.10.1/user/install.html) and
|
||||
[Git](https://www.atlassian.com/git/tutorials/install-git) installed on your machine.
|
||||
[NumPy](https://numpy.org/install/) and
|
||||
[Git](https://git-scm.com/downloads/mac) installed on your machine.
|
||||
|
||||
@note
|
||||
OSX comes with Python 2.7 by default, you will need to install Python 3.8 if you want to use it specifically.
|
||||
- macOS up to 12.2 (Monterey): Comes with Python 2.7 pre-installed.
|
||||
- macOS 12.3 and later: Python 2.7 has been removed, and no version of Python is included by default.
|
||||
|
||||
It is recommended to install the latest version of Python 3.x (at least Python 3.8) for compatibility with the latest OpenCV Python bindings.
|
||||
|
||||
@note
|
||||
If you XCode and XCode Command Line-Tools installed, you already have git installed on your machine.
|
||||
If you have Xcode and Xcode Command Line Tools installed, Git is already available on your machine.
|
||||
|
||||
Installing CMake
|
||||
----------------
|
||||
-# Find the version for your system and download CMake from their release's [page](https://cmake.org/download/)
|
||||
|
||||
-# Install the dmg package and launch it from Applications. That will give you the UI app of CMake
|
||||
-# Install the `.dmg` package and launch it from Applications. That will give you the UI app of CMake
|
||||
|
||||
-# From the CMake app window, choose menu Tools --> How to Install For Command Line Use. Then, follow the instructions from the pop-up there.
|
||||
|
||||
-# Install folder will be /usr/bin/ by default, submit it by choosing Install command line links.
|
||||
-# The install folder will be `/usr/local/bin/` by default. Complete the installation by choosing Install command line links.
|
||||
|
||||
-# Test that CMake is installed correctly by running:
|
||||
|
||||
-# Test that it works by running
|
||||
@code{.bash}
|
||||
cmake --version
|
||||
@endcode
|
||||
|
||||
@note You can use [Homebrew](https://brew.sh/) to install CMake with @code{.bash} brew install cmake @endcode
|
||||
@note You can use [Homebrew](https://brew.sh/) to install CMake with:
|
||||
|
||||
@code{.bash}
|
||||
brew install cmake
|
||||
@endcode
|
||||
|
||||
Getting OpenCV Source Code
|
||||
--------------------------
|
||||
@@ -53,20 +61,22 @@ You can use the latest stable OpenCV version or you can grab the latest snapshot
|
||||
|
||||
### Getting the Latest Stable OpenCV Version
|
||||
|
||||
- Go to our [downloads page](https://opencv.org/releases).
|
||||
- Download the source archive and unpack it.
|
||||
- Go to our [OpenCV releases page](https://opencv.org/releases).
|
||||
- Download the source archive of the latest version (e.g., OpenCV 4.x) and unpack it.
|
||||
|
||||
### Getting the Cutting-edge OpenCV from the Git Repository
|
||||
|
||||
Launch Git client and clone [OpenCV repository](http://github.com/opencv/opencv).
|
||||
If you need modules from [OpenCV contrib repository](http://github.com/opencv/opencv_contrib) then clone it as well.
|
||||
Launch Git client and clone [OpenCV repository](https://github.com/opencv/opencv).
|
||||
If you need modules from [OpenCV contrib repository](https://github.com/opencv/opencv_contrib) then clone it as well.
|
||||
|
||||
For example:
|
||||
|
||||
@code{.bash}
|
||||
cd ~/<your_working_directory>
|
||||
git clone https://github.com/opencv/opencv.git
|
||||
git clone https://github.com/opencv/opencv_contrib.git
|
||||
@endcode
|
||||
|
||||
For example
|
||||
@code{.bash}
|
||||
cd ~/<my_working_directory>
|
||||
git clone https://github.com/opencv/opencv.git
|
||||
git clone https://github.com/opencv/opencv_contrib.git
|
||||
@endcode
|
||||
Building OpenCV from Source Using CMake
|
||||
---------------------------------------
|
||||
|
||||
@@ -74,51 +84,96 @@ Building OpenCV from Source Using CMake
|
||||
the generated Makefiles, project files as well the object files and output binaries and enter
|
||||
there.
|
||||
|
||||
For example
|
||||
For example:
|
||||
|
||||
@code{.bash}
|
||||
mkdir build_opencv
|
||||
cd build_opencv
|
||||
@endcode
|
||||
|
||||
@note It is good practice to keep clean your source code directories. Create build directory outside of source tree.
|
||||
@note It is good practice to keep your source code directories clean. Create the build directory outside of the source tree.
|
||||
|
||||
-# Configuring. Run `cmake [<some optional parameters>] <path to the OpenCV source directory>`
|
||||
|
||||
For example
|
||||
For example:
|
||||
|
||||
@code{.bash}
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON ../opencv
|
||||
@endcode
|
||||
|
||||
or cmake-gui
|
||||
Alternatively, you can use the CMake GUI (`cmake-gui`):
|
||||
|
||||
- set the OpenCV source code path to, e.g. `/home/user/opencv`
|
||||
- set the binary build path to your CMake build directory, e.g. `/home/user/build_opencv`
|
||||
- set the OpenCV source code path to, e.g. `/Users/your_username/opencv`
|
||||
- set the binary build path to your CMake build directory, e.g. `/Users/your_username/build_opencv`
|
||||
- set optional parameters
|
||||
- run: "Configure"
|
||||
- run: "Generate"
|
||||
|
||||
-# Description of some parameters
|
||||
- build type: `CMAKE_BUILD_TYPE=Release` (or `Debug`)
|
||||
- to build with modules from opencv_contrib set `OPENCV_EXTRA_MODULES_PATH` to `<path to
|
||||
opencv_contrib>/modules`
|
||||
- set `BUILD_DOCS=ON` for building documents (doxygen is required)
|
||||
- set `BUILD_EXAMPLES=ON` to build all examples
|
||||
- build type: `-DCMAKE_BUILD_TYPE=Release` (or `Debug`).
|
||||
- include Extra Modules: If you cloned the `opencv_contrib` repository and want to include its modules, set:
|
||||
|
||||
@code{.bash}
|
||||
-DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules
|
||||
@endcode
|
||||
- set `-DBUILD_DOCS=ON` for building documents (doxygen is required)
|
||||
- set `-DBUILD_EXAMPLES=ON` to build all examples
|
||||
|
||||
-# [optional] Building python. Set the following python parameters:
|
||||
- `PYTHON3_EXECUTABLE = <path to python>`
|
||||
- `PYTHON3_INCLUDE_DIR = /usr/include/python<version>`
|
||||
- `PYTHON3_NUMPY_INCLUDE_DIRS =
|
||||
/usr/lib/python<version>/dist-packages/numpy/core/include/`
|
||||
- `-DPYTHON3_EXECUTABLE=$(which python3)`
|
||||
- `-DPYTHON3_INCLUDE_DIR=$(python3 -c "from sysconfig import get_paths as gp; print(gp()['include'])")`
|
||||
- `-DPYTHON3_NUMPY_INCLUDE_DIRS=$(python3 -c "import numpy; print(numpy.get_include())")`
|
||||
|
||||
-# Build. From build directory execute *make*, it is recommended to do this in several threads
|
||||
|
||||
For example
|
||||
For example:
|
||||
|
||||
@code{.bash}
|
||||
make -j7 # runs 7 jobs in parallel
|
||||
make -j$(sysctl -n hw.ncpu) # runs the build using all available CPU cores
|
||||
@endcode
|
||||
|
||||
-# To use OpenCV in your CMake-based projects through `find_package(OpenCV)` specify `OpenCV_DIR=<path_to_build_or_install_directory>` variable.
|
||||
-# After building, you can install OpenCV system-wide using:
|
||||
|
||||
@code{.bash}
|
||||
sudo make install
|
||||
@endcode
|
||||
|
||||
-# To use OpenCV in your CMake-based projects through `find_package(OpenCV)`, specify the `OpenCV_DIR` variable pointing to the build or install directory.
|
||||
|
||||
For example:
|
||||
|
||||
@code{.bash}
|
||||
cmake -DOpenCV_DIR=~/build_opencv ..
|
||||
@endcode
|
||||
|
||||
### Verifying the OpenCV Installation
|
||||
|
||||
After building (and optionally installing) OpenCV, you can verify the installation by checking the version using Python:
|
||||
|
||||
@code{.bash}
|
||||
python3 -c "import cv2; print(cv2.__version__)"
|
||||
@endcode
|
||||
|
||||
This command should output the version of OpenCV you have installed.
|
||||
|
||||
@note
|
||||
You can also use a package manager like [Homebrew](https://brew.sh/)
|
||||
or [pip](https://pip.pypa.io/en/stable/) to install releases of OpenCV only (Not the cutting edge).
|
||||
|
||||
- Installing via Homebrew:
|
||||
|
||||
For example:
|
||||
|
||||
@code{.bash}
|
||||
brew install opencv
|
||||
@endcode
|
||||
|
||||
- Installing via pip:
|
||||
|
||||
For example:
|
||||
|
||||
@code{.bash}
|
||||
pip install opencv-python
|
||||
@endcode
|
||||
|
||||
@note To access the extra modules from `opencv_contrib`, install the `opencv-contrib-python` package using `pip install opencv-contrib-python`.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"undistort",
|
||||
"fisheye_initUndistortRectifyMap",
|
||||
"fisheye_projectPoints"
|
||||
]
|
||||
],
|
||||
"UsacParams": ["UsacParams"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,8 +534,8 @@ void cv::fisheye::initUndistortRectifyMap( InputArray K, InputArray D, InputArra
|
||||
|
||||
if( m1type == CV_16SC2 )
|
||||
{
|
||||
int iu = cv::saturate_cast<int>(u*cv::INTER_TAB_SIZE);
|
||||
int iv = cv::saturate_cast<int>(v*cv::INTER_TAB_SIZE);
|
||||
int iu = cv::saturate_cast<int>(u*static_cast<double>(cv::INTER_TAB_SIZE));
|
||||
int iv = cv::saturate_cast<int>(v*static_cast<double>(cv::INTER_TAB_SIZE));
|
||||
m1[j*2+0] = (short)(iu >> cv::INTER_BITS);
|
||||
m1[j*2+1] = (short)(iv >> cv::INTER_BITS);
|
||||
m2[j] = (ushort)((iv & (cv::INTER_TAB_SIZE-1))*cv::INTER_TAB_SIZE + (iu & (cv::INTER_TAB_SIZE-1)));
|
||||
|
||||
@@ -353,6 +353,11 @@ Mat findHomography( InputArray _points1, InputArray _points2,
|
||||
|
||||
if( result && npoints > 4 && method != RHO)
|
||||
{
|
||||
// save the original points before compressing
|
||||
const int npoints_input = npoints;
|
||||
const Mat src_input = src.clone();
|
||||
const Mat dst_input = dst.clone();
|
||||
|
||||
compressElems( src.ptr<Point2f>(), tempMask.ptr<uchar>(), 1, npoints );
|
||||
npoints = compressElems( dst.ptr<Point2f>(), tempMask.ptr<uchar>(), 1, npoints );
|
||||
if( npoints > 0 )
|
||||
@@ -414,6 +419,16 @@ Mat findHomography( InputArray _points1, InputArray _points2,
|
||||
.setGeodesic(true));
|
||||
solver.optimize();
|
||||
H.convertTo(H, H.type(), scaleFor(H.at<double>(2, 2)));
|
||||
|
||||
// find new inliers
|
||||
const float thr_sqr = static_cast<float>(ransacReprojThreshold * ransacReprojThreshold);
|
||||
cv::Mat errors;
|
||||
cb->computeError(src_input, dst_input, H, errors);
|
||||
uchar* maskptr = tempMask.ptr<uchar>();
|
||||
const float * const errors_ptr = errors.ptr<float>();
|
||||
for (int i = 0; i < npoints_input; i++) {
|
||||
maskptr[i] = static_cast<uchar>(errors_ptr[i] <= thr_sqr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -259,8 +259,8 @@ public:
|
||||
double v = fy*invProj*vecTilt(1) + v0;
|
||||
if( m1type == CV_16SC2 )
|
||||
{
|
||||
int iu = saturate_cast<int>(u*INTER_TAB_SIZE);
|
||||
int iv = saturate_cast<int>(v*INTER_TAB_SIZE);
|
||||
int iu = saturate_cast<int>(u*static_cast<double>(INTER_TAB_SIZE));
|
||||
int iv = saturate_cast<int>(v*static_cast<double>(INTER_TAB_SIZE));
|
||||
m1[j*2] = (short)(iu >> INTER_BITS);
|
||||
m1[j*2+1] = (short)(iv >> INTER_BITS);
|
||||
m2[j] = (ushort)((iv & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (iu & (INTER_TAB_SIZE-1)));
|
||||
|
||||
@@ -1384,11 +1384,11 @@ void CV_StereoCalibrationTest::run( int )
|
||||
rotMats1, transVecs1, rmsErrorPerView1, rmsErrorPerView2,
|
||||
TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 1e-6),
|
||||
CALIB_SAME_FOCAL_LENGTH
|
||||
//+ CV_CALIB_FIX_ASPECT_RATIO
|
||||
//+ CALIB_FIX_ASPECT_RATIO
|
||||
+ CALIB_FIX_PRINCIPAL_POINT
|
||||
+ CALIB_ZERO_TANGENT_DIST
|
||||
+ CALIB_FIX_K3
|
||||
+ CALIB_FIX_K4 + CALIB_FIX_K5 //+ CV_CALIB_FIX_K6
|
||||
+ CALIB_FIX_K4 + CALIB_FIX_K5 //+ CALIB_FIX_K6
|
||||
);
|
||||
|
||||
/* rmsErrorFromStereoCalib /= nframes*npoints; */
|
||||
|
||||
@@ -413,8 +413,9 @@ public:
|
||||
data, which means that no data is copied. This operation is very efficient and can be used to
|
||||
process external data using OpenCV functions. The external data is not automatically deallocated, so
|
||||
you should take care of it.
|
||||
@param step Array of _size.size()-1 steps in case of a multi-dimensional array (the last step is always
|
||||
set to the element size). If not specified, the matrix is assumed to be continuous.
|
||||
@param step Array of _size.size() or _size.size()-1 steps in case of a multi-dimensional array
|
||||
(if specified, the last step must be equal to the element size, otherwise it will be added as such).
|
||||
If not specified, the matrix is assumed to be continuous.
|
||||
*/
|
||||
GpuMatND(SizeArray size, int type, void* data, StepArray step = StepArray());
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_float64x2, double)
|
||||
inline _Tpvec v_setzero_##suffix() { return _Tpvec(vec_splats((_Tp)0)); } \
|
||||
inline _Tpvec v_setall_##suffix(_Tp v) { return _Tpvec(vec_splats((_Tp)v));} \
|
||||
template <> inline _Tpvec v_setzero_() { return v_setzero_##suffix(); } \
|
||||
template <> inline _Tpvec v_setall_(_Tp v) { return v_setall_##suffix(_Tp v); } \
|
||||
template <> inline _Tpvec v_setall_(_Tp v) { return v_setall_##suffix(v); } \
|
||||
template<typename _Tpvec0> inline _Tpvec v_reinterpret_as_##suffix(const _Tpvec0 &a) \
|
||||
{ return _Tpvec((cast)a.val); }
|
||||
|
||||
@@ -650,11 +650,11 @@ OPENCV_HAL_IMPL_VSX_SELECT(v_float64x2, vec_bdword2_c)
|
||||
#define OPENCV_HAL_IMPL_VSX_INT_CMP_OP(_Tpvec) \
|
||||
inline _Tpvec v_eq(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(vec_cmpeq(a.val, b.val)); } \
|
||||
inline _Tpvec V_ne(const _Tpvec& a, const _Tpvec& b) \
|
||||
inline _Tpvec v_ne(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(vec_cmpne(a.val, b.val)); } \
|
||||
inline _Tpvec v_lt(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(vec_cmplt(a.val, b.val)); } \
|
||||
inline _Tpvec V_gt(const _Tpvec& a, const _Tpvec& b) \
|
||||
inline _Tpvec v_gt(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(vec_cmpgt(a.val, b.val)); } \
|
||||
inline _Tpvec v_le(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(vec_cmple(a.val, b.val)); } \
|
||||
@@ -1507,7 +1507,7 @@ inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b, cons
|
||||
inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b)
|
||||
{ return v_dotprod(a, b); }
|
||||
inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c)
|
||||
{ return v_int32x4(vec_msum(a.val, b.val, vec_int4_z)) + c; }
|
||||
{ return v_add(v_int32x4(vec_msum(a.val, b.val, vec_int4_z)), c); }
|
||||
// 32 >> 64
|
||||
inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b)
|
||||
{ return v_dotprod(a, b); }
|
||||
@@ -1518,7 +1518,7 @@ inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_
|
||||
inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b)
|
||||
{ return v_dotprod_expand(a, b); }
|
||||
inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c)
|
||||
{ return v_uint32x4(vec_msum(a.val, b.val, vec_uint4_z)) + c; }
|
||||
{ return v_add(v_uint32x4(vec_msum(a.val, b.val, vec_uint4_z)), c); }
|
||||
|
||||
inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b)
|
||||
{
|
||||
|
||||
@@ -538,7 +538,7 @@ CV__DEBUG_NS_END
|
||||
|
||||
template<typename _Tp> inline
|
||||
Mat::Mat(const std::vector<_Tp>& vec, bool copyData)
|
||||
: flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1),
|
||||
: flags(+MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1),
|
||||
cols((int)vec.size()), data(0), datastart(0), dataend(0), datalimit(0),
|
||||
allocator(0), u(0), size(&cols)
|
||||
{
|
||||
@@ -583,7 +583,7 @@ Mat::Mat(const std::initializer_list<int> sizes, const std::initializer_list<_Tp
|
||||
|
||||
template<typename _Tp, std::size_t _Nm> inline
|
||||
Mat::Mat(const std::array<_Tp, _Nm>& arr, bool copyData)
|
||||
: flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1),
|
||||
: flags(+MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1),
|
||||
cols((int)arr.size()), data(0), datastart(0), dataend(0), datalimit(0),
|
||||
allocator(0), u(0), size(&cols), step(0)
|
||||
{
|
||||
@@ -604,7 +604,7 @@ Mat::Mat(const std::array<_Tp, _Nm>& arr, bool copyData)
|
||||
|
||||
template<typename _Tp, int n> inline
|
||||
Mat::Mat(const Vec<_Tp, n>& vec, bool copyData)
|
||||
: flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1), cols(n), data(0),
|
||||
: flags(+MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1), cols(n), data(0),
|
||||
datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&cols), step(0)
|
||||
{
|
||||
if( !copyData )
|
||||
@@ -639,7 +639,7 @@ Mat::Mat(const Matx<_Tp,m,n>& M, bool copyData)
|
||||
|
||||
template<typename _Tp> inline
|
||||
Mat::Mat(const Point_<_Tp>& pt, bool copyData)
|
||||
: flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1), cols(2), data(0),
|
||||
: flags(+MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1), cols(2), data(0),
|
||||
datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&cols), step(0)
|
||||
{
|
||||
if( !copyData )
|
||||
@@ -661,8 +661,8 @@ Mat::Mat(const Point_<_Tp>& pt, bool copyData)
|
||||
|
||||
template<typename _Tp> inline
|
||||
Mat::Mat(const Point3_<_Tp>& pt, bool copyData)
|
||||
: flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(1), rows(1), cols(3), data(0),
|
||||
datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&cols), step(0)
|
||||
: flags(+MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(2), rows(3), cols(1), data(0),
|
||||
datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0)
|
||||
{
|
||||
if( !copyData )
|
||||
{
|
||||
@@ -683,7 +683,7 @@ Mat::Mat(const Point3_<_Tp>& pt, bool copyData)
|
||||
|
||||
template<typename _Tp> inline
|
||||
Mat::Mat(const MatCommaInitializer_<_Tp>& commaInitializer)
|
||||
: flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(0), rows(0), cols(0), data(0),
|
||||
: flags(+MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(0), rows(0), cols(0), data(0),
|
||||
datastart(0), dataend(0), allocator(0), u(0), size(&rows)
|
||||
{
|
||||
*this = commaInitializer.operator Mat_<_Tp>();
|
||||
@@ -2250,7 +2250,7 @@ SparseMatConstIterator_<_Tp> SparseMat::end() const
|
||||
template<typename _Tp> inline
|
||||
SparseMat_<_Tp>::SparseMat_()
|
||||
{
|
||||
flags = MAGIC_VAL + traits::Type<_Tp>::value;
|
||||
flags = +MAGIC_VAL + traits::Type<_Tp>::value;
|
||||
}
|
||||
|
||||
template<typename _Tp> inline
|
||||
|
||||
@@ -9,7 +9,12 @@
|
||||
#include <opencv2/core/utils/filesystem.hpp>
|
||||
#include <opencv2/core/utils/filesystem.private.hpp>
|
||||
|
||||
namespace cv { namespace utils {
|
||||
namespace cv {
|
||||
static inline std::ostream& operator<<(std::ostream& os, const Rect& rect)
|
||||
{
|
||||
return os << "[x=" << rect.x << ", y=" << rect.y << ", w=" << rect.width << ", h=" << rect.height << ']';
|
||||
}
|
||||
namespace utils {
|
||||
|
||||
String dumpInputArray(InputArray argument)
|
||||
{
|
||||
@@ -51,9 +56,13 @@ String dumpInputArray(InputArray argument)
|
||||
ss << " type(-1)=" << cv::typeToString(argument.type(-1));
|
||||
} while (0);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
ss << " ERROR: exception occurred: " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ss << " ERROR: exception occurred, dump is non-complete"; // need to properly support different kinds
|
||||
ss << " ERROR: unknown exception occurred, dump is non-complete";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
@@ -104,9 +113,13 @@ CV_EXPORTS_W String dumpInputArrayOfArrays(InputArrayOfArrays argument)
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
ss << " ERROR: exception occurred: " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ss << " ERROR: exception occurred, dump is non-complete"; // need to properly support different kinds
|
||||
ss << " ERROR: unknown exception occurred, dump is non-complete";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
@@ -151,9 +164,13 @@ CV_EXPORTS_W String dumpInputOutputArray(InputOutputArray argument)
|
||||
ss << " type(-1)=" << cv::typeToString(argument.type(-1));
|
||||
} while (0);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
ss << " ERROR: exception occurred: " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ss << " ERROR: exception occurred, dump is non-complete"; // need to properly support different kinds
|
||||
ss << " ERROR: unknown exception occurred, dump is non-complete";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
@@ -204,28 +221,28 @@ CV_EXPORTS_W String dumpInputOutputArrayOfArrays(InputOutputArrayOfArrays argume
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
ss << " ERROR: exception occurred: " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ss << " ERROR: exception occurred, dump is non-complete"; // need to properly support different kinds
|
||||
ss << " ERROR: unknown exception occurred, dump is non-complete";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& os, const cv::Rect& rect)
|
||||
{
|
||||
return os << "[x=" << rect.x << ", y=" << rect.y << ", w=" << rect.width << ", h=" << rect.height << ']';
|
||||
}
|
||||
|
||||
template <class T, class Formatter>
|
||||
static inline String dumpVector(const std::vector<T>& vec, Formatter format)
|
||||
{
|
||||
std::ostringstream oss("[", std::ios::ate);
|
||||
if (!vec.empty())
|
||||
{
|
||||
oss << format << vec[0];
|
||||
format(oss) << vec[0];
|
||||
for (std::size_t i = 1; i < vec.size(); ++i)
|
||||
{
|
||||
oss << ", " << format << vec[i];
|
||||
oss << ", ";
|
||||
format(oss) << vec[i];
|
||||
}
|
||||
}
|
||||
oss << "]";
|
||||
|
||||
@@ -12,7 +12,8 @@ GpuMatND::~GpuMatND() = default;
|
||||
GpuMatND::GpuMatND(SizeArray _size, int _type, void* _data, StepArray _step) :
|
||||
flags(0), dims(0), data(static_cast<uchar*>(_data)), offset(0)
|
||||
{
|
||||
CV_Assert(_step.empty() || _size.size() == _step.size() + 1);
|
||||
CV_Assert(_step.empty() || _size.size() == _step.size() + 1 ||
|
||||
(_size.size() == _step.size() && _step.back() == (size_t)CV_ELEM_SIZE(_type)));
|
||||
|
||||
setFields(std::move(_size), _type, std::move(_step));
|
||||
}
|
||||
@@ -118,7 +119,8 @@ void GpuMatND::setFields(SizeArray _size, int _type, StepArray _step)
|
||||
else
|
||||
{
|
||||
step = std::move(_step);
|
||||
step.push_back(elemSize());
|
||||
if (step.size() < size.size())
|
||||
step.push_back(elemSize());
|
||||
|
||||
flags = cv::updateContinuityFlag(flags, dims, size.data(), step.data());
|
||||
}
|
||||
|
||||
@@ -2536,8 +2536,7 @@ double dotProd_16s(const short* src1, const short* src2, int len)
|
||||
|
||||
double dotProd_32s(const int* src1, const int* src2, int len)
|
||||
{
|
||||
#if CV_SIMD_64F // TODO: enable for CV_SIMD_SCALABLE_64F
|
||||
// Test failed on RVV(QEMU): Too big difference (=1.20209e-08 > 1.11022e-12)
|
||||
#if CV_SIMD_64F || CV_SIMD_SCALABLE_64F
|
||||
double r = .0;
|
||||
int i = 0;
|
||||
const int step = VTraits<v_int32>::vlanes();
|
||||
|
||||
@@ -170,7 +170,14 @@ void SparseMat::Hdr::clear()
|
||||
hashtab.clear();
|
||||
hashtab.resize(HASH_SIZE0);
|
||||
pool.clear();
|
||||
#if defined(__GNUC__) && (__GNUC__ == 13) && !defined(__clang__) && (__cplusplus >= 202002L)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
#endif
|
||||
pool.resize(nodeSize);
|
||||
#if defined(__GNUC__) && (__GNUC__ == 13) && !defined(__clang__) && (__cplusplus >= 202002L)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
nodeCount = freeList = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,12 +48,16 @@ int normHamming(const uchar* a, int n)
|
||||
# if defined CV_POPCNT_U64
|
||||
for(; i <= n - 8; i += 8)
|
||||
{
|
||||
result += (int)CV_POPCNT_U64(*(uint64*)(a + i));
|
||||
uint64_t val;
|
||||
std::memcpy(&val, a + i, sizeof(val));
|
||||
result += (int)CV_POPCNT_U64(val);
|
||||
}
|
||||
# endif
|
||||
for(; i <= n - 4; i += 4)
|
||||
{
|
||||
result += CV_POPCNT_U32(*(uint*)(a + i));
|
||||
uint32_t val;
|
||||
std::memcpy(&val, a + i, sizeof(val));
|
||||
result += CV_POPCNT_U32(val);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -92,12 +96,18 @@ int normHamming(const uchar* a, const uchar* b, int n)
|
||||
# if defined CV_POPCNT_U64
|
||||
for(; i <= n - 8; i += 8)
|
||||
{
|
||||
result += (int)CV_POPCNT_U64(*(uint64*)(a + i) ^ *(uint64*)(b + i));
|
||||
uint64_t val_a, val_b;
|
||||
std::memcpy(&val_a, a + i, sizeof(val_a));
|
||||
std::memcpy(&val_b, b + i, sizeof(val_b));
|
||||
result += (int)CV_POPCNT_U64(val_a ^ val_b);
|
||||
}
|
||||
# endif
|
||||
for(; i <= n - 4; i += 4)
|
||||
{
|
||||
result += CV_POPCNT_U32(*(uint*)(a + i) ^ *(uint*)(b + i));
|
||||
uint32_t val_a, val_b;
|
||||
std::memcpy(&val_a, a + i, sizeof(val_a));
|
||||
std::memcpy(&val_b, b + i, sizeof(val_b));
|
||||
result += (int)CV_POPCNT_U32(val_a ^ val_b);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1655,18 +1655,22 @@ TEST(Core_Mat_array, copyTo_roi_row)
|
||||
EXPECT_EQ(5, (int)dst2[4]);
|
||||
}
|
||||
|
||||
TEST(Core_Mat_array, SplitMerge)
|
||||
typedef testing::TestWithParam< tuple<int, perf::MatType> > Core_Mat_arrays;
|
||||
|
||||
TEST_P(Core_Mat_arrays, SplitMerge)
|
||||
{
|
||||
std::array<cv::Mat, 3> src;
|
||||
int cn = get<0>(GetParam());
|
||||
int type = get<1>(GetParam());
|
||||
std::vector<cv::Mat> src(cn);
|
||||
for (size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
src[i] = Mat(10, 10, CV_8U, Scalar((double)(16 * (i + 1))));
|
||||
src[i] = Mat(10, 10, type, Scalar((double)(16 * (i + 1))));
|
||||
}
|
||||
|
||||
Mat merged;
|
||||
merge(src, merged);
|
||||
|
||||
std::array<cv::Mat, 3> dst;
|
||||
std::vector<cv::Mat> dst(cn);
|
||||
split(merged, dst);
|
||||
|
||||
for (size_t i = 0; i < dst.size(); ++i)
|
||||
@@ -1675,6 +1679,17 @@ TEST(Core_Mat_array, SplitMerge)
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Core_Mat_arrays, testing::Combine(
|
||||
testing::Range(1, 9),
|
||||
testing::Values(
|
||||
perf::MatType(CV_8U),
|
||||
perf::MatType(CV_16U),
|
||||
perf::MatType(CV_32S),
|
||||
perf::MatType(CV_64F)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
TEST(Mat, regression_8680)
|
||||
{
|
||||
Mat_<Point2i> mat(3,1);
|
||||
|
||||
@@ -478,8 +478,9 @@ class Core_DotProductTest : public Core_MatrixTest
|
||||
public:
|
||||
Core_DotProductTest();
|
||||
protected:
|
||||
void run_func();
|
||||
void prepare_to_validation( int test_case_idx );
|
||||
void run_func() CV_OVERRIDE;
|
||||
void prepare_to_validation( int test_case_idx ) CV_OVERRIDE;
|
||||
double get_success_error_level( int test_case_idx, int i, int j ) CV_OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
@@ -499,6 +500,15 @@ void Core_DotProductTest::prepare_to_validation( int )
|
||||
test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = Scalar(cvtest::crossCorr( test_mat[INPUT][0], test_mat[INPUT][1] ));
|
||||
}
|
||||
|
||||
double Core_DotProductTest::get_success_error_level( int test_case_idx, int i, int j )
|
||||
{
|
||||
#ifdef __riscv
|
||||
const int depth = test_mat[i][j].depth();
|
||||
if (depth == CV_64F)
|
||||
return 1.7e-5;
|
||||
#endif
|
||||
return Core_MatrixTest::get_success_error_level( test_case_idx, i, j );
|
||||
}
|
||||
|
||||
///////// crossproduct //////////
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2017, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
|
||||
#include "perf_precomp.hpp"
|
||||
|
||||
namespace opencv_test {
|
||||
|
||||
using Utils_blobFromImage = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage, HWC_TO_NCHW) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_32FC3);
|
||||
randu(input, -10.0f, 10.f);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage,
|
||||
Values(std::vector<int>{ 32, 32},
|
||||
std::vector<int>{ 64, 64},
|
||||
std::vector<int>{ 128, 128},
|
||||
std::vector<int>{ 256, 256},
|
||||
std::vector<int>{ 512, 512},
|
||||
std::vector<int>{1024, 1024},
|
||||
std::vector<int>{2048, 2048})
|
||||
);
|
||||
|
||||
using Utils_blobFromImages = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImages, HWC_TO_NCHW) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
int batch = input_shape.front();
|
||||
std::vector<int> input_shape_no_batch(input_shape.begin()+1, input_shape.end());
|
||||
|
||||
std::vector<Mat> inputs;
|
||||
for (int i = 0; i < batch; i++) {
|
||||
Mat input(input_shape_no_batch, CV_32FC3);
|
||||
randu(input, -10.0f, 10.f);
|
||||
inputs.push_back(input);
|
||||
}
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blobs = blobFromImages(inputs);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImages,
|
||||
Values(std::vector<int>{16, 32, 32},
|
||||
std::vector<int>{16, 64, 64},
|
||||
std::vector<int>{16, 128, 128},
|
||||
std::vector<int>{16, 256, 256},
|
||||
std::vector<int>{16, 512, 512},
|
||||
std::vector<int>{16, 1024, 1024},
|
||||
std::vector<int>{16, 2048, 2048})
|
||||
);
|
||||
|
||||
}
|
||||
@@ -129,8 +129,8 @@ public:
|
||||
const google::protobuf::UnknownField& field = unknownFields.field(i);
|
||||
CV_Assert(field.type() == google::protobuf::UnknownField::TYPE_GROUP);
|
||||
CV_CheckGE(field.group().field_count(), 2, "UnknownField should have at least 2 items: name and value");
|
||||
std::string fieldName = field.group().field(0).length_delimited();
|
||||
std::string fieldValue = field.group().field(1).length_delimited();
|
||||
std::string fieldName(field.group().field(0).length_delimited());
|
||||
std::string fieldValue(field.group().field(1).length_delimited());
|
||||
params.set(fieldName, fieldValue);
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public:
|
||||
const Reflection *refl = msg.GetReflection();
|
||||
int type = field->cpp_type();
|
||||
bool isRepeated = field->is_repeated();
|
||||
const std::string &name = field->name();
|
||||
const std::string name(field->name());
|
||||
|
||||
#define SET_UP_FILED(getter, arrayConstr, gtype) \
|
||||
if (isRepeated) { \
|
||||
@@ -192,7 +192,7 @@ public:
|
||||
params.set(name, DictValue::arrayString(buf.begin(), size));
|
||||
}
|
||||
else {
|
||||
params.set(name, refl->GetEnum(msg, field)->name());
|
||||
params.set(name, std::string(refl->GetEnum(msg, field)->name()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -215,7 +215,7 @@ public:
|
||||
{
|
||||
const FieldDescriptor *fd = msgDesc->field(fieldId);
|
||||
|
||||
if (!isInternal && !ends_with_param(fd->name()))
|
||||
if (!isInternal && !ends_with_param(std::string(fd->name())))
|
||||
continue;
|
||||
|
||||
const google::protobuf::UnknownFieldSet& unknownFields = msgRefl->GetUnknownFields(msg);
|
||||
|
||||
+152
-22
@@ -126,6 +126,111 @@ Mat blobFromImagesWithParams(InputArrayOfArrays images, const Image2BlobParams&
|
||||
return blob;
|
||||
}
|
||||
|
||||
template<typename Tinp, typename Tout>
|
||||
void blobFromImagesNCHWImpl(const std::vector<Mat>& images, Mat& blob_, const Image2BlobParams& param)
|
||||
{
|
||||
int w = images[0].cols;
|
||||
int h = images[0].rows;
|
||||
int wh = w * h;
|
||||
int nch = images[0].channels();
|
||||
CV_Assert(nch == 1 || nch == 3 || nch == 4);
|
||||
int sz[] = { (int)images.size(), nch, h, w};
|
||||
blob_.create(4, sz, param.ddepth);
|
||||
|
||||
for (size_t k = 0; k < images.size(); ++k)
|
||||
{
|
||||
CV_Assert(images[k].depth() == images[0].depth());
|
||||
CV_Assert(images[k].channels() == images[0].channels());
|
||||
CV_Assert(images[k].size() == images[0].size());
|
||||
|
||||
Tout* p_blob = blob_.ptr<Tout>() + k * nch * wh;
|
||||
Tout* p_blob_r = p_blob;
|
||||
Tout* p_blob_g = p_blob + wh;
|
||||
Tout* p_blob_b = p_blob + 2 * wh;
|
||||
Tout* p_blob_a = p_blob + 3 * wh;
|
||||
|
||||
if (param.swapRB)
|
||||
std::swap(p_blob_r, p_blob_b);
|
||||
|
||||
for (size_t i = 0; i < h; ++i)
|
||||
{
|
||||
const Tinp* p_img_row = images[k].ptr<Tinp>(i);
|
||||
|
||||
if (nch == 1)
|
||||
{
|
||||
for (size_t j = 0; j < w; ++j)
|
||||
{
|
||||
p_blob[i * w + j] = p_img_row[j];
|
||||
}
|
||||
}
|
||||
else if (nch == 3)
|
||||
{
|
||||
for (size_t j = 0; j < w; ++j)
|
||||
{
|
||||
p_blob_r[i * w + j] = p_img_row[j * 3 ];
|
||||
p_blob_g[i * w + j] = p_img_row[j * 3 + 1];
|
||||
p_blob_b[i * w + j] = p_img_row[j * 3 + 2];
|
||||
}
|
||||
}
|
||||
else // if (nch == 4)
|
||||
{
|
||||
for (size_t j = 0; j < w; ++j)
|
||||
{
|
||||
p_blob_r[i * w + j] = p_img_row[j * 4 ];
|
||||
p_blob_g[i * w + j] = p_img_row[j * 4 + 1];
|
||||
p_blob_b[i * w + j] = p_img_row[j * 4 + 2];
|
||||
p_blob_a[i * w + j] = p_img_row[j * 4 + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (param.mean == Scalar() && param.scalefactor == Scalar::all(1.0))
|
||||
return;
|
||||
CV_CheckTypeEQ(param.ddepth, CV_32F, "Scaling and mean substraction is supported only for CV_32F blob depth");
|
||||
|
||||
for (size_t k = 0; k < images.size(); ++k)
|
||||
{
|
||||
for (size_t ch = 0; ch < nch; ++ch)
|
||||
{
|
||||
float cur_mean = param.mean[ch];
|
||||
float cur_scale = param.scalefactor[ch];
|
||||
Tout* p_blob = blob_.ptr<Tout>() + k * nch * wh + ch * wh;
|
||||
for (size_t i = 0; i < wh; ++i)
|
||||
{
|
||||
p_blob[i] = (p_blob[i] - cur_mean) * cur_scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Tout>
|
||||
void blobFromImagesNCHW(const std::vector<Mat>& images, Mat& blob_, const Image2BlobParams& param)
|
||||
{
|
||||
if (images[0].depth() == CV_8U)
|
||||
blobFromImagesNCHWImpl<uint8_t, Tout>(images, blob_, param);
|
||||
else if (images[0].depth() == CV_8S)
|
||||
blobFromImagesNCHWImpl<int8_t, Tout>(images, blob_, param);
|
||||
else if (images[0].depth() == CV_16U)
|
||||
blobFromImagesNCHWImpl<uint16_t, Tout>(images, blob_, param);
|
||||
else if (images[0].depth() == CV_16S)
|
||||
blobFromImagesNCHWImpl<int16_t, Tout>(images, blob_, param);
|
||||
else if (images[0].depth() == CV_32S)
|
||||
blobFromImagesNCHWImpl<int32_t, Tout>(images, blob_, param);
|
||||
else if (images[0].depth() == CV_32F)
|
||||
blobFromImagesNCHWImpl<float, Tout>(images, blob_, param);
|
||||
else if (images[0].depth() == CV_64F)
|
||||
blobFromImagesNCHWImpl<double, Tout>(images, blob_, param);
|
||||
else
|
||||
CV_Error(Error::BadDepth, "Unsupported input image depth for blobFromImagesNCHW");
|
||||
}
|
||||
|
||||
template<typename Tout>
|
||||
void blobFromImagesNCHW(const std::vector<UMat>& images, UMat& blob_, const Image2BlobParams& param)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "");
|
||||
}
|
||||
|
||||
template<class Tmat>
|
||||
void blobFromImagesWithParamsImpl(InputArrayOfArrays images_, Tmat& blob_, const Image2BlobParams& param)
|
||||
{
|
||||
@@ -154,19 +259,6 @@ void blobFromImagesWithParamsImpl(InputArrayOfArrays images_, Tmat& blob_, const
|
||||
Scalar scalefactor = param.scalefactor;
|
||||
Scalar mean = param.mean;
|
||||
|
||||
if (param.swapRB)
|
||||
{
|
||||
if (nch > 2)
|
||||
{
|
||||
std::swap(mean[0], mean[2]);
|
||||
std::swap(scalefactor[0], scalefactor[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "Red/blue color swapping requires at least three image channels.");
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < images.size(); i++)
|
||||
{
|
||||
Size imgSize = images[i].size();
|
||||
@@ -203,18 +295,35 @@ void blobFromImagesWithParamsImpl(InputArrayOfArrays images_, Tmat& blob_, const
|
||||
resize(images[i], images[i], size, 0, 0, INTER_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
if (images[i].depth() == CV_8U && param.ddepth == CV_32F)
|
||||
images[i].convertTo(images[i], CV_32F);
|
||||
|
||||
subtract(images[i], mean, images[i]);
|
||||
multiply(images[i], scalefactor, images[i]);
|
||||
}
|
||||
|
||||
size_t nimages = images.size();
|
||||
Tmat image0 = images[0];
|
||||
CV_Assert(image0.dims == 2);
|
||||
|
||||
if (std::is_same<Tmat, Mat>::value && param.datalayout == DNN_LAYOUT_NCHW)
|
||||
{
|
||||
// Fast implementation for HWC cv::Mat images -> NCHW cv::Mat blob
|
||||
if (param.ddepth == CV_8U)
|
||||
blobFromImagesNCHW<uint8_t>(images, blob_, param);
|
||||
else
|
||||
blobFromImagesNCHW<float>(images, blob_, param);
|
||||
return;
|
||||
}
|
||||
|
||||
if (param.swapRB)
|
||||
{
|
||||
if (nch > 2)
|
||||
{
|
||||
std::swap(mean[0], mean[2]);
|
||||
std::swap(scalefactor[0], scalefactor[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "Red/blue color swapping requires at least three image channels.");
|
||||
}
|
||||
}
|
||||
|
||||
if (param.datalayout == DNN_LAYOUT_NCHW)
|
||||
{
|
||||
if (nch == 3 || nch == 4)
|
||||
@@ -225,7 +334,14 @@ void blobFromImagesWithParamsImpl(InputArrayOfArrays images_, Tmat& blob_, const
|
||||
|
||||
for (size_t i = 0; i < nimages; i++)
|
||||
{
|
||||
const Tmat& image = images[i];
|
||||
Tmat& image = images[i];
|
||||
if (image.depth() == CV_8U && param.ddepth == CV_32F)
|
||||
image.convertTo(image, CV_32F);
|
||||
if (mean != Scalar())
|
||||
subtract(image, mean, image);
|
||||
if (scalefactor != Scalar::all(1.0))
|
||||
multiply(image, scalefactor, image);
|
||||
|
||||
CV_Assert(image.depth() == blob_.depth());
|
||||
nch = image.channels();
|
||||
CV_Assert(image.dims == 2 && (nch == 3 || nch == 4));
|
||||
@@ -250,7 +366,14 @@ void blobFromImagesWithParamsImpl(InputArrayOfArrays images_, Tmat& blob_, const
|
||||
|
||||
for (size_t i = 0; i < nimages; i++)
|
||||
{
|
||||
const Tmat& image = images[i];
|
||||
Tmat& image = images[i];
|
||||
if (image.depth() == CV_8U && param.ddepth == CV_32F)
|
||||
image.convertTo(image, CV_32F);
|
||||
if (mean != Scalar())
|
||||
subtract(image, mean, image);
|
||||
if (scalefactor != Scalar::all(1.0))
|
||||
multiply(image, scalefactor, image);
|
||||
|
||||
CV_Assert(image.depth() == blob_.depth());
|
||||
nch = image.channels();
|
||||
CV_Assert(image.dims == 2 && (nch == 1));
|
||||
@@ -269,7 +392,14 @@ void blobFromImagesWithParamsImpl(InputArrayOfArrays images_, Tmat& blob_, const
|
||||
int subMatType = CV_MAKETYPE(param.ddepth, nch);
|
||||
for (size_t i = 0; i < nimages; i++)
|
||||
{
|
||||
const Tmat& image = images[i];
|
||||
Tmat& image = images[i];
|
||||
if (image.depth() == CV_8U && param.ddepth == CV_32F)
|
||||
image.convertTo(image, CV_32F);
|
||||
if (mean != Scalar())
|
||||
subtract(image, mean, image);
|
||||
if (scalefactor != Scalar::all(1.0))
|
||||
multiply(image, scalefactor, image);
|
||||
|
||||
CV_Assert(image.depth() == blob_.depth());
|
||||
CV_Assert(image.channels() == image0.channels());
|
||||
CV_Assert(image.size() == image0.size());
|
||||
|
||||
@@ -809,6 +809,15 @@ struct GeluFunctor : public BaseFunctor {
|
||||
}
|
||||
#endif // HAVE_DNN_NGRAPH
|
||||
|
||||
#ifdef HAVE_CANN
|
||||
Ptr<BackendNode> initCannOp(const std::string& name,
|
||||
const std::vector<Ptr<BackendWrapper> > &inputs,
|
||||
const std::vector<Ptr<BackendNode> >& nodes)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "");
|
||||
}
|
||||
#endif // HAVE_CANN
|
||||
|
||||
int64 getFLOPSPerElement() const { return 100; }
|
||||
};
|
||||
|
||||
|
||||
@@ -108,3 +108,18 @@ void Net::Impl::initCUDABackend(const std::vector<LayerPin>& blobsToKeep_)
|
||||
CV__DNN_INLINE_NS_END
|
||||
}} // namespace cv::dnn
|
||||
#endif // HAVE_CUDA
|
||||
|
||||
namespace cv { namespace dnn {
|
||||
|
||||
bool haveCUDA()
|
||||
{
|
||||
#ifdef HAVE_CUDA
|
||||
int dev = 0;
|
||||
static bool ret = (cudaGetDevice(&dev) == cudaSuccess);
|
||||
return ret;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}} // namespace cv::dnn
|
||||
|
||||
@@ -29,13 +29,7 @@ namespace cv { namespace dnn {
|
||||
return id == DNN_TARGET_CUDA_FP16 || id == DNN_TARGET_CUDA;
|
||||
}
|
||||
|
||||
constexpr bool haveCUDA() {
|
||||
#ifdef HAVE_CUDA
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
bool haveCUDA();
|
||||
|
||||
#ifdef HAVE_CUDA
|
||||
namespace cuda4dnn { namespace csl {
|
||||
|
||||
@@ -103,25 +103,6 @@ static const std::map<std::string, OpenVINOModelTestCaseInfo>& getOpenVINOTestMo
|
||||
"intel/age-gender-recognition-retail-0013/FP16/age-gender-recognition-retail-0013",
|
||||
"intel/age-gender-recognition-retail-0013/FP32/age-gender-recognition-retail-0013"
|
||||
}},
|
||||
#endif
|
||||
#if INF_ENGINE_RELEASE >= 2021020000
|
||||
// OMZ: 2020.2
|
||||
{ "face-detection-0105", {
|
||||
"intel/face-detection-0105/FP32/face-detection-0105",
|
||||
"intel/face-detection-0105/FP16/face-detection-0105"
|
||||
}},
|
||||
{ "face-detection-0106", {
|
||||
"intel/face-detection-0106/FP32/face-detection-0106",
|
||||
"intel/face-detection-0106/FP16/face-detection-0106"
|
||||
}},
|
||||
#endif
|
||||
#if INF_ENGINE_RELEASE >= 2021040000
|
||||
// OMZ: 2021.4
|
||||
{ "person-vehicle-bike-detection-2004", {
|
||||
"intel/person-vehicle-bike-detection-2004/FP32/person-vehicle-bike-detection-2004",
|
||||
"intel/person-vehicle-bike-detection-2004/FP16/person-vehicle-bike-detection-2004"
|
||||
//"intel/person-vehicle-bike-detection-2004/FP16-INT8/person-vehicle-bike-detection-2004"
|
||||
}},
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -228,7 +209,12 @@ void runIE(Target target, const std::string& xmlPath, const std::string& binPath
|
||||
for (auto&& it : model->inputs())
|
||||
{
|
||||
auto type = it.get_element_type();
|
||||
auto shape = it.get_shape();
|
||||
auto shape_ = it.get_partial_shape();
|
||||
if (shape_.is_dynamic())
|
||||
{
|
||||
FAIL() << "Model should not have dynamic shapes (" << it.get_any_name() << " => " << shape_ << ")";
|
||||
}
|
||||
auto shape = shape_.to_shape();
|
||||
auto& m = inputsMap[it.get_any_name()];
|
||||
|
||||
auto tensor = ov::Tensor(type, shape);
|
||||
@@ -265,10 +251,10 @@ void runIE(Target target, const std::string& xmlPath, const std::string& binPath
|
||||
for (const auto& it : model->outputs())
|
||||
{
|
||||
auto type = it.get_element_type();
|
||||
auto shape = it.get_shape();
|
||||
auto& m = outputsMap[it.get_any_name()];
|
||||
|
||||
auto tensor = infRequest.get_tensor(it);
|
||||
auto shape = tensor.get_shape();
|
||||
if (type == ov::element::f32)
|
||||
{
|
||||
m.create(std::vector<int>(shape.begin(), shape.end()), CV_32F);
|
||||
@@ -341,22 +327,9 @@ TEST_P(DNNTestOpenVINO, models)
|
||||
if (targetId == DNN_TARGET_MYRIAD && (false
|
||||
|| modelName == "person-detection-retail-0013" // ncDeviceOpen:1013 Failed to find booted device after boot
|
||||
|| modelName == "age-gender-recognition-retail-0013" // ncDeviceOpen:1013 Failed to find booted device after boot
|
||||
|| modelName == "face-detection-0105" // get_element_type() must be called on a node with exactly one output
|
||||
|| modelName == "face-detection-0106" // get_element_type() must be called on a node with exactly one output
|
||||
|| modelName == "person-vehicle-bike-detection-2004" // 2021.4+: ncDeviceOpen:1013 Failed to find booted device after boot
|
||||
)
|
||||
)
|
||||
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
|
||||
if (targetId == DNN_TARGET_OPENCL && (false
|
||||
|| modelName == "face-detection-0106" // Operation: 2278 of type ExperimentalDetectronPriorGridGenerator(op::v6) is not supported
|
||||
)
|
||||
)
|
||||
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
|
||||
if (targetId == DNN_TARGET_OPENCL_FP16 && (false
|
||||
|| modelName == "face-detection-0106" // Operation: 2278 of type ExperimentalDetectronPriorGridGenerator(op::v6) is not supported
|
||||
)
|
||||
)
|
||||
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
|
||||
#endif
|
||||
|
||||
#if INF_ENGINE_VER_MAJOR_GE(2020020000)
|
||||
@@ -399,14 +372,6 @@ TEST_P(DNNTestOpenVINO, models)
|
||||
if (targetId == DNN_TARGET_CPU && checkHardwareSupport(CV_CPU_AVX_512F))
|
||||
eps = 1e-5;
|
||||
#endif
|
||||
#if INF_ENGINE_VER_MAJOR_GE(2021030000)
|
||||
if (targetId == DNN_TARGET_CPU && modelName == "face-detection-0105")
|
||||
eps = 2e-4;
|
||||
#endif
|
||||
#if INF_ENGINE_VER_MAJOR_GE(2021040000)
|
||||
if (targetId == DNN_TARGET_CPU && modelName == "person-vehicle-bike-detection-2004")
|
||||
eps = 1e-6;
|
||||
#endif
|
||||
|
||||
EXPECT_EQ(ieOutputsMap.size(), cvOutputsMap.size());
|
||||
for (auto& srcIt : ieOutputsMap)
|
||||
|
||||
@@ -2812,7 +2812,7 @@ void yoloPostProcessing(
|
||||
if (model_name == "yolonas"){
|
||||
EXPECT_EQ(cv::MatShape({1, 8400, 80}), outs[0].shape());
|
||||
EXPECT_EQ(cv::MatShape({1, 8400, 4}), outs[1].shape());
|
||||
// outs contains 2 elemets of shape [1, 8400, 80] and [1, 8400, 4]. Concat them to get [1, 8400, 84]
|
||||
// outs contains 2 elemets of shape [1, 8400, nc] and [1, 8400, 4]. Concat them to get [1, 8400, 84]
|
||||
Mat concat_out;
|
||||
// squeeze the first dimension
|
||||
outs[0] = outs[0].reshape(1, outs[0].size[1]);
|
||||
@@ -2822,12 +2822,12 @@ void yoloPostProcessing(
|
||||
// remove the second element
|
||||
outs.pop_back();
|
||||
// unsqueeze the first dimension
|
||||
outs[0] = outs[0].reshape(0, std::vector<int>{1, 8400, 84});
|
||||
outs[0] = outs[0].reshape(0, std::vector<int>{1, outs[0].size[0], outs[0].size[1]});
|
||||
}
|
||||
|
||||
// assert if last dim is 85 or 84
|
||||
CV_CheckEQ(outs[0].dims, 3, "Invalid output shape. The shape should be [1, #anchors, 85 or 84]");
|
||||
CV_CheckEQ((outs[0].size[2] == nc + 5 || outs[0].size[2] == 80 + 4), true, "Invalid output shape: ");
|
||||
// assert if last dim is nc+5 or nc+4
|
||||
CV_CheckEQ(outs[0].dims, 3, "Invalid output shape. The shape should be [1, #anchors, nc+5 or nc+4]");
|
||||
CV_CheckEQ((outs[0].size[2] == nc + 5 || outs[0].size[2] == nc + 4), true, "Invalid output shape: ");
|
||||
|
||||
for (auto preds : outs){
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ TEST_P(Test_TFLite, face_landmark)
|
||||
{
|
||||
if (backend == DNN_BACKEND_CUDA && target == DNN_TARGET_CUDA_FP16)
|
||||
applyTestTag(CV_TEST_TAG_DNN_SKIP_CUDA_FP16);
|
||||
double l1 = 2e-5, lInf = 2e-4;
|
||||
double l1 = 2.2e-5, lInf = 2e-4;
|
||||
if (target == DNN_TARGET_CPU_FP16 || target == DNN_TARGET_CUDA_FP16 || target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD ||
|
||||
(backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL))
|
||||
{
|
||||
|
||||
@@ -43,9 +43,6 @@
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
const string FEATURES2D_DIR = "features2d";
|
||||
const string IMAGE_FILENAME = "tsukuba.png";
|
||||
|
||||
/****************************************************************************************\
|
||||
* Algorithmic tests for descriptor matchers *
|
||||
\****************************************************************************************/
|
||||
|
||||
@@ -83,6 +83,7 @@ if(WITH_WAYLAND AND HAVE_WAYLAND)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
ocv_module_include_directories(${WAYLAND_CLIENT_INCLUDE_DIRS} ${XKBCOMMON_INCLUDE_DIRS})
|
||||
elseif(HAVE_QT)
|
||||
set(OPENCV_HIGHGUI_BUILTIN_BACKEND "QT${QT_VERSION_MAJOR}")
|
||||
add_definitions(-DHAVE_QT)
|
||||
|
||||
@@ -532,16 +532,20 @@ control panel.
|
||||
Clicking the label of each trackbar enables editing the trackbar values manually.
|
||||
|
||||
@param trackbarname Name of the created trackbar.
|
||||
@param winname Name of the window that will be used as a parent of the created trackbar.
|
||||
@param value Optional pointer to an integer variable whose value reflects the position of the
|
||||
slider. Upon creation, the slider position is defined by this variable.
|
||||
@param count Maximal position of the slider. The minimal position is always 0.
|
||||
@param onChange Pointer to the function to be called every time the slider changes position. This
|
||||
function should be prototyped as void Foo(int,void\*); , where the first parameter is the trackbar
|
||||
position and the second parameter is the user data (see the next parameter). If the callback is
|
||||
the NULL pointer, no callbacks are called, but only value is updated.
|
||||
@param userdata User data that is passed as is to the callback. It can be used to handle trackbar
|
||||
events without using global variables.
|
||||
@param winname Name of the window that will contain the trackbar.
|
||||
@param value Pointer to the integer value that will be changed by the trackbar.
|
||||
Pass `nullptr` if the value pointer is not used. In this case, manually handle
|
||||
the trackbar position in the callback function.
|
||||
@param count Maximum position of the trackbar.
|
||||
@param onChange Pointer to the function to be called every time the slider changes position.
|
||||
This function should have the prototype void Foo(int, void\*);, where the first parameter is
|
||||
the trackbar position, and the second parameter is the user data (see the next parameter).
|
||||
If the callback is a nullptr, no callbacks are called, but the trackbar's value will still be
|
||||
updated automatically.
|
||||
@param userdata Optional user data that is passed to the callback.
|
||||
@note If the `value` pointer is `nullptr`, the trackbar position must be manually managed.
|
||||
Call the callback function manually with the desired initial value to avoid runtime warnings.
|
||||
@see \ref tutorial_trackbar
|
||||
*/
|
||||
CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname,
|
||||
int* value, int count,
|
||||
|
||||
@@ -219,7 +219,7 @@ void cv::setWindowProperty(const String& name, int prop_id, double prop_value)
|
||||
//change between fullscreen or not.
|
||||
case cv::WND_PROP_FULLSCREEN:
|
||||
|
||||
if (prop_value != cv::WINDOW_NORMAL && prop_value != cv::WINDOW_FULLSCREEN) // bad argument
|
||||
if ((int)prop_value != cv::WINDOW_NORMAL && (int)prop_value != cv::WINDOW_FULLSCREEN) // bad argument
|
||||
break;
|
||||
|
||||
#if defined (HAVE_QT)
|
||||
|
||||
@@ -595,14 +595,16 @@ cv::Rect cvGetWindowRect_COCOA( const char* name )
|
||||
{
|
||||
CV_Error( cv::Error::StsNullPtr, "NULL window" );
|
||||
} else {
|
||||
NSRect rect = [window frame];
|
||||
@autoreleasepool {
|
||||
NSRect rect = [window frame];
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_6
|
||||
NSPoint pt = [window convertRectToScreen:rect].origin;
|
||||
NSPoint pt = [window convertRectToScreen:rect].origin;
|
||||
#else
|
||||
NSPoint pt = [window convertBaseToScreen:rect.origin];
|
||||
NSPoint pt = [window convertBaseToScreen:rect.origin];
|
||||
#endif
|
||||
NSSize sz = [[[window contentView] image] size];
|
||||
result = cv::Rect(pt.x, pt.y, sz.width, sz.height);
|
||||
NSSize sz = [[[window contentView] image] size];
|
||||
result = cv::Rect(pt.x, pt.y, sz.width, sz.height);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2108,7 +2108,7 @@ public:
|
||||
switch (prop)
|
||||
{
|
||||
case cv::WND_PROP_FULLSCREEN:
|
||||
if (value != cv::WINDOW_NORMAL && value != cv::WINDOW_FULLSCREEN) // bad arg
|
||||
if ((int)value != cv::WINDOW_NORMAL && (int)value != cv::WINDOW_FULLSCREEN) // bad arg
|
||||
break;
|
||||
setModeWindow_(window, value);
|
||||
return true;
|
||||
|
||||
@@ -2111,6 +2111,9 @@ static void showSaveDialog(CvWindow& window)
|
||||
#ifdef HAVE_JPEG
|
||||
"JPEG files (*.jpeg;*.jpg;*.jpe)\0*.jpeg;*.jpg;*.jpe\0"
|
||||
#endif
|
||||
#ifdef HAVE_JPEGXL
|
||||
"JPEG XL files (*.jxl)\0*.jxl\0"
|
||||
#endif
|
||||
#ifdef HAVE_TIFF
|
||||
"TIFF Files (*.tiff;*.tif)\0*.tiff;*.tif\0"
|
||||
#endif
|
||||
@@ -2686,7 +2689,7 @@ public:
|
||||
switch ((WindowPropertyFlags)prop)
|
||||
{
|
||||
case WND_PROP_FULLSCREEN:
|
||||
if (value != WINDOW_NORMAL && value != WINDOW_FULLSCREEN) // bad arg
|
||||
if ((int)value != WINDOW_NORMAL && (int)value != WINDOW_FULLSCREEN) // bad arg
|
||||
break;
|
||||
setModeWindow_(window, (int)value);
|
||||
return true;
|
||||
|
||||
@@ -23,6 +23,11 @@ if(HAVE_JPEG)
|
||||
list(APPEND GRFMT_LIBS ${JPEG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_JPEGXL)
|
||||
ocv_include_directories(${OPENJPEG_INCLUDE_DIRS})
|
||||
list(APPEND GRFMT_LIBS ${OPENJPEG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_WEBP)
|
||||
add_definitions(-DHAVE_WEBP)
|
||||
ocv_include_directories(${WEBP_INCLUDE_DIR})
|
||||
@@ -51,6 +56,12 @@ if(HAVE_TIFF)
|
||||
list(APPEND GRFMT_LIBS ${TIFF_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_JPEGXL)
|
||||
ocv_include_directories(${JPEGXL_INCLUDE_DIRS})
|
||||
message(STATUS "JPEGXL_INCLUDE_DIRS: ${JPEGXL_INCLUDE_DIRS}")
|
||||
list(APPEND GRFMT_LIBS ${JPEGXL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_OPENJPEG)
|
||||
ocv_include_directories(${OPENJPEG_INCLUDE_DIRS})
|
||||
list(APPEND GRFMT_LIBS ${OPENJPEG_LIBRARIES})
|
||||
@@ -78,7 +89,7 @@ if(HAVE_OPENEXR)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_PNG OR HAVE_TIFF OR HAVE_OPENEXR OR HAVE_SPNG)
|
||||
if(HAVE_PNG OR HAVE_TIFF OR HAVE_OPENEXR OR HAVE_SPNG OR HAVE_JPEGXL)
|
||||
ocv_include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
list(APPEND GRFMT_LIBS ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
@@ -88,6 +99,10 @@ if(HAVE_GDAL)
|
||||
list(APPEND GRFMT_LIBS ${GDAL_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(HAVE_IMGCODEC_GIF)
|
||||
add_definitions(-DHAVE_IMGCODEC_GIF)
|
||||
endif()
|
||||
|
||||
if(HAVE_IMGCODEC_HDR)
|
||||
add_definitions(-DHAVE_IMGCODEC_HDR)
|
||||
endif()
|
||||
|
||||
@@ -111,8 +111,18 @@ enum ImwriteFlags {
|
||||
IMWRITE_JPEG2000_COMPRESSION_X1000 = 272,//!< For JPEG2000, use to specify the target compression rate (multiplied by 1000). The value can be from 0 to 1000. Default is 1000.
|
||||
IMWRITE_AVIF_QUALITY = 512,//!< For AVIF, it can be a quality between 0 and 100 (the higher the better). Default is 95.
|
||||
IMWRITE_AVIF_DEPTH = 513,//!< For AVIF, it can be 8, 10 or 12. If >8, it is stored/read as CV_32F. Default is 8.
|
||||
IMWRITE_AVIF_SPEED = 514 //!< For AVIF, it is between 0 (slowest) and (fastest). Default is 9.
|
||||
};
|
||||
IMWRITE_AVIF_SPEED = 514,//!< For AVIF, it is between 0 (slowest) and (fastest). Default is 9.
|
||||
IMWRITE_JPEGXL_QUALITY = 640,//!< For JPEG XL, it can be a quality from 0 to 100 (the higher is the better). Default value is 95. If set, distance parameter is re-calicurated from quality level automatically. This parameter request libjxl v0.10 or later.
|
||||
IMWRITE_JPEGXL_EFFORT = 641,//!< For JPEG XL, encoder effort/speed level without affecting decoding speed; it is between 1 (fastest) and 10 (slowest). Default is 7.
|
||||
IMWRITE_JPEGXL_DISTANCE = 642,//!< For JPEG XL, distance level for lossy compression: target max butteraugli distance, lower = higher quality, 0 = lossless; range: 0 .. 25. Default is 1.
|
||||
IMWRITE_JPEGXL_DECODING_SPEED = 643,//!< For JPEG XL, decoding speed tier for the provided options; minimum is 0 (slowest to decode, best quality/density), and maximum is 4 (fastest to decode, at the cost of some quality/density). Default is 0.
|
||||
IMWRITE_GIF_LOOP = 1024,//!< For GIF, it can be a loop flag from 0 to 65535. Default is 0 - loop forever.
|
||||
IMWRITE_GIF_SPEED = 1025,//!< For GIF, it is between 1 (slowest) and 100 (fastest). Default is 96.
|
||||
IMWRITE_GIF_QUALITY = 1026, //!< For GIF, it can be a quality from 1 to 8. Default is 2. See cv::ImwriteGifCompressionFlags.
|
||||
IMWRITE_GIF_DITHER = 1027, //!< For GIF, it can be a quality from -1(most dither) to 3(no dither). Default is 0.
|
||||
IMWRITE_GIF_TRANSPARENCY = 1028, //!< For GIF, the alpha channel lower than this will be set to transparent. Default is 1.
|
||||
IMWRITE_GIF_COLORTABLE = 1029 //!< For GIF, 0 means global color table is used, 1 means local color table is used. Default is 0.
|
||||
};
|
||||
|
||||
enum ImwriteJPEGSamplingFactorParams {
|
||||
IMWRITE_JPEG_SAMPLING_FACTOR_411 = 0x411111, //!< 4x1,1x1,1x1
|
||||
@@ -216,8 +226,50 @@ enum ImwriteHDRCompressionFlags {
|
||||
IMWRITE_HDR_COMPRESSION_RLE = 1
|
||||
};
|
||||
|
||||
//! Imwrite GIF specific values for IMWRITE_GIF_QUALITY parameter key, if larger than 3, then its related to the size of the color table.
|
||||
enum ImwriteGIFCompressionFlags {
|
||||
IMWRITE_GIF_FAST_NO_DITHER = 1,
|
||||
IMWRITE_GIF_FAST_FLOYD_DITHER = 2,
|
||||
IMWRITE_GIF_COLORTABLE_SIZE_8 = 3,
|
||||
IMWRITE_GIF_COLORTABLE_SIZE_16 = 4,
|
||||
IMWRITE_GIF_COLORTABLE_SIZE_32 = 5,
|
||||
IMWRITE_GIF_COLORTABLE_SIZE_64 = 6,
|
||||
IMWRITE_GIF_COLORTABLE_SIZE_128 = 7,
|
||||
IMWRITE_GIF_COLORTABLE_SIZE_256 = 8
|
||||
};
|
||||
|
||||
//! @} imgcodecs_flags
|
||||
|
||||
/** @brief Represents an animation with multiple frames.
|
||||
The `Animation` struct is designed to store and manage data for animated sequences such as those from animated formats (e.g., GIF, AVIF, APNG, WebP).
|
||||
It provides support for looping, background color settings, frame timing, and frame storage.
|
||||
*/
|
||||
struct CV_EXPORTS_W_SIMPLE Animation
|
||||
{
|
||||
//! Number of times the animation should loop. 0 means infinite looping.
|
||||
CV_PROP_RW int loop_count;
|
||||
//! Background color of the animation in BGRA format.
|
||||
CV_PROP_RW Scalar bgcolor;
|
||||
//! Duration for each frame in milliseconds.
|
||||
CV_PROP_RW std::vector<int> durations;
|
||||
//! Vector of frames, where each Mat represents a single frame.
|
||||
CV_PROP_RW std::vector<Mat> frames;
|
||||
|
||||
/** @brief Constructs an Animation object with optional loop count and background color.
|
||||
|
||||
@param loopCount An integer representing the number of times the animation should loop:
|
||||
- `0` (default) indicates infinite looping, meaning the animation will replay continuously.
|
||||
- Positive values denote finite repeat counts, allowing the animation to play a limited number of times.
|
||||
- If a negative value or a value beyond the maximum of `0xffff` (65535) is provided, it is reset to `0`
|
||||
(infinite looping) to maintain valid bounds.
|
||||
|
||||
@param bgColor A `Scalar` object representing the background color in BGRA format:
|
||||
- Defaults to `Scalar()`, indicating an empty color (usually transparent if supported).
|
||||
- This background color provides a solid fill behind frames that have transparency, ensuring a consistent display appearance.
|
||||
*/
|
||||
Animation(int loopCount = 0, Scalar bgColor = Scalar());
|
||||
};
|
||||
|
||||
/** @brief Loads an image from a file.
|
||||
|
||||
@anchor imread
|
||||
@@ -229,6 +281,7 @@ returns an empty matrix.
|
||||
Currently, the following file formats are supported:
|
||||
|
||||
- Windows bitmaps - \*.bmp, \*.dib (always supported)
|
||||
- GIF files - \*.gif (always supported)
|
||||
- JPEG files - \*.jpeg, \*.jpg, \*.jpe (see the *Note* section)
|
||||
- JPEG 2000 files - \*.jp2 (see the *Note* section)
|
||||
- Portable Network Graphics - \*.png (see the *Note* section)
|
||||
@@ -304,6 +357,38 @@ The function imreadmulti loads a specified range from a multi-page image from th
|
||||
*/
|
||||
CV_EXPORTS_W bool imreadmulti(const String& filename, CV_OUT std::vector<Mat>& mats, int start, int count, int flags = IMREAD_ANYCOLOR);
|
||||
|
||||
/** @example samples/cpp/tutorial_code/imgcodecs/animations.cpp
|
||||
An example to show usage of cv::imreadanimation and cv::imwriteanimation functions.
|
||||
Check @ref tutorial_animations "the corresponding tutorial" for more details
|
||||
*/
|
||||
|
||||
/** @brief Loads frames from an animated image file into an Animation structure.
|
||||
|
||||
The function imreadanimation loads frames from an animated image file (e.g., GIF, AVIF, APNG, WEBP) into the provided Animation struct.
|
||||
|
||||
@param filename A string containing the path to the file.
|
||||
@param animation A reference to an Animation structure where the loaded frames will be stored. It should be initialized before the function is called.
|
||||
@param start The index of the first frame to load. This is optional and defaults to 0.
|
||||
@param count The number of frames to load. This is optional and defaults to 32767.
|
||||
|
||||
@return Returns true if the file was successfully loaded and frames were extracted; returns false otherwise.
|
||||
*/
|
||||
CV_EXPORTS_W bool imreadanimation(const String& filename, CV_OUT Animation& animation, int start = 0, int count = INT16_MAX);
|
||||
|
||||
/** @brief Saves an Animation to a specified file.
|
||||
|
||||
The function imwriteanimation saves the provided Animation data to the specified file in an animated format.
|
||||
Supported formats depend on the implementation and may include formats like GIF, AVIF, APNG, or WEBP.
|
||||
|
||||
@param filename The name of the file where the animation will be saved. The file extension determines the format.
|
||||
@param animation A constant reference to an Animation struct containing the frames and metadata to be saved.
|
||||
@param params Optional format-specific parameters encoded as pairs (paramId_1, paramValue_1, paramId_2, paramValue_2, ...).
|
||||
These parameters are used to specify additional options for the encoding process. Refer to `cv::ImwriteFlags` for details on possible parameters.
|
||||
|
||||
@return Returns true if the animation was successfully saved; returns false otherwise.
|
||||
*/
|
||||
CV_EXPORTS_W bool imwriteanimation(const String& filename, const Animation& animation, const std::vector<int>& params = std::vector<int>());
|
||||
|
||||
/** @brief Returns the number of images inside the given file
|
||||
|
||||
The function imcount returns the number of pages in a multi-page image (e.g. TIFF), the number of frames in an animation (e.g. AVIF), and 1 otherwise.
|
||||
@@ -326,6 +411,10 @@ can be saved using this function, with these exceptions:
|
||||
- With Radiance HDR encoder, non 64-bit float (CV_64F) images can be saved.
|
||||
- All images will be converted to 32-bit float (CV_32F).
|
||||
- With JPEG 2000 encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- With JPEG XL encoder, 8-bit unsigned (CV_8U), 16-bit unsigned (CV_16U) and 32-bit float(CV_32F) images can be saved.
|
||||
- JPEG XL images with an alpha channel can be saved using this function.
|
||||
To do this, create 8-bit (or 16-bit, 32-bit float) 4-channel image BGRA, where the alpha channel goes last.
|
||||
Fully transparent pixels should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535/1.0.
|
||||
- With PAM encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- With PNG encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- PNG images with an alpha channel can be saved using this function. To do this, create
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "grfmt_avif.hpp"
|
||||
|
||||
@@ -242,6 +243,8 @@ bool AvifDecoder::readData(Mat &img) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_animation.durations.push_back(decoder_->imageTiming.duration * 1000);
|
||||
|
||||
if (decoder_->image->exif.size > 0) {
|
||||
m_exif.parseExif(decoder_->image->exif.data, decoder_->image->exif.size);
|
||||
}
|
||||
@@ -297,16 +300,11 @@ bool AvifEncoder::isFormatSupported(int depth) const {
|
||||
|
||||
bool AvifEncoder::write(const Mat &img, const std::vector<int> ¶ms) {
|
||||
std::vector<Mat> img_vec(1, img);
|
||||
return writeToOutput(img_vec, params);
|
||||
return writemulti(img_vec, params);
|
||||
}
|
||||
|
||||
bool AvifEncoder::writemulti(const std::vector<Mat> &img_vec,
|
||||
const std::vector<int> ¶ms) {
|
||||
return writeToOutput(img_vec, params);
|
||||
}
|
||||
|
||||
bool AvifEncoder::writeToOutput(const std::vector<Mat> &img_vec,
|
||||
const std::vector<int> ¶ms) {
|
||||
bool AvifEncoder::writeanimation(const Animation& animation,
|
||||
const std::vector<int> ¶ms) {
|
||||
int bit_depth = 8;
|
||||
int speed = AVIF_SPEED_FASTEST;
|
||||
for (size_t i = 0; i < params.size(); i += 2) {
|
||||
@@ -340,12 +338,12 @@ bool AvifEncoder::writeToOutput(const std::vector<Mat> &img_vec,
|
||||
#endif
|
||||
encoder_->speed = speed;
|
||||
|
||||
const avifAddImageFlags flag = (img_vec.size() == 1)
|
||||
const avifAddImageFlags flag = (animation.frames.size() == 1)
|
||||
? AVIF_ADD_IMAGE_FLAG_SINGLE
|
||||
: AVIF_ADD_IMAGE_FLAG_NONE;
|
||||
std::vector<AvifImageUniquePtr> images;
|
||||
std::vector<cv::Mat> imgs_scaled;
|
||||
for (const cv::Mat &img : img_vec) {
|
||||
for (const cv::Mat &img : animation.frames) {
|
||||
CV_CheckType(
|
||||
img.type(),
|
||||
(bit_depth == 8 && img.depth() == CV_8U) ||
|
||||
@@ -358,13 +356,15 @@ bool AvifEncoder::writeToOutput(const std::vector<Mat> &img_vec,
|
||||
|
||||
images.emplace_back(ConvertToAvif(img, do_lossless, bit_depth));
|
||||
}
|
||||
for (const AvifImageUniquePtr &image : images) {
|
||||
|
||||
for (size_t i = 0; i < images.size(); i++)
|
||||
{
|
||||
OPENCV_AVIF_CHECK_STATUS(
|
||||
avifEncoderAddImage(encoder_, image.get(), /*durationInTimescale=*/1,
|
||||
flag),
|
||||
avifEncoderAddImage(encoder_, images[i].get(), animation.durations[i], flag),
|
||||
encoder_);
|
||||
}
|
||||
|
||||
encoder_->timescale = 1000;
|
||||
OPENCV_AVIF_CHECK_STATUS(avifEncoderFinish(encoder_, output.get()), encoder_);
|
||||
|
||||
if (m_buf) {
|
||||
|
||||
@@ -41,17 +41,12 @@ class AvifEncoder CV_FINAL : public BaseImageEncoder {
|
||||
~AvifEncoder() CV_OVERRIDE;
|
||||
|
||||
bool isFormatSupported(int depth) const CV_OVERRIDE;
|
||||
|
||||
bool write(const Mat& img, const std::vector<int>& params) CV_OVERRIDE;
|
||||
|
||||
bool writemulti(const std::vector<Mat>& img_vec,
|
||||
const std::vector<int>& params) CV_OVERRIDE;
|
||||
bool writeanimation(const Animation& animation, const std::vector<int>& params) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
|
||||
private:
|
||||
bool writeToOutput(const std::vector<Mat>& img_vec,
|
||||
const std::vector<int>& params);
|
||||
avifEncoder* encoder_;
|
||||
};
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
@@ -139,7 +140,22 @@ bool BaseImageEncoder::setDestination( std::vector<uchar>& buf )
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseImageEncoder::writemulti(const std::vector<Mat>&, const std::vector<int>& )
|
||||
bool BaseImageEncoder::writemulti(const std::vector<Mat>& img_vec, const std::vector<int>& params)
|
||||
{
|
||||
if(img_vec.size() > 1)
|
||||
CV_LOG_INFO(NULL, "Multi page image will be written as animation with 1 second frame duration.");
|
||||
|
||||
Animation animation;
|
||||
animation.frames = img_vec;
|
||||
|
||||
for (size_t i = 0; i < animation.frames.size(); i++)
|
||||
{
|
||||
animation.durations.push_back(1000);
|
||||
}
|
||||
return writeanimation(animation, params);
|
||||
}
|
||||
|
||||
bool BaseImageEncoder::writeanimation(const Animation&, const std::vector<int>& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,8 @@ public:
|
||||
*/
|
||||
virtual bool checkSignature(const String& signature) const;
|
||||
|
||||
const Animation& animation() const { return m_animation; };
|
||||
|
||||
/**
|
||||
* @brief Create and return a new instance of the derived image decoder.
|
||||
* @return A new ImageDecoder object.
|
||||
@@ -151,6 +153,7 @@ protected:
|
||||
bool m_use_rgb; ///< Flag indicating whether to decode the image in RGB order.
|
||||
ExifReader m_exif; ///< Object for reading EXIF metadata from the image.
|
||||
size_t m_frame_count; ///< Number of frames in the image (for animations and multi-page images).
|
||||
Animation m_animation;
|
||||
};
|
||||
|
||||
|
||||
@@ -215,6 +218,8 @@ public:
|
||||
*/
|
||||
virtual bool writemulti(const std::vector<Mat>& img_vec, const std::vector<int>& params);
|
||||
|
||||
virtual bool writeanimation(const Animation& animation, const std::vector<int>& params);
|
||||
|
||||
/**
|
||||
* @brief Get a description of the image encoder (e.g., the format it supports).
|
||||
* @return A string describing the encoder.
|
||||
|
||||
@@ -208,7 +208,12 @@ bool BmpDecoder::readHeader()
|
||||
// in 32 bit case alpha channel is used - so require CV_8UC4 type
|
||||
m_type = iscolor ? ((m_bpp == 32 && m_rle_code != BMP_RGB) ? CV_8UC4 : CV_8UC3 ) : CV_8UC1;
|
||||
m_origin = m_height > 0 ? ORIGIN_BL : ORIGIN_TL;
|
||||
m_height = std::abs(m_height);
|
||||
if ( m_height == std::numeric_limits<int>::min() ) {
|
||||
// abs(std::numeric_limits<int>::min()) is undefined behavior.
|
||||
result = false;
|
||||
} else {
|
||||
m_height = std::abs(m_height);
|
||||
}
|
||||
|
||||
if( !result )
|
||||
{
|
||||
|
||||
@@ -235,6 +235,17 @@ bool ExrDecoder::readData( Mat& img )
|
||||
( (m_iscolor && !m_ischroma) || color) ? 3 : alphasupported ? 2 : 1 ); // number of channels to read may exceed channels in output img
|
||||
size_t xStride = floatsize * channelstoread;
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/26705
|
||||
// If ALGO_HINT_ACCURATE is set, read BGR and swap to RGB.
|
||||
// If ALGO_HINT_APPROX is set, read RGB directly.
|
||||
bool doReadRGB = m_use_rgb;
|
||||
bool doPostColorSwap = false; // After decoding, swap BGR to RGB
|
||||
if(m_use_rgb && (getDefaultAlgorithmHint() == ALGO_HINT_ACCURATE) )
|
||||
{
|
||||
doReadRGB = false;
|
||||
doPostColorSwap = true;
|
||||
}
|
||||
|
||||
AutoBuffer<char> copy_buffer;
|
||||
|
||||
if( !justcopy )
|
||||
@@ -373,7 +384,7 @@ bool ExrDecoder::readData( Mat& img )
|
||||
|
||||
if( m_iscolor )
|
||||
{
|
||||
if (m_use_rgb)
|
||||
if (doReadRGB)
|
||||
{
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSample( data, channelstoread, step / xstep, m_red->xSampling, m_red->ySampling );
|
||||
@@ -397,7 +408,7 @@ bool ExrDecoder::readData( Mat& img )
|
||||
|
||||
if( chromatorgb )
|
||||
{
|
||||
if (m_use_rgb)
|
||||
if (doReadRGB)
|
||||
ChromaToRGB( (float *)data, m_height, channelstoread, step / xstep );
|
||||
else
|
||||
ChromaToBGR( (float *)data, m_height, channelstoread, step / xstep );
|
||||
@@ -424,7 +435,7 @@ bool ExrDecoder::readData( Mat& img )
|
||||
{
|
||||
if( chromatorgb )
|
||||
{
|
||||
if (m_use_rgb)
|
||||
if (doReadRGB)
|
||||
ChromaToRGB( (float *)buffer, 1, defaultchannels, step );
|
||||
else
|
||||
ChromaToBGR( (float *)buffer, 1, defaultchannels, step );
|
||||
@@ -452,7 +463,7 @@ bool ExrDecoder::readData( Mat& img )
|
||||
}
|
||||
if( color )
|
||||
{
|
||||
if (m_use_rgb)
|
||||
if (doReadRGB)
|
||||
{
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSampleY( data, defaultchannels, step / xstep, m_red->ySampling );
|
||||
@@ -477,6 +488,11 @@ bool ExrDecoder::readData( Mat& img )
|
||||
|
||||
close();
|
||||
|
||||
if(doPostColorSwap)
|
||||
{
|
||||
cvtColor( img, img, cv::COLOR_BGR2RGB );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,181 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level
|
||||
// directory of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_GRFMT_GIF_HPP
|
||||
#define OPENCV_GRFMT_GIF_HPP
|
||||
#ifdef HAVE_IMGCODEC_GIF
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
enum GifOpMode
|
||||
{
|
||||
GRFMT_GIF_Nothing = 0,
|
||||
GRFMT_GIF_PreviousImage = 1,
|
||||
GRFMT_GIF_Background = 2,
|
||||
GRFMT_GIF_Cover = 3
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//// GIF Decoder ////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GifDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
GifDecoder();
|
||||
~GifDecoder() CV_OVERRIDE;
|
||||
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
bool readData(Mat& img) CV_OVERRIDE;
|
||||
bool nextPage() CV_OVERRIDE;
|
||||
void close();
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
RLByteStream m_strm;
|
||||
|
||||
int bgColor;
|
||||
int depth;
|
||||
int idx;
|
||||
|
||||
GifOpMode opMode;
|
||||
bool hasTransparentColor;
|
||||
uchar transparentColor;
|
||||
int top, left, width, height;
|
||||
|
||||
bool hasRead;
|
||||
std::vector<uchar> globalColorTable;
|
||||
std::vector<uchar> localColorTable;
|
||||
|
||||
int lzwMinCodeSize;
|
||||
int globalColorTableSize;
|
||||
int localColorTableSize;
|
||||
|
||||
Mat lastImage;
|
||||
std::vector<uchar> imgCodeStream;
|
||||
|
||||
struct lzwNodeD
|
||||
{
|
||||
int length;
|
||||
uchar suffix;
|
||||
std::vector<uchar> prefix;
|
||||
};
|
||||
|
||||
void readExtensions();
|
||||
void code2pixel(Mat& img, int start, int k);
|
||||
bool lzwDecode();
|
||||
bool getFrameCount_();
|
||||
bool skipHeader();
|
||||
};
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//// GIF Encoder ////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class GifEncoder CV_FINAL : public BaseImageEncoder {
|
||||
public:
|
||||
GifEncoder();
|
||||
~GifEncoder() CV_OVERRIDE;
|
||||
|
||||
bool isFormatSupported(int depth) const CV_OVERRIDE;
|
||||
|
||||
bool write(const Mat& img, const std::vector<int>& params) CV_OVERRIDE;
|
||||
bool writeanimation(const Animation& animation, const std::vector<int>& params) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
|
||||
private:
|
||||
/** Color Quantization **/
|
||||
class OctreeColorQuant
|
||||
{
|
||||
struct OctreeNode
|
||||
{
|
||||
bool isLeaf;
|
||||
std::shared_ptr<OctreeNode> children[8]{};
|
||||
int level;
|
||||
uchar index;
|
||||
int leaf;
|
||||
int pixelCount;
|
||||
size_t redSum, greenSum, blueSum;
|
||||
|
||||
OctreeNode();
|
||||
};
|
||||
|
||||
std::shared_ptr<OctreeNode> root;
|
||||
std::vector<std::shared_ptr<OctreeNode>> m_nodeList[8];
|
||||
int32_t m_bitLength;
|
||||
int32_t m_maxColors;
|
||||
int32_t m_leafCount;
|
||||
uchar m_criticalTransparency;
|
||||
uchar r, g, b; // color under transparent color
|
||||
|
||||
public:
|
||||
explicit OctreeColorQuant(int maxColors = 256, int bitLength = 8, uchar criticalTransparency = 1);
|
||||
|
||||
int getPalette(uchar* colorTable);
|
||||
uchar getLeaf(uchar red, uchar green, uchar blue);
|
||||
|
||||
void addMat(const Mat& img);
|
||||
void addMats(const std::vector<Mat>& img_vec);
|
||||
void addColor(int red, int green, int blue);
|
||||
void reduceTree();
|
||||
void recurseReduce(const std::shared_ptr<OctreeNode>& node);
|
||||
};
|
||||
|
||||
enum GifDithering // normal dithering level is -1 to 2
|
||||
{
|
||||
GRFMT_GIF_None = 3,
|
||||
GRFMT_GIF_FloydSteinberg = 4
|
||||
};
|
||||
|
||||
WLByteStream strm;
|
||||
int m_width, m_height;
|
||||
|
||||
int globalColorTableSize;
|
||||
int localColorTableSize;
|
||||
|
||||
uchar opMode;
|
||||
uchar criticalTransparency;
|
||||
uchar transparentColor;
|
||||
Vec3b transparentRGB;
|
||||
int top, left, width, height;
|
||||
|
||||
OctreeColorQuant quantG;
|
||||
OctreeColorQuant quantL;
|
||||
|
||||
std::vector<int16_t> lzwTable;
|
||||
std::vector<uchar> imgCodeStream;
|
||||
|
||||
std::vector<uchar> globalColorTable;
|
||||
std::vector<uchar> localColorTable;
|
||||
|
||||
// params
|
||||
int loopCount;
|
||||
int frameDelay;
|
||||
int colorNum;
|
||||
int bitDepth;
|
||||
int dithering;
|
||||
int lzwMinCodeSize, lzwMaxCodeSize;
|
||||
bool fast;
|
||||
|
||||
bool writeFrames(const std::vector<Mat>& img_vec, const std::vector<int>& params);
|
||||
bool writeHeader(const std::vector<Mat>& img_vec);
|
||||
bool writeFrame(const Mat& img);
|
||||
bool pixel2code(const Mat& img);
|
||||
void getColorTable(const std::vector<Mat>& img_vec, bool isGlobal);
|
||||
static int ditheringKernel(const Mat &img, Mat &img_, int depth, uchar transparency);
|
||||
bool lzwEncode();
|
||||
void close();
|
||||
};
|
||||
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // HAVE_IMGCODEC_GIF
|
||||
#endif //OPENCV_GRFMT_GIF_HPP
|
||||
@@ -0,0 +1,420 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "precomp.hpp"
|
||||
#include "grfmt_jpegxl.hpp"
|
||||
|
||||
#ifdef HAVE_JPEGXL
|
||||
|
||||
#include <jxl/encode_cxx.h>
|
||||
#include <jxl/version.h>
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/////////////////////// JpegXLDecoder ///////////////////
|
||||
|
||||
JpegXLDecoder::JpegXLDecoder() : m_f(nullptr, &fclose)
|
||||
{
|
||||
m_signature = "\xFF\x0A";
|
||||
m_decoder = nullptr;
|
||||
m_buf_supported = false;
|
||||
m_type = m_convert = -1;
|
||||
m_status = JXL_DEC_NEED_MORE_INPUT;
|
||||
}
|
||||
|
||||
JpegXLDecoder::~JpegXLDecoder()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void JpegXLDecoder::close()
|
||||
{
|
||||
if (m_decoder)
|
||||
m_decoder.release();
|
||||
if (m_f)
|
||||
m_f.release();
|
||||
m_read_buffer = {};
|
||||
m_width = m_height = 0;
|
||||
m_type = m_convert = -1;
|
||||
m_status = JXL_DEC_NEED_MORE_INPUT;
|
||||
}
|
||||
|
||||
// see https://github.com/libjxl/libjxl/blob/v0.10.0/doc/format_overview.md
|
||||
size_t JpegXLDecoder::signatureLength() const
|
||||
{
|
||||
return 12; // For an ISOBMFF-based container
|
||||
}
|
||||
|
||||
bool JpegXLDecoder::checkSignature( const String& signature ) const
|
||||
{
|
||||
// A "naked" codestream.
|
||||
if (
|
||||
( signature.size() >= 2 ) &&
|
||||
( memcmp( signature.c_str(), "\xFF\x0A", 2 ) == 0 )
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// An ISOBMFF-based container.
|
||||
// 0x0000_000C_4A58_4C20_0D0A_870A.
|
||||
if (
|
||||
( signature.size() >= 12 ) &&
|
||||
( memcmp( signature.c_str(), "\x00\x00\x00\x0C\x4A\x58\x4C\x20\x0D\x0A\x87\x0A", 12 ) == 0 )
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageDecoder JpegXLDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<JpegXLDecoder>();
|
||||
}
|
||||
|
||||
bool JpegXLDecoder::read(Mat* pimg)
|
||||
{
|
||||
// Open file
|
||||
if (!m_f) {
|
||||
m_f.reset(fopen(m_filename.c_str(), "rb"));
|
||||
if (!m_f)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize decoder
|
||||
if (!m_decoder) {
|
||||
m_decoder = JxlDecoderMake(nullptr);
|
||||
if (!m_decoder)
|
||||
return false;
|
||||
// Subscribe to the basic info event
|
||||
JxlDecoderStatus status = JxlDecoderSubscribeEvents(m_decoder.get(), JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE);
|
||||
if (status != JXL_DEC_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up parallel m_parallel_runner
|
||||
if (!m_parallel_runner) {
|
||||
m_parallel_runner = JxlThreadParallelRunnerMake(nullptr, cv::getNumThreads());
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetParallelRunner(m_decoder.get(),
|
||||
JxlThreadParallelRunner,
|
||||
m_parallel_runner.get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Create buffer for reading
|
||||
const size_t read_buffer_size = 16384; // 16KB chunks
|
||||
if (m_read_buffer.capacity() < read_buffer_size)
|
||||
m_read_buffer.resize(read_buffer_size);
|
||||
|
||||
// Create image if needed
|
||||
if (m_type != -1 && pimg) {
|
||||
pimg->create(m_height, m_width, m_type);
|
||||
if (!pimg->isContinuous())
|
||||
return false;
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(m_decoder.get(),
|
||||
&m_format,
|
||||
pimg->ptr<uint8_t>(),
|
||||
pimg->total() * pimg->elemSize())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Start decoding loop
|
||||
do {
|
||||
// Check if we need more input
|
||||
if (m_status == JXL_DEC_NEED_MORE_INPUT) {
|
||||
size_t remaining = JxlDecoderReleaseInput(m_decoder.get());
|
||||
// Move any remaining bytes to the beginning
|
||||
if (remaining > 0)
|
||||
memmove(m_read_buffer.data(), m_read_buffer.data() + m_read_buffer.size() - remaining, remaining);
|
||||
// Read more data from file
|
||||
size_t bytes_read = fread(m_read_buffer.data() + remaining,
|
||||
1, m_read_buffer.size() - remaining, m_f.get());
|
||||
if (bytes_read == 0) {
|
||||
if (ferror(m_f.get())) {
|
||||
CV_LOG_WARNING(NULL, "Error reading input file");
|
||||
return false;
|
||||
}
|
||||
// If we reached EOF but decoder needs more input, file is truncated
|
||||
if (m_status == JXL_DEC_NEED_MORE_INPUT) {
|
||||
CV_LOG_WARNING(NULL, "Truncated JXL file");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set input buffer
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetInput(m_decoder.get(),
|
||||
m_read_buffer.data(),
|
||||
bytes_read + remaining)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next decoder status
|
||||
m_status = JxlDecoderProcessInput(m_decoder.get());
|
||||
|
||||
// Handle different decoder states
|
||||
switch (m_status) {
|
||||
case JXL_DEC_BASIC_INFO: {
|
||||
if (m_type != -1)
|
||||
return false;
|
||||
JxlBasicInfo info;
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderGetBasicInfo(m_decoder.get(), &info))
|
||||
return false;
|
||||
|
||||
// total channels (Color + Alpha)
|
||||
const uint32_t ncn = info.num_color_channels + info.num_extra_channels;
|
||||
|
||||
m_width = info.xsize;
|
||||
m_height = info.ysize;
|
||||
m_format = {
|
||||
ncn,
|
||||
JXL_TYPE_UINT8, // (temporary)
|
||||
JXL_LITTLE_ENDIAN, // endianness
|
||||
0 // align stride to bytes
|
||||
};
|
||||
if (!m_use_rgb) {
|
||||
switch (ncn) {
|
||||
case 3:
|
||||
m_convert = cv::COLOR_RGB2BGR;
|
||||
break;
|
||||
case 4:
|
||||
m_convert = cv::COLOR_RGBA2BGRA;
|
||||
break;
|
||||
default:
|
||||
m_convert = -1;
|
||||
}
|
||||
}
|
||||
if (info.exponent_bits_per_sample > 0) {
|
||||
m_format.data_type = JXL_TYPE_FLOAT;
|
||||
m_type = CV_MAKETYPE( CV_32F, ncn );
|
||||
} else {
|
||||
switch (info.bits_per_sample) {
|
||||
case 8:
|
||||
m_format.data_type = JXL_TYPE_UINT8;
|
||||
m_type = CV_MAKETYPE( CV_8U, ncn );
|
||||
break;
|
||||
case 16:
|
||||
m_format.data_type = JXL_TYPE_UINT16;
|
||||
m_type = CV_MAKETYPE( CV_16U, ncn );
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!pimg)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case JXL_DEC_FULL_IMAGE: {
|
||||
// Image is ready
|
||||
if (m_convert != -1)
|
||||
cv::cvtColor(*pimg, *pimg, m_convert);
|
||||
break;
|
||||
}
|
||||
case JXL_DEC_ERROR: {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (m_status != JXL_DEC_SUCCESS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JpegXLDecoder::readHeader()
|
||||
{
|
||||
close();
|
||||
return read(nullptr);
|
||||
}
|
||||
|
||||
bool JpegXLDecoder::readData(Mat& img)
|
||||
{
|
||||
if (!m_decoder || m_width == 0 || m_height == 0)
|
||||
return false;
|
||||
return read(&img);
|
||||
}
|
||||
|
||||
/////////////////////// JpegXLEncoder ///////////////////
|
||||
|
||||
JpegXLEncoder::JpegXLEncoder()
|
||||
{
|
||||
m_description = "JPEG XL files (*.jxl)";
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
JpegXLEncoder::~JpegXLEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
ImageEncoder JpegXLEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<JpegXLEncoder>();
|
||||
}
|
||||
|
||||
bool JpegXLEncoder::isFormatSupported( int depth ) const
|
||||
{
|
||||
return depth == CV_8U || depth == CV_16U || depth == CV_32F;
|
||||
}
|
||||
|
||||
bool JpegXLEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
m_last_error.clear();
|
||||
|
||||
JxlEncoderPtr encoder = JxlEncoderMake(nullptr);
|
||||
if (!encoder)
|
||||
return false;
|
||||
|
||||
JxlThreadParallelRunnerPtr runner = JxlThreadParallelRunnerMake(
|
||||
/*memory_manager=*/nullptr, cv::getNumThreads());
|
||||
if (JXL_ENC_SUCCESS != JxlEncoderSetParallelRunner(encoder.get(), JxlThreadParallelRunner, runner.get()))
|
||||
return false;
|
||||
|
||||
CV_CheckDepth(img.depth(),
|
||||
( img.depth() == CV_8U || img.depth() == CV_16U || img.depth() == CV_32F ),
|
||||
"JPEG XL encoder only supports CV_8U, CV_16U, CV_32F");
|
||||
CV_CheckChannels(img.channels(),
|
||||
( img.channels() == 1 || img.channels() == 3 || img.channels() == 4) ,
|
||||
"JPEG XL encoder only supports 1, 3, 4 channels");
|
||||
|
||||
WLByteStream strm;
|
||||
if( m_buf ) {
|
||||
if( !strm.open( *m_buf ) )
|
||||
return false;
|
||||
}
|
||||
else if( !strm.open( m_filename )) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JxlBasicInfo info;
|
||||
JxlEncoderInitBasicInfo(&info);
|
||||
info.xsize = img.cols;
|
||||
info.ysize = img.rows;
|
||||
info.uses_original_profile = JXL_FALSE;
|
||||
|
||||
if( img.channels() == 4 )
|
||||
{
|
||||
info.num_color_channels = 3;
|
||||
info.num_extra_channels = 1;
|
||||
|
||||
info.bits_per_sample =
|
||||
info.alpha_bits = 8 * static_cast<int>(img.elemSize1());
|
||||
|
||||
info.exponent_bits_per_sample =
|
||||
info.alpha_exponent_bits = img.depth() == CV_32F ? 8 : 0;
|
||||
}else{
|
||||
info.num_color_channels = img.channels();
|
||||
info.bits_per_sample = 8 * static_cast<int>(img.elemSize1());
|
||||
info.exponent_bits_per_sample = img.depth() == CV_32F ? 8 : 0;
|
||||
}
|
||||
|
||||
if (JxlEncoderSetBasicInfo(encoder.get(), &info) != JXL_ENC_SUCCESS)
|
||||
return false;
|
||||
|
||||
JxlDataType type = JXL_TYPE_UINT8;
|
||||
if (img.depth() == CV_32F)
|
||||
type = JXL_TYPE_FLOAT;
|
||||
else if (img.depth() == CV_16U)
|
||||
type = JXL_TYPE_UINT16;
|
||||
JxlPixelFormat format = {(uint32_t)img.channels(), type, JXL_NATIVE_ENDIAN, 0};
|
||||
JxlColorEncoding color_encoding = {};
|
||||
JXL_BOOL is_gray(format.num_channels < 3 ? JXL_TRUE : JXL_FALSE);
|
||||
JxlColorEncodingSetToSRGB(&color_encoding, is_gray);
|
||||
if (JXL_ENC_SUCCESS != JxlEncoderSetColorEncoding(encoder.get(), &color_encoding))
|
||||
return false;
|
||||
|
||||
Mat image;
|
||||
switch ( img.channels() ) {
|
||||
case 3:
|
||||
cv::cvtColor(img, image, cv::COLOR_BGR2RGB);
|
||||
break;
|
||||
case 4:
|
||||
cv::cvtColor(img, image, cv::COLOR_BGRA2RGBA);
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
if(img.isContinuous()) {
|
||||
image = img;
|
||||
} else {
|
||||
image = img.clone(); // reconstruction as continuous image.
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!image.isContinuous())
|
||||
return false;
|
||||
|
||||
JxlEncoderFrameSettings* frame_settings = JxlEncoderFrameSettingsCreate(encoder.get(), nullptr);
|
||||
// set frame settings from params if available
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
if( params[i] == IMWRITE_JPEGXL_QUALITY )
|
||||
{
|
||||
#if JPEGXL_MAJOR_VERSION > 0 || JPEGXL_MINOR_VERSION >= 10
|
||||
int quality = params[i+1];
|
||||
quality = MIN(MAX(quality, 0), 100);
|
||||
const float distance = JxlEncoderDistanceFromQuality(static_cast<float>(quality));
|
||||
JxlEncoderSetFrameDistance(frame_settings, distance);
|
||||
if (distance == 0)
|
||||
JxlEncoderSetFrameLossless(frame_settings, JXL_TRUE);
|
||||
#else
|
||||
CV_LOG_ONCE_WARNING(NULL, "Quality parameter is supported with libjxl v0.10.0 or later");
|
||||
#endif
|
||||
}
|
||||
if( params[i] == IMWRITE_JPEGXL_DISTANCE )
|
||||
{
|
||||
int distance = params[i+1];
|
||||
distance = MIN(MAX(distance, 0), 25);
|
||||
JxlEncoderSetFrameDistance(frame_settings, distance);
|
||||
if (distance == 0)
|
||||
JxlEncoderSetFrameLossless(frame_settings, JXL_TRUE);
|
||||
}
|
||||
if( params[i] == IMWRITE_JPEGXL_EFFORT )
|
||||
{
|
||||
int effort = params[i+1];
|
||||
effort = MIN(MAX(effort, 1), 10);
|
||||
JxlEncoderFrameSettingsSetOption(frame_settings, JXL_ENC_FRAME_SETTING_EFFORT, effort);
|
||||
}
|
||||
if( params[i] == IMWRITE_JPEGXL_DECODING_SPEED )
|
||||
{
|
||||
int speed = params[i+1];
|
||||
speed = MIN(MAX(speed, 0), 4);
|
||||
JxlEncoderFrameSettingsSetOption(frame_settings, JXL_ENC_FRAME_SETTING_DECODING_SPEED, speed);
|
||||
}
|
||||
}
|
||||
if (JXL_ENC_SUCCESS !=
|
||||
JxlEncoderAddImageFrame(frame_settings, &format,
|
||||
static_cast<const void*>(image.ptr<uint8_t>()),
|
||||
image.total() * image.elemSize())) {
|
||||
return false;
|
||||
}
|
||||
JxlEncoderCloseInput(encoder.get());
|
||||
|
||||
const size_t buffer_size = 16384; // 16KB chunks
|
||||
|
||||
std::vector<uint8_t> compressed(buffer_size);
|
||||
JxlEncoderStatus process_result = JXL_ENC_NEED_MORE_OUTPUT;
|
||||
while (process_result == JXL_ENC_NEED_MORE_OUTPUT) {
|
||||
uint8_t* next_out = compressed.data();
|
||||
size_t avail_out = buffer_size;
|
||||
process_result = JxlEncoderProcessOutput(encoder.get(), &next_out, &avail_out);
|
||||
if (JXL_ENC_ERROR == process_result)
|
||||
return false;
|
||||
const size_t write_size = buffer_size - avail_out;
|
||||
if ( strm.putBytes(compressed.data(), write_size) == false )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* End of file. */
|
||||
@@ -0,0 +1,68 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#ifndef _GRFMT_JPEGXL_H_
|
||||
#define _GRFMT_JPEGXL_H_
|
||||
|
||||
#ifdef HAVE_JPEGXL
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include <jxl/decode_cxx.h>
|
||||
#include <jxl/thread_parallel_runner_cxx.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
// Jpeg XL codec
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief JpegXL codec using libjxl library
|
||||
*/
|
||||
|
||||
class JpegXLDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
JpegXLDecoder();
|
||||
virtual ~JpegXLDecoder();
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
size_t signatureLength() const CV_OVERRIDE;
|
||||
bool checkSignature( const String& signature ) const CV_OVERRIDE;
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<FILE, int (*)(FILE*)> m_f;
|
||||
JxlDecoderPtr m_decoder;
|
||||
JxlThreadParallelRunnerPtr m_parallel_runner;
|
||||
JxlPixelFormat m_format;
|
||||
int m_convert;
|
||||
std::vector<uint8_t> m_read_buffer;
|
||||
JxlDecoderStatus m_status;
|
||||
|
||||
private:
|
||||
bool read(Mat* pimg);
|
||||
};
|
||||
|
||||
|
||||
class JpegXLEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
JpegXLEncoder();
|
||||
virtual ~JpegXLEncoder();
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif/*_GRFMT_JPEGXL_H_*/
|
||||
+1343
-98
File diff suppressed because it is too large
Load Diff
@@ -47,34 +47,161 @@
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
#include <png.h>
|
||||
#include <zlib.h>
|
||||
#include <vector>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
struct Chunk { std::vector<unsigned char> p; };
|
||||
struct OP { unsigned char* p; uint32_t size; int x, y, w, h, valid, filters; };
|
||||
|
||||
typedef struct {
|
||||
unsigned char r, g, b;
|
||||
} rgb;
|
||||
|
||||
class APNGFrame {
|
||||
public:
|
||||
|
||||
APNGFrame();
|
||||
|
||||
// Destructor
|
||||
~APNGFrame();
|
||||
|
||||
bool setMat(const cv::Mat& src, unsigned delayNum = 1, unsigned delayDen = 1000);
|
||||
|
||||
// Getters and Setters
|
||||
unsigned char* getPixels() const { return _pixels; }
|
||||
void setPixels(unsigned char* pixels);
|
||||
|
||||
unsigned int getWidth() const { return _width; }
|
||||
void setWidth(unsigned int width);
|
||||
|
||||
unsigned int getHeight() const { return _height; }
|
||||
void setHeight(unsigned int height);
|
||||
|
||||
unsigned char getColorType() const { return _colorType; }
|
||||
void setColorType(unsigned char colorType);
|
||||
|
||||
rgb* getPalette() { return _palette; }
|
||||
void setPalette(const rgb* palette);
|
||||
|
||||
unsigned char* getTransparency() { return _transparency; }
|
||||
void setTransparency(const unsigned char* transparency);
|
||||
|
||||
int getPaletteSize() const { return _paletteSize; }
|
||||
void setPaletteSize(int paletteSize);
|
||||
|
||||
int getTransparencySize() const { return _transparencySize; }
|
||||
void setTransparencySize(int transparencySize);
|
||||
|
||||
unsigned int getDelayNum() const { return _delayNum; }
|
||||
void setDelayNum(unsigned int delayNum);
|
||||
|
||||
unsigned int getDelayDen() const { return _delayDen; }
|
||||
void setDelayDen(unsigned int delayDen);
|
||||
|
||||
std::vector<png_bytep>& getRows() { return _rows; }
|
||||
|
||||
private:
|
||||
unsigned char* _pixels;
|
||||
unsigned int _width;
|
||||
unsigned int _height;
|
||||
unsigned char _colorType;
|
||||
rgb _palette[256];
|
||||
unsigned char _transparency[256];
|
||||
int _paletteSize;
|
||||
int _transparencySize;
|
||||
unsigned int _delayNum;
|
||||
unsigned int _delayDen;
|
||||
std::vector<png_bytep> _rows;
|
||||
};
|
||||
|
||||
class PngDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
PngDecoder();
|
||||
virtual ~PngDecoder();
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
bool nextPage() CV_OVERRIDE;
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
static void readDataFromBuf(void* png_ptr, uchar* dst, size_t size);
|
||||
static void info_fn(png_structp png_ptr, png_infop info_ptr);
|
||||
static void row_fn(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass);
|
||||
bool processing_start(void* frame_ptr, const Mat& img);
|
||||
bool processing_finish();
|
||||
void compose_frame(std::vector<png_bytep>& rows_dst, const std::vector<png_bytep>& rows_src, unsigned char bop, uint32_t x, uint32_t y, uint32_t w, uint32_t h, Mat& img);
|
||||
bool read_from_io(void* buffer, size_t num_bytes);
|
||||
uint32_t read_chunk(Chunk& chunk);
|
||||
|
||||
struct PngPtrs {
|
||||
public:
|
||||
PngPtrs() {
|
||||
png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
|
||||
if (png_ptr) {
|
||||
info_ptr = png_create_info_struct( png_ptr );
|
||||
end_info = png_create_info_struct( png_ptr );
|
||||
} else {
|
||||
info_ptr = end_info = nullptr;
|
||||
}
|
||||
}
|
||||
~PngPtrs() {
|
||||
clear();
|
||||
}
|
||||
PngPtrs& operator=(PngPtrs&& other) {
|
||||
clear();
|
||||
png_ptr = other.png_ptr;
|
||||
info_ptr = other.info_ptr;
|
||||
end_info = other.end_info;
|
||||
other.png_ptr = nullptr;
|
||||
other.info_ptr = other.end_info = nullptr;
|
||||
return *this;
|
||||
}
|
||||
void clear() {
|
||||
if (png_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
png_ptr = nullptr;
|
||||
info_ptr = end_info = nullptr;
|
||||
}
|
||||
}
|
||||
png_structp getPng() const { return png_ptr; }
|
||||
png_infop getInfo() const { return info_ptr; }
|
||||
png_infop getEndInfo() const { return end_info; }
|
||||
private:
|
||||
png_structp png_ptr; // pointer to decompression structure
|
||||
png_infop info_ptr; // pointer to image information structure
|
||||
png_infop end_info; // pointer to one more image information structure
|
||||
};
|
||||
|
||||
PngPtrs m_png_ptrs;
|
||||
int m_bit_depth;
|
||||
void* m_png_ptr; // pointer to decompression structure
|
||||
void* m_info_ptr; // pointer to image information structure
|
||||
void* m_end_info; // pointer to one more image information structure
|
||||
FILE* m_f;
|
||||
int m_color_type;
|
||||
Chunk m_chunkIHDR;
|
||||
int m_frame_no;
|
||||
size_t m_buf_pos;
|
||||
std::vector<Chunk> m_chunksInfo;
|
||||
APNGFrame frameRaw;
|
||||
APNGFrame frameNext;
|
||||
APNGFrame frameCur;
|
||||
Mat m_mat_raw;
|
||||
Mat m_mat_next;
|
||||
uint32_t w0;
|
||||
uint32_t h0;
|
||||
uint32_t x0;
|
||||
uint32_t y0;
|
||||
uint32_t delay_num;
|
||||
uint32_t delay_den;
|
||||
uint32_t dop;
|
||||
uint32_t bop;
|
||||
bool m_is_fcTL_loaded;
|
||||
bool m_is_IDAT_loaded;
|
||||
};
|
||||
|
||||
|
||||
@@ -84,14 +211,39 @@ public:
|
||||
PngEncoder();
|
||||
virtual ~PngEncoder();
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
bool writeanimation(const Animation& animinfo, const std::vector<int>& params) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
static void writeDataToBuf(void* png_ptr, uchar* src, size_t size);
|
||||
static void writeDataToBuf(void* png_ptr, unsigned char* src, size_t size);
|
||||
static void flushBuf(void* png_ptr);
|
||||
size_t write_to_io(void const* _Buffer, size_t _ElementSize, size_t _ElementCount, FILE* _Stream);
|
||||
|
||||
private:
|
||||
void writeChunk(FILE* f, const char* name, unsigned char* data, uint32_t length);
|
||||
void writeIDATs(FILE* f, int frame, unsigned char* data, uint32_t length, uint32_t idat_size);
|
||||
void processRect(unsigned char* row, int rowbytes, int bpp, int stride, int h, unsigned char* rows);
|
||||
void deflateRectFin(unsigned char* zbuf, uint32_t* zsize, int bpp, int stride, unsigned char* rows, int zbuf_size, int n);
|
||||
void deflateRectOp(unsigned char* pdata, int x, int y, int w, int h, int bpp, int stride, int zbuf_size, int n);
|
||||
bool getRect(uint32_t w, uint32_t h, unsigned char* pimage1, unsigned char* pimage2, unsigned char* ptemp, uint32_t bpp, uint32_t stride, int zbuf_size, uint32_t has_tcolor, uint32_t tcolor, int n);
|
||||
|
||||
AutoBuffer<unsigned char> op_zbuf1;
|
||||
AutoBuffer<unsigned char> op_zbuf2;
|
||||
AutoBuffer<unsigned char> row_buf;
|
||||
AutoBuffer<unsigned char> sub_row;
|
||||
AutoBuffer<unsigned char> up_row;
|
||||
AutoBuffer<unsigned char> avg_row;
|
||||
AutoBuffer<unsigned char> paeth_row;
|
||||
z_stream op_zstream1;
|
||||
z_stream op_zstream2;
|
||||
OP op[6];
|
||||
rgb palette[256];
|
||||
unsigned char trns[256];
|
||||
uint32_t palsize, trnssize;
|
||||
uint32_t next_seq_num;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -44,17 +44,15 @@
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <webp/decode.h>
|
||||
#include <webp/encode.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "grfmt_webp.hpp"
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
#include <webp/decode.h>
|
||||
#include <webp/encode.h>
|
||||
#include <webp/demux.h>
|
||||
#include <webp/mux.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
@@ -67,12 +65,18 @@ static const size_t WEBP_HEADER_SIZE = 32;
|
||||
WebPDecoder::WebPDecoder()
|
||||
{
|
||||
m_buf_supported = true;
|
||||
channels = 0;
|
||||
fs_size = 0;
|
||||
m_has_animation = false;
|
||||
m_previous_timestamp = 0;
|
||||
}
|
||||
|
||||
WebPDecoder::~WebPDecoder() {}
|
||||
|
||||
void WebPDecoder::UniquePtrDeleter::operator()(WebPAnimDecoder* decoder) const
|
||||
{
|
||||
WebPAnimDecoderDelete(decoder);
|
||||
}
|
||||
|
||||
size_t WebPDecoder::signatureLength() const
|
||||
{
|
||||
return WEBP_HEADER_SIZE;
|
||||
@@ -102,6 +106,11 @@ ImageDecoder WebPDecoder::newDecoder() const
|
||||
|
||||
bool WebPDecoder::readHeader()
|
||||
{
|
||||
if (m_has_animation)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t header[WEBP_HEADER_SIZE] = { 0 };
|
||||
if (m_buf.empty())
|
||||
{
|
||||
@@ -124,28 +133,49 @@ bool WebPDecoder::readHeader()
|
||||
}
|
||||
|
||||
WebPBitstreamFeatures features;
|
||||
if (VP8_STATUS_OK == WebPGetFeatures(header, sizeof(header), &features))
|
||||
if (VP8_STATUS_OK < WebPGetFeatures(header, sizeof(header), &features)) return false;
|
||||
|
||||
m_has_animation = features.has_animation == 1;
|
||||
|
||||
if (m_has_animation)
|
||||
{
|
||||
CV_CheckEQ(features.has_animation, 0, "WebP backend does not support animated webp images");
|
||||
|
||||
m_width = features.width;
|
||||
m_height = features.height;
|
||||
|
||||
if (features.has_alpha)
|
||||
if (m_buf.empty())
|
||||
{
|
||||
m_type = CV_8UC4;
|
||||
channels = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = CV_8UC3;
|
||||
channels = 3;
|
||||
fs.seekg(0, std::ios::beg); CV_Assert(fs && "File stream error");
|
||||
data.create(1, validateToInt(fs_size), CV_8UC1);
|
||||
fs.read((char*)data.ptr(), fs_size);
|
||||
CV_Assert(fs && "Can't read file data");
|
||||
fs.close();
|
||||
}
|
||||
|
||||
return true;
|
||||
CV_Assert(data.type() == CV_8UC1); CV_Assert(data.rows == 1);
|
||||
|
||||
WebPData webp_data;
|
||||
webp_data.bytes = (const uint8_t*)data.ptr();
|
||||
webp_data.size = data.total();
|
||||
|
||||
WebPAnimDecoderOptions dec_options;
|
||||
WebPAnimDecoderOptionsInit(&dec_options);
|
||||
|
||||
dec_options.color_mode = m_use_rgb ? MODE_RGBA : MODE_BGRA;
|
||||
anim_decoder.reset(WebPAnimDecoderNew(&webp_data, &dec_options));
|
||||
CV_Assert(anim_decoder.get() && "Error parsing image");
|
||||
|
||||
WebPAnimInfo anim_info;
|
||||
WebPAnimDecoderGetInfo(anim_decoder.get(), &anim_info);
|
||||
m_animation.loop_count = anim_info.loop_count;
|
||||
|
||||
m_animation.bgcolor[0] = (anim_info.bgcolor >> 24) & 0xFF;
|
||||
m_animation.bgcolor[1] = (anim_info.bgcolor >> 16) & 0xFF;
|
||||
m_animation.bgcolor[2] = (anim_info.bgcolor >> 8) & 0xFF;
|
||||
m_animation.bgcolor[3] = anim_info.bgcolor & 0xFF;
|
||||
m_frame_count = anim_info.frame_count;
|
||||
}
|
||||
m_width = features.width;
|
||||
m_height = features.height;
|
||||
m_type = features.has_alpha ? CV_8UC4 : CV_8UC3;
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebPDecoder::readData(Mat &img)
|
||||
@@ -155,7 +185,7 @@ bool WebPDecoder::readData(Mat &img)
|
||||
CV_CheckEQ(img.cols, m_width, "");
|
||||
CV_CheckEQ(img.rows, m_height, "");
|
||||
|
||||
if (m_buf.empty())
|
||||
if (data.empty())
|
||||
{
|
||||
fs.seekg(0, std::ios::beg); CV_Assert(fs && "File stream error");
|
||||
data.create(1, validateToInt(fs_size), CV_8UC1);
|
||||
@@ -165,70 +195,96 @@ bool WebPDecoder::readData(Mat &img)
|
||||
}
|
||||
CV_Assert(data.type() == CV_8UC1); CV_Assert(data.rows == 1);
|
||||
|
||||
Mat read_img;
|
||||
CV_CheckType(img.type(), img.type() == CV_8UC1 || img.type() == CV_8UC3 || img.type() == CV_8UC4, "");
|
||||
if (img.type() != m_type || img.cols != m_width || img.rows != m_height)
|
||||
{
|
||||
Mat read_img;
|
||||
CV_CheckType(img.type(), img.type() == CV_8UC1 || img.type() == CV_8UC3 || img.type() == CV_8UC4, "");
|
||||
if (img.type() != m_type)
|
||||
read_img.create(m_height, m_width, m_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
read_img = img; // copy header
|
||||
}
|
||||
|
||||
uchar* out_data = read_img.ptr();
|
||||
size_t out_data_size = read_img.dataend - out_data;
|
||||
|
||||
uchar* res_ptr = NULL;
|
||||
|
||||
if (m_has_animation)
|
||||
{
|
||||
uint8_t* buf;
|
||||
int timestamp;
|
||||
|
||||
WebPAnimDecoderGetNext(anim_decoder.get(), &buf, ×tamp);
|
||||
Mat tmp(Size(m_width, m_height), CV_8UC4, buf);
|
||||
|
||||
if (img.type() == CV_8UC1)
|
||||
{
|
||||
read_img.create(m_height, m_width, m_type);
|
||||
cvtColor(tmp, img, COLOR_BGR2GRAY);
|
||||
}
|
||||
else
|
||||
if (img.type() == CV_8UC3)
|
||||
{
|
||||
read_img = img; // copy header
|
||||
}
|
||||
|
||||
uchar* out_data = read_img.ptr();
|
||||
size_t out_data_size = read_img.dataend - out_data;
|
||||
|
||||
uchar *res_ptr = NULL;
|
||||
if (channels == 3)
|
||||
{
|
||||
CV_CheckTypeEQ(read_img.type(), CV_8UC3, "");
|
||||
if (m_use_rgb)
|
||||
res_ptr = WebPDecodeRGBInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
else
|
||||
res_ptr = WebPDecodeBGRInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
}
|
||||
else if (channels == 4)
|
||||
{
|
||||
CV_CheckTypeEQ(read_img.type(), CV_8UC4, "");
|
||||
if (m_use_rgb)
|
||||
res_ptr = WebPDecodeRGBAInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
else
|
||||
res_ptr = WebPDecodeBGRAInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
}
|
||||
|
||||
if (res_ptr != out_data)
|
||||
return false;
|
||||
|
||||
if (read_img.data == img.data && img.type() == m_type)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
else if (img.type() == CV_8UC1)
|
||||
{
|
||||
cvtColor(read_img, img, COLOR_BGR2GRAY);
|
||||
}
|
||||
else if (img.type() == CV_8UC3 && m_type == CV_8UC4)
|
||||
{
|
||||
cvtColor(read_img, img, COLOR_BGRA2BGR);
|
||||
}
|
||||
else if (img.type() == CV_8UC4 && m_type == CV_8UC3)
|
||||
{
|
||||
cvtColor(read_img, img, COLOR_BGR2BGRA);
|
||||
cvtColor(tmp, img, COLOR_BGRA2BGR);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
tmp.copyTo(img);
|
||||
|
||||
m_animation.durations.push_back(timestamp - m_previous_timestamp);
|
||||
m_previous_timestamp = timestamp;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_type == CV_8UC3)
|
||||
{
|
||||
CV_CheckTypeEQ(read_img.type(), CV_8UC3, "");
|
||||
if (m_use_rgb)
|
||||
res_ptr = WebPDecodeRGBInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
else
|
||||
res_ptr = WebPDecodeBGRInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
}
|
||||
else if (m_type == CV_8UC4)
|
||||
{
|
||||
CV_CheckTypeEQ(read_img.type(), CV_8UC4, "");
|
||||
if (m_use_rgb)
|
||||
res_ptr = WebPDecodeRGBAInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
else
|
||||
res_ptr = WebPDecodeBGRAInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
}
|
||||
|
||||
if (res_ptr != out_data)
|
||||
return false;
|
||||
|
||||
if (read_img.data == img.data && img.type() == m_type)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
else if (img.type() == CV_8UC1)
|
||||
{
|
||||
cvtColor(read_img, img, COLOR_BGR2GRAY);
|
||||
}
|
||||
else if (img.type() == CV_8UC3 && m_type == CV_8UC4)
|
||||
{
|
||||
cvtColor(read_img, img, COLOR_BGRA2BGR);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebPDecoder::nextPage()
|
||||
{
|
||||
// Prepare the next page, if any.
|
||||
return WebPAnimDecoderHasMoreFrames(anim_decoder.get()) > 0;
|
||||
}
|
||||
|
||||
WebPEncoder::WebPEncoder()
|
||||
{
|
||||
m_description = "WebP files (*.webp)";
|
||||
@@ -312,23 +368,138 @@ bool WebPEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
#endif
|
||||
|
||||
CV_Assert(size > 0);
|
||||
|
||||
size_t bytes_written = 0;
|
||||
if (m_buf)
|
||||
{
|
||||
m_buf->resize(size);
|
||||
memcpy(&(*m_buf)[0], out, size);
|
||||
bytes_written = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *fd = fopen(m_filename.c_str(), "wb");
|
||||
if (fd != NULL)
|
||||
{
|
||||
fwrite(out, size, sizeof(uint8_t), fd);
|
||||
bytes_written = fwrite(out, sizeof(uint8_t), size, fd);
|
||||
if (size != bytes_written)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("Only %zu or %zu bytes are written\n",bytes_written, size));
|
||||
}
|
||||
fclose(fd); fd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return size > 0;
|
||||
return (size > 0) && (bytes_written == size);
|
||||
}
|
||||
|
||||
bool WebPEncoder::writeanimation(const Animation& animation, const std::vector<int>& params)
|
||||
{
|
||||
CV_CheckDepthEQ(animation.frames[0].depth(), CV_8U, "WebP codec supports only 8-bit unsigned images");
|
||||
int ok = 0;
|
||||
int timestamp = 0;
|
||||
const int width = animation.frames[0].cols, height = animation.frames[0].rows;
|
||||
|
||||
WebPAnimEncoderOptions anim_config;
|
||||
WebPConfig config;
|
||||
WebPPicture pic;
|
||||
WebPData webp_data;
|
||||
|
||||
WebPDataInit(&webp_data);
|
||||
if (!WebPAnimEncoderOptionsInit(&anim_config) ||
|
||||
!WebPConfigInit(&config) ||
|
||||
!WebPPictureInit(&pic)) {
|
||||
CV_LOG_ERROR(NULL, "Library version mismatch!\n");
|
||||
WebPDataClear(&webp_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
int bgvalue = (static_cast<int>(animation.bgcolor[0]) & 0xFF) << 24 |
|
||||
(static_cast<int>(animation.bgcolor[1]) & 0xFF) << 16 |
|
||||
(static_cast<int>(animation.bgcolor[2]) & 0xFF) << 8 |
|
||||
(static_cast<int>(animation.bgcolor[3]) & 0xFF);
|
||||
|
||||
anim_config.anim_params.bgcolor = bgvalue;
|
||||
anim_config.anim_params.loop_count = animation.loop_count;
|
||||
|
||||
if (params.size() > 1)
|
||||
{
|
||||
if (params[0] == IMWRITE_WEBP_QUALITY)
|
||||
{
|
||||
config.lossless = 0;
|
||||
config.quality = static_cast<float>(params[1]);
|
||||
if (config.quality < 1.0f)
|
||||
{
|
||||
config.quality = 1.0f;
|
||||
}
|
||||
if (config.quality >= 100.0f)
|
||||
{
|
||||
config.lossless = 1;
|
||||
}
|
||||
}
|
||||
anim_config.minimize_size = 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<WebPAnimEncoder, void (*)(WebPAnimEncoder*)> anim_encoder(
|
||||
WebPAnimEncoderNew(width, height, &anim_config), WebPAnimEncoderDelete);
|
||||
|
||||
pic.width = width;
|
||||
pic.height = height;
|
||||
pic.use_argb = 1;
|
||||
pic.argb_stride = width;
|
||||
WebPEncode(&config, &pic);
|
||||
|
||||
bool is_input_rgba = animation.frames[0].channels() == 4;
|
||||
Size canvas_size = Size(animation.frames[0].cols,animation.frames[0].rows);
|
||||
|
||||
for (size_t i = 0; i < animation.frames.size(); i++)
|
||||
{
|
||||
Mat argb;
|
||||
CV_Assert(canvas_size == Size(animation.frames[i].cols,animation.frames[i].rows));
|
||||
if (is_input_rgba)
|
||||
pic.argb = (uint32_t*)animation.frames[i].data;
|
||||
else
|
||||
{
|
||||
cvtColor(animation.frames[i], argb, COLOR_BGR2BGRA);
|
||||
pic.argb = (uint32_t*)argb.data;
|
||||
}
|
||||
ok = WebPAnimEncoderAdd(anim_encoder.get(), &pic, timestamp, &config);
|
||||
timestamp += animation.durations[i];
|
||||
}
|
||||
|
||||
// add a last fake frame to signal the last duration
|
||||
ok = ok & WebPAnimEncoderAdd(anim_encoder.get(), NULL, timestamp, NULL);
|
||||
ok = ok & WebPAnimEncoderAssemble(anim_encoder.get(), &webp_data);
|
||||
|
||||
size_t bytes_written = 0;
|
||||
if (ok)
|
||||
{
|
||||
if (m_buf)
|
||||
{
|
||||
m_buf->resize(webp_data.size);
|
||||
memcpy(&(*m_buf)[0], webp_data.bytes, webp_data.size);
|
||||
bytes_written = webp_data.size;
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE* fd = fopen(m_filename.c_str(), "wb");
|
||||
if (fd != NULL)
|
||||
{
|
||||
bytes_written = fwrite(webp_data.bytes, sizeof(uint8_t), webp_data.size, fd);
|
||||
if (webp_data.size != bytes_written)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("Only %zu or %zu bytes are written\n",bytes_written, webp_data.size));
|
||||
}
|
||||
fclose(fd); fd = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool status = (ok > 0) && (webp_data.size == bytes_written);
|
||||
|
||||
// free resources
|
||||
WebPDataClear(&webp_data);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
struct WebPAnimDecoder;
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
@@ -61,6 +63,7 @@ public:
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
bool nextPage() CV_OVERRIDE;
|
||||
|
||||
size_t signatureLength() const CV_OVERRIDE;
|
||||
bool checkSignature( const String& signature) const CV_OVERRIDE;
|
||||
@@ -68,10 +71,16 @@ public:
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
struct UniquePtrDeleter {
|
||||
void operator()(WebPAnimDecoder* decoder) const;
|
||||
};
|
||||
|
||||
std::ifstream fs;
|
||||
size_t fs_size;
|
||||
Mat data;
|
||||
int channels;
|
||||
std::unique_ptr<WebPAnimDecoder, UniquePtrDeleter> anim_decoder;
|
||||
bool m_has_animation;
|
||||
int m_previous_timestamp;
|
||||
};
|
||||
|
||||
class WebPEncoder CV_FINAL : public BaseImageEncoder
|
||||
@@ -81,6 +90,7 @@ public:
|
||||
~WebPEncoder() CV_OVERRIDE;
|
||||
|
||||
bool write(const Mat& img, const std::vector<int>& params) CV_OVERRIDE;
|
||||
bool writeanimation(const Animation& animation, const std::vector<int>& params) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
@@ -45,8 +45,10 @@
|
||||
#include "grfmt_base.hpp"
|
||||
#include "grfmt_avif.hpp"
|
||||
#include "grfmt_bmp.hpp"
|
||||
#include "grfmt_gif.hpp"
|
||||
#include "grfmt_sunras.hpp"
|
||||
#include "grfmt_jpeg.hpp"
|
||||
#include "grfmt_jpegxl.hpp"
|
||||
#include "grfmt_pxm.hpp"
|
||||
#include "grfmt_pfm.hpp"
|
||||
#include "grfmt_tiff.hpp"
|
||||
|
||||
@@ -151,14 +151,18 @@ struct ImageCodecInitializer
|
||||
*/
|
||||
ImageCodecInitializer()
|
||||
{
|
||||
#ifdef HAVE_AVIF
|
||||
decoders.push_back(makePtr<AvifDecoder>());
|
||||
encoders.push_back(makePtr<AvifEncoder>());
|
||||
#endif
|
||||
/// BMP Support
|
||||
decoders.push_back( makePtr<BmpDecoder>() );
|
||||
encoders.push_back( makePtr<BmpEncoder>() );
|
||||
|
||||
#ifdef HAVE_IMGCODEC_GIF
|
||||
decoders.push_back( makePtr<GifDecoder>() );
|
||||
encoders.push_back( makePtr<GifEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_AVIF
|
||||
decoders.push_back(makePtr<AvifDecoder>());
|
||||
encoders.push_back(makePtr<AvifEncoder>());
|
||||
#endif
|
||||
#ifdef HAVE_IMGCODEC_HDR
|
||||
decoders.push_back( makePtr<HdrDecoder>() );
|
||||
encoders.push_back( makePtr<HdrEncoder>() );
|
||||
@@ -206,6 +210,10 @@ struct ImageCodecInitializer
|
||||
decoders.push_back( makePtr<Jpeg2KDecoder>() );
|
||||
encoders.push_back( makePtr<Jpeg2KEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_JPEGXL
|
||||
decoders.push_back( makePtr<JpegXLDecoder>() );
|
||||
encoders.push_back( makePtr<JpegXLEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_OPENJPEG
|
||||
decoders.push_back( makePtr<Jpeg2KJP2OpjDecoder>() );
|
||||
decoders.push_back( makePtr<Jpeg2KJ2KOpjDecoder>() );
|
||||
@@ -685,6 +693,117 @@ bool imreadmulti(const String& filename, std::vector<Mat>& mats, int start, int
|
||||
return imreadmulti_(filename, flags, mats, start, count);
|
||||
}
|
||||
|
||||
static bool
|
||||
imreadanimation_(const String& filename, int flags, int start, int count, Animation& animation)
|
||||
{
|
||||
bool success = false;
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
if (count < 0) {
|
||||
count = INT16_MAX;
|
||||
}
|
||||
|
||||
/// Search for the relevant decoder to handle the imagery
|
||||
ImageDecoder decoder;
|
||||
decoder = findDecoder(filename);
|
||||
|
||||
/// if no decoder was found, return false.
|
||||
if (!decoder) {
|
||||
CV_LOG_WARNING(NULL, "Decoder for " << filename << " not found!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// set the filename in the driver
|
||||
decoder->setSource(filename);
|
||||
// read the header to make sure it succeeds
|
||||
try
|
||||
{
|
||||
// read the header to make sure it succeeds
|
||||
if (!decoder->readHeader())
|
||||
return false;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "imreadanimation_('" << filename << "'): can't read header: " << e.what());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "imreadanimation_('" << filename << "'): can't read header: unknown exception");
|
||||
return false;
|
||||
}
|
||||
|
||||
int current = 0;
|
||||
int frame_count = (int)decoder->getFrameCount();
|
||||
count = count + start > frame_count ? frame_count - start : count;
|
||||
|
||||
uint64 pixels = (uint64)decoder->width() * (uint64)decoder->height() * (uint64)(count + 4);
|
||||
if (pixels > CV_IO_MAX_IMAGE_PIXELS) {
|
||||
CV_LOG_WARNING(NULL, "\nyou are trying to read " << pixels <<
|
||||
" bytes that exceed CV_IO_MAX_IMAGE_PIXELS.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (current < start + count)
|
||||
{
|
||||
// grab the decoded type
|
||||
const int type = calcType(decoder->type(), flags);
|
||||
|
||||
// established the required input image size
|
||||
Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
|
||||
|
||||
// read the image data
|
||||
Mat mat(size.height, size.width, type);
|
||||
success = false;
|
||||
try
|
||||
{
|
||||
if (decoder->readData(mat))
|
||||
success = true;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "imreadanimation_('" << filename << "'): can't read data: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "imreadanimation_('" << filename << "'): can't read data: unknown exception");
|
||||
}
|
||||
if (!success)
|
||||
break;
|
||||
|
||||
// optionally rotate the data if EXIF' orientation flag says so
|
||||
if ((flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED)
|
||||
{
|
||||
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
|
||||
}
|
||||
|
||||
if (current >= start)
|
||||
{
|
||||
int duration = decoder->animation().durations.size() > 0 ? decoder->animation().durations.back() : 1000;
|
||||
animation.durations.push_back(duration);
|
||||
animation.frames.push_back(mat);
|
||||
}
|
||||
|
||||
if (!decoder->nextPage())
|
||||
{
|
||||
break;
|
||||
}
|
||||
++current;
|
||||
}
|
||||
animation.bgcolor = decoder->animation().bgcolor;
|
||||
animation.loop_count = decoder->animation().loop_count;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool imreadanimation(const String& filename, CV_OUT Animation& animation, int start, int count)
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
return imreadanimation_(filename, IMREAD_UNCHANGED, start, count, animation);
|
||||
}
|
||||
|
||||
static
|
||||
size_t imcount_(const String& filename, int flags)
|
||||
{
|
||||
@@ -801,6 +920,55 @@ bool imwrite( const String& filename, InputArray _img,
|
||||
return imwrite_(filename, img_vec, params, false);
|
||||
}
|
||||
|
||||
static bool imwriteanimation_(const String& filename, const Animation& animation, const std::vector<int>& params)
|
||||
{
|
||||
ImageEncoder encoder = findEncoder(filename);
|
||||
if (!encoder)
|
||||
CV_Error(Error::StsError, "could not find a writer for the specified extension");
|
||||
|
||||
encoder->setDestination(filename);
|
||||
|
||||
bool code = false;
|
||||
try
|
||||
{
|
||||
code = encoder->writeanimation(animation, params);
|
||||
|
||||
if (!code)
|
||||
{
|
||||
FILE* f = fopen(filename.c_str(), "wb");
|
||||
if (!f)
|
||||
{
|
||||
if (errno == EACCES)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "imwriteanimation_('" << filename << "'): can't open file for writing: permission denied");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(f);
|
||||
remove(filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "imwriteanimation_('" << filename << "'): can't write data: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "imwriteanimation_('" << filename << "'): can't write data: unknown exception");
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
bool imwriteanimation(const String& filename, const Animation& animation, const std::vector<int>& params)
|
||||
{
|
||||
CV_Assert(!animation.frames.empty());
|
||||
CV_Assert(animation.frames.size() == animation.durations.size());
|
||||
return imwriteanimation_(filename, animation, params);
|
||||
}
|
||||
|
||||
static bool
|
||||
imdecode_( const Mat& buf, int flags, Mat& mat )
|
||||
{
|
||||
@@ -1427,6 +1595,13 @@ ImageCollection::iterator ImageCollection::iterator::operator++(int) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Animation::Animation(int loopCount, Scalar bgColor)
|
||||
: loop_count(loopCount), bgcolor(bgColor)
|
||||
{
|
||||
if (loopCount < 0 || loopCount > 0xffff)
|
||||
this->loop_count = 0; // loop_count should be non-negative
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
|
||||
@@ -137,7 +137,11 @@ uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette );
|
||||
|
||||
CV_INLINE bool isBigEndian( void )
|
||||
{
|
||||
return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,536 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
static void readFileBytes(const std::string& fname, std::vector<unsigned char>& buf)
|
||||
{
|
||||
FILE * wfile = fopen(fname.c_str(), "rb");
|
||||
if (wfile != NULL)
|
||||
{
|
||||
fseek(wfile, 0, SEEK_END);
|
||||
size_t wfile_size = ftell(wfile);
|
||||
fseek(wfile, 0, SEEK_SET);
|
||||
|
||||
buf.resize(wfile_size);
|
||||
|
||||
size_t data_size = fread(&buf[0], 1, wfile_size, wfile);
|
||||
|
||||
if(wfile)
|
||||
{
|
||||
fclose(wfile);
|
||||
}
|
||||
|
||||
EXPECT_EQ(data_size, wfile_size);
|
||||
}
|
||||
}
|
||||
|
||||
static bool fillFrames(Animation& animation, bool hasAlpha, int n = 14)
|
||||
{
|
||||
// Set the path to the test image directory and filename for loading.
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "pngsuite/tp1n3p08.png";
|
||||
|
||||
EXPECT_TRUE(imreadanimation(filename, animation));
|
||||
EXPECT_EQ(1000, animation.durations.back());
|
||||
|
||||
if (!hasAlpha)
|
||||
cvtColor(animation.frames[0], animation.frames[0], COLOR_BGRA2BGR);
|
||||
|
||||
animation.loop_count = 0xffff; // 0xffff is the maximum value to set.
|
||||
|
||||
// Add the first frame with a duration value of 400 milliseconds.
|
||||
int duration = 80;
|
||||
animation.durations[0] = duration * 5;
|
||||
Mat image = animation.frames[0].clone();
|
||||
putText(animation.frames[0], "0", Point(5, 28), FONT_HERSHEY_SIMPLEX, .5, Scalar(100, 255, 0, 255), 2);
|
||||
|
||||
// Define a region of interest (ROI)
|
||||
Rect roi(2, 16, 26, 16);
|
||||
|
||||
// Modify the ROI in n iterations to simulate slight changes in animation frames.
|
||||
for (int i = 1; i < n; i++)
|
||||
{
|
||||
roi.x++;
|
||||
roi.width -= 2;
|
||||
RNG rng = theRNG();
|
||||
for (int x = roi.x; x < roi.x + roi.width; x++)
|
||||
for (int y = roi.y; y < roi.y + roi.height; y++)
|
||||
{
|
||||
if (hasAlpha)
|
||||
{
|
||||
Vec4b& pixel = image.at<Vec4b>(y, x);
|
||||
if (pixel[3] > 0)
|
||||
{
|
||||
if (pixel[0] > 10) pixel[0] -= (uchar)rng.uniform(2, 5);
|
||||
if (pixel[1] > 10) pixel[1] -= (uchar)rng.uniform(2, 5);
|
||||
if (pixel[2] > 10) pixel[2] -= (uchar)rng.uniform(2, 5);
|
||||
pixel[3] -= (uchar)rng.uniform(2, 5);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vec3b& pixel = image.at<Vec3b>(y, x);
|
||||
if (pixel[0] > 50) pixel[0] -= (uchar)rng.uniform(2, 5);
|
||||
if (pixel[1] > 50) pixel[1] -= (uchar)rng.uniform(2, 5);
|
||||
if (pixel[2] > 50) pixel[2] -= (uchar)rng.uniform(2, 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the duration and add the modified frame to the animation.
|
||||
duration += rng.uniform(2, 10); // Increase duration with random value (to be sure different duration values saved correctly).
|
||||
animation.frames.push_back(image.clone());
|
||||
putText(animation.frames[i], format("%d", i), Point(5, 28), FONT_HERSHEY_SIMPLEX, .5, Scalar(100, 255, 0, 255), 2);
|
||||
animation.durations.push_back(duration);
|
||||
}
|
||||
|
||||
// Add two identical frames with the same duration.
|
||||
if (animation.frames.size() > 1 && animation.frames.size() < 20)
|
||||
{
|
||||
animation.durations.push_back(++duration);
|
||||
animation.frames.push_back(animation.frames.back());
|
||||
animation.durations.push_back(++duration);
|
||||
animation.frames.push_back(animation.frames.back());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IMGCODEC_GIF
|
||||
|
||||
TEST(Imgcodecs_Gif, imwriteanimation_rgba)
|
||||
{
|
||||
Animation s_animation, l_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true));
|
||||
s_animation.bgcolor = Scalar(0, 0, 0, 0); // TO DO not implemented yet.
|
||||
|
||||
// Create a temporary output filename for saving the animation.
|
||||
string output = cv::tempfile(".gif");
|
||||
|
||||
// Write the animation to a .webp file and verify success.
|
||||
EXPECT_TRUE(imwriteanimation(output, s_animation));
|
||||
|
||||
// Read the animation back and compare with the original.
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation));
|
||||
|
||||
size_t expected_frame_count = s_animation.frames.size();
|
||||
|
||||
// Verify that the number of frames matches the expected count.
|
||||
EXPECT_EQ(expected_frame_count, imcount(output));
|
||||
EXPECT_EQ(expected_frame_count, l_animation.frames.size());
|
||||
|
||||
// Check that the background color and loop count match between saved and loaded animations.
|
||||
EXPECT_EQ(l_animation.bgcolor, s_animation.bgcolor); // written as BGRA order
|
||||
EXPECT_EQ(l_animation.loop_count, s_animation.loop_count);
|
||||
|
||||
// Verify that the durations of frames match.
|
||||
for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
|
||||
EXPECT_EQ(cvRound(s_animation.durations[i] / 10), cvRound(l_animation.durations[i] / 10));
|
||||
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation, 5, 3));
|
||||
EXPECT_EQ(expected_frame_count + 3, l_animation.frames.size());
|
||||
EXPECT_EQ(l_animation.frames.size(), l_animation.durations.size());
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[5], l_animation.frames[16], NORM_INF));
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[6], l_animation.frames[17], NORM_INF));
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[7], l_animation.frames[18], NORM_INF));
|
||||
|
||||
// Verify whether the imread function successfully loads the first frame
|
||||
Mat frame = imread(output, IMREAD_UNCHANGED);
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[0], frame, NORM_INF));
|
||||
|
||||
std::vector<uchar> buf;
|
||||
readFileBytes(output, buf);
|
||||
vector<Mat> webp_frames;
|
||||
|
||||
EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, webp_frames));
|
||||
EXPECT_EQ(expected_frame_count, webp_frames.size());
|
||||
|
||||
// Clean up by removing the temporary file.
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
#endif // HAVE_IMGCODEC_GIF
|
||||
|
||||
#ifdef HAVE_WEBP
|
||||
|
||||
TEST(Imgcodecs_WebP, imwriteanimation_rgba)
|
||||
{
|
||||
Animation s_animation, l_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true));
|
||||
s_animation.bgcolor = Scalar(50, 100, 150, 128); // different values for test purpose.
|
||||
|
||||
// Create a temporary output filename for saving the animation.
|
||||
string output = cv::tempfile(".webp");
|
||||
|
||||
// Write the animation to a .webp file and verify success.
|
||||
EXPECT_TRUE(imwriteanimation(output, s_animation));
|
||||
|
||||
// Read the animation back and compare with the original.
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation));
|
||||
|
||||
// Since the last frames are identical, WebP optimizes by storing only one of them,
|
||||
// and the duration value for the last frame is handled by libwebp.
|
||||
size_t expected_frame_count = s_animation.frames.size() - 2;
|
||||
|
||||
// Verify that the number of frames matches the expected count.
|
||||
EXPECT_EQ(expected_frame_count, imcount(output));
|
||||
EXPECT_EQ(expected_frame_count, l_animation.frames.size());
|
||||
|
||||
// Check that the background color and loop count match between saved and loaded animations.
|
||||
EXPECT_EQ(l_animation.bgcolor, s_animation.bgcolor); // written as BGRA order
|
||||
EXPECT_EQ(l_animation.loop_count, s_animation.loop_count);
|
||||
|
||||
// Verify that the durations of frames match.
|
||||
for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
|
||||
EXPECT_EQ(s_animation.durations[i], l_animation.durations[i]);
|
||||
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation, 5, 3));
|
||||
EXPECT_EQ(expected_frame_count + 3, l_animation.frames.size());
|
||||
EXPECT_EQ(l_animation.frames.size(), l_animation.durations.size());
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[5], l_animation.frames[14], NORM_INF));
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[6], l_animation.frames[15], NORM_INF));
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[7], l_animation.frames[16], NORM_INF));
|
||||
|
||||
// Verify whether the imread function successfully loads the first frame
|
||||
Mat frame = imread(output, IMREAD_UNCHANGED);
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[0], frame, NORM_INF));
|
||||
|
||||
std::vector<uchar> buf;
|
||||
readFileBytes(output, buf);
|
||||
vector<Mat> webp_frames;
|
||||
|
||||
EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, webp_frames));
|
||||
EXPECT_EQ(expected_frame_count, webp_frames.size());
|
||||
|
||||
// Clean up by removing the temporary file.
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_WebP, imwriteanimation_rgb)
|
||||
{
|
||||
Animation s_animation, l_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, false));
|
||||
|
||||
// Create a temporary output filename for saving the animation.
|
||||
string output = cv::tempfile(".webp");
|
||||
|
||||
// Write the animation to a .webp file and verify success.
|
||||
EXPECT_TRUE(imwriteanimation(output, s_animation));
|
||||
|
||||
// Read the animation back and compare with the original.
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation));
|
||||
|
||||
// Since the last frames are identical, WebP optimizes by storing only one of them,
|
||||
// and the duration value for the last frame is handled by libwebp.
|
||||
size_t expected_frame_count = s_animation.frames.size() - 2;
|
||||
|
||||
// Verify that the number of frames matches the expected count.
|
||||
EXPECT_EQ(expected_frame_count, imcount(output));
|
||||
EXPECT_EQ(expected_frame_count, l_animation.frames.size());
|
||||
|
||||
// Verify that the durations of frames match.
|
||||
for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
|
||||
EXPECT_EQ(s_animation.durations[i], l_animation.durations[i]);
|
||||
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation, 5, 3));
|
||||
EXPECT_EQ(expected_frame_count + 3, l_animation.frames.size());
|
||||
EXPECT_EQ(l_animation.frames.size(), l_animation.durations.size());
|
||||
EXPECT_TRUE(cvtest::norm(l_animation.frames[5], l_animation.frames[14], NORM_INF) == 0);
|
||||
EXPECT_TRUE(cvtest::norm(l_animation.frames[6], l_animation.frames[15], NORM_INF) == 0);
|
||||
EXPECT_TRUE(cvtest::norm(l_animation.frames[7], l_animation.frames[16], NORM_INF) == 0);
|
||||
|
||||
// Verify whether the imread function successfully loads the first frame
|
||||
Mat frame = imread(output, IMREAD_COLOR);
|
||||
EXPECT_TRUE(cvtest::norm(l_animation.frames[0], frame, NORM_INF) == 0);
|
||||
|
||||
std::vector<uchar> buf;
|
||||
readFileBytes(output, buf);
|
||||
|
||||
vector<Mat> webp_frames;
|
||||
EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, webp_frames));
|
||||
EXPECT_EQ(expected_frame_count,webp_frames.size());
|
||||
|
||||
// Clean up by removing the temporary file.
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_WebP, imwritemulti_rgba)
|
||||
{
|
||||
Animation s_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true));
|
||||
|
||||
string output = cv::tempfile(".webp");
|
||||
ASSERT_TRUE(imwrite(output, s_animation.frames));
|
||||
vector<Mat> read_frames;
|
||||
ASSERT_TRUE(imreadmulti(output, read_frames, IMREAD_UNCHANGED));
|
||||
EXPECT_EQ(s_animation.frames.size() - 2, read_frames.size());
|
||||
EXPECT_EQ(4, s_animation.frames[0].channels());
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_WebP, imwritemulti_rgb)
|
||||
{
|
||||
Animation s_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, false));
|
||||
|
||||
string output = cv::tempfile(".webp");
|
||||
ASSERT_TRUE(imwrite(output, s_animation.frames));
|
||||
vector<Mat> read_frames;
|
||||
ASSERT_TRUE(imreadmulti(output, read_frames));
|
||||
EXPECT_EQ(s_animation.frames.size() - 2, read_frames.size());
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_WebP, imencode_rgba)
|
||||
{
|
||||
Animation s_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true, 3));
|
||||
|
||||
std::vector<uchar> buf;
|
||||
vector<Mat> apng_frames;
|
||||
|
||||
// Test encoding and decoding the images in memory (without saving to disk).
|
||||
EXPECT_TRUE(imencode(".webp", s_animation.frames, buf));
|
||||
EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, apng_frames));
|
||||
EXPECT_EQ(s_animation.frames.size() - 2, apng_frames.size());
|
||||
}
|
||||
|
||||
#endif // HAVE_WEBP
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
|
||||
TEST(Imgcodecs_APNG, imwriteanimation_rgba)
|
||||
{
|
||||
Animation s_animation, l_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true));
|
||||
|
||||
// Create a temporary output filename for saving the animation.
|
||||
string output = cv::tempfile(".png");
|
||||
|
||||
// Write the animation to a .png file and verify success.
|
||||
EXPECT_TRUE(imwriteanimation(output, s_animation));
|
||||
|
||||
// Read the animation back and compare with the original.
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation));
|
||||
|
||||
size_t expected_frame_count = s_animation.frames.size() - 2;
|
||||
|
||||
// Verify that the number of frames matches the expected count.
|
||||
EXPECT_EQ(expected_frame_count, imcount(output));
|
||||
EXPECT_EQ(expected_frame_count, l_animation.frames.size());
|
||||
|
||||
for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
|
||||
{
|
||||
EXPECT_EQ(s_animation.durations[i], l_animation.durations[i]);
|
||||
EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], l_animation.frames[i], NORM_INF));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation, 5, 3));
|
||||
EXPECT_EQ(expected_frame_count + 3, l_animation.frames.size());
|
||||
EXPECT_EQ(l_animation.frames.size(), l_animation.durations.size());
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[5], l_animation.frames[14], NORM_INF));
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[6], l_animation.frames[15], NORM_INF));
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[7], l_animation.frames[16], NORM_INF));
|
||||
|
||||
// Verify whether the imread function successfully loads the first frame
|
||||
Mat frame = imread(output, IMREAD_UNCHANGED);
|
||||
EXPECT_EQ(0, cvtest::norm(l_animation.frames[0], frame, NORM_INF));
|
||||
|
||||
std::vector<uchar> buf;
|
||||
readFileBytes(output, buf);
|
||||
vector<Mat> apng_frames;
|
||||
|
||||
EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, apng_frames));
|
||||
EXPECT_EQ(expected_frame_count, apng_frames.size());
|
||||
|
||||
apng_frames.clear();
|
||||
// Test saving the animation frames as individual still images.
|
||||
EXPECT_TRUE(imwrite(output, s_animation.frames));
|
||||
|
||||
// Read back the still images into a vector of Mats.
|
||||
EXPECT_TRUE(imreadmulti(output, apng_frames));
|
||||
|
||||
// Expect all frames written as multi-page image
|
||||
EXPECT_EQ(expected_frame_count, apng_frames.size());
|
||||
|
||||
// Clean up by removing the temporary file.
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_APNG, imwriteanimation_rgba16u)
|
||||
{
|
||||
Animation s_animation, l_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true));
|
||||
|
||||
for (size_t i = 0; i < s_animation.frames.size(); i++)
|
||||
{
|
||||
s_animation.frames[i].convertTo(s_animation.frames[i], CV_16U, 255);
|
||||
}
|
||||
// Create a temporary output filename for saving the animation.
|
||||
string output = cv::tempfile(".png");
|
||||
|
||||
// Write the animation to a .png file and verify success.
|
||||
EXPECT_TRUE(imwriteanimation(output, s_animation));
|
||||
|
||||
// Read the animation back and compare with the original.
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation));
|
||||
|
||||
size_t expected_frame_count = s_animation.frames.size() - 2;
|
||||
|
||||
// Verify that the number of frames matches the expected count.
|
||||
EXPECT_EQ(expected_frame_count, imcount(output));
|
||||
EXPECT_EQ(expected_frame_count, l_animation.frames.size());
|
||||
|
||||
std::vector<uchar> buf;
|
||||
readFileBytes(output, buf);
|
||||
vector<Mat> apng_frames;
|
||||
|
||||
EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, apng_frames));
|
||||
EXPECT_EQ(expected_frame_count, apng_frames.size());
|
||||
|
||||
apng_frames.clear();
|
||||
// Test saving the animation frames as individual still images.
|
||||
EXPECT_TRUE(imwrite(output, s_animation.frames));
|
||||
|
||||
// Read back the still images into a vector of Mats.
|
||||
EXPECT_TRUE(imreadmulti(output, apng_frames));
|
||||
|
||||
// Expect all frames written as multi-page image
|
||||
EXPECT_EQ(expected_frame_count, apng_frames.size());
|
||||
|
||||
// Clean up by removing the temporary file.
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_APNG, imwriteanimation_rgb)
|
||||
{
|
||||
Animation s_animation, l_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, false));
|
||||
|
||||
string output = cv::tempfile(".png");
|
||||
|
||||
// Write the animation to a .png file and verify success.
|
||||
EXPECT_TRUE(imwriteanimation(output, s_animation));
|
||||
|
||||
// Read the animation back and compare with the original.
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation));
|
||||
EXPECT_EQ(l_animation.frames.size(), s_animation.frames.size() - 2);
|
||||
for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
|
||||
{
|
||||
EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], l_animation.frames[i], NORM_INF));
|
||||
}
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_APNG, imwritemulti_rgba)
|
||||
{
|
||||
Animation s_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true));
|
||||
|
||||
string output = cv::tempfile(".png");
|
||||
EXPECT_EQ(true, imwrite(output, s_animation.frames));
|
||||
vector<Mat> read_frames;
|
||||
EXPECT_EQ(true, imreadmulti(output, read_frames, IMREAD_UNCHANGED));
|
||||
EXPECT_EQ(read_frames.size(), s_animation.frames.size() - 2);
|
||||
EXPECT_EQ(imcount(output), read_frames.size());
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_APNG, imwritemulti_rgb)
|
||||
{
|
||||
Animation s_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, false));
|
||||
|
||||
string output = cv::tempfile(".png");
|
||||
ASSERT_TRUE(imwrite(output, s_animation.frames));
|
||||
vector<Mat> read_frames;
|
||||
ASSERT_TRUE(imreadmulti(output, read_frames));
|
||||
EXPECT_EQ(read_frames.size(), s_animation.frames.size() - 2);
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
|
||||
for (size_t i = 0; i < read_frames.size(); i++)
|
||||
{
|
||||
EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], read_frames[i], NORM_INF));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_APNG, imwritemulti_gray)
|
||||
{
|
||||
Animation s_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, false));
|
||||
|
||||
for (size_t i = 0; i < s_animation.frames.size(); i++)
|
||||
{
|
||||
cvtColor(s_animation.frames[i], s_animation.frames[i], COLOR_BGR2GRAY);
|
||||
}
|
||||
|
||||
string output = cv::tempfile(".png");
|
||||
EXPECT_TRUE(imwrite(output, s_animation.frames));
|
||||
vector<Mat> read_frames;
|
||||
EXPECT_TRUE(imreadmulti(output, read_frames));
|
||||
EXPECT_EQ(1, read_frames[0].channels());
|
||||
read_frames.clear();
|
||||
EXPECT_TRUE(imreadmulti(output, read_frames, IMREAD_UNCHANGED));
|
||||
EXPECT_EQ(1, read_frames[0].channels());
|
||||
read_frames.clear();
|
||||
EXPECT_TRUE(imreadmulti(output, read_frames, IMREAD_COLOR));
|
||||
EXPECT_EQ(3, read_frames[0].channels());
|
||||
read_frames.clear();
|
||||
EXPECT_TRUE(imreadmulti(output, read_frames, IMREAD_GRAYSCALE));
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
|
||||
for (size_t i = 0; i < read_frames.size(); i++)
|
||||
{
|
||||
EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], read_frames[i], NORM_INF));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_APNG, imwriteanimation_bgcolor)
|
||||
{
|
||||
Animation s_animation, l_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true, 2));
|
||||
s_animation.bgcolor = Scalar(50, 100, 150, 128); // different values for test purpose.
|
||||
|
||||
// Create a temporary output filename for saving the animation.
|
||||
string output = cv::tempfile(".png");
|
||||
|
||||
// Write the animation to a .png file and verify success.
|
||||
EXPECT_TRUE(imwriteanimation(output, s_animation));
|
||||
|
||||
// Read the animation back and compare with the original.
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation));
|
||||
|
||||
// Check that the background color match between saved and loaded animations.
|
||||
EXPECT_EQ(l_animation.bgcolor, s_animation.bgcolor);
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
|
||||
EXPECT_TRUE(fillFrames(s_animation, true, 2));
|
||||
s_animation.bgcolor = Scalar();
|
||||
|
||||
output = cv::tempfile(".png");
|
||||
EXPECT_TRUE(imwriteanimation(output, s_animation));
|
||||
EXPECT_TRUE(imreadanimation(output, l_animation));
|
||||
EXPECT_EQ(l_animation.bgcolor, s_animation.bgcolor);
|
||||
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_APNG, imencode_rgba)
|
||||
{
|
||||
Animation s_animation;
|
||||
EXPECT_TRUE(fillFrames(s_animation, true, 3));
|
||||
|
||||
std::vector<uchar> buf;
|
||||
vector<Mat> read_frames;
|
||||
// Test encoding and decoding the images in memory (without saving to disk).
|
||||
EXPECT_TRUE(imencode(".png", s_animation.frames, buf));
|
||||
EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, read_frames));
|
||||
EXPECT_EQ(read_frames.size(), s_animation.frames.size() - 2);
|
||||
}
|
||||
|
||||
#endif // HAVE_PNG
|
||||
|
||||
}} // namespace
|
||||
@@ -2,6 +2,9 @@
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level
|
||||
// directory of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
@@ -110,7 +113,7 @@ TEST_P(Exif, exif_orientation)
|
||||
}
|
||||
}
|
||||
|
||||
const string exif_files[] =
|
||||
const std::vector<std::string> exif_files
|
||||
{
|
||||
#ifdef HAVE_JPEG
|
||||
"readwrite/testExifOrientation_1.jpg",
|
||||
|
||||
@@ -35,7 +35,8 @@ TEST(Imgcodecs_EXR, readWrite_32FC1)
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
// Check generated file size to ensure that it's compressed with proper options
|
||||
ASSERT_EQ(396u, getFileSize(filenameOutput));
|
||||
ASSERT_LE(396u, getFileSize(filenameOutput)); // OpenEXR 2
|
||||
ASSERT_LE( getFileSize(filenameOutput), 440u); // OpenEXR 3.2+
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
@@ -199,7 +200,11 @@ TEST(Imgcodecs_EXR, read_YC_changeDepth)
|
||||
|
||||
cvtColor(img_rgb, img_rgb, COLOR_RGB2BGR);
|
||||
|
||||
EXPECT_TRUE(cvtest::norm(img, img_rgb, NORM_INF) == 0);
|
||||
// See https://github.com/opencv/opencv/issues/26705
|
||||
// If ALGO_HINT_ACCURATE is set, norm should be 0.
|
||||
// If ALGO_HINT_APPROX is set, norm should be 1(or 0).
|
||||
EXPECT_LE(cvtest::norm(img, img_rgb, NORM_INF),
|
||||
(cv::getDefaultAlgorithmHint() == ALGO_HINT_ACCURATE)?0:1);
|
||||
|
||||
// Cannot test writing, EXR encoder doesn't support 8U depth
|
||||
}
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
#ifdef HAVE_IMGCODEC_GIF
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
const string gifsuite_files_multi[]={
|
||||
"basi3p01",
|
||||
"basi3p02",
|
||||
"basi3p04",
|
||||
"basn3p01",
|
||||
"basn3p02",
|
||||
"basn3p04",
|
||||
"ccwn3p08",
|
||||
"ch1n3p04",
|
||||
"cs3n3p08",
|
||||
"cs5n3p08",
|
||||
"cs8n3p08",
|
||||
"g03n3p04",
|
||||
"g04n3p04",
|
||||
"g05n3p04",
|
||||
"g07n3p04",
|
||||
"g10n3p04",
|
||||
"g25n3p04",
|
||||
"s32i3p04",
|
||||
"s32n3p04",
|
||||
"tp0n3p08",
|
||||
};
|
||||
|
||||
const string gifsuite_files_read_single[] = {
|
||||
"basi3p01",
|
||||
"basi3p02",
|
||||
"basi3p04",
|
||||
"basn3p01",
|
||||
"basn3p02",
|
||||
"basn3p04",
|
||||
"ccwn3p08",
|
||||
"cdfn2c08",
|
||||
"cdhn2c08",
|
||||
"cdsn2c08",
|
||||
"cdun2c08",
|
||||
"ch1n3p04",
|
||||
"cs3n3p08",
|
||||
"cs5n2c08",
|
||||
"cs5n3p08",
|
||||
"cs8n2c08",
|
||||
"cs8n3p08",
|
||||
"exif2c08",
|
||||
"g03n2c08",
|
||||
"g03n3p04",
|
||||
"g04n2c08",
|
||||
"g04n3p04",
|
||||
"g05n2c08",
|
||||
"g05n3p04",
|
||||
"g07n2c08",
|
||||
"g07n3p04",
|
||||
"g10n2c08",
|
||||
"g10n3p04"
|
||||
};
|
||||
|
||||
const string gifsuite_files_read_write_suite[]={
|
||||
"g25n2c08",
|
||||
"g25n3p04",
|
||||
"s01i3p01",
|
||||
"s01n3p01",
|
||||
"s02i3p01",
|
||||
"s02n3p01",
|
||||
"s03i3p01",
|
||||
"s03n3p01",
|
||||
"s04i3p01",
|
||||
"s04n3p01",
|
||||
"s05i3p02",
|
||||
"s05n3p02",
|
||||
"s06i3p02",
|
||||
"s06n3p02",
|
||||
"s07i3p02",
|
||||
"s07n3p02",
|
||||
"s08i3p02",
|
||||
"s08n3p02",
|
||||
"s09i3p02",
|
||||
"s09n3p02",
|
||||
"s32i3p04",
|
||||
"s32n3p04",
|
||||
"s33i3p04",
|
||||
"s33n3p04",
|
||||
"s34i3p04",
|
||||
"s34n3p04",
|
||||
"s35i3p04",
|
||||
"s35n3p04",
|
||||
"s36i3p04",
|
||||
"s36n3p04",
|
||||
"s37i3p04",
|
||||
"s37n3p04",
|
||||
"s38i3p04",
|
||||
"s38n3p04",
|
||||
"s39i3p04",
|
||||
"s39n3p04",
|
||||
"s40i3p04",
|
||||
"s40n3p04",
|
||||
"tp0n3p08",
|
||||
};
|
||||
|
||||
const std::pair<string,int> gifsuite_files_bgra[]={
|
||||
make_pair("gif_bgra1",53287),
|
||||
make_pair("gif_bgra2",52651),
|
||||
make_pair("gif_bgra3",54809),
|
||||
make_pair("gif_bgra4",57562),
|
||||
make_pair("gif_bgra5",56733),
|
||||
make_pair("gif_bgra6",52110),
|
||||
};
|
||||
|
||||
TEST(Imgcodecs_Gif, read_gif_multi)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "gifsuite/gif_multi.gif";
|
||||
vector<cv::Mat> img_vec_8UC4;
|
||||
ASSERT_NO_THROW(cv::imreadmulti(filename, img_vec_8UC4,0,20,IMREAD_UNCHANGED));
|
||||
EXPECT_EQ(img_vec_8UC4.size(), imcount(filename));
|
||||
vector<cv::Mat> img_vec_8UC3;
|
||||
for(const auto & i : img_vec_8UC4){
|
||||
cv::Mat img_tmp;
|
||||
cvtColor(i,img_tmp,COLOR_BGRA2BGR);
|
||||
img_vec_8UC3.push_back(img_tmp);
|
||||
}
|
||||
const long unsigned int expected_size=20;
|
||||
EXPECT_EQ(img_vec_8UC3.size(),expected_size);
|
||||
for(long unsigned int i=0;i<img_vec_8UC3.size();i++){
|
||||
cv::Mat img=img_vec_8UC3[i];
|
||||
const string png_filename = root + "pngsuite/" + gifsuite_files_multi[i] + ".png";
|
||||
cv::Mat img_png;
|
||||
ASSERT_NO_THROW(img_png = imread(png_filename,IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img_png.empty());
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_png);
|
||||
}
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Gif_GifSuite_SingleFrame;
|
||||
|
||||
TEST_P(Imgcodecs_Gif_GifSuite_SingleFrame, read_gif_single)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "gifsuite/" + GetParam() + ".gif";
|
||||
const string png_filename=root + "pngsuite/" + GetParam() + ".png";
|
||||
const long unsigned int expected_size = 1;
|
||||
|
||||
EXPECT_EQ(expected_size, imcount(filename));
|
||||
cv::Mat img_8UC4;
|
||||
ASSERT_NO_THROW(img_8UC4 = cv::imread(filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img_8UC4.empty());
|
||||
cv::Mat img_8UC3;
|
||||
ASSERT_NO_THROW(cvtColor(img_8UC4, img_8UC3, COLOR_BGRA2BGR));
|
||||
cv::Mat img_png;
|
||||
ASSERT_NO_THROW(img_png = cv::imread(png_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img_png.empty());
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img_8UC3, img_png);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Gif_GifSuite_SingleFrame,
|
||||
testing::ValuesIn(gifsuite_files_read_single));
|
||||
|
||||
TEST(Imgcodecs_Gif, read_gif_big){
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string gif_filename = root + "gifsuite/gif_big.gif";
|
||||
const string png_filename = root + "gifsuite/gif_big.png";
|
||||
cv::Mat img_8UC4;
|
||||
ASSERT_NO_THROW(img_8UC4 = imread(gif_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img_8UC4.empty());
|
||||
cv::Mat img_8UC3;
|
||||
const int expected_col=1303;
|
||||
const int expected_row=1391;
|
||||
EXPECT_EQ(expected_col, img_8UC4.cols);
|
||||
EXPECT_EQ(expected_row, img_8UC4.rows);
|
||||
ASSERT_NO_THROW(cvtColor(img_8UC4, img_8UC3,COLOR_BGRA2BGR));
|
||||
EXPECT_EQ(expected_col, img_8UC3.cols);
|
||||
EXPECT_EQ(expected_row, img_8UC3.rows);
|
||||
cv::Mat img_png;
|
||||
ASSERT_NO_THROW(img_png=imread(png_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img_png.empty());
|
||||
cv::Mat img_png_8UC3;
|
||||
ASSERT_NO_THROW(cvtColor(img_png,img_png_8UC3, COLOR_BGRA2BGR));
|
||||
EXPECT_EQ(img_8UC3.size, img_png_8UC3.size);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img_8UC3, img_png_8UC3);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<std::pair<string,int>> Imgcodecs_Gif_GifSuite_SingleFrame_BGRA;
|
||||
|
||||
TEST_P(Imgcodecs_Gif_GifSuite_SingleFrame_BGRA, read_gif_single_bgra){
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string gif_filename = root + "gifsuite/" + GetParam().first + ".gif";
|
||||
const string png_filename = root + "gifsuite/" + GetParam().first + ".png";
|
||||
cv::Mat gif_img;
|
||||
cv::Mat png_img;
|
||||
ASSERT_NO_THROW(gif_img = cv::imread(gif_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(gif_img.empty());
|
||||
ASSERT_NO_THROW(png_img = cv::imread(png_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(png_img.empty());
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), gif_img, png_img);
|
||||
int transparent_count = 0;
|
||||
for(int i=0; i<gif_img.rows; i++){
|
||||
for(int j=0; j<gif_img.cols; j++){
|
||||
cv::Vec4b pixel1 = gif_img.at<cv::Vec4b>(i,j);
|
||||
if((int)(pixel1[3]) == 0){
|
||||
transparent_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(transparent_count,GetParam().second);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Gif_GifSuite_SingleFrame_BGRA ,
|
||||
testing::ValuesIn(gifsuite_files_bgra));
|
||||
|
||||
TEST(Imgcodecs_Gif,read_gif_multi_bgra){
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string gif_filename = root + "gifsuite/gif_multi_bgra.gif";
|
||||
vector<cv::Mat> img_vec;
|
||||
ASSERT_NO_THROW(cv::imreadmulti(gif_filename, img_vec, IMREAD_UNCHANGED));
|
||||
EXPECT_EQ(imcount(gif_filename), img_vec.size());
|
||||
const int fixed_transparent_count = 53211;
|
||||
for(auto & frame_count : img_vec){
|
||||
int transparent_count=0;
|
||||
for(int i=0; i<frame_count.rows; i++){
|
||||
for(int j=0; j<frame_count.cols; j++){
|
||||
cv::Vec4b pixel1 = frame_count.at<cv::Vec4b>(i,j);
|
||||
if((int)(pixel1[3]) == 0){
|
||||
transparent_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(fixed_transparent_count,transparent_count);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Gif, read_gif_special){
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string gif_filename1 = root + "gifsuite/special1.gif";
|
||||
const string png_filename1 = root + "gifsuite/special1.png";
|
||||
const string gif_filename2 = root + "gifsuite/special2.gif";
|
||||
const string png_filename2 = root + "gifsuite/special2.png";
|
||||
cv::Mat gif_img1;
|
||||
ASSERT_NO_THROW(gif_img1 = cv::imread(gif_filename1,IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(gif_img1.empty());
|
||||
cv::Mat png_img1;
|
||||
ASSERT_NO_THROW(png_img1 = cv::imread(png_filename1,IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(png_img1.empty());
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), gif_img1, png_img1);
|
||||
cv::Mat gif_img2;
|
||||
ASSERT_NO_THROW(gif_img2 = cv::imread(gif_filename2,IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(gif_img2.empty());
|
||||
cv::Mat png_img2;
|
||||
ASSERT_NO_THROW(png_img2 = cv::imread(png_filename2,IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(png_img2.empty());
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), gif_img2, png_img2);
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Gif,write_gif_flags){
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string png_filename = root + "gifsuite/special1.png";
|
||||
vector<uchar> buff;
|
||||
const int expected_rows=611;
|
||||
const int expected_cols=293;
|
||||
Mat img_gt = Mat::ones(expected_rows, expected_cols, CV_8UC1);
|
||||
vector<int> param;
|
||||
param.push_back(IMWRITE_GIF_QUALITY);
|
||||
param.push_back(7);
|
||||
param.push_back(IMWRITE_GIF_DITHER);
|
||||
param.push_back(2);
|
||||
EXPECT_NO_THROW(imencode(".png", img_gt, buff, param));
|
||||
Mat img;
|
||||
EXPECT_NO_THROW(img = imdecode(buff, IMREAD_ANYDEPTH)); // hang
|
||||
EXPECT_FALSE(img.empty());
|
||||
EXPECT_EQ(img.cols, expected_cols);
|
||||
EXPECT_EQ(img.rows, expected_rows);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_gt);
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Gif, write_gif_big) {
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string png_filename = root + "gifsuite/gif_big.png";
|
||||
const string gif_filename = cv::tempfile(".png");
|
||||
cv::Mat img;
|
||||
ASSERT_NO_THROW(img = cv::imread(png_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(1303, img.cols);
|
||||
EXPECT_EQ(1391, img.rows);
|
||||
ASSERT_NO_THROW(imwrite(gif_filename, img));
|
||||
cv::Mat img_gif;
|
||||
ASSERT_NO_THROW(img_gif = cv::imread(gif_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img_gif.empty());
|
||||
EXPECT_EQ(1303, img_gif.cols);
|
||||
EXPECT_EQ(1391, img_gif.rows);
|
||||
EXPECT_EQ(0, remove(gif_filename.c_str()));
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Gif_GifSuite_Read_Write_Suite;
|
||||
|
||||
TEST_P(Imgcodecs_Gif_GifSuite_Read_Write_Suite ,read_gif_single)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string png_filename = root + "pngsuite/"+GetParam()+".png";
|
||||
const string gif_filename = cv::tempfile(".gif");
|
||||
cv::Mat img;
|
||||
ASSERT_NO_THROW(img = cv::imread(png_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img.empty());
|
||||
vector<int> param;
|
||||
param.push_back(IMWRITE_GIF_QUALITY);
|
||||
param.push_back(8);
|
||||
param.push_back(IMWRITE_GIF_DITHER);
|
||||
param.push_back(3);
|
||||
ASSERT_NO_THROW(imwrite(gif_filename, img, param));
|
||||
cv::Mat img_gif;
|
||||
ASSERT_NO_THROW(img_gif = cv::imread(gif_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img_gif.empty());
|
||||
cv::Mat img_8UC3;
|
||||
ASSERT_NO_THROW(cv::cvtColor(img_gif, img_8UC3, COLOR_BGRA2BGR));
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(29, 0), img, img_8UC3);
|
||||
EXPECT_EQ(0, remove(gif_filename.c_str()));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Gif_GifSuite_Read_Write_Suite ,
|
||||
testing::ValuesIn(gifsuite_files_read_write_suite));
|
||||
|
||||
TEST(Imgcodecs_Gif, write_gif_multi) {
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string gif_filename = cv::tempfile(".gif");
|
||||
vector<cv::Mat> img_vec;
|
||||
for (long unsigned int i = 0; i < 20; i++) {
|
||||
const string png_filename = root + "pngsuite/" + gifsuite_files_multi[i] + ".png";
|
||||
cv::Mat img;
|
||||
ASSERT_NO_THROW(img = cv::imread(png_filename, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(img.empty());
|
||||
img_vec.push_back(img);
|
||||
}
|
||||
vector<int> param;
|
||||
param.push_back(IMWRITE_GIF_QUALITY);
|
||||
param.push_back(8);
|
||||
param.push_back(IMWRITE_GIF_DITHER);
|
||||
param.push_back(3);
|
||||
ASSERT_NO_THROW(cv::imwritemulti(gif_filename, img_vec, param));
|
||||
vector<cv::Mat> img_vec_gif;
|
||||
ASSERT_NO_THROW(cv::imreadmulti(gif_filename, img_vec_gif));
|
||||
EXPECT_EQ(img_vec.size(), img_vec_gif.size());
|
||||
for (long unsigned int i = 0; i < img_vec.size(); i++) {
|
||||
cv::Mat img_8UC3;
|
||||
ASSERT_NO_THROW(cv::cvtColor(img_vec_gif[i], img_8UC3, COLOR_BGRA2BGR));
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(29, 0), img_vec[i], img_8UC3);
|
||||
}
|
||||
EXPECT_EQ(0, remove(gif_filename.c_str()));
|
||||
}
|
||||
|
||||
}//opencv_test
|
||||
}//namespace
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,186 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level
|
||||
// directory of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_JPEGXL
|
||||
|
||||
typedef tuple<perf::MatType, int> MatType_and_Distance;
|
||||
typedef testing::TestWithParam<MatType_and_Distance> Imgcodecs_JpegXL_MatType;
|
||||
|
||||
TEST_P(Imgcodecs_JpegXL_MatType, write_read)
|
||||
{
|
||||
const int matType = get<0>(GetParam());
|
||||
const int distanceParam = get<1>(GetParam());
|
||||
|
||||
cv::Scalar col;
|
||||
// Jpeg XL is lossy compression.
|
||||
// There may be small differences in decoding results by environments.
|
||||
double th;
|
||||
|
||||
switch( CV_MAT_DEPTH(matType) )
|
||||
{
|
||||
case CV_16U:
|
||||
col = cv::Scalar(124 * 256, 76 * 256, 42 * 256, 192 * 256 );
|
||||
th = 656; // = 65535 / 100;
|
||||
break;
|
||||
case CV_32F:
|
||||
col = cv::Scalar(0.486, 0.298, 0.165, 0.75);
|
||||
th = 1.0 / 100.0;
|
||||
break;
|
||||
default:
|
||||
case CV_8U:
|
||||
col = cv::Scalar(124, 76, 42, 192);
|
||||
th = 3; // = 255 / 100 (1%);
|
||||
break;
|
||||
}
|
||||
|
||||
// If increasing distanceParam, threshold should be increased.
|
||||
th *= (distanceParam >= 25) ? 5 : ( distanceParam > 2 ) ? 3 : (distanceParam == 2) ? 2: 1;
|
||||
|
||||
bool ret = false;
|
||||
string tmp_fname = cv::tempfile(".jxl");
|
||||
Mat img_org(320, 480, matType, col);
|
||||
vector<int> param;
|
||||
param.push_back(IMWRITE_JPEGXL_DISTANCE);
|
||||
param.push_back(distanceParam);
|
||||
EXPECT_NO_THROW(ret = imwrite(tmp_fname, img_org, param));
|
||||
EXPECT_TRUE(ret);
|
||||
Mat img_decoded;
|
||||
EXPECT_NO_THROW(img_decoded = imread(tmp_fname, IMREAD_UNCHANGED));
|
||||
EXPECT_FALSE(img_decoded.empty());
|
||||
|
||||
EXPECT_LE(cvtest::norm(img_org, img_decoded, NORM_INF), th);
|
||||
|
||||
EXPECT_EQ(0, remove(tmp_fname.c_str()));
|
||||
}
|
||||
|
||||
TEST_P(Imgcodecs_JpegXL_MatType, encode_decode)
|
||||
{
|
||||
const int matType = get<0>(GetParam());
|
||||
const int distanceParam = get<1>(GetParam());
|
||||
|
||||
cv::Scalar col;
|
||||
// Jpeg XL is lossy compression.
|
||||
// There may be small differences in decoding results by environments.
|
||||
double th;
|
||||
|
||||
// If alpha=0, libjxl modify color channels(BGR). So do not set it.
|
||||
switch( CV_MAT_DEPTH(matType) )
|
||||
{
|
||||
case CV_16U:
|
||||
col = cv::Scalar(124 * 256, 76 * 256, 42 * 256, 192 * 256 );
|
||||
th = 656; // = 65535 / 100;
|
||||
break;
|
||||
case CV_32F:
|
||||
col = cv::Scalar(0.486, 0.298, 0.165, 0.75);
|
||||
th = 1.0 / 100.0;
|
||||
break;
|
||||
default:
|
||||
case CV_8U:
|
||||
col = cv::Scalar(124, 76, 42, 192);
|
||||
th = 3; // = 255 / 100 (1%);
|
||||
break;
|
||||
}
|
||||
|
||||
// If increasing distanceParam, threshold should be increased.
|
||||
th *= (distanceParam >= 25) ? 5 : ( distanceParam > 2 ) ? 3 : (distanceParam == 2) ? 2: 1;
|
||||
|
||||
bool ret = false;
|
||||
vector<uchar> buff;
|
||||
Mat img_org(320, 480, matType, col);
|
||||
vector<int> param;
|
||||
param.push_back(IMWRITE_JPEGXL_DISTANCE);
|
||||
param.push_back(distanceParam);
|
||||
EXPECT_NO_THROW(ret = imencode(".jxl", img_org, buff, param));
|
||||
EXPECT_TRUE(ret);
|
||||
Mat img_decoded;
|
||||
EXPECT_NO_THROW(img_decoded = imdecode(buff, IMREAD_UNCHANGED));
|
||||
EXPECT_FALSE(img_decoded.empty());
|
||||
|
||||
EXPECT_LE(cvtest::norm(img_org, img_decoded, NORM_INF), th);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
/**/,
|
||||
Imgcodecs_JpegXL_MatType,
|
||||
testing::Combine(
|
||||
testing::Values(
|
||||
CV_8UC1, CV_8UC3, CV_8UC4,
|
||||
CV_16UC1, CV_16UC3, CV_16UC4,
|
||||
CV_32FC1, CV_32FC3, CV_32FC4
|
||||
),
|
||||
testing::Values( // Distance
|
||||
0, // Lossless
|
||||
1, // Default
|
||||
3, // Recomended Lossy Max
|
||||
25 // Specification Max
|
||||
)
|
||||
) );
|
||||
|
||||
|
||||
typedef tuple<int, int> Effort_and_Decoding_speed;
|
||||
typedef testing::TestWithParam<Effort_and_Decoding_speed> Imgcodecs_JpegXL_Effort_DecodingSpeed;
|
||||
|
||||
TEST_P(Imgcodecs_JpegXL_Effort_DecodingSpeed, encode_decode)
|
||||
{
|
||||
const int effort = get<0>(GetParam());
|
||||
const int speed = get<1>(GetParam());
|
||||
|
||||
cv::Scalar col = cv::Scalar(124,76,42);
|
||||
// Jpeg XL is lossy compression.
|
||||
// There may be small differences in decoding results by environments.
|
||||
double th = 3; // = 255 / 100 (1%);
|
||||
|
||||
bool ret = false;
|
||||
vector<uchar> buff;
|
||||
Mat img_org(320, 480, CV_8UC3, col);
|
||||
vector<int> param;
|
||||
param.push_back(IMWRITE_JPEGXL_EFFORT);
|
||||
param.push_back(effort);
|
||||
param.push_back(IMWRITE_JPEGXL_DECODING_SPEED);
|
||||
param.push_back(speed);
|
||||
EXPECT_NO_THROW(ret = imencode(".jxl", img_org, buff, param));
|
||||
EXPECT_TRUE(ret);
|
||||
Mat img_decoded;
|
||||
EXPECT_NO_THROW(img_decoded = imdecode(buff, IMREAD_UNCHANGED));
|
||||
EXPECT_FALSE(img_decoded.empty());
|
||||
|
||||
EXPECT_LE(cvtest::norm(img_org, img_decoded, NORM_INF), th);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
/**/,
|
||||
Imgcodecs_JpegXL_Effort_DecodingSpeed,
|
||||
testing::Combine(
|
||||
testing::Values( // Effort
|
||||
1, // fastest
|
||||
7, // default
|
||||
9 // slowest
|
||||
),
|
||||
testing::Values( // Decoding Speed
|
||||
0, // default, slowest, and best quality/density
|
||||
2,
|
||||
4 // fastest, at the cost of some qulity/density
|
||||
)
|
||||
) );
|
||||
|
||||
TEST(Imgcodecs_JpegXL, encode_from_uncontinued_image)
|
||||
{
|
||||
cv::Mat src(100, 100, CV_8UC1, Scalar(40,50,10));
|
||||
cv::Mat roi = src(cv::Rect(10,20,30,50));
|
||||
EXPECT_FALSE(roi.isContinuous()); // uncontinued image
|
||||
|
||||
vector<uint8_t> buff;
|
||||
vector<int> param;
|
||||
bool ret = false;
|
||||
EXPECT_NO_THROW(ret = cv::imencode(".jxl", roi, buff, param));
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
#endif // HAVE_JPEGXL
|
||||
|
||||
} // namespace
|
||||
} // namespace opencv_test
|
||||
@@ -157,6 +157,9 @@ const string exts[] = {
|
||||
#ifdef HAVE_JPEG
|
||||
"jpg",
|
||||
#endif
|
||||
#ifdef HAVE_JPEGXL
|
||||
"jxl",
|
||||
#endif
|
||||
#if (defined(HAVE_JASPER) && defined(OPENCV_IMGCODECS_ENABLE_JASPER_TESTS)) \
|
||||
|| defined(HAVE_OPENJPEG)
|
||||
"jp2",
|
||||
@@ -238,6 +241,8 @@ TEST_P(Imgcodecs_Image, read_write_BGR)
|
||||
double psnrThreshold = 100;
|
||||
if (ext == "jpg")
|
||||
psnrThreshold = 32;
|
||||
if (ext == "jxl")
|
||||
psnrThreshold = 30;
|
||||
#if defined(HAVE_JASPER)
|
||||
if (ext == "jp2")
|
||||
psnrThreshold = 95;
|
||||
@@ -268,6 +273,8 @@ TEST_P(Imgcodecs_Image, read_write_GRAYSCALE)
|
||||
double psnrThreshold = 100;
|
||||
if (ext == "jpg")
|
||||
psnrThreshold = 40;
|
||||
if (ext == "jxl")
|
||||
psnrThreshold = 40;
|
||||
#if defined(HAVE_JASPER)
|
||||
if (ext == "jp2")
|
||||
psnrThreshold = 70;
|
||||
|
||||
@@ -1,29 +1,16 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_WEBP
|
||||
|
||||
TEST(Imgcodecs_WebP, encode_decode_lossless_webp)
|
||||
static void readFileBytes(const std::string& fname, std::vector<unsigned char>& buf)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
string filename = root + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(filename);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
string output = cv::tempfile(".webp");
|
||||
EXPECT_NO_THROW(cv::imwrite(output, img)); // lossless
|
||||
|
||||
cv::Mat img_webp = cv::imread(output);
|
||||
|
||||
std::vector<unsigned char> buf;
|
||||
|
||||
FILE * wfile = NULL;
|
||||
|
||||
wfile = fopen(output.c_str(), "rb");
|
||||
FILE * wfile = fopen(fname.c_str(), "rb");
|
||||
if (wfile != NULL)
|
||||
{
|
||||
fseek(wfile, 0, SEEK_END);
|
||||
@@ -39,12 +26,24 @@ TEST(Imgcodecs_WebP, encode_decode_lossless_webp)
|
||||
fclose(wfile);
|
||||
}
|
||||
|
||||
if (data_size != wfile_size)
|
||||
{
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
EXPECT_EQ(data_size, wfile_size);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_WebP, encode_decode_lossless_webp)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
string filename = root + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(filename);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
string output = cv::tempfile(".webp");
|
||||
EXPECT_NO_THROW(cv::imwrite(output, img)); // lossless
|
||||
|
||||
cv::Mat img_webp = cv::imread(output);
|
||||
|
||||
std::vector<unsigned char> buf;
|
||||
readFileBytes(output, buf);
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
|
||||
cv::Mat decode = cv::imdecode(buf, IMREAD_COLOR);
|
||||
|
||||
@@ -2195,11 +2195,13 @@ Must fall between 0 and max_theta.
|
||||
@param max_theta For standard and multi-scale Hough transform, an upper bound for the angle.
|
||||
Must fall between min_theta and CV_PI. The actual maximum angle in the accumulator may be slightly
|
||||
less than max_theta, depending on the parameters min_theta and theta.
|
||||
@param use_edgeval True if you want to use weighted Hough transform.
|
||||
*/
|
||||
CV_EXPORTS_W void HoughLines( InputArray image, OutputArray lines,
|
||||
double rho, double theta, int threshold,
|
||||
double srn = 0, double stn = 0,
|
||||
double min_theta = 0, double max_theta = CV_PI );
|
||||
double min_theta = 0, double max_theta = CV_PI,
|
||||
bool use_edgeval = false );
|
||||
|
||||
/** @brief Finds line segments in a binary image using the probabilistic Hough transform.
|
||||
|
||||
@@ -4398,7 +4400,7 @@ CV_EXPORTS_W RotatedRect fitEllipseAMS( InputArray points );
|
||||
|
||||
The function calculates the ellipse that fits a set of 2D points.
|
||||
It returns the rotated rectangle in which the ellipse is inscribed.
|
||||
The Direct least square (Direct) method by @cite Fitzgibbon1999 is used.
|
||||
The Direct least square (Direct) method by @cite oy1998NumericallySD is used.
|
||||
|
||||
For an ellipse, this basis set is \f$ \chi= \left(x^2, x y, y^2, x, y, 1\right) \f$,
|
||||
which is a set of six free coefficients \f$ A^T=\left\{A_{\text{xx}},A_{\text{xy}},A_{\text{yy}},A_x,A_y,A_0\right\} \f$.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "opencv2/core/cvdef.h"
|
||||
#include "opencv2/core/cvstd.hpp"
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/core/hal/interface.h"
|
||||
|
||||
namespace cv { namespace hal {
|
||||
@@ -158,12 +159,14 @@ CV_EXPORTS void cvtGraytoBGR5x5(const uchar * src_data, size_t src_step,
|
||||
CV_EXPORTS void cvtBGRtoYUV(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int depth, int scn, bool swapBlue, bool isCbCr);
|
||||
int depth, int scn, bool swapBlue, bool isCbCr,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
CV_EXPORTS void cvtYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int depth, int dcn, bool swapBlue, bool isCbCr);
|
||||
int depth, int dcn, bool swapBlue, bool isCbCr,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
CV_EXPORTS void cvtBGRtoXYZ(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
@@ -198,28 +201,33 @@ CV_EXPORTS void cvtLabtoBGR(const uchar * src_data, size_t src_step,
|
||||
CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int dst_width, int dst_height,
|
||||
int dcn, bool swapBlue, int uIdx);
|
||||
int dcn, bool swapBlue, int uIdx,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
//! Separate Y and UV planes
|
||||
CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int dst_width, int dst_height,
|
||||
int dcn, bool swapBlue, int uIdx);
|
||||
int dcn, bool swapBlue, int uIdx,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * y_data, size_t y_step, const uchar * uv_data, size_t uv_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int dst_width, int dst_height,
|
||||
int dcn, bool swapBlue, int uIdx);
|
||||
int dcn, bool swapBlue, int uIdx,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
CV_EXPORTS void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int dst_width, int dst_height,
|
||||
int dcn, bool swapBlue, int uIdx);
|
||||
int dcn, bool swapBlue, int uIdx,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
CV_EXPORTS void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int scn, bool swapBlue, int uIdx);
|
||||
int scn, bool swapBlue, int uIdx,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
//! Separate Y and UV planes
|
||||
CV_EXPORTS void cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step,
|
||||
@@ -230,12 +238,14 @@ CV_EXPORTS void cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step,
|
||||
CV_EXPORTS void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int dcn, bool swapBlue, int uIdx, int ycn);
|
||||
int dcn, bool swapBlue, int uIdx, int ycn,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
CV_EXPORTS void cvtOnePlaneBGRtoYUV(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int scn, bool swapBlue, int uIdx, int ycn);
|
||||
int scn, bool swapBlue, int uIdx, int ycn,
|
||||
AlgorithmHint hint = ALGO_HINT_DEFAULT);
|
||||
|
||||
CV_EXPORTS void cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
*
|
||||
* @param targetPt The target point
|
||||
* @param[out] contour The list of pixels which contains optimal path between the source and the target points of the image. Type is CV_32SC2 (compatible with `std::vector<Point>`)
|
||||
* @param backward Flag to indicate reverse order of retrived pixels (use "true" value to fetch points from the target to the source point)
|
||||
* @param backward Flag to indicate reverse order of retrieved pixels (use "true" value to fetch points from the target to the source point)
|
||||
*/
|
||||
CV_WRAP void getContour(const Point& targetPt, OutputArray contour, bool backward = false) const;
|
||||
|
||||
|
||||
@@ -2,82 +2,105 @@
|
||||
"whitelist":
|
||||
{
|
||||
"": [
|
||||
"Canny",
|
||||
"GaussianBlur",
|
||||
"Laplacian",
|
||||
"HoughLines",
|
||||
"HoughLinesP",
|
||||
"HoughCircles",
|
||||
"Scharr",
|
||||
"Sobel",
|
||||
"adaptiveThreshold",
|
||||
"applyColorMap",
|
||||
"approxPolyDP",
|
||||
"approxPolyN",
|
||||
"arcLength",
|
||||
"arrowedLine",
|
||||
"bilateralFilter",
|
||||
"blendLinear",
|
||||
"blur",
|
||||
"boundingRect",
|
||||
"boxFilter",
|
||||
"calcBackProject",
|
||||
"calcHist",
|
||||
"Canny",
|
||||
"circle",
|
||||
"clipLine",
|
||||
"compareHist",
|
||||
"connectedComponents",
|
||||
"connectedComponentsWithStats",
|
||||
"contourArea",
|
||||
"convertMaps",
|
||||
"convexHull",
|
||||
"convexityDefects",
|
||||
"cornerHarris",
|
||||
"cornerMinEigenVal",
|
||||
"createCLAHE",
|
||||
"createHanningWindow",
|
||||
"createLineSegmentDetector",
|
||||
"cvtColor",
|
||||
"demosaicing",
|
||||
"dilate",
|
||||
"distanceTransform",
|
||||
"distanceTransformWithLabels",
|
||||
"divSpectrums",
|
||||
"drawContours",
|
||||
"drawMarker",
|
||||
"ellipse",
|
||||
"ellipse2Poly",
|
||||
"equalizeHist",
|
||||
"erode",
|
||||
"fillConvexPoly",
|
||||
"fillPoly",
|
||||
"filter2D",
|
||||
"findContours",
|
||||
"findContoursLinkRuns",
|
||||
"fitEllipse",
|
||||
"fitEllipseAMS",
|
||||
"fitEllipseDirect",
|
||||
"fitLine",
|
||||
"floodFill",
|
||||
"GaussianBlur",
|
||||
"getAffineTransform",
|
||||
"getFontScaleFromHeight",
|
||||
"getPerspectiveTransform",
|
||||
"getRectSubPix",
|
||||
"getRotationMatrix2D",
|
||||
"getStructuringElement",
|
||||
"goodFeaturesToTrack",
|
||||
"grabCut",
|
||||
"HoughCircles",
|
||||
"HoughLines",
|
||||
"HoughLinesP",
|
||||
"HuMoments",
|
||||
"integral",
|
||||
"integral2",
|
||||
"intersectConvexConvex",
|
||||
"invertAffineTransform",
|
||||
"isContourConvex",
|
||||
"Laplacian",
|
||||
"line",
|
||||
"matchShapes",
|
||||
"matchTemplate",
|
||||
"medianBlur",
|
||||
"minAreaRect",
|
||||
"minEnclosingCircle",
|
||||
"minEnclosingTriangle",
|
||||
"moments",
|
||||
"morphologyEx",
|
||||
"pointPolygonTest",
|
||||
"polylines",
|
||||
"preCornerDetect",
|
||||
"putText",
|
||||
"pyrDown",
|
||||
"pyrUp",
|
||||
"rectangle",
|
||||
"remap",
|
||||
"resize",
|
||||
"rotatedRectangleIntersection",
|
||||
"Scharr",
|
||||
"sepFilter2D",
|
||||
"Sobel",
|
||||
"spatialGradient",
|
||||
"sqrBoxFilter",
|
||||
"stackBlur",
|
||||
"threshold",
|
||||
"warpAffine",
|
||||
"warpPerspective",
|
||||
"warpPolar",
|
||||
"watershed",
|
||||
"fillPoly",
|
||||
"fillConvexPoly",
|
||||
"polylines"
|
||||
"watershed"
|
||||
],
|
||||
"CLAHE": ["apply", "collectGarbage", "getClipLimit", "getTilesGridSize", "setClipLimit", "setTilesGridSize"],
|
||||
"segmentation_IntelligentScissorsMB": [
|
||||
|
||||
@@ -45,6 +45,10 @@ typedef perf::TestBaseWithParam<Size_MatType_BorderType_t> Size_MatType_BorderTy
|
||||
typedef tuple<Size, int, BorderType3x3> Size_ksize_BorderType_t;
|
||||
typedef perf::TestBaseWithParam<Size_ksize_BorderType_t> Size_ksize_BorderType;
|
||||
|
||||
typedef tuple<Size, MatType, BorderType, int> Size_MatType_BorderType_ksize_t;
|
||||
typedef perf::TestBaseWithParam<Size_MatType_BorderType_ksize_t> Size_MatType_BorderType_ksize;
|
||||
|
||||
|
||||
PERF_TEST_P(Size_MatType_BorderType3x3, gaussianBlur3x3,
|
||||
testing::Combine(
|
||||
testing::Values(szODD, szQVGA, szVGA, sz720p),
|
||||
@@ -114,24 +118,27 @@ PERF_TEST_P(Size_MatType_BorderType, blur16x16,
|
||||
SANITY_CHECK(dst, eps);
|
||||
}
|
||||
|
||||
PERF_TEST_P(Size_MatType_BorderType3x3, box3x3,
|
||||
PERF_TEST_P(Size_MatType_BorderType_ksize, box,
|
||||
testing::Combine(
|
||||
testing::Values(szODD, szQVGA, szVGA, sz720p),
|
||||
testing::Values(CV_8UC1, CV_16SC1, CV_32SC1, CV_32FC1, CV_32FC3),
|
||||
BorderType3x3::all()
|
||||
BorderType::all(),
|
||||
testing::Values(3, 5)
|
||||
)
|
||||
)
|
||||
{
|
||||
Size size = get<0>(GetParam());
|
||||
int type = get<1>(GetParam());
|
||||
BorderType3x3 btype = get<2>(GetParam());
|
||||
auto p = GetParam();
|
||||
Size size = get<0>(p);
|
||||
int type = get<1>(p);
|
||||
BorderType btype = get<2>(p);
|
||||
int ksize = get<3>(p);
|
||||
|
||||
Mat src(size, type);
|
||||
Mat dst(size, type);
|
||||
|
||||
declare.in(src, WARMUP_RNG).out(dst);
|
||||
|
||||
TEST_CYCLE() boxFilter(src, dst, -1, Size(3,3), Point(-1,-1), false, btype);
|
||||
TEST_CYCLE() boxFilter(src, dst, -1, Size(ksize, ksize), Point(-1,-1), false, btype);
|
||||
|
||||
SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE);
|
||||
}
|
||||
@@ -158,17 +165,20 @@ PERF_TEST_P(Size_ksize_BorderType, box_CV8U_CV16U,
|
||||
SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE);
|
||||
}
|
||||
|
||||
PERF_TEST_P(Size_MatType_BorderType3x3, box3x3_inplace,
|
||||
PERF_TEST_P(Size_MatType_BorderType_ksize, box_inplace,
|
||||
testing::Combine(
|
||||
testing::Values(szODD, szQVGA, szVGA, sz720p),
|
||||
testing::Values(CV_8UC1, CV_16SC1, CV_32SC1, CV_32FC1, CV_32FC3),
|
||||
BorderType3x3::all()
|
||||
BorderType::all(),
|
||||
testing::Values(3, 5)
|
||||
)
|
||||
)
|
||||
{
|
||||
Size size = get<0>(GetParam());
|
||||
int type = get<1>(GetParam());
|
||||
BorderType3x3 btype = get<2>(GetParam());
|
||||
auto p = GetParam();
|
||||
Size size = get<0>(p);
|
||||
int type = get<1>(p);
|
||||
BorderType btype = get<2>(p);
|
||||
int ksize = get<3>(p);
|
||||
|
||||
Mat src(size, type);
|
||||
Mat dst(size, type);
|
||||
@@ -179,7 +189,7 @@ PERF_TEST_P(Size_MatType_BorderType3x3, box3x3_inplace,
|
||||
{
|
||||
src.copyTo(dst);
|
||||
startTimer();
|
||||
boxFilter(dst, dst, -1, Size(3,3), Point(-1,-1), false, btype);
|
||||
boxFilter(dst, dst, -1, Size(ksize, ksize), Point(-1,-1), false, btype);
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
|
||||
@@ -1982,7 +1982,7 @@ struct RGB2Lab_f
|
||||
clipv(bvec0); clipv(bvec1);
|
||||
#undef clipv
|
||||
/* int iR = R*LAB_BASE, iG = G*LAB_BASE, iB = B*LAB_BASE, iL, ia, ib; */
|
||||
v_float32 basef = vx_setall_f32(LAB_BASE);
|
||||
v_float32 basef = vx_setall_f32(static_cast<float>(LAB_BASE));
|
||||
rvec0 = v_mul(rvec0, basef), gvec0 = v_mul(gvec0, basef), bvec0 = v_mul(bvec0, basef);
|
||||
rvec1 = v_mul(rvec1, basef), gvec1 = v_mul(gvec1, basef), bvec1 = v_mul(bvec1, basef);
|
||||
|
||||
@@ -2013,14 +2013,14 @@ struct RGB2Lab_f
|
||||
b_vec0 = v_cvt_f32(i_bvec0); b_vec1 = v_cvt_f32(i_bvec1);
|
||||
|
||||
/* dst[i] = L*100.0f */
|
||||
v_float32 v100dBase = vx_setall_f32(100.0f/LAB_BASE);
|
||||
v_float32 v100dBase = vx_setall_f32(100.0f / static_cast<float>(LAB_BASE));
|
||||
l_vec0 = v_mul(l_vec0, v100dBase);
|
||||
l_vec1 = v_mul(l_vec1, v100dBase);
|
||||
/*
|
||||
dst[i + 1] = a*256.0f - 128.0f;
|
||||
dst[i + 2] = b*256.0f - 128.0f;
|
||||
*/
|
||||
v_float32 v256dBase = vx_setall_f32(256.0f/LAB_BASE), vm128 = vx_setall_f32(-128.f);
|
||||
v_float32 v256dBase = vx_setall_f32(256.0f / static_cast<float>(LAB_BASE)), vm128 = vx_setall_f32(-128.f);
|
||||
a_vec0 = v_fma(a_vec0, v256dBase, vm128);
|
||||
a_vec1 = v_fma(a_vec1, v256dBase, vm128);
|
||||
b_vec0 = v_fma(b_vec0, v256dBase, vm128);
|
||||
@@ -2038,10 +2038,10 @@ struct RGB2Lab_f
|
||||
float G = clip(src[1]);
|
||||
float B = clip(src[bIdx^2]);
|
||||
|
||||
int iR = cvRound(R*LAB_BASE), iG = cvRound(G*LAB_BASE), iB = cvRound(B*LAB_BASE);
|
||||
int iR = cvRound(R*static_cast<float>(LAB_BASE)), iG = cvRound(G*static_cast<float>(LAB_BASE)), iB = cvRound(B*static_cast<float>(LAB_BASE));
|
||||
int iL, ia, ib;
|
||||
trilinearInterpolate(iR, iG, iB, LABLUVLUTs16.RGB2LabLUT_s16, iL, ia, ib);
|
||||
float L = iL*1.0f/LAB_BASE, a = ia*1.0f/LAB_BASE, b = ib*1.0f/LAB_BASE;
|
||||
float L = iL*1.0f/static_cast<float>(LAB_BASE), a = ia*1.0f/static_cast<float>(LAB_BASE), b = ib*1.0f/static_cast<float>(LAB_BASE);
|
||||
|
||||
dst[i] = L*100.0f;
|
||||
dst[i + 1] = a*256.0f - 128.0f;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace cv {
|
||||
namespace hal {
|
||||
|
||||
// 8u, 16u, 32f
|
||||
static void cvtBGRtoYUV(const uchar * src_data, size_t src_step,
|
||||
void cvtBGRtoYUV(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int depth, int scn, bool swapBlue, bool isCbCr, AlgorithmHint hint)
|
||||
@@ -71,7 +71,7 @@ static void cvtBGRtoYUV(const uchar * src_data, size_t src_step,
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
}
|
||||
|
||||
static void cvtYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
void cvtYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int depth, int dcn, bool swapBlue, bool isCbCr, AlgorithmHint hint)
|
||||
@@ -128,7 +128,7 @@ static void cvtYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
// 4:2:0, two planes: Y, UV interleaved
|
||||
// Y : [16, 235]; Cb, Cr: [16, 240] centered at 128
|
||||
// 20-bit fixed-point arithmetics
|
||||
static void cvtTwoPlaneYUVtoBGR(const uchar * y_data, size_t y_step, const uchar * uv_data, size_t uv_step,
|
||||
void cvtTwoPlaneYUVtoBGR(const uchar * y_data, size_t y_step, const uchar * uv_data, size_t uv_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int dst_width, int dst_height,
|
||||
int dcn, bool swapBlue, int uIdx, AlgorithmHint hint)
|
||||
@@ -151,7 +151,7 @@ static void cvtTwoPlaneYUVtoBGR(const uchar * y_data, size_t y_step, const uchar
|
||||
// 4:2:0, two planes in one array: Y, UV interleaved
|
||||
// Y : [16, 235]; Cb, Cr: [16, 240] centered at 128
|
||||
// 20-bit fixed-point arithmetics
|
||||
static void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int dst_width, int dst_height,
|
||||
int dcn, bool swapBlue, int uIdx, AlgorithmHint hint)
|
||||
@@ -173,7 +173,7 @@ static void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
// 4:2:0, two planes: Y, UV interleaved
|
||||
// Y : [16, 235]; Cb, Cr: [16, 240] centered at 128
|
||||
// 20-bit fixed-point arithmetics
|
||||
static void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, size_t src_step,
|
||||
void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int dst_width, int dst_height,
|
||||
int dcn, bool swapBlue, int uIdx, AlgorithmHint hint)
|
||||
@@ -186,7 +186,7 @@ static void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, siz
|
||||
// 4:2:0, three planes in one array: Y, U, V
|
||||
// Y : [16, 235]; Cb, Cr: [16, 240] centered at 128
|
||||
// 20-bit fixed-point arithmetics
|
||||
static void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int dst_width, int dst_height,
|
||||
int dcn, bool swapBlue, int uIdx, AlgorithmHint hint)
|
||||
@@ -207,7 +207,7 @@ static void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
// 4:2:0, three planes in one array: Y, U, V
|
||||
// Y : [16, 235]; Cb, Cr: [16, 240] centered at 128
|
||||
// 20-bit fixed-point arithmetics
|
||||
static void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step,
|
||||
void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int scn, bool swapBlue, int uIdx, AlgorithmHint hint)
|
||||
@@ -225,10 +225,27 @@ static void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step,
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
}
|
||||
|
||||
// 4:2:0, two planes: Y, UV interleaved
|
||||
// Y : [16, 235]; Cb, Cr: [16, 240] centered at 128
|
||||
// 20-bit fixed-point arithmetics
|
||||
void cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step,
|
||||
uchar * y_data, uchar * uv_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int scn, bool swapBlue, int uIdx)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CALL_HAL(cvtBGRtoTwoPlaneYUV, cv_hal_cvtBGRtoTwoPlaneYUV,
|
||||
src_data, src_step, y_data, dst_step, uv_data, dst_step, width, height, scn, swapBlue, uIdx);
|
||||
|
||||
CV_CPU_DISPATCH(cvtBGRtoTwoPlaneYUV, (src_data, src_step, y_data, uv_data, dst_step, width, height, scn, swapBlue, uIdx),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
}
|
||||
|
||||
// 4:2:2 interleaved
|
||||
// Y : [16, 235]; Cb, Cr: [16, 240] centered at 128
|
||||
// 20-bit fixed-point arithmetics
|
||||
static void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int dcn, bool swapBlue, int uIdx, int ycn, AlgorithmHint hint)
|
||||
@@ -249,7 +266,7 @@ static void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
|
||||
// 4:2:2 interleaved
|
||||
// Y : [16, 235]; Cb, Cr: [16, 240] centered at 128
|
||||
// 14-bit fixed-point arithmetics is used
|
||||
static void cvtOnePlaneBGRtoYUV(const uchar * src_data, size_t src_step,
|
||||
void cvtOnePlaneBGRtoYUV(const uchar * src_data, size_t src_step,
|
||||
uchar * dst_data, size_t dst_step,
|
||||
int width, int height,
|
||||
int scn, bool swapBlue, int uIdx, int ycn, AlgorithmHint hint)
|
||||
|
||||
@@ -368,10 +368,6 @@ CNode& ContourScanner_::makeContour(schar& nbd_, const bool is_hole, const int x
|
||||
const Point start_pt(x - (is_hole ? 1 : 0), y);
|
||||
|
||||
CNode& res = tree.newElem();
|
||||
if (isChain)
|
||||
res.body.codes.reserve(200);
|
||||
else
|
||||
res.body.pts.reserve(200);
|
||||
res.body.isHole = is_hole;
|
||||
res.body.isChain = isChain;
|
||||
res.body.origin = start_pt + offset;
|
||||
|
||||
@@ -1027,8 +1027,8 @@ EllipseEx( Mat& img, Point2l center, Size2l axes,
|
||||
for (unsigned int i = 0; i < _v.size(); ++i)
|
||||
{
|
||||
Point2l pt;
|
||||
pt.x = (int64)cvRound(_v[i].x / XY_ONE) << XY_SHIFT;
|
||||
pt.y = (int64)cvRound(_v[i].y / XY_ONE) << XY_SHIFT;
|
||||
pt.x = (int64)cvRound(_v[i].x / static_cast<double>(XY_ONE)) << XY_SHIFT;
|
||||
pt.y = (int64)cvRound(_v[i].y / static_cast<double>(XY_ONE)) << XY_SHIFT;
|
||||
pt.x += cvRound(_v[i].x - pt.x);
|
||||
pt.y += cvRound(_v[i].y - pt.y);
|
||||
if (pt != prevPt) {
|
||||
@@ -1645,7 +1645,7 @@ static void
|
||||
ThickLine( Mat& img, Point2l p0, Point2l p1, const void* color,
|
||||
int thickness, int line_type, int flags, int shift )
|
||||
{
|
||||
static const double INV_XY_ONE = 1./XY_ONE;
|
||||
static const double INV_XY_ONE = 1./static_cast<double>(XY_ONE);
|
||||
|
||||
p0.x <<= XY_SHIFT - shift;
|
||||
p0.y <<= XY_SHIFT - shift;
|
||||
@@ -1981,8 +1981,8 @@ void ellipse(InputOutputArray _img, const RotatedRect& box, const Scalar& color,
|
||||
int _angle = cvRound(box.angle);
|
||||
Point2l center(cvRound(box.center.x),
|
||||
cvRound(box.center.y));
|
||||
center.x = (center.x << XY_SHIFT) + cvRound((box.center.x - center.x)*XY_ONE);
|
||||
center.y = (center.y << XY_SHIFT) + cvRound((box.center.y - center.y)*XY_ONE);
|
||||
center.x = (center.x << XY_SHIFT) + cvRound((box.center.x - center.x)*static_cast<float>(XY_ONE));
|
||||
center.y = (center.y << XY_SHIFT) + cvRound((box.center.y - center.y)*static_cast<float>(XY_ONE));
|
||||
Size2l axes(cvRound(box.size.width),
|
||||
cvRound(box.size.height));
|
||||
axes.width = (axes.width << (XY_SHIFT - 1)) + cvRound((box.size.width - axes.width)*(XY_ONE>>1));
|
||||
@@ -2153,21 +2153,70 @@ void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
|
||||
CV_Assert(ncontours <= (size_t)std::numeric_limits<int>::max());
|
||||
if (lineType == cv::LINE_AA && _image.depth() != CV_8U)
|
||||
lineType = 8;
|
||||
Mat image = _image.getMat(), hierarchy = _hierarchy.getMat();
|
||||
Mat image = _image.getMat();
|
||||
Mat_<Vec4i> hierarchy = _hierarchy.getMat();
|
||||
|
||||
if (thickness >= 0) // contour lines
|
||||
int i = 0, end = (int)ncontours;
|
||||
if (contourIdx >= 0)
|
||||
{
|
||||
double color_buf[4] {};
|
||||
scalarToRawData(color, color_buf, _image.type(), 0 );
|
||||
int i = 0, end = (int)ncontours;
|
||||
if (contourIdx >= 0)
|
||||
i = contourIdx;
|
||||
end = i + 1;
|
||||
}
|
||||
std::vector<int> indexesToFill;
|
||||
if (hierarchy.empty() || maxLevel == 0)
|
||||
{
|
||||
indexesToFill.resize(end - i);
|
||||
std::iota(indexesToFill.begin(), indexesToFill.end(), i);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stack<int> indexes;
|
||||
for (; i != end; ++i)
|
||||
{
|
||||
i = contourIdx;
|
||||
end = i + 1;
|
||||
// either all from the top level or a single contour
|
||||
if (hierarchy(i)[3] < 0 || contourIdx >= 0)
|
||||
indexes.push(i);
|
||||
}
|
||||
for (; i < end; ++i)
|
||||
while (!indexes.empty())
|
||||
{
|
||||
// get current element
|
||||
const int cur = indexes.top();
|
||||
indexes.pop();
|
||||
|
||||
// check current element depth
|
||||
int curLevel = -1;
|
||||
int par = cur;
|
||||
while (par >= 0)
|
||||
{
|
||||
par = hierarchy(par)[3]; // parent
|
||||
++curLevel;
|
||||
}
|
||||
if (curLevel <= maxLevel)
|
||||
{
|
||||
indexesToFill.push_back(cur);
|
||||
}
|
||||
|
||||
int next = hierarchy(cur)[2]; // first child
|
||||
while (next > 0)
|
||||
{
|
||||
indexes.push(next);
|
||||
next = hierarchy(next)[0]; // next sibling
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<Mat> contoursToFill;
|
||||
contoursToFill.reserve(indexesToFill.size());
|
||||
for (const int& idx : indexesToFill)
|
||||
contoursToFill.emplace_back(_contours.getMat(idx));
|
||||
|
||||
if (thickness < 0)
|
||||
fillPoly(image, contoursToFill, color, lineType, 0, offset);
|
||||
else
|
||||
{
|
||||
double color_buf[4]{};
|
||||
scalarToRawData(color, color_buf, _image.type(), 0);
|
||||
for (const Mat& cnt : contoursToFill)
|
||||
{
|
||||
Mat cnt = _contours.getMat(i);
|
||||
if (cnt.empty())
|
||||
continue;
|
||||
const int npoints = cnt.checkVector(2, CV_32S);
|
||||
@@ -2181,59 +2230,4 @@ void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
|
||||
}
|
||||
}
|
||||
}
|
||||
else // filled polygons
|
||||
{
|
||||
int i = 0, end = (int)ncontours;
|
||||
if (contourIdx >= 0)
|
||||
{
|
||||
i = contourIdx;
|
||||
end = i + 1;
|
||||
}
|
||||
std::vector<int> indexesToFill;
|
||||
if (hierarchy.empty() || maxLevel == 0)
|
||||
{
|
||||
for (; i != end; ++i)
|
||||
indexesToFill.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stack<int> indexes;
|
||||
for (; i != end; ++i)
|
||||
{
|
||||
// either all from the top level or a single contour
|
||||
if (hierarchy.at<Vec4i>(i)[3] < 0 || contourIdx >= 0)
|
||||
indexes.push(i);
|
||||
}
|
||||
while (!indexes.empty())
|
||||
{
|
||||
// get current element
|
||||
const int cur = indexes.top();
|
||||
indexes.pop();
|
||||
|
||||
// check current element depth
|
||||
int curLevel = -1;
|
||||
int par = cur;
|
||||
while (par >= 0)
|
||||
{
|
||||
par = hierarchy.at<Vec4i>(par)[3]; // parent
|
||||
++curLevel;
|
||||
}
|
||||
if (curLevel <= maxLevel)
|
||||
{
|
||||
indexesToFill.push_back(cur);
|
||||
}
|
||||
|
||||
int next = hierarchy.at<Vec4i>(cur)[2]; // first child
|
||||
while (next > 0)
|
||||
{
|
||||
indexes.push(next);
|
||||
next = hierarchy.at<Vec4i>(next)[0]; // next sibling
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<Mat> contoursToFill;
|
||||
for (const int & idx : indexesToFill)
|
||||
contoursToFill.push_back(_contours.getMat(idx));
|
||||
fillPoly(image, contoursToFill, color, lineType, 0, offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -692,7 +692,11 @@ namespace
|
||||
getContourPoints(edges, dx, dy, points);
|
||||
|
||||
features.resize(levels_ + 1);
|
||||
std::for_each(features.begin(), features.end(), [=](std::vector<Feature>& e) { e.clear(); e.reserve(maxBufferSize_); });
|
||||
const size_t maxBufferSize = maxBufferSize_;
|
||||
std::for_each(features.begin(), features.end(), [maxBufferSize](std::vector<Feature>& e) {
|
||||
e.clear();
|
||||
e.reserve(maxBufferSize);
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < points.size(); ++i)
|
||||
{
|
||||
|
||||
@@ -1216,7 +1216,7 @@ void cv::calcHist( InputArrayOfArrays images, const std::vector<int>& channels,
|
||||
CV_OCL_RUN(images.total() == 1 && channels.size() == 1 && images.channels(0) == 1 &&
|
||||
channels[0] == 0 && images.isUMatVector() && mask.empty() && !accumulate &&
|
||||
histSize.size() == 1 && histSize[0] == BINS && ranges.size() == 2 &&
|
||||
ranges[0] == 0 && ranges[1] == BINS,
|
||||
ranges[0] == 0 && ranges[1] == static_cast<float>(BINS),
|
||||
ocl_calcHist(images, hist))
|
||||
|
||||
int i, dims = (int)histSize.size(), rsz = (int)ranges.size(), csz = (int)channels.size();
|
||||
|
||||
@@ -120,7 +120,7 @@ static void
|
||||
HoughLinesStandard( InputArray src, OutputArray lines, int type,
|
||||
float rho, float theta,
|
||||
int threshold, int linesMax,
|
||||
double min_theta, double max_theta )
|
||||
double min_theta, double max_theta, bool use_edgeval = false )
|
||||
{
|
||||
CV_CheckType(type, type == CV_32FC2 || type == CV_32FC3, "Internal error");
|
||||
|
||||
@@ -184,17 +184,31 @@ HoughLinesStandard( InputArray src, OutputArray lines, int type,
|
||||
irho, tabSin, tabCos);
|
||||
|
||||
// stage 1. fill accumulator
|
||||
for( i = 0; i < height; i++ )
|
||||
for( j = 0; j < width; j++ )
|
||||
{
|
||||
if( image[i * step + j] != 0 )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
|
||||
r += (numrho - 1) / 2;
|
||||
accum[(n+1) * (numrho+2) + r+1]++;
|
||||
}
|
||||
}
|
||||
if (use_edgeval) {
|
||||
for( i = 0; i < height; i++ )
|
||||
for( j = 0; j < width; j++ )
|
||||
{
|
||||
if( image[i * step + j] != 0 )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
|
||||
r += (numrho - 1) / 2;
|
||||
accum[(n + 1) * (numrho + 2) + r + 1] += image[i * step + j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for( i = 0; i < height; i++ )
|
||||
for( j = 0; j < width; j++ )
|
||||
{
|
||||
if( image[i * step + j] != 0 )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
|
||||
r += (numrho - 1) / 2;
|
||||
accum[(n + 1) * (numrho + 2) + r + 1]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stage 2. find local maximums
|
||||
findLocalMaximums( numrho, numangle, threshold, accum, _sort_buf );
|
||||
@@ -561,7 +575,8 @@ HoughLinesProbabilistic( Mat& image,
|
||||
Point line_end[2];
|
||||
float a, b;
|
||||
int* adata = accum.ptr<int>();
|
||||
int i = point.y, j = point.x, k, x0, y0, dx0, dy0, xflag;
|
||||
int i = point.y, j = point.x, k, xflag;
|
||||
int64_t x0, y0, dx0, dy0;
|
||||
int good_line;
|
||||
const int shift = 16;
|
||||
|
||||
@@ -612,8 +627,8 @@ HoughLinesProbabilistic( Mat& image,
|
||||
|
||||
for( k = 0; k < 2; k++ )
|
||||
{
|
||||
int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0;
|
||||
|
||||
int gap = 0;
|
||||
int64_t x = x0, y = y0, dx = dx0, dy = dy0 ;
|
||||
if( k > 0 )
|
||||
dx = -dx, dy = -dy;
|
||||
|
||||
@@ -622,7 +637,7 @@ HoughLinesProbabilistic( Mat& image,
|
||||
for( ;; x += dx, y += dy )
|
||||
{
|
||||
uchar* mdata;
|
||||
int i1, j1;
|
||||
int64_t i1, j1;
|
||||
|
||||
if( xflag )
|
||||
{
|
||||
@@ -647,8 +662,8 @@ HoughLinesProbabilistic( Mat& image,
|
||||
if( *mdata )
|
||||
{
|
||||
gap = 0;
|
||||
line_end[k].y = i1;
|
||||
line_end[k].x = j1;
|
||||
line_end[k].y = static_cast<int>(i1);
|
||||
line_end[k].x = static_cast<int>(j1);
|
||||
}
|
||||
else if( ++gap > lineGap )
|
||||
break;
|
||||
@@ -660,7 +675,7 @@ HoughLinesProbabilistic( Mat& image,
|
||||
|
||||
for( k = 0; k < 2; k++ )
|
||||
{
|
||||
int x = x0, y = y0, dx = dx0, dy = dy0;
|
||||
int64_t x = x0, y = y0, dx = dx0, dy = dy0;
|
||||
|
||||
if( k > 0 )
|
||||
dx = -dx, dy = -dy;
|
||||
@@ -670,7 +685,7 @@ HoughLinesProbabilistic( Mat& image,
|
||||
for( ;; x += dx, y += dy )
|
||||
{
|
||||
uchar* mdata;
|
||||
int i1, j1;
|
||||
int64_t i1, j1;
|
||||
|
||||
if( xflag )
|
||||
{
|
||||
@@ -907,7 +922,7 @@ static bool ocl_HoughLinesP(InputArray _src, OutputArray _lines, double rho, dou
|
||||
|
||||
void HoughLines( InputArray _image, OutputArray lines,
|
||||
double rho, double theta, int threshold,
|
||||
double srn, double stn, double min_theta, double max_theta )
|
||||
double srn, double stn, double min_theta, double max_theta, bool use_edgeval )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
@@ -922,7 +937,7 @@ void HoughLines( InputArray _image, OutputArray lines,
|
||||
ocl_HoughLines(_image, lines, rho, theta, threshold, min_theta, max_theta));
|
||||
|
||||
if( srn == 0 && stn == 0 )
|
||||
HoughLinesStandard(_image, lines, type, (float)rho, (float)theta, threshold, INT_MAX, min_theta, max_theta );
|
||||
HoughLinesStandard(_image, lines, type, (float)rho, (float)theta, threshold, INT_MAX, min_theta, max_theta, use_edgeval );
|
||||
else
|
||||
HoughLinesSDiv(_image, lines, type, (float)rho, (float)theta, threshold, cvRound(srn), cvRound(stn), INT_MAX, min_theta, max_theta);
|
||||
}
|
||||
|
||||
@@ -1276,8 +1276,8 @@ public:
|
||||
#endif
|
||||
for( ; x1 < bcols; x1++ )
|
||||
{
|
||||
int sx = cvRound(sX[x1]*INTER_TAB_SIZE);
|
||||
int sy = cvRound(sY[x1]*INTER_TAB_SIZE);
|
||||
int sx = cvRound(sX[x1]*static_cast<float>(INTER_TAB_SIZE));
|
||||
int sy = cvRound(sY[x1]*static_cast<float>(INTER_TAB_SIZE));
|
||||
int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1));
|
||||
XY[x1*2] = saturate_cast<short>(sx >> INTER_BITS);
|
||||
XY[x1*2+1] = saturate_cast<short>(sy >> INTER_BITS);
|
||||
@@ -1316,8 +1316,8 @@ public:
|
||||
|
||||
for( ; x1 < bcols; x1++ )
|
||||
{
|
||||
int sx = cvRound(sXY[x1*2]*INTER_TAB_SIZE);
|
||||
int sy = cvRound(sXY[x1*2+1]*INTER_TAB_SIZE);
|
||||
int sx = cvRound(sXY[x1*2]*static_cast<float>(INTER_TAB_SIZE));
|
||||
int sy = cvRound(sXY[x1*2+1]*static_cast<float>(INTER_TAB_SIZE));
|
||||
int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1));
|
||||
XY[x1*2] = saturate_cast<short>(sx >> INTER_BITS);
|
||||
XY[x1*2+1] = saturate_cast<short>(sy >> INTER_BITS);
|
||||
@@ -2016,7 +2016,7 @@ void cv::convertMaps( InputArray _map1, InputArray _map2,
|
||||
bool useSSE4_1 = CV_CPU_HAS_SUPPORT_SSE4_1;
|
||||
#endif
|
||||
|
||||
const float scale = 1.f/INTER_TAB_SIZE;
|
||||
const float scale = 1.f/static_cast<float>(INTER_TAB_SIZE);
|
||||
int x, y;
|
||||
for( y = 0; y < size.height; y++ )
|
||||
{
|
||||
@@ -2096,8 +2096,8 @@ void cv::convertMaps( InputArray _map1, InputArray _map2,
|
||||
#endif
|
||||
for( ; x < size.width; x++ )
|
||||
{
|
||||
int ix = saturate_cast<int>(src1f[x]*INTER_TAB_SIZE);
|
||||
int iy = saturate_cast<int>(src2f[x]*INTER_TAB_SIZE);
|
||||
int ix = saturate_cast<int>(src1f[x]*static_cast<float>(INTER_TAB_SIZE));
|
||||
int iy = saturate_cast<int>(src2f[x]*static_cast<float>(INTER_TAB_SIZE));
|
||||
dst1[x*2] = saturate_cast<short>(ix >> INTER_BITS);
|
||||
dst1[x*2+1] = saturate_cast<short>(iy >> INTER_BITS);
|
||||
dst2[x] = (ushort)((iy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (ix & (INTER_TAB_SIZE-1)));
|
||||
@@ -2142,8 +2142,8 @@ void cv::convertMaps( InputArray _map1, InputArray _map2,
|
||||
#endif
|
||||
for( ; x < size.width; x++ )
|
||||
{
|
||||
int ix = saturate_cast<int>(src1f[x*2]*INTER_TAB_SIZE);
|
||||
int iy = saturate_cast<int>(src1f[x*2+1]*INTER_TAB_SIZE);
|
||||
int ix = saturate_cast<int>(src1f[x*2]*static_cast<float>(INTER_TAB_SIZE));
|
||||
int iy = saturate_cast<int>(src1f[x*2+1]*static_cast<float>(INTER_TAB_SIZE));
|
||||
dst1[x*2] = saturate_cast<short>(ix >> INTER_BITS);
|
||||
dst1[x*2+1] = saturate_cast<short>(iy >> INTER_BITS);
|
||||
dst2[x] = (ushort)((iy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (ix & (INTER_TAB_SIZE-1)));
|
||||
@@ -3270,7 +3270,7 @@ void WarpPerspectiveLine_Process_CV_SIMD(const double *M, short* xy, short* alph
|
||||
for( ; x1 < bw; x1++ )
|
||||
{
|
||||
double W = W0 + M[6]*x1;
|
||||
W = W ? INTER_TAB_SIZE/W : 0;
|
||||
W = W ? static_cast<double>(INTER_TAB_SIZE)/W : 0;
|
||||
double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (X0 + M[0]*x1)*W));
|
||||
double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (Y0 + M[3]*x1)*W));
|
||||
int X = saturate_cast<int>(fX);
|
||||
|
||||
@@ -157,8 +157,8 @@ void convertMaps_32f1c16s_SSE41(const float* src1f, const float* src2f, short* d
|
||||
}
|
||||
for (; x < width; x++)
|
||||
{
|
||||
int ix = saturate_cast<int>(src1f[x] * INTER_TAB_SIZE);
|
||||
int iy = saturate_cast<int>(src2f[x] * INTER_TAB_SIZE);
|
||||
int ix = saturate_cast<int>(src1f[x] * static_cast<float>(INTER_TAB_SIZE));
|
||||
int iy = saturate_cast<int>(src2f[x] * static_cast<float>(INTER_TAB_SIZE));
|
||||
dst1[x * 2] = saturate_cast<short>(ix >> INTER_BITS);
|
||||
dst1[x * 2 + 1] = saturate_cast<short>(iy >> INTER_BITS);
|
||||
dst2[x] = (ushort)((iy & (INTER_TAB_SIZE - 1))*INTER_TAB_SIZE + (ix & (INTER_TAB_SIZE - 1)));
|
||||
@@ -190,8 +190,8 @@ void convertMaps_32f2c16s_SSE41(const float* src1f, short* dst1, ushort* dst2, i
|
||||
}
|
||||
for (; x < width; x++)
|
||||
{
|
||||
int ix = saturate_cast<int>(src1f[x * 2] * INTER_TAB_SIZE);
|
||||
int iy = saturate_cast<int>(src1f[x * 2 + 1] * INTER_TAB_SIZE);
|
||||
int ix = saturate_cast<int>(src1f[x * 2] * static_cast<float>(INTER_TAB_SIZE));
|
||||
int iy = saturate_cast<int>(src1f[x * 2 + 1] * static_cast<float>(INTER_TAB_SIZE));
|
||||
dst1[x * 2] = saturate_cast<short>(ix >> INTER_BITS);
|
||||
dst1[x * 2 + 1] = saturate_cast<short>(iy >> INTER_BITS);
|
||||
dst2[x] = (ushort)((iy & (INTER_TAB_SIZE - 1))*INTER_TAB_SIZE + (ix & (INTER_TAB_SIZE - 1)));
|
||||
@@ -469,7 +469,7 @@ public:
|
||||
for (; x1 < bw; x1++)
|
||||
{
|
||||
double W = W0 + M[6] * x1;
|
||||
W = W ? INTER_TAB_SIZE / W : 0;
|
||||
W = W ? static_cast<double>(INTER_TAB_SIZE) / W : 0;
|
||||
double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (X0 + M[0] * x1)*W));
|
||||
double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (Y0 + M[3] * x1)*W));
|
||||
int X = saturate_cast<int>(fX);
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
#include <stack>
|
||||
#include <numeric>
|
||||
|
||||
#define GET_OPTIMIZED(func) (func)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user