From 05d187ec90c2e36c8804ede67b98c6736a64ec5c Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sat, 10 Dec 2016 19:41:34 +0300 Subject: [PATCH 001/144] ocl: move deprecated code from ocl.cpp --- modules/core/src/ocl.cpp | 1210 +------------------------- modules/core/src/ocl_deprecated.hpp | 1211 +++++++++++++++++++++++++++ 2 files changed, 1212 insertions(+), 1209 deletions(-) create mode 100644 modules/core/src/ocl_deprecated.hpp diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 60ecc69546..2f51adcfc0 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -145,1215 +145,7 @@ static size_t getConfigurationParameterForSize(const char* name, size_t defaultV #include "opencv2/core/opencl/runtime/opencl_core.hpp" #else // TODO FIXIT: This file can't be build without OPENCL - -/* - Part of the file is an extract from the standard OpenCL headers from Khronos site. - Below is the original copyright. -*/ - -/******************************************************************************* - * Copyright (c) 2008 - 2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ******************************************************************************/ - -#if 0 //defined __APPLE__ -#define HAVE_OPENCL 1 -#else -#undef HAVE_OPENCL -#endif - -#define OPENCV_CL_NOT_IMPLEMENTED -1000 - -#ifdef HAVE_OPENCL - -#if defined __APPLE__ -#include -#else -#include -#endif - -static const bool g_haveOpenCL = true; - -#else - -extern "C" { - -struct _cl_platform_id { int dummy; }; -struct _cl_device_id { int dummy; }; -struct _cl_context { int dummy; }; -struct _cl_command_queue { int dummy; }; -struct _cl_mem { int dummy; }; -struct _cl_program { int dummy; }; -struct _cl_kernel { int dummy; }; -struct _cl_event { int dummy; }; -struct _cl_sampler { int dummy; }; - -typedef struct _cl_platform_id * cl_platform_id; -typedef struct _cl_device_id * cl_device_id; -typedef struct _cl_context * cl_context; -typedef struct _cl_command_queue * cl_command_queue; -typedef struct _cl_mem * cl_mem; -typedef struct _cl_program * cl_program; -typedef struct _cl_kernel * cl_kernel; -typedef struct _cl_event * cl_event; -typedef struct _cl_sampler * cl_sampler; - -typedef int cl_int; -typedef unsigned cl_uint; -#if defined (_WIN32) && defined(_MSC_VER) - typedef __int64 cl_long; - typedef unsigned __int64 cl_ulong; -#else - typedef long cl_long; - typedef unsigned long cl_ulong; -#endif - -typedef cl_uint cl_bool; /* WARNING! Unlike cl_ types in cl_platform.h, cl_bool is not guaranteed to be the same size as the bool in kernels. */ -typedef cl_ulong cl_bitfield; -typedef cl_bitfield cl_device_type; -typedef cl_uint cl_platform_info; -typedef cl_uint cl_device_info; -typedef cl_bitfield cl_device_fp_config; -typedef cl_uint cl_device_mem_cache_type; -typedef cl_uint cl_device_local_mem_type; -typedef cl_bitfield cl_device_exec_capabilities; -typedef cl_bitfield cl_command_queue_properties; -typedef intptr_t cl_device_partition_property; -typedef cl_bitfield cl_device_affinity_domain; - -typedef intptr_t cl_context_properties; -typedef cl_uint cl_context_info; -typedef cl_uint cl_command_queue_info; -typedef cl_uint cl_channel_order; -typedef cl_uint cl_channel_type; -typedef cl_bitfield cl_mem_flags; -typedef cl_uint cl_mem_object_type; -typedef cl_uint cl_mem_info; -typedef cl_bitfield cl_mem_migration_flags; -typedef cl_uint cl_image_info; -typedef cl_uint cl_buffer_create_type; -typedef cl_uint cl_addressing_mode; -typedef cl_uint cl_filter_mode; -typedef cl_uint cl_sampler_info; -typedef cl_bitfield cl_map_flags; -typedef cl_uint cl_program_info; -typedef cl_uint cl_program_build_info; -typedef cl_uint cl_program_binary_type; -typedef cl_int cl_build_status; -typedef cl_uint cl_kernel_info; -typedef cl_uint cl_kernel_arg_info; -typedef cl_uint cl_kernel_arg_address_qualifier; -typedef cl_uint cl_kernel_arg_access_qualifier; -typedef cl_bitfield cl_kernel_arg_type_qualifier; -typedef cl_uint cl_kernel_work_group_info; -typedef cl_uint cl_event_info; -typedef cl_uint cl_command_type; -typedef cl_uint cl_profiling_info; - - -typedef struct _cl_image_format { - cl_channel_order image_channel_order; - cl_channel_type image_channel_data_type; -} cl_image_format; - -typedef struct _cl_image_desc { - cl_mem_object_type image_type; - size_t image_width; - size_t image_height; - size_t image_depth; - size_t image_array_size; - size_t image_row_pitch; - size_t image_slice_pitch; - cl_uint num_mip_levels; - cl_uint num_samples; - cl_mem buffer; -} cl_image_desc; - -typedef struct _cl_buffer_region { - size_t origin; - size_t size; -} cl_buffer_region; - - -////////////////////////////////////////////////////////// - -#define CL_SUCCESS 0 -#define CL_DEVICE_NOT_FOUND -1 -#define CL_DEVICE_NOT_AVAILABLE -2 -#define CL_COMPILER_NOT_AVAILABLE -3 -#define CL_MEM_OBJECT_ALLOCATION_FAILURE -4 -#define CL_OUT_OF_RESOURCES -5 -#define CL_OUT_OF_HOST_MEMORY -6 -#define CL_PROFILING_INFO_NOT_AVAILABLE -7 -#define CL_MEM_COPY_OVERLAP -8 -#define CL_IMAGE_FORMAT_MISMATCH -9 -#define CL_IMAGE_FORMAT_NOT_SUPPORTED -10 -#define CL_BUILD_PROGRAM_FAILURE -11 -#define CL_MAP_FAILURE -12 -#define CL_MISALIGNED_SUB_BUFFER_OFFSET -13 -#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14 -#define CL_COMPILE_PROGRAM_FAILURE -15 -#define CL_LINKER_NOT_AVAILABLE -16 -#define CL_LINK_PROGRAM_FAILURE -17 -#define CL_DEVICE_PARTITION_FAILED -18 -#define CL_KERNEL_ARG_INFO_NOT_AVAILABLE -19 - -#define CL_INVALID_VALUE -30 -#define CL_INVALID_DEVICE_TYPE -31 -#define CL_INVALID_PLATFORM -32 -#define CL_INVALID_DEVICE -33 -#define CL_INVALID_CONTEXT -34 -#define CL_INVALID_QUEUE_PROPERTIES -35 -#define CL_INVALID_COMMAND_QUEUE -36 -#define CL_INVALID_HOST_PTR -37 -#define CL_INVALID_MEM_OBJECT -38 -#define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR -39 -#define CL_INVALID_IMAGE_SIZE -40 -#define CL_INVALID_SAMPLER -41 -#define CL_INVALID_BINARY -42 -#define CL_INVALID_BUILD_OPTIONS -43 -#define CL_INVALID_PROGRAM -44 -#define CL_INVALID_PROGRAM_EXECUTABLE -45 -#define CL_INVALID_KERNEL_NAME -46 -#define CL_INVALID_KERNEL_DEFINITION -47 -#define CL_INVALID_KERNEL -48 -#define CL_INVALID_ARG_INDEX -49 -#define CL_INVALID_ARG_VALUE -50 -#define CL_INVALID_ARG_SIZE -51 -#define CL_INVALID_KERNEL_ARGS -52 -#define CL_INVALID_WORK_DIMENSION -53 -#define CL_INVALID_WORK_GROUP_SIZE -54 -#define CL_INVALID_WORK_ITEM_SIZE -55 -#define CL_INVALID_GLOBAL_OFFSET -56 -#define CL_INVALID_EVENT_WAIT_LIST -57 -#define CL_INVALID_EVENT -58 -#define CL_INVALID_OPERATION -59 -#define CL_INVALID_GL_OBJECT -60 -#define CL_INVALID_BUFFER_SIZE -61 -#define CL_INVALID_MIP_LEVEL -62 -#define CL_INVALID_GLOBAL_WORK_SIZE -63 -#define CL_INVALID_PROPERTY -64 -#define CL_INVALID_IMAGE_DESCRIPTOR -65 -#define CL_INVALID_COMPILER_OPTIONS -66 -#define CL_INVALID_LINKER_OPTIONS -67 -#define CL_INVALID_DEVICE_PARTITION_COUNT -68 - -/*#define CL_VERSION_1_0 1 -#define CL_VERSION_1_1 1 -#define CL_VERSION_1_2 1*/ - -#define CL_FALSE 0 -#define CL_TRUE 1 -#define CL_BLOCKING CL_TRUE -#define CL_NON_BLOCKING CL_FALSE - -#define CL_PLATFORM_PROFILE 0x0900 -#define CL_PLATFORM_VERSION 0x0901 -#define CL_PLATFORM_NAME 0x0902 -#define CL_PLATFORM_VENDOR 0x0903 -#define CL_PLATFORM_EXTENSIONS 0x0904 - -#define CL_DEVICE_TYPE_DEFAULT (1 << 0) -#define CL_DEVICE_TYPE_CPU (1 << 1) -#define CL_DEVICE_TYPE_GPU (1 << 2) -#define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) -#define CL_DEVICE_TYPE_CUSTOM (1 << 4) -#define CL_DEVICE_TYPE_ALL 0xFFFFFFFF -#define CL_DEVICE_TYPE 0x1000 -#define CL_DEVICE_VENDOR_ID 0x1001 -#define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 -#define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 -#define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 -#define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B -#define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C -#define CL_DEVICE_ADDRESS_BITS 0x100D -#define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E -#define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F -#define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 -#define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 -#define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 -#define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 -#define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 -#define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 -#define CL_DEVICE_IMAGE_SUPPORT 0x1016 -#define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 -#define CL_DEVICE_MAX_SAMPLERS 0x1018 -#define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 -#define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A -#define CL_DEVICE_SINGLE_FP_CONFIG 0x101B -#define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C -#define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D -#define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E -#define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F -#define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 -#define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 -#define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 -#define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 -#define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 -#define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 -#define CL_DEVICE_ENDIAN_LITTLE 0x1026 -#define CL_DEVICE_AVAILABLE 0x1027 -#define CL_DEVICE_COMPILER_AVAILABLE 0x1028 -#define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 -#define CL_DEVICE_QUEUE_PROPERTIES 0x102A -#define CL_DEVICE_NAME 0x102B -#define CL_DEVICE_VENDOR 0x102C -#define CL_DRIVER_VERSION 0x102D -#define CL_DEVICE_PROFILE 0x102E -#define CL_DEVICE_VERSION 0x102F -#define CL_DEVICE_EXTENSIONS 0x1030 -#define CL_DEVICE_PLATFORM 0x1031 -#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 -#define CL_DEVICE_HALF_FP_CONFIG 0x1033 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034 -#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C -#define CL_DEVICE_OPENCL_C_VERSION 0x103D -#define CL_DEVICE_LINKER_AVAILABLE 0x103E -#define CL_DEVICE_BUILT_IN_KERNELS 0x103F -#define CL_DEVICE_IMAGE_MAX_BUFFER_SIZE 0x1040 -#define CL_DEVICE_IMAGE_MAX_ARRAY_SIZE 0x1041 -#define CL_DEVICE_PARENT_DEVICE 0x1042 -#define CL_DEVICE_PARTITION_MAX_SUB_DEVICES 0x1043 -#define CL_DEVICE_PARTITION_PROPERTIES 0x1044 -#define CL_DEVICE_PARTITION_AFFINITY_DOMAIN 0x1045 -#define CL_DEVICE_PARTITION_TYPE 0x1046 -#define CL_DEVICE_REFERENCE_COUNT 0x1047 -#define CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 0x1048 -#define CL_DEVICE_PRINTF_BUFFER_SIZE 0x1049 -#define CL_DEVICE_IMAGE_PITCH_ALIGNMENT 0x104A -#define CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT 0x104B - -#define CL_FP_DENORM (1 << 0) -#define CL_FP_INF_NAN (1 << 1) -#define CL_FP_ROUND_TO_NEAREST (1 << 2) -#define CL_FP_ROUND_TO_ZERO (1 << 3) -#define CL_FP_ROUND_TO_INF (1 << 4) -#define CL_FP_FMA (1 << 5) -#define CL_FP_SOFT_FLOAT (1 << 6) -#define CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT (1 << 7) - -#define CL_NONE 0x0 -#define CL_READ_ONLY_CACHE 0x1 -#define CL_READ_WRITE_CACHE 0x2 -#define CL_LOCAL 0x1 -#define CL_GLOBAL 0x2 -#define CL_EXEC_KERNEL (1 << 0) -#define CL_EXEC_NATIVE_KERNEL (1 << 1) -#define CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE (1 << 0) -#define CL_QUEUE_PROFILING_ENABLE (1 << 1) - -#define CL_CONTEXT_REFERENCE_COUNT 0x1080 -#define CL_CONTEXT_DEVICES 0x1081 -#define CL_CONTEXT_PROPERTIES 0x1082 -#define CL_CONTEXT_NUM_DEVICES 0x1083 -#define CL_CONTEXT_PLATFORM 0x1084 -#define CL_CONTEXT_INTEROP_USER_SYNC 0x1085 - -#define CL_DEVICE_PARTITION_EQUALLY 0x1086 -#define CL_DEVICE_PARTITION_BY_COUNTS 0x1087 -#define CL_DEVICE_PARTITION_BY_COUNTS_LIST_END 0x0 -#define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN 0x1088 -#define CL_DEVICE_AFFINITY_DOMAIN_NUMA (1 << 0) -#define CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE (1 << 1) -#define CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE (1 << 2) -#define CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE (1 << 3) -#define CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE (1 << 4) -#define CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE (1 << 5) -#define CL_QUEUE_CONTEXT 0x1090 -#define CL_QUEUE_DEVICE 0x1091 -#define CL_QUEUE_REFERENCE_COUNT 0x1092 -#define CL_QUEUE_PROPERTIES 0x1093 -#define CL_MEM_READ_WRITE (1 << 0) -#define CL_MEM_WRITE_ONLY (1 << 1) -#define CL_MEM_READ_ONLY (1 << 2) -#define CL_MEM_USE_HOST_PTR (1 << 3) -#define CL_MEM_ALLOC_HOST_PTR (1 << 4) -#define CL_MEM_COPY_HOST_PTR (1 << 5) -// reserved (1 << 6) -#define CL_MEM_HOST_WRITE_ONLY (1 << 7) -#define CL_MEM_HOST_READ_ONLY (1 << 8) -#define CL_MEM_HOST_NO_ACCESS (1 << 9) -#define CL_MIGRATE_MEM_OBJECT_HOST (1 << 0) -#define CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED (1 << 1) - -#define CL_R 0x10B0 -#define CL_A 0x10B1 -#define CL_RG 0x10B2 -#define CL_RA 0x10B3 -#define CL_RGB 0x10B4 -#define CL_RGBA 0x10B5 -#define CL_BGRA 0x10B6 -#define CL_ARGB 0x10B7 -#define CL_INTENSITY 0x10B8 -#define CL_LUMINANCE 0x10B9 -#define CL_Rx 0x10BA -#define CL_RGx 0x10BB -#define CL_RGBx 0x10BC -#define CL_DEPTH 0x10BD -#define CL_DEPTH_STENCIL 0x10BE - -#define CL_SNORM_INT8 0x10D0 -#define CL_SNORM_INT16 0x10D1 -#define CL_UNORM_INT8 0x10D2 -#define CL_UNORM_INT16 0x10D3 -#define CL_UNORM_SHORT_565 0x10D4 -#define CL_UNORM_SHORT_555 0x10D5 -#define CL_UNORM_INT_101010 0x10D6 -#define CL_SIGNED_INT8 0x10D7 -#define CL_SIGNED_INT16 0x10D8 -#define CL_SIGNED_INT32 0x10D9 -#define CL_UNSIGNED_INT8 0x10DA -#define CL_UNSIGNED_INT16 0x10DB -#define CL_UNSIGNED_INT32 0x10DC -#define CL_HALF_FLOAT 0x10DD -#define CL_FLOAT 0x10DE -#define CL_UNORM_INT24 0x10DF - -#define CL_MEM_OBJECT_BUFFER 0x10F0 -#define CL_MEM_OBJECT_IMAGE2D 0x10F1 -#define CL_MEM_OBJECT_IMAGE3D 0x10F2 -#define CL_MEM_OBJECT_IMAGE2D_ARRAY 0x10F3 -#define CL_MEM_OBJECT_IMAGE1D 0x10F4 -#define CL_MEM_OBJECT_IMAGE1D_ARRAY 0x10F5 -#define CL_MEM_OBJECT_IMAGE1D_BUFFER 0x10F6 - -#define CL_MEM_TYPE 0x1100 -#define CL_MEM_FLAGS 0x1101 -#define CL_MEM_SIZE 0x1102 -#define CL_MEM_HOST_PTR 0x1103 -#define CL_MEM_MAP_COUNT 0x1104 -#define CL_MEM_REFERENCE_COUNT 0x1105 -#define CL_MEM_CONTEXT 0x1106 -#define CL_MEM_ASSOCIATED_MEMOBJECT 0x1107 -#define CL_MEM_OFFSET 0x1108 - -#define CL_IMAGE_FORMAT 0x1110 -#define CL_IMAGE_ELEMENT_SIZE 0x1111 -#define CL_IMAGE_ROW_PITCH 0x1112 -#define CL_IMAGE_SLICE_PITCH 0x1113 -#define CL_IMAGE_WIDTH 0x1114 -#define CL_IMAGE_HEIGHT 0x1115 -#define CL_IMAGE_DEPTH 0x1116 -#define CL_IMAGE_ARRAY_SIZE 0x1117 -#define CL_IMAGE_BUFFER 0x1118 -#define CL_IMAGE_NUM_MIP_LEVELS 0x1119 -#define CL_IMAGE_NUM_SAMPLES 0x111A - -#define CL_ADDRESS_NONE 0x1130 -#define CL_ADDRESS_CLAMP_TO_EDGE 0x1131 -#define CL_ADDRESS_CLAMP 0x1132 -#define CL_ADDRESS_REPEAT 0x1133 -#define CL_ADDRESS_MIRRORED_REPEAT 0x1134 - -#define CL_FILTER_NEAREST 0x1140 -#define CL_FILTER_LINEAR 0x1141 - -#define CL_SAMPLER_REFERENCE_COUNT 0x1150 -#define CL_SAMPLER_CONTEXT 0x1151 -#define CL_SAMPLER_NORMALIZED_COORDS 0x1152 -#define CL_SAMPLER_ADDRESSING_MODE 0x1153 -#define CL_SAMPLER_FILTER_MODE 0x1154 - -#define CL_MAP_READ (1 << 0) -#define CL_MAP_WRITE (1 << 1) -#define CL_MAP_WRITE_INVALIDATE_REGION (1 << 2) - -#define CL_PROGRAM_REFERENCE_COUNT 0x1160 -#define CL_PROGRAM_CONTEXT 0x1161 -#define CL_PROGRAM_NUM_DEVICES 0x1162 -#define CL_PROGRAM_DEVICES 0x1163 -#define CL_PROGRAM_SOURCE 0x1164 -#define CL_PROGRAM_BINARY_SIZES 0x1165 -#define CL_PROGRAM_BINARIES 0x1166 -#define CL_PROGRAM_NUM_KERNELS 0x1167 -#define CL_PROGRAM_KERNEL_NAMES 0x1168 -#define CL_PROGRAM_BUILD_STATUS 0x1181 -#define CL_PROGRAM_BUILD_OPTIONS 0x1182 -#define CL_PROGRAM_BUILD_LOG 0x1183 -#define CL_PROGRAM_BINARY_TYPE 0x1184 -#define CL_PROGRAM_BINARY_TYPE_NONE 0x0 -#define CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT 0x1 -#define CL_PROGRAM_BINARY_TYPE_LIBRARY 0x2 -#define CL_PROGRAM_BINARY_TYPE_EXECUTABLE 0x4 - -#define CL_BUILD_SUCCESS 0 -#define CL_BUILD_NONE -1 -#define CL_BUILD_ERROR -2 -#define CL_BUILD_IN_PROGRESS -3 - -#define CL_KERNEL_FUNCTION_NAME 0x1190 -#define CL_KERNEL_NUM_ARGS 0x1191 -#define CL_KERNEL_REFERENCE_COUNT 0x1192 -#define CL_KERNEL_CONTEXT 0x1193 -#define CL_KERNEL_PROGRAM 0x1194 -#define CL_KERNEL_ATTRIBUTES 0x1195 -#define CL_KERNEL_ARG_ADDRESS_QUALIFIER 0x1196 -#define CL_KERNEL_ARG_ACCESS_QUALIFIER 0x1197 -#define CL_KERNEL_ARG_TYPE_NAME 0x1198 -#define CL_KERNEL_ARG_TYPE_QUALIFIER 0x1199 -#define CL_KERNEL_ARG_NAME 0x119A -#define CL_KERNEL_ARG_ADDRESS_GLOBAL 0x119B -#define CL_KERNEL_ARG_ADDRESS_LOCAL 0x119C -#define CL_KERNEL_ARG_ADDRESS_CONSTANT 0x119D -#define CL_KERNEL_ARG_ADDRESS_PRIVATE 0x119E -#define CL_KERNEL_ARG_ACCESS_READ_ONLY 0x11A0 -#define CL_KERNEL_ARG_ACCESS_WRITE_ONLY 0x11A1 -#define CL_KERNEL_ARG_ACCESS_READ_WRITE 0x11A2 -#define CL_KERNEL_ARG_ACCESS_NONE 0x11A3 -#define CL_KERNEL_ARG_TYPE_NONE 0 -#define CL_KERNEL_ARG_TYPE_CONST (1 << 0) -#define CL_KERNEL_ARG_TYPE_RESTRICT (1 << 1) -#define CL_KERNEL_ARG_TYPE_VOLATILE (1 << 2) -#define CL_KERNEL_WORK_GROUP_SIZE 0x11B0 -#define CL_KERNEL_COMPILE_WORK_GROUP_SIZE 0x11B1 -#define CL_KERNEL_LOCAL_MEM_SIZE 0x11B2 -#define CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE 0x11B3 -#define CL_KERNEL_PRIVATE_MEM_SIZE 0x11B4 -#define CL_KERNEL_GLOBAL_WORK_SIZE 0x11B5 - -#define CL_EVENT_COMMAND_QUEUE 0x11D0 -#define CL_EVENT_COMMAND_TYPE 0x11D1 -#define CL_EVENT_REFERENCE_COUNT 0x11D2 -#define CL_EVENT_COMMAND_EXECUTION_STATUS 0x11D3 -#define CL_EVENT_CONTEXT 0x11D4 - -#define CL_COMMAND_NDRANGE_KERNEL 0x11F0 -#define CL_COMMAND_TASK 0x11F1 -#define CL_COMMAND_NATIVE_KERNEL 0x11F2 -#define CL_COMMAND_READ_BUFFER 0x11F3 -#define CL_COMMAND_WRITE_BUFFER 0x11F4 -#define CL_COMMAND_COPY_BUFFER 0x11F5 -#define CL_COMMAND_READ_IMAGE 0x11F6 -#define CL_COMMAND_WRITE_IMAGE 0x11F7 -#define CL_COMMAND_COPY_IMAGE 0x11F8 -#define CL_COMMAND_COPY_IMAGE_TO_BUFFER 0x11F9 -#define CL_COMMAND_COPY_BUFFER_TO_IMAGE 0x11FA -#define CL_COMMAND_MAP_BUFFER 0x11FB -#define CL_COMMAND_MAP_IMAGE 0x11FC -#define CL_COMMAND_UNMAP_MEM_OBJECT 0x11FD -#define CL_COMMAND_MARKER 0x11FE -#define CL_COMMAND_ACQUIRE_GL_OBJECTS 0x11FF -#define CL_COMMAND_RELEASE_GL_OBJECTS 0x1200 -#define CL_COMMAND_READ_BUFFER_RECT 0x1201 -#define CL_COMMAND_WRITE_BUFFER_RECT 0x1202 -#define CL_COMMAND_COPY_BUFFER_RECT 0x1203 -#define CL_COMMAND_USER 0x1204 -#define CL_COMMAND_BARRIER 0x1205 -#define CL_COMMAND_MIGRATE_MEM_OBJECTS 0x1206 -#define CL_COMMAND_FILL_BUFFER 0x1207 -#define CL_COMMAND_FILL_IMAGE 0x1208 - -#define CL_COMPLETE 0x0 -#define CL_RUNNING 0x1 -#define CL_SUBMITTED 0x2 -#define CL_QUEUED 0x3 -#define CL_BUFFER_CREATE_TYPE_REGION 0x1220 - -#define CL_PROFILING_COMMAND_QUEUED 0x1280 -#define CL_PROFILING_COMMAND_SUBMIT 0x1281 -#define CL_PROFILING_COMMAND_START 0x1282 -#define CL_PROFILING_COMMAND_END 0x1283 - -#define CL_CALLBACK CV_STDCALL - - -#ifdef HAVE_OPENCL -static const char* oclFuncToCheck = "clEnqueueReadBufferRect"; -static volatile bool g_haveOpenCL = false; -#endif - -#if defined(__APPLE__) && defined(HAVE_OPENCL) -#include - -static void* initOpenCLAndLoad(const char* funcname) -{ - static bool initialized = false; - static void* handle = 0; - if (!handle) - { - if(!initialized) - { - const char* oclpath = getenv("OPENCV_OPENCL_RUNTIME"); - oclpath = oclpath && strlen(oclpath) > 0 ? oclpath : - "/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL"; - handle = dlopen(oclpath, RTLD_LAZY); - initialized = true; - g_haveOpenCL = handle != 0 && dlsym(handle, oclFuncToCheck) != 0; - if( g_haveOpenCL ) - fprintf(stderr, "Successfully loaded OpenCL v1.1+ runtime from %s\n", oclpath); - else - fprintf(stderr, "Failed to load OpenCL runtime\n"); - } - if(!handle) - return 0; - } - - return funcname && handle ? dlsym(handle, funcname) : 0; -} - -#elif (defined WIN32 || defined _WIN32) && defined(HAVE_OPENCL) - -#ifndef _WIN32_WINNT // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?) - #define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx -#endif -#include -#if (_WIN32_WINNT >= 0x0602) - #include -#endif -#undef small -#undef min -#undef max -#undef abs - -static void* initOpenCLAndLoad(const char* funcname) -{ - static bool initialized = false; - static HMODULE handle = 0; - if (!handle) - { -#ifndef WINRT - if(!initialized) - { - handle = LoadLibraryA("OpenCL.dll"); - initialized = true; - g_haveOpenCL = handle != 0 && GetProcAddress(handle, oclFuncToCheck) != 0; - } -#endif - if(!handle) - return 0; - } - - return funcname ? (void*)GetProcAddress(handle, funcname) : 0; -} - -#elif defined(__linux) && defined(HAVE_OPENCL) - -#include -#include - -static void* initOpenCLAndLoad(const char* funcname) -{ - static bool initialized = false; - static void* handle = 0; - if (!handle) - { - if(!initialized) - { - handle = dlopen("libOpenCL.so", RTLD_LAZY); - if(!handle) - handle = dlopen("libCL.so", RTLD_LAZY); - initialized = true; - g_haveOpenCL = handle != 0 && dlsym(handle, oclFuncToCheck) != 0; - } - if(!handle) - return 0; - } - - return funcname ? (void*)dlsym(handle, funcname) : 0; -} - -#else - -static void* initOpenCLAndLoad(const char*) -{ - return 0; -} - -#endif - - -#define OCL_FUNC(rettype, funcname, argsdecl, args) \ - typedef rettype (CV_STDCALL * funcname##_t) argsdecl; \ - static rettype funcname argsdecl \ - { \ - static funcname##_t funcname##_p = 0; \ - if( !funcname##_p ) \ - { \ - funcname##_p = (funcname##_t)initOpenCLAndLoad(#funcname); \ - if( !funcname##_p ) \ - return OPENCV_CL_NOT_IMPLEMENTED; \ - } \ - return funcname##_p args; \ - } - - -#define OCL_FUNC_P(rettype, funcname, argsdecl, args) \ - typedef rettype (CV_STDCALL * funcname##_t) argsdecl; \ - static rettype funcname argsdecl \ - { \ - static funcname##_t funcname##_p = 0; \ - if( !funcname##_p ) \ - { \ - funcname##_p = (funcname##_t)initOpenCLAndLoad(#funcname); \ - if( !funcname##_p ) \ - { \ - if( errcode_ret ) \ - *errcode_ret = OPENCV_CL_NOT_IMPLEMENTED; \ - return 0; \ - } \ - } \ - return funcname##_p args; \ - } - -OCL_FUNC(cl_int, clGetPlatformIDs, - (cl_uint num_entries, cl_platform_id* platforms, cl_uint* num_platforms), - (num_entries, platforms, num_platforms)) - -OCL_FUNC(cl_int, clGetPlatformInfo, - (cl_platform_id platform, cl_platform_info param_name, - size_t param_value_size, void * param_value, - size_t * param_value_size_ret), - (platform, param_name, param_value_size, param_value, param_value_size_ret)) - -OCL_FUNC(cl_int, clGetDeviceInfo, - (cl_device_id device, - cl_device_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (device, param_name, param_value_size, param_value, param_value_size_ret)) - - -OCL_FUNC(cl_int, clGetDeviceIDs, - (cl_platform_id platform, - cl_device_type device_type, - cl_uint num_entries, - cl_device_id * devices, - cl_uint * num_devices), - (platform, device_type, num_entries, devices, num_devices)) - -OCL_FUNC_P(cl_context, clCreateContext, - (const cl_context_properties * properties, - cl_uint num_devices, - const cl_device_id * devices, - void (CL_CALLBACK * pfn_notify)(const char *, const void *, size_t, void *), - void * user_data, - cl_int * errcode_ret), - (properties, num_devices, devices, pfn_notify, user_data, errcode_ret)) - -OCL_FUNC(cl_int, clReleaseContext, (cl_context context), (context)) - - -OCL_FUNC(cl_int, clRetainContext, (cl_context context), (context)) -/* -OCL_FUNC_P(cl_context, clCreateContextFromType, - (const cl_context_properties * properties, - cl_device_type device_type, - void (CL_CALLBACK * pfn_notify)(const char *, const void *, size_t, void *), - void * user_data, - cl_int * errcode_ret), - (properties, device_type, pfn_notify, user_data, errcode_ret)) - -OCL_FUNC(cl_int, clGetContextInfo, - (cl_context context, - cl_context_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (context, param_name, param_value_size, - param_value, param_value_size_ret)) -*/ -OCL_FUNC_P(cl_command_queue, clCreateCommandQueue, - (cl_context context, - cl_device_id device, - cl_command_queue_properties properties, - cl_int * errcode_ret), - (context, device, properties, errcode_ret)) - -OCL_FUNC(cl_int, clReleaseCommandQueue, (cl_command_queue command_queue), (command_queue)) - -OCL_FUNC_P(cl_mem, clCreateBuffer, - (cl_context context, - cl_mem_flags flags, - size_t size, - void * host_ptr, - cl_int * errcode_ret), - (context, flags, size, host_ptr, errcode_ret)) - -/* -OCL_FUNC(cl_int, clRetainCommandQueue, (cl_command_queue command_queue), (command_queue)) - -OCL_FUNC(cl_int, clGetCommandQueueInfo, - (cl_command_queue command_queue, - cl_command_queue_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (command_queue, param_name, param_value_size, param_value, param_value_size_ret)) - -OCL_FUNC_P(cl_mem, clCreateSubBuffer, - (cl_mem buffer, - cl_mem_flags flags, - cl_buffer_create_type buffer_create_type, - const void * buffer_create_info, - cl_int * errcode_ret), - (buffer, flags, buffer_create_type, buffer_create_info, errcode_ret)) -*/ - -OCL_FUNC_P(cl_mem, clCreateImage, - (cl_context context, - cl_mem_flags flags, - const cl_image_format * image_format, - const cl_image_desc * image_desc, - void * host_ptr, - cl_int * errcode_ret), - (context, flags, image_format, image_desc, host_ptr, errcode_ret)) - -OCL_FUNC_P(cl_mem, clCreateImage2D, - (cl_context context, - cl_mem_flags flags, - const cl_image_format * image_format, - size_t image_width, - size_t image_height, - size_t image_row_pitch, - void * host_ptr, - cl_int *errcode_ret), - (context, flags, image_format, image_width, image_height, image_row_pitch, host_ptr, errcode_ret)) - -OCL_FUNC(cl_int, clGetSupportedImageFormats, - (cl_context context, - cl_mem_flags flags, - cl_mem_object_type image_type, - cl_uint num_entries, - cl_image_format * image_formats, - cl_uint * num_image_formats), - (context, flags, image_type, num_entries, image_formats, num_image_formats)) - - -OCL_FUNC(cl_int, clGetMemObjectInfo, - (cl_mem memobj, - cl_mem_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (memobj, param_name, param_value_size, param_value, param_value_size_ret)) - -OCL_FUNC(cl_int, clGetImageInfo, - (cl_mem image, - cl_image_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (image, param_name, param_value_size, param_value, param_value_size_ret)) - -/* -OCL_FUNC(cl_int, clCreateKernelsInProgram, - (cl_program program, - cl_uint num_kernels, - cl_kernel * kernels, - cl_uint * num_kernels_ret), - (program, num_kernels, kernels, num_kernels_ret)) - -OCL_FUNC(cl_int, clRetainKernel, (cl_kernel kernel), (kernel)) - -OCL_FUNC(cl_int, clGetKernelArgInfo, - (cl_kernel kernel, - cl_uint arg_indx, - cl_kernel_arg_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (kernel, arg_indx, param_name, param_value_size, param_value, param_value_size_ret)) - -OCL_FUNC(cl_int, clEnqueueReadImage, - (cl_command_queue command_queue, - cl_mem image, - cl_bool blocking_read, - const size_t * origin[3], - const size_t * region[3], - size_t row_pitch, - size_t slice_pitch, - void * ptr, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, image, blocking_read, origin, region, - row_pitch, slice_pitch, - ptr, - num_events_in_wait_list, - event_wait_list, - event)) - -OCL_FUNC(cl_int, clEnqueueWriteImage, - (cl_command_queue command_queue, - cl_mem image, - cl_bool blocking_write, - const size_t * origin[3], - const size_t * region[3], - size_t input_row_pitch, - size_t input_slice_pitch, - const void * ptr, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, image, blocking_write, origin, region, input_row_pitch, - input_slice_pitch, ptr, num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueFillImage, - (cl_command_queue command_queue, - cl_mem image, - const void * fill_color, - const size_t * origin[3], - const size_t * region[3], - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, image, fill_color, origin, region, - num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueCopyImage, - (cl_command_queue command_queue, - cl_mem src_image, - cl_mem dst_image, - const size_t * src_origin[3], - const size_t * dst_origin[3], - const size_t * region[3], - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, src_image, dst_image, src_origin, dst_origin, - region, num_events_in_wait_list, event_wait_list, event)) -*/ - -OCL_FUNC(cl_int, clEnqueueCopyImageToBuffer, - (cl_command_queue command_queue, - cl_mem src_image, - cl_mem dst_buffer, - const size_t * src_origin, - const size_t * region, - size_t dst_offset, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, src_image, dst_buffer, src_origin, region, dst_offset, - num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueCopyBufferToImage, - (cl_command_queue command_queue, - cl_mem src_buffer, - cl_mem dst_image, - size_t src_offset, - const size_t dst_origin[3], - const size_t region[3], - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, src_buffer, dst_image, src_offset, dst_origin, - region, num_events_in_wait_list, event_wait_list, event)) - - OCL_FUNC(cl_int, clFlush, - (cl_command_queue command_queue), - (command_queue)) - -/* -OCL_FUNC_P(void*, clEnqueueMapImage, - (cl_command_queue command_queue, - cl_mem image, - cl_bool blocking_map, - cl_map_flags map_flags, - const size_t * origin[3], - const size_t * region[3], - size_t * image_row_pitch, - size_t * image_slice_pitch, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event, - cl_int * errcode_ret), - (command_queue, image, blocking_map, map_flags, origin, region, - image_row_pitch, image_slice_pitch, num_events_in_wait_list, - event_wait_list, event, errcode_ret)) -*/ - -/* -OCL_FUNC(cl_int, clRetainProgram, (cl_program program), (program)) - -OCL_FUNC(cl_int, clGetKernelInfo, - (cl_kernel kernel, - cl_kernel_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (kernel, param_name, param_value_size, param_value, param_value_size_ret)) - -*/ - -OCL_FUNC(cl_int, clRetainMemObject, (cl_mem memobj), (memobj)) - -OCL_FUNC(cl_int, clReleaseMemObject, (cl_mem memobj), (memobj)) - - -OCL_FUNC_P(cl_program, clCreateProgramWithSource, - (cl_context context, - cl_uint count, - const char ** strings, - const size_t * lengths, - cl_int * errcode_ret), - (context, count, strings, lengths, errcode_ret)) - -OCL_FUNC_P(cl_program, clCreateProgramWithBinary, - (cl_context context, - cl_uint num_devices, - const cl_device_id * device_list, - const size_t * lengths, - const unsigned char ** binaries, - cl_int * binary_status, - cl_int * errcode_ret), - (context, num_devices, device_list, lengths, binaries, binary_status, errcode_ret)) - -OCL_FUNC(cl_int, clReleaseProgram, (cl_program program), (program)) - -OCL_FUNC(cl_int, clBuildProgram, - (cl_program program, - cl_uint num_devices, - const cl_device_id * device_list, - const char * options, - void (CL_CALLBACK * pfn_notify)(cl_program, void *), - void * user_data), - (program, num_devices, device_list, options, pfn_notify, user_data)) - -OCL_FUNC(cl_int, clGetProgramInfo, - (cl_program program, - cl_program_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (program, param_name, param_value_size, param_value, param_value_size_ret)) - -OCL_FUNC(cl_int, clGetProgramBuildInfo, - (cl_program program, - cl_device_id device, - cl_program_build_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (program, device, param_name, param_value_size, param_value, param_value_size_ret)) - -OCL_FUNC_P(cl_kernel, clCreateKernel, - (cl_program program, - const char * kernel_name, - cl_int * errcode_ret), - (program, kernel_name, errcode_ret)) - -OCL_FUNC(cl_int, clReleaseKernel, (cl_kernel kernel), (kernel)) - -OCL_FUNC(cl_int, clSetKernelArg, - (cl_kernel kernel, - cl_uint arg_index, - size_t arg_size, - const void * arg_value), - (kernel, arg_index, arg_size, arg_value)) - -OCL_FUNC(cl_int, clGetKernelWorkGroupInfo, - (cl_kernel kernel, - cl_device_id device, - cl_kernel_work_group_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret), - (kernel, device, param_name, param_value_size, param_value, param_value_size_ret)) - -OCL_FUNC(cl_int, clFinish, (cl_command_queue command_queue), (command_queue)) - -OCL_FUNC(cl_int, clEnqueueReadBuffer, - (cl_command_queue command_queue, - cl_mem buffer, - cl_bool blocking_read, - size_t offset, - size_t size, - void * ptr, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, buffer, blocking_read, offset, size, ptr, - num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueReadBufferRect, - (cl_command_queue command_queue, - cl_mem buffer, - cl_bool blocking_read, - const size_t * buffer_offset, - const size_t * host_offset, - const size_t * region, - size_t buffer_row_pitch, - size_t buffer_slice_pitch, - size_t host_row_pitch, - size_t host_slice_pitch, - void * ptr, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, buffer, blocking_read, buffer_offset, host_offset, region, buffer_row_pitch, - buffer_slice_pitch, host_row_pitch, host_slice_pitch, ptr, num_events_in_wait_list, - event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueWriteBuffer, - (cl_command_queue command_queue, - cl_mem buffer, - cl_bool blocking_write, - size_t offset, - size_t size, - const void * ptr, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, buffer, blocking_write, offset, size, ptr, - num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueWriteBufferRect, - (cl_command_queue command_queue, - cl_mem buffer, - cl_bool blocking_write, - const size_t * buffer_offset, - const size_t * host_offset, - const size_t * region, - size_t buffer_row_pitch, - size_t buffer_slice_pitch, - size_t host_row_pitch, - size_t host_slice_pitch, - const void * ptr, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, buffer, blocking_write, buffer_offset, host_offset, - region, buffer_row_pitch, buffer_slice_pitch, host_row_pitch, - host_slice_pitch, ptr, num_events_in_wait_list, event_wait_list, event)) - -/*OCL_FUNC(cl_int, clEnqueueFillBuffer, - (cl_command_queue command_queue, - cl_mem buffer, - const void * pattern, - size_t pattern_size, - size_t offset, - size_t size, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, buffer, pattern, pattern_size, offset, size, - num_events_in_wait_list, event_wait_list, event))*/ - -OCL_FUNC(cl_int, clEnqueueCopyBuffer, - (cl_command_queue command_queue, - cl_mem src_buffer, - cl_mem dst_buffer, - size_t src_offset, - size_t dst_offset, - size_t size, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, src_buffer, dst_buffer, src_offset, dst_offset, - size, num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueCopyBufferRect, - (cl_command_queue command_queue, - cl_mem src_buffer, - cl_mem dst_buffer, - const size_t * src_origin, - const size_t * dst_origin, - const size_t * region, - size_t src_row_pitch, - size_t src_slice_pitch, - size_t dst_row_pitch, - size_t dst_slice_pitch, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, src_buffer, dst_buffer, src_origin, dst_origin, - region, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch, - num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC_P(void*, clEnqueueMapBuffer, - (cl_command_queue command_queue, - cl_mem buffer, - cl_bool blocking_map, - cl_map_flags map_flags, - size_t offset, - size_t size, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event, - cl_int * errcode_ret), - (command_queue, buffer, blocking_map, map_flags, offset, size, - num_events_in_wait_list, event_wait_list, event, errcode_ret)) - -OCL_FUNC(cl_int, clEnqueueUnmapMemObject, - (cl_command_queue command_queue, - cl_mem memobj, - void * mapped_ptr, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, memobj, mapped_ptr, num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueNDRangeKernel, - (cl_command_queue command_queue, - cl_kernel kernel, - cl_uint work_dim, - const size_t * global_work_offset, - const size_t * global_work_size, - const size_t * local_work_size, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, kernel, work_dim, global_work_offset, global_work_size, - local_work_size, num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clEnqueueTask, - (cl_command_queue command_queue, - cl_kernel kernel, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event), - (command_queue, kernel, num_events_in_wait_list, event_wait_list, event)) - -OCL_FUNC(cl_int, clSetEventCallback, - (cl_event event, - cl_int command_exec_callback_type , - void (CL_CALLBACK *pfn_event_notify) (cl_event event, cl_int event_command_exec_status, void *user_data), - void *user_data), - (event, command_exec_callback_type, pfn_event_notify, user_data)) - -OCL_FUNC(cl_int, clReleaseEvent, (cl_event event), (event)) - -} - -#endif - -#ifndef CL_VERSION_1_2 -#define CL_VERSION_1_2 -#endif - +#include "ocl_deprecated.hpp" #endif // HAVE_OPENCL #ifdef _DEBUG diff --git a/modules/core/src/ocl_deprecated.hpp b/modules/core/src/ocl_deprecated.hpp new file mode 100644 index 0000000000..49ff368aae --- /dev/null +++ b/modules/core/src/ocl_deprecated.hpp @@ -0,0 +1,1211 @@ +// 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. + +/* + Part of the file is an extract from the standard OpenCL headers from Khronos site. + Below is the original copyright. +*/ + +/******************************************************************************* + * Copyright (c) 2008 - 2012 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +#if 0 //defined __APPLE__ +#define HAVE_OPENCL 1 +#else +#undef HAVE_OPENCL +#endif + +#define OPENCV_CL_NOT_IMPLEMENTED -1000 + +#ifdef HAVE_OPENCL + +#if defined __APPLE__ +#include +#else +#include +#endif + +static const bool g_haveOpenCL = true; + +#else + +extern "C" { + +struct _cl_platform_id { int dummy; }; +struct _cl_device_id { int dummy; }; +struct _cl_context { int dummy; }; +struct _cl_command_queue { int dummy; }; +struct _cl_mem { int dummy; }; +struct _cl_program { int dummy; }; +struct _cl_kernel { int dummy; }; +struct _cl_event { int dummy; }; +struct _cl_sampler { int dummy; }; + +typedef struct _cl_platform_id * cl_platform_id; +typedef struct _cl_device_id * cl_device_id; +typedef struct _cl_context * cl_context; +typedef struct _cl_command_queue * cl_command_queue; +typedef struct _cl_mem * cl_mem; +typedef struct _cl_program * cl_program; +typedef struct _cl_kernel * cl_kernel; +typedef struct _cl_event * cl_event; +typedef struct _cl_sampler * cl_sampler; + +typedef int cl_int; +typedef unsigned cl_uint; +#if defined (_WIN32) && defined(_MSC_VER) + typedef __int64 cl_long; + typedef unsigned __int64 cl_ulong; +#else + typedef long cl_long; + typedef unsigned long cl_ulong; +#endif + +typedef cl_uint cl_bool; /* WARNING! Unlike cl_ types in cl_platform.h, cl_bool is not guaranteed to be the same size as the bool in kernels. */ +typedef cl_ulong cl_bitfield; +typedef cl_bitfield cl_device_type; +typedef cl_uint cl_platform_info; +typedef cl_uint cl_device_info; +typedef cl_bitfield cl_device_fp_config; +typedef cl_uint cl_device_mem_cache_type; +typedef cl_uint cl_device_local_mem_type; +typedef cl_bitfield cl_device_exec_capabilities; +typedef cl_bitfield cl_command_queue_properties; +typedef intptr_t cl_device_partition_property; +typedef cl_bitfield cl_device_affinity_domain; + +typedef intptr_t cl_context_properties; +typedef cl_uint cl_context_info; +typedef cl_uint cl_command_queue_info; +typedef cl_uint cl_channel_order; +typedef cl_uint cl_channel_type; +typedef cl_bitfield cl_mem_flags; +typedef cl_uint cl_mem_object_type; +typedef cl_uint cl_mem_info; +typedef cl_bitfield cl_mem_migration_flags; +typedef cl_uint cl_image_info; +typedef cl_uint cl_buffer_create_type; +typedef cl_uint cl_addressing_mode; +typedef cl_uint cl_filter_mode; +typedef cl_uint cl_sampler_info; +typedef cl_bitfield cl_map_flags; +typedef cl_uint cl_program_info; +typedef cl_uint cl_program_build_info; +typedef cl_uint cl_program_binary_type; +typedef cl_int cl_build_status; +typedef cl_uint cl_kernel_info; +typedef cl_uint cl_kernel_arg_info; +typedef cl_uint cl_kernel_arg_address_qualifier; +typedef cl_uint cl_kernel_arg_access_qualifier; +typedef cl_bitfield cl_kernel_arg_type_qualifier; +typedef cl_uint cl_kernel_work_group_info; +typedef cl_uint cl_event_info; +typedef cl_uint cl_command_type; +typedef cl_uint cl_profiling_info; + + +typedef struct _cl_image_format { + cl_channel_order image_channel_order; + cl_channel_type image_channel_data_type; +} cl_image_format; + +typedef struct _cl_image_desc { + cl_mem_object_type image_type; + size_t image_width; + size_t image_height; + size_t image_depth; + size_t image_array_size; + size_t image_row_pitch; + size_t image_slice_pitch; + cl_uint num_mip_levels; + cl_uint num_samples; + cl_mem buffer; +} cl_image_desc; + +typedef struct _cl_buffer_region { + size_t origin; + size_t size; +} cl_buffer_region; + + +////////////////////////////////////////////////////////// + +#define CL_SUCCESS 0 +#define CL_DEVICE_NOT_FOUND -1 +#define CL_DEVICE_NOT_AVAILABLE -2 +#define CL_COMPILER_NOT_AVAILABLE -3 +#define CL_MEM_OBJECT_ALLOCATION_FAILURE -4 +#define CL_OUT_OF_RESOURCES -5 +#define CL_OUT_OF_HOST_MEMORY -6 +#define CL_PROFILING_INFO_NOT_AVAILABLE -7 +#define CL_MEM_COPY_OVERLAP -8 +#define CL_IMAGE_FORMAT_MISMATCH -9 +#define CL_IMAGE_FORMAT_NOT_SUPPORTED -10 +#define CL_BUILD_PROGRAM_FAILURE -11 +#define CL_MAP_FAILURE -12 +#define CL_MISALIGNED_SUB_BUFFER_OFFSET -13 +#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14 +#define CL_COMPILE_PROGRAM_FAILURE -15 +#define CL_LINKER_NOT_AVAILABLE -16 +#define CL_LINK_PROGRAM_FAILURE -17 +#define CL_DEVICE_PARTITION_FAILED -18 +#define CL_KERNEL_ARG_INFO_NOT_AVAILABLE -19 + +#define CL_INVALID_VALUE -30 +#define CL_INVALID_DEVICE_TYPE -31 +#define CL_INVALID_PLATFORM -32 +#define CL_INVALID_DEVICE -33 +#define CL_INVALID_CONTEXT -34 +#define CL_INVALID_QUEUE_PROPERTIES -35 +#define CL_INVALID_COMMAND_QUEUE -36 +#define CL_INVALID_HOST_PTR -37 +#define CL_INVALID_MEM_OBJECT -38 +#define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR -39 +#define CL_INVALID_IMAGE_SIZE -40 +#define CL_INVALID_SAMPLER -41 +#define CL_INVALID_BINARY -42 +#define CL_INVALID_BUILD_OPTIONS -43 +#define CL_INVALID_PROGRAM -44 +#define CL_INVALID_PROGRAM_EXECUTABLE -45 +#define CL_INVALID_KERNEL_NAME -46 +#define CL_INVALID_KERNEL_DEFINITION -47 +#define CL_INVALID_KERNEL -48 +#define CL_INVALID_ARG_INDEX -49 +#define CL_INVALID_ARG_VALUE -50 +#define CL_INVALID_ARG_SIZE -51 +#define CL_INVALID_KERNEL_ARGS -52 +#define CL_INVALID_WORK_DIMENSION -53 +#define CL_INVALID_WORK_GROUP_SIZE -54 +#define CL_INVALID_WORK_ITEM_SIZE -55 +#define CL_INVALID_GLOBAL_OFFSET -56 +#define CL_INVALID_EVENT_WAIT_LIST -57 +#define CL_INVALID_EVENT -58 +#define CL_INVALID_OPERATION -59 +#define CL_INVALID_GL_OBJECT -60 +#define CL_INVALID_BUFFER_SIZE -61 +#define CL_INVALID_MIP_LEVEL -62 +#define CL_INVALID_GLOBAL_WORK_SIZE -63 +#define CL_INVALID_PROPERTY -64 +#define CL_INVALID_IMAGE_DESCRIPTOR -65 +#define CL_INVALID_COMPILER_OPTIONS -66 +#define CL_INVALID_LINKER_OPTIONS -67 +#define CL_INVALID_DEVICE_PARTITION_COUNT -68 + +/*#define CL_VERSION_1_0 1 +#define CL_VERSION_1_1 1 +#define CL_VERSION_1_2 1*/ + +#define CL_FALSE 0 +#define CL_TRUE 1 +#define CL_BLOCKING CL_TRUE +#define CL_NON_BLOCKING CL_FALSE + +#define CL_PLATFORM_PROFILE 0x0900 +#define CL_PLATFORM_VERSION 0x0901 +#define CL_PLATFORM_NAME 0x0902 +#define CL_PLATFORM_VENDOR 0x0903 +#define CL_PLATFORM_EXTENSIONS 0x0904 + +#define CL_DEVICE_TYPE_DEFAULT (1 << 0) +#define CL_DEVICE_TYPE_CPU (1 << 1) +#define CL_DEVICE_TYPE_GPU (1 << 2) +#define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) +#define CL_DEVICE_TYPE_CUSTOM (1 << 4) +#define CL_DEVICE_TYPE_ALL 0xFFFFFFFF +#define CL_DEVICE_TYPE 0x1000 +#define CL_DEVICE_VENDOR_ID 0x1001 +#define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 +#define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 +#define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 +#define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B +#define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C +#define CL_DEVICE_ADDRESS_BITS 0x100D +#define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E +#define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F +#define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 +#define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 +#define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 +#define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 +#define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 +#define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 +#define CL_DEVICE_IMAGE_SUPPORT 0x1016 +#define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 +#define CL_DEVICE_MAX_SAMPLERS 0x1018 +#define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 +#define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A +#define CL_DEVICE_SINGLE_FP_CONFIG 0x101B +#define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C +#define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D +#define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E +#define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F +#define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 +#define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 +#define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 +#define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 +#define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 +#define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 +#define CL_DEVICE_ENDIAN_LITTLE 0x1026 +#define CL_DEVICE_AVAILABLE 0x1027 +#define CL_DEVICE_COMPILER_AVAILABLE 0x1028 +#define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 +#define CL_DEVICE_QUEUE_PROPERTIES 0x102A +#define CL_DEVICE_NAME 0x102B +#define CL_DEVICE_VENDOR 0x102C +#define CL_DRIVER_VERSION 0x102D +#define CL_DEVICE_PROFILE 0x102E +#define CL_DEVICE_VERSION 0x102F +#define CL_DEVICE_EXTENSIONS 0x1030 +#define CL_DEVICE_PLATFORM 0x1031 +#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 +#define CL_DEVICE_HALF_FP_CONFIG 0x1033 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034 +#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C +#define CL_DEVICE_OPENCL_C_VERSION 0x103D +#define CL_DEVICE_LINKER_AVAILABLE 0x103E +#define CL_DEVICE_BUILT_IN_KERNELS 0x103F +#define CL_DEVICE_IMAGE_MAX_BUFFER_SIZE 0x1040 +#define CL_DEVICE_IMAGE_MAX_ARRAY_SIZE 0x1041 +#define CL_DEVICE_PARENT_DEVICE 0x1042 +#define CL_DEVICE_PARTITION_MAX_SUB_DEVICES 0x1043 +#define CL_DEVICE_PARTITION_PROPERTIES 0x1044 +#define CL_DEVICE_PARTITION_AFFINITY_DOMAIN 0x1045 +#define CL_DEVICE_PARTITION_TYPE 0x1046 +#define CL_DEVICE_REFERENCE_COUNT 0x1047 +#define CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 0x1048 +#define CL_DEVICE_PRINTF_BUFFER_SIZE 0x1049 +#define CL_DEVICE_IMAGE_PITCH_ALIGNMENT 0x104A +#define CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT 0x104B + +#define CL_FP_DENORM (1 << 0) +#define CL_FP_INF_NAN (1 << 1) +#define CL_FP_ROUND_TO_NEAREST (1 << 2) +#define CL_FP_ROUND_TO_ZERO (1 << 3) +#define CL_FP_ROUND_TO_INF (1 << 4) +#define CL_FP_FMA (1 << 5) +#define CL_FP_SOFT_FLOAT (1 << 6) +#define CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT (1 << 7) + +#define CL_NONE 0x0 +#define CL_READ_ONLY_CACHE 0x1 +#define CL_READ_WRITE_CACHE 0x2 +#define CL_LOCAL 0x1 +#define CL_GLOBAL 0x2 +#define CL_EXEC_KERNEL (1 << 0) +#define CL_EXEC_NATIVE_KERNEL (1 << 1) +#define CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE (1 << 0) +#define CL_QUEUE_PROFILING_ENABLE (1 << 1) + +#define CL_CONTEXT_REFERENCE_COUNT 0x1080 +#define CL_CONTEXT_DEVICES 0x1081 +#define CL_CONTEXT_PROPERTIES 0x1082 +#define CL_CONTEXT_NUM_DEVICES 0x1083 +#define CL_CONTEXT_PLATFORM 0x1084 +#define CL_CONTEXT_INTEROP_USER_SYNC 0x1085 + +#define CL_DEVICE_PARTITION_EQUALLY 0x1086 +#define CL_DEVICE_PARTITION_BY_COUNTS 0x1087 +#define CL_DEVICE_PARTITION_BY_COUNTS_LIST_END 0x0 +#define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN 0x1088 +#define CL_DEVICE_AFFINITY_DOMAIN_NUMA (1 << 0) +#define CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE (1 << 1) +#define CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE (1 << 2) +#define CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE (1 << 3) +#define CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE (1 << 4) +#define CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE (1 << 5) +#define CL_QUEUE_CONTEXT 0x1090 +#define CL_QUEUE_DEVICE 0x1091 +#define CL_QUEUE_REFERENCE_COUNT 0x1092 +#define CL_QUEUE_PROPERTIES 0x1093 +#define CL_MEM_READ_WRITE (1 << 0) +#define CL_MEM_WRITE_ONLY (1 << 1) +#define CL_MEM_READ_ONLY (1 << 2) +#define CL_MEM_USE_HOST_PTR (1 << 3) +#define CL_MEM_ALLOC_HOST_PTR (1 << 4) +#define CL_MEM_COPY_HOST_PTR (1 << 5) +// reserved (1 << 6) +#define CL_MEM_HOST_WRITE_ONLY (1 << 7) +#define CL_MEM_HOST_READ_ONLY (1 << 8) +#define CL_MEM_HOST_NO_ACCESS (1 << 9) +#define CL_MIGRATE_MEM_OBJECT_HOST (1 << 0) +#define CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED (1 << 1) + +#define CL_R 0x10B0 +#define CL_A 0x10B1 +#define CL_RG 0x10B2 +#define CL_RA 0x10B3 +#define CL_RGB 0x10B4 +#define CL_RGBA 0x10B5 +#define CL_BGRA 0x10B6 +#define CL_ARGB 0x10B7 +#define CL_INTENSITY 0x10B8 +#define CL_LUMINANCE 0x10B9 +#define CL_Rx 0x10BA +#define CL_RGx 0x10BB +#define CL_RGBx 0x10BC +#define CL_DEPTH 0x10BD +#define CL_DEPTH_STENCIL 0x10BE + +#define CL_SNORM_INT8 0x10D0 +#define CL_SNORM_INT16 0x10D1 +#define CL_UNORM_INT8 0x10D2 +#define CL_UNORM_INT16 0x10D3 +#define CL_UNORM_SHORT_565 0x10D4 +#define CL_UNORM_SHORT_555 0x10D5 +#define CL_UNORM_INT_101010 0x10D6 +#define CL_SIGNED_INT8 0x10D7 +#define CL_SIGNED_INT16 0x10D8 +#define CL_SIGNED_INT32 0x10D9 +#define CL_UNSIGNED_INT8 0x10DA +#define CL_UNSIGNED_INT16 0x10DB +#define CL_UNSIGNED_INT32 0x10DC +#define CL_HALF_FLOAT 0x10DD +#define CL_FLOAT 0x10DE +#define CL_UNORM_INT24 0x10DF + +#define CL_MEM_OBJECT_BUFFER 0x10F0 +#define CL_MEM_OBJECT_IMAGE2D 0x10F1 +#define CL_MEM_OBJECT_IMAGE3D 0x10F2 +#define CL_MEM_OBJECT_IMAGE2D_ARRAY 0x10F3 +#define CL_MEM_OBJECT_IMAGE1D 0x10F4 +#define CL_MEM_OBJECT_IMAGE1D_ARRAY 0x10F5 +#define CL_MEM_OBJECT_IMAGE1D_BUFFER 0x10F6 + +#define CL_MEM_TYPE 0x1100 +#define CL_MEM_FLAGS 0x1101 +#define CL_MEM_SIZE 0x1102 +#define CL_MEM_HOST_PTR 0x1103 +#define CL_MEM_MAP_COUNT 0x1104 +#define CL_MEM_REFERENCE_COUNT 0x1105 +#define CL_MEM_CONTEXT 0x1106 +#define CL_MEM_ASSOCIATED_MEMOBJECT 0x1107 +#define CL_MEM_OFFSET 0x1108 + +#define CL_IMAGE_FORMAT 0x1110 +#define CL_IMAGE_ELEMENT_SIZE 0x1111 +#define CL_IMAGE_ROW_PITCH 0x1112 +#define CL_IMAGE_SLICE_PITCH 0x1113 +#define CL_IMAGE_WIDTH 0x1114 +#define CL_IMAGE_HEIGHT 0x1115 +#define CL_IMAGE_DEPTH 0x1116 +#define CL_IMAGE_ARRAY_SIZE 0x1117 +#define CL_IMAGE_BUFFER 0x1118 +#define CL_IMAGE_NUM_MIP_LEVELS 0x1119 +#define CL_IMAGE_NUM_SAMPLES 0x111A + +#define CL_ADDRESS_NONE 0x1130 +#define CL_ADDRESS_CLAMP_TO_EDGE 0x1131 +#define CL_ADDRESS_CLAMP 0x1132 +#define CL_ADDRESS_REPEAT 0x1133 +#define CL_ADDRESS_MIRRORED_REPEAT 0x1134 + +#define CL_FILTER_NEAREST 0x1140 +#define CL_FILTER_LINEAR 0x1141 + +#define CL_SAMPLER_REFERENCE_COUNT 0x1150 +#define CL_SAMPLER_CONTEXT 0x1151 +#define CL_SAMPLER_NORMALIZED_COORDS 0x1152 +#define CL_SAMPLER_ADDRESSING_MODE 0x1153 +#define CL_SAMPLER_FILTER_MODE 0x1154 + +#define CL_MAP_READ (1 << 0) +#define CL_MAP_WRITE (1 << 1) +#define CL_MAP_WRITE_INVALIDATE_REGION (1 << 2) + +#define CL_PROGRAM_REFERENCE_COUNT 0x1160 +#define CL_PROGRAM_CONTEXT 0x1161 +#define CL_PROGRAM_NUM_DEVICES 0x1162 +#define CL_PROGRAM_DEVICES 0x1163 +#define CL_PROGRAM_SOURCE 0x1164 +#define CL_PROGRAM_BINARY_SIZES 0x1165 +#define CL_PROGRAM_BINARIES 0x1166 +#define CL_PROGRAM_NUM_KERNELS 0x1167 +#define CL_PROGRAM_KERNEL_NAMES 0x1168 +#define CL_PROGRAM_BUILD_STATUS 0x1181 +#define CL_PROGRAM_BUILD_OPTIONS 0x1182 +#define CL_PROGRAM_BUILD_LOG 0x1183 +#define CL_PROGRAM_BINARY_TYPE 0x1184 +#define CL_PROGRAM_BINARY_TYPE_NONE 0x0 +#define CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT 0x1 +#define CL_PROGRAM_BINARY_TYPE_LIBRARY 0x2 +#define CL_PROGRAM_BINARY_TYPE_EXECUTABLE 0x4 + +#define CL_BUILD_SUCCESS 0 +#define CL_BUILD_NONE -1 +#define CL_BUILD_ERROR -2 +#define CL_BUILD_IN_PROGRESS -3 + +#define CL_KERNEL_FUNCTION_NAME 0x1190 +#define CL_KERNEL_NUM_ARGS 0x1191 +#define CL_KERNEL_REFERENCE_COUNT 0x1192 +#define CL_KERNEL_CONTEXT 0x1193 +#define CL_KERNEL_PROGRAM 0x1194 +#define CL_KERNEL_ATTRIBUTES 0x1195 +#define CL_KERNEL_ARG_ADDRESS_QUALIFIER 0x1196 +#define CL_KERNEL_ARG_ACCESS_QUALIFIER 0x1197 +#define CL_KERNEL_ARG_TYPE_NAME 0x1198 +#define CL_KERNEL_ARG_TYPE_QUALIFIER 0x1199 +#define CL_KERNEL_ARG_NAME 0x119A +#define CL_KERNEL_ARG_ADDRESS_GLOBAL 0x119B +#define CL_KERNEL_ARG_ADDRESS_LOCAL 0x119C +#define CL_KERNEL_ARG_ADDRESS_CONSTANT 0x119D +#define CL_KERNEL_ARG_ADDRESS_PRIVATE 0x119E +#define CL_KERNEL_ARG_ACCESS_READ_ONLY 0x11A0 +#define CL_KERNEL_ARG_ACCESS_WRITE_ONLY 0x11A1 +#define CL_KERNEL_ARG_ACCESS_READ_WRITE 0x11A2 +#define CL_KERNEL_ARG_ACCESS_NONE 0x11A3 +#define CL_KERNEL_ARG_TYPE_NONE 0 +#define CL_KERNEL_ARG_TYPE_CONST (1 << 0) +#define CL_KERNEL_ARG_TYPE_RESTRICT (1 << 1) +#define CL_KERNEL_ARG_TYPE_VOLATILE (1 << 2) +#define CL_KERNEL_WORK_GROUP_SIZE 0x11B0 +#define CL_KERNEL_COMPILE_WORK_GROUP_SIZE 0x11B1 +#define CL_KERNEL_LOCAL_MEM_SIZE 0x11B2 +#define CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE 0x11B3 +#define CL_KERNEL_PRIVATE_MEM_SIZE 0x11B4 +#define CL_KERNEL_GLOBAL_WORK_SIZE 0x11B5 + +#define CL_EVENT_COMMAND_QUEUE 0x11D0 +#define CL_EVENT_COMMAND_TYPE 0x11D1 +#define CL_EVENT_REFERENCE_COUNT 0x11D2 +#define CL_EVENT_COMMAND_EXECUTION_STATUS 0x11D3 +#define CL_EVENT_CONTEXT 0x11D4 + +#define CL_COMMAND_NDRANGE_KERNEL 0x11F0 +#define CL_COMMAND_TASK 0x11F1 +#define CL_COMMAND_NATIVE_KERNEL 0x11F2 +#define CL_COMMAND_READ_BUFFER 0x11F3 +#define CL_COMMAND_WRITE_BUFFER 0x11F4 +#define CL_COMMAND_COPY_BUFFER 0x11F5 +#define CL_COMMAND_READ_IMAGE 0x11F6 +#define CL_COMMAND_WRITE_IMAGE 0x11F7 +#define CL_COMMAND_COPY_IMAGE 0x11F8 +#define CL_COMMAND_COPY_IMAGE_TO_BUFFER 0x11F9 +#define CL_COMMAND_COPY_BUFFER_TO_IMAGE 0x11FA +#define CL_COMMAND_MAP_BUFFER 0x11FB +#define CL_COMMAND_MAP_IMAGE 0x11FC +#define CL_COMMAND_UNMAP_MEM_OBJECT 0x11FD +#define CL_COMMAND_MARKER 0x11FE +#define CL_COMMAND_ACQUIRE_GL_OBJECTS 0x11FF +#define CL_COMMAND_RELEASE_GL_OBJECTS 0x1200 +#define CL_COMMAND_READ_BUFFER_RECT 0x1201 +#define CL_COMMAND_WRITE_BUFFER_RECT 0x1202 +#define CL_COMMAND_COPY_BUFFER_RECT 0x1203 +#define CL_COMMAND_USER 0x1204 +#define CL_COMMAND_BARRIER 0x1205 +#define CL_COMMAND_MIGRATE_MEM_OBJECTS 0x1206 +#define CL_COMMAND_FILL_BUFFER 0x1207 +#define CL_COMMAND_FILL_IMAGE 0x1208 + +#define CL_COMPLETE 0x0 +#define CL_RUNNING 0x1 +#define CL_SUBMITTED 0x2 +#define CL_QUEUED 0x3 +#define CL_BUFFER_CREATE_TYPE_REGION 0x1220 + +#define CL_PROFILING_COMMAND_QUEUED 0x1280 +#define CL_PROFILING_COMMAND_SUBMIT 0x1281 +#define CL_PROFILING_COMMAND_START 0x1282 +#define CL_PROFILING_COMMAND_END 0x1283 + +#define CL_CALLBACK CV_STDCALL + + +#ifdef HAVE_OPENCL +static const char* oclFuncToCheck = "clEnqueueReadBufferRect"; +static volatile bool g_haveOpenCL = false; +#endif + +#if defined(__APPLE__) && defined(HAVE_OPENCL) +#include + +static void* initOpenCLAndLoad(const char* funcname) +{ + static bool initialized = false; + static void* handle = 0; + if (!handle) + { + if(!initialized) + { + const char* oclpath = getenv("OPENCV_OPENCL_RUNTIME"); + oclpath = oclpath && strlen(oclpath) > 0 ? oclpath : + "/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL"; + handle = dlopen(oclpath, RTLD_LAZY); + initialized = true; + g_haveOpenCL = handle != 0 && dlsym(handle, oclFuncToCheck) != 0; + if( g_haveOpenCL ) + fprintf(stderr, "Successfully loaded OpenCL v1.1+ runtime from %s\n", oclpath); + else + fprintf(stderr, "Failed to load OpenCL runtime\n"); + } + if(!handle) + return 0; + } + + return funcname && handle ? dlsym(handle, funcname) : 0; +} + +#elif (defined WIN32 || defined _WIN32) && defined(HAVE_OPENCL) + +#ifndef _WIN32_WINNT // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?) + #define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx +#endif +#include +#if (_WIN32_WINNT >= 0x0602) + #include +#endif +#undef small +#undef min +#undef max +#undef abs + +static void* initOpenCLAndLoad(const char* funcname) +{ + static bool initialized = false; + static HMODULE handle = 0; + if (!handle) + { +#ifndef WINRT + if(!initialized) + { + handle = LoadLibraryA("OpenCL.dll"); + initialized = true; + g_haveOpenCL = handle != 0 && GetProcAddress(handle, oclFuncToCheck) != 0; + } +#endif + if(!handle) + return 0; + } + + return funcname ? (void*)GetProcAddress(handle, funcname) : 0; +} + +#elif defined(__linux) && defined(HAVE_OPENCL) + +#include +#include + +static void* initOpenCLAndLoad(const char* funcname) +{ + static bool initialized = false; + static void* handle = 0; + if (!handle) + { + if(!initialized) + { + handle = dlopen("libOpenCL.so", RTLD_LAZY); + if(!handle) + handle = dlopen("libCL.so", RTLD_LAZY); + initialized = true; + g_haveOpenCL = handle != 0 && dlsym(handle, oclFuncToCheck) != 0; + } + if(!handle) + return 0; + } + + return funcname ? (void*)dlsym(handle, funcname) : 0; +} + +#else + +static void* initOpenCLAndLoad(const char*) +{ + return 0; +} + +#endif + + +#define OCL_FUNC(rettype, funcname, argsdecl, args) \ + typedef rettype (CV_STDCALL * funcname##_t) argsdecl; \ + static rettype funcname argsdecl \ + { \ + static funcname##_t funcname##_p = 0; \ + if( !funcname##_p ) \ + { \ + funcname##_p = (funcname##_t)initOpenCLAndLoad(#funcname); \ + if( !funcname##_p ) \ + return OPENCV_CL_NOT_IMPLEMENTED; \ + } \ + return funcname##_p args; \ + } + + +#define OCL_FUNC_P(rettype, funcname, argsdecl, args) \ + typedef rettype (CV_STDCALL * funcname##_t) argsdecl; \ + static rettype funcname argsdecl \ + { \ + static funcname##_t funcname##_p = 0; \ + if( !funcname##_p ) \ + { \ + funcname##_p = (funcname##_t)initOpenCLAndLoad(#funcname); \ + if( !funcname##_p ) \ + { \ + if( errcode_ret ) \ + *errcode_ret = OPENCV_CL_NOT_IMPLEMENTED; \ + return 0; \ + } \ + } \ + return funcname##_p args; \ + } + +OCL_FUNC(cl_int, clGetPlatformIDs, + (cl_uint num_entries, cl_platform_id* platforms, cl_uint* num_platforms), + (num_entries, platforms, num_platforms)) + +OCL_FUNC(cl_int, clGetPlatformInfo, + (cl_platform_id platform, cl_platform_info param_name, + size_t param_value_size, void * param_value, + size_t * param_value_size_ret), + (platform, param_name, param_value_size, param_value, param_value_size_ret)) + +OCL_FUNC(cl_int, clGetDeviceInfo, + (cl_device_id device, + cl_device_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (device, param_name, param_value_size, param_value, param_value_size_ret)) + + +OCL_FUNC(cl_int, clGetDeviceIDs, + (cl_platform_id platform, + cl_device_type device_type, + cl_uint num_entries, + cl_device_id * devices, + cl_uint * num_devices), + (platform, device_type, num_entries, devices, num_devices)) + +OCL_FUNC_P(cl_context, clCreateContext, + (const cl_context_properties * properties, + cl_uint num_devices, + const cl_device_id * devices, + void (CL_CALLBACK * pfn_notify)(const char *, const void *, size_t, void *), + void * user_data, + cl_int * errcode_ret), + (properties, num_devices, devices, pfn_notify, user_data, errcode_ret)) + +OCL_FUNC(cl_int, clReleaseContext, (cl_context context), (context)) + + +OCL_FUNC(cl_int, clRetainContext, (cl_context context), (context)) +/* +OCL_FUNC_P(cl_context, clCreateContextFromType, + (const cl_context_properties * properties, + cl_device_type device_type, + void (CL_CALLBACK * pfn_notify)(const char *, const void *, size_t, void *), + void * user_data, + cl_int * errcode_ret), + (properties, device_type, pfn_notify, user_data, errcode_ret)) + +OCL_FUNC(cl_int, clGetContextInfo, + (cl_context context, + cl_context_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (context, param_name, param_value_size, + param_value, param_value_size_ret)) +*/ +OCL_FUNC_P(cl_command_queue, clCreateCommandQueue, + (cl_context context, + cl_device_id device, + cl_command_queue_properties properties, + cl_int * errcode_ret), + (context, device, properties, errcode_ret)) + +OCL_FUNC(cl_int, clReleaseCommandQueue, (cl_command_queue command_queue), (command_queue)) + +OCL_FUNC_P(cl_mem, clCreateBuffer, + (cl_context context, + cl_mem_flags flags, + size_t size, + void * host_ptr, + cl_int * errcode_ret), + (context, flags, size, host_ptr, errcode_ret)) + +/* +OCL_FUNC(cl_int, clRetainCommandQueue, (cl_command_queue command_queue), (command_queue)) + +OCL_FUNC(cl_int, clGetCommandQueueInfo, + (cl_command_queue command_queue, + cl_command_queue_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (command_queue, param_name, param_value_size, param_value, param_value_size_ret)) + +OCL_FUNC_P(cl_mem, clCreateSubBuffer, + (cl_mem buffer, + cl_mem_flags flags, + cl_buffer_create_type buffer_create_type, + const void * buffer_create_info, + cl_int * errcode_ret), + (buffer, flags, buffer_create_type, buffer_create_info, errcode_ret)) +*/ + +OCL_FUNC_P(cl_mem, clCreateImage, + (cl_context context, + cl_mem_flags flags, + const cl_image_format * image_format, + const cl_image_desc * image_desc, + void * host_ptr, + cl_int * errcode_ret), + (context, flags, image_format, image_desc, host_ptr, errcode_ret)) + +OCL_FUNC_P(cl_mem, clCreateImage2D, + (cl_context context, + cl_mem_flags flags, + const cl_image_format * image_format, + size_t image_width, + size_t image_height, + size_t image_row_pitch, + void * host_ptr, + cl_int *errcode_ret), + (context, flags, image_format, image_width, image_height, image_row_pitch, host_ptr, errcode_ret)) + +OCL_FUNC(cl_int, clGetSupportedImageFormats, + (cl_context context, + cl_mem_flags flags, + cl_mem_object_type image_type, + cl_uint num_entries, + cl_image_format * image_formats, + cl_uint * num_image_formats), + (context, flags, image_type, num_entries, image_formats, num_image_formats)) + + +OCL_FUNC(cl_int, clGetMemObjectInfo, + (cl_mem memobj, + cl_mem_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (memobj, param_name, param_value_size, param_value, param_value_size_ret)) + +OCL_FUNC(cl_int, clGetImageInfo, + (cl_mem image, + cl_image_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (image, param_name, param_value_size, param_value, param_value_size_ret)) + +/* +OCL_FUNC(cl_int, clCreateKernelsInProgram, + (cl_program program, + cl_uint num_kernels, + cl_kernel * kernels, + cl_uint * num_kernels_ret), + (program, num_kernels, kernels, num_kernels_ret)) + +OCL_FUNC(cl_int, clRetainKernel, (cl_kernel kernel), (kernel)) + +OCL_FUNC(cl_int, clGetKernelArgInfo, + (cl_kernel kernel, + cl_uint arg_indx, + cl_kernel_arg_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (kernel, arg_indx, param_name, param_value_size, param_value, param_value_size_ret)) + +OCL_FUNC(cl_int, clEnqueueReadImage, + (cl_command_queue command_queue, + cl_mem image, + cl_bool blocking_read, + const size_t * origin[3], + const size_t * region[3], + size_t row_pitch, + size_t slice_pitch, + void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, image, blocking_read, origin, region, + row_pitch, slice_pitch, + ptr, + num_events_in_wait_list, + event_wait_list, + event)) + +OCL_FUNC(cl_int, clEnqueueWriteImage, + (cl_command_queue command_queue, + cl_mem image, + cl_bool blocking_write, + const size_t * origin[3], + const size_t * region[3], + size_t input_row_pitch, + size_t input_slice_pitch, + const void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, image, blocking_write, origin, region, input_row_pitch, + input_slice_pitch, ptr, num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueFillImage, + (cl_command_queue command_queue, + cl_mem image, + const void * fill_color, + const size_t * origin[3], + const size_t * region[3], + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, image, fill_color, origin, region, + num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueCopyImage, + (cl_command_queue command_queue, + cl_mem src_image, + cl_mem dst_image, + const size_t * src_origin[3], + const size_t * dst_origin[3], + const size_t * region[3], + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, src_image, dst_image, src_origin, dst_origin, + region, num_events_in_wait_list, event_wait_list, event)) +*/ + +OCL_FUNC(cl_int, clEnqueueCopyImageToBuffer, + (cl_command_queue command_queue, + cl_mem src_image, + cl_mem dst_buffer, + const size_t * src_origin, + const size_t * region, + size_t dst_offset, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, src_image, dst_buffer, src_origin, region, dst_offset, + num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueCopyBufferToImage, + (cl_command_queue command_queue, + cl_mem src_buffer, + cl_mem dst_image, + size_t src_offset, + const size_t dst_origin[3], + const size_t region[3], + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, src_buffer, dst_image, src_offset, dst_origin, + region, num_events_in_wait_list, event_wait_list, event)) + + OCL_FUNC(cl_int, clFlush, + (cl_command_queue command_queue), + (command_queue)) + +/* +OCL_FUNC_P(void*, clEnqueueMapImage, + (cl_command_queue command_queue, + cl_mem image, + cl_bool blocking_map, + cl_map_flags map_flags, + const size_t * origin[3], + const size_t * region[3], + size_t * image_row_pitch, + size_t * image_slice_pitch, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event, + cl_int * errcode_ret), + (command_queue, image, blocking_map, map_flags, origin, region, + image_row_pitch, image_slice_pitch, num_events_in_wait_list, + event_wait_list, event, errcode_ret)) +*/ + +/* +OCL_FUNC(cl_int, clRetainProgram, (cl_program program), (program)) + +OCL_FUNC(cl_int, clGetKernelInfo, + (cl_kernel kernel, + cl_kernel_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (kernel, param_name, param_value_size, param_value, param_value_size_ret)) + +*/ + +OCL_FUNC(cl_int, clRetainMemObject, (cl_mem memobj), (memobj)) + +OCL_FUNC(cl_int, clReleaseMemObject, (cl_mem memobj), (memobj)) + + +OCL_FUNC_P(cl_program, clCreateProgramWithSource, + (cl_context context, + cl_uint count, + const char ** strings, + const size_t * lengths, + cl_int * errcode_ret), + (context, count, strings, lengths, errcode_ret)) + +OCL_FUNC_P(cl_program, clCreateProgramWithBinary, + (cl_context context, + cl_uint num_devices, + const cl_device_id * device_list, + const size_t * lengths, + const unsigned char ** binaries, + cl_int * binary_status, + cl_int * errcode_ret), + (context, num_devices, device_list, lengths, binaries, binary_status, errcode_ret)) + +OCL_FUNC(cl_int, clReleaseProgram, (cl_program program), (program)) + +OCL_FUNC(cl_int, clBuildProgram, + (cl_program program, + cl_uint num_devices, + const cl_device_id * device_list, + const char * options, + void (CL_CALLBACK * pfn_notify)(cl_program, void *), + void * user_data), + (program, num_devices, device_list, options, pfn_notify, user_data)) + +OCL_FUNC(cl_int, clGetProgramInfo, + (cl_program program, + cl_program_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (program, param_name, param_value_size, param_value, param_value_size_ret)) + +OCL_FUNC(cl_int, clGetProgramBuildInfo, + (cl_program program, + cl_device_id device, + cl_program_build_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (program, device, param_name, param_value_size, param_value, param_value_size_ret)) + +OCL_FUNC_P(cl_kernel, clCreateKernel, + (cl_program program, + const char * kernel_name, + cl_int * errcode_ret), + (program, kernel_name, errcode_ret)) + +OCL_FUNC(cl_int, clReleaseKernel, (cl_kernel kernel), (kernel)) + +OCL_FUNC(cl_int, clSetKernelArg, + (cl_kernel kernel, + cl_uint arg_index, + size_t arg_size, + const void * arg_value), + (kernel, arg_index, arg_size, arg_value)) + +OCL_FUNC(cl_int, clGetKernelWorkGroupInfo, + (cl_kernel kernel, + cl_device_id device, + cl_kernel_work_group_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret), + (kernel, device, param_name, param_value_size, param_value, param_value_size_ret)) + +OCL_FUNC(cl_int, clFinish, (cl_command_queue command_queue), (command_queue)) + +OCL_FUNC(cl_int, clEnqueueReadBuffer, + (cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_read, + size_t offset, + size_t size, + void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, buffer, blocking_read, offset, size, ptr, + num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueReadBufferRect, + (cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_read, + const size_t * buffer_offset, + const size_t * host_offset, + const size_t * region, + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, buffer, blocking_read, buffer_offset, host_offset, region, buffer_row_pitch, + buffer_slice_pitch, host_row_pitch, host_slice_pitch, ptr, num_events_in_wait_list, + event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueWriteBuffer, + (cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_write, + size_t offset, + size_t size, + const void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, buffer, blocking_write, offset, size, ptr, + num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueWriteBufferRect, + (cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_write, + const size_t * buffer_offset, + const size_t * host_offset, + const size_t * region, + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + const void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, buffer, blocking_write, buffer_offset, host_offset, + region, buffer_row_pitch, buffer_slice_pitch, host_row_pitch, + host_slice_pitch, ptr, num_events_in_wait_list, event_wait_list, event)) + +/*OCL_FUNC(cl_int, clEnqueueFillBuffer, + (cl_command_queue command_queue, + cl_mem buffer, + const void * pattern, + size_t pattern_size, + size_t offset, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, buffer, pattern, pattern_size, offset, size, + num_events_in_wait_list, event_wait_list, event))*/ + +OCL_FUNC(cl_int, clEnqueueCopyBuffer, + (cl_command_queue command_queue, + cl_mem src_buffer, + cl_mem dst_buffer, + size_t src_offset, + size_t dst_offset, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, src_buffer, dst_buffer, src_offset, dst_offset, + size, num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueCopyBufferRect, + (cl_command_queue command_queue, + cl_mem src_buffer, + cl_mem dst_buffer, + const size_t * src_origin, + const size_t * dst_origin, + const size_t * region, + size_t src_row_pitch, + size_t src_slice_pitch, + size_t dst_row_pitch, + size_t dst_slice_pitch, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, src_buffer, dst_buffer, src_origin, dst_origin, + region, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch, + num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC_P(void*, clEnqueueMapBuffer, + (cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_map, + cl_map_flags map_flags, + size_t offset, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event, + cl_int * errcode_ret), + (command_queue, buffer, blocking_map, map_flags, offset, size, + num_events_in_wait_list, event_wait_list, event, errcode_ret)) + +OCL_FUNC(cl_int, clEnqueueUnmapMemObject, + (cl_command_queue command_queue, + cl_mem memobj, + void * mapped_ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, memobj, mapped_ptr, num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueNDRangeKernel, + (cl_command_queue command_queue, + cl_kernel kernel, + cl_uint work_dim, + const size_t * global_work_offset, + const size_t * global_work_size, + const size_t * local_work_size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, kernel, work_dim, global_work_offset, global_work_size, + local_work_size, num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clEnqueueTask, + (cl_command_queue command_queue, + cl_kernel kernel, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event), + (command_queue, kernel, num_events_in_wait_list, event_wait_list, event)) + +OCL_FUNC(cl_int, clSetEventCallback, + (cl_event event, + cl_int command_exec_callback_type , + void (CL_CALLBACK *pfn_event_notify) (cl_event event, cl_int event_command_exec_status, void *user_data), + void *user_data), + (event, command_exec_callback_type, pfn_event_notify, user_data)) + +OCL_FUNC(cl_int, clReleaseEvent, (cl_event event), (event)) + +} + +#endif + +#ifndef CL_VERSION_1_2 +#define CL_VERSION_1_2 +#endif From 7a95e654eb9abf23e946aa5744f41296d3d78e82 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 19 Dec 2016 00:38:33 +0300 Subject: [PATCH 002/144] ocl: update compiled programs - minimize library initialization time (lazy calculations of program hash) - LRU cache of in-memory compiled programs --- cmake/cl2cpp.cmake | 26 ++-- modules/core/include/opencv2/core/ocl.hpp | 9 +- .../core/include/opencv2/core/ocl_genbase.hpp | 25 +-- modules/core/src/ocl.cpp | 142 ++++++++++++++---- 4 files changed, 141 insertions(+), 61 deletions(-) diff --git a/cmake/cl2cpp.cmake b/cmake/cl2cpp.cmake index ed5dcb8761..13918ce5c2 100644 --- a/cmake/cl2cpp.cmake +++ b/cmake/cl2cpp.cmake @@ -12,14 +12,8 @@ endif() string(REPLACE ".cpp" ".hpp" OUTPUT_HPP "${OUTPUT}") get_filename_component(OUTPUT_HPP_NAME "${OUTPUT_HPP}" NAME) -if("${MODULE_NAME}" STREQUAL "ocl") - set(nested_namespace_start "") - set(nested_namespace_end "") -else() - set(new_mode ON) - set(nested_namespace_start "namespace ${MODULE_NAME}\n{") - set(nested_namespace_end "}") -endif() +set(nested_namespace_start "namespace ${MODULE_NAME}\n{") +set(nested_namespace_end "}") set(STR_CPP "// This file is auto-generated. Do not edit! @@ -35,6 +29,8 @@ namespace ocl { ${nested_namespace_start} +static const char* const moduleName = \"${MODULE_NAME}\"; + ") set(STR_HPP "// This file is auto-generated. Do not edit! @@ -76,19 +72,15 @@ foreach(cl ${cl_list}) string(MD5 hash "${lines}") - set(STR_CPP_DECL "const struct ProgramEntry ${cl_filename}={\"${cl_filename}\",\n\"${lines}, \"${hash}\"};\n") - set(STR_HPP_DECL "extern const struct ProgramEntry ${cl_filename};\n") - if(new_mode) - set(STR_CPP_DECL "${STR_CPP_DECL}ProgramSource ${cl_filename}_oclsrc(${cl_filename}.programStr);\n") - set(STR_HPP_DECL "${STR_HPP_DECL}extern ProgramSource ${cl_filename}_oclsrc;\n") - endif() + set(STR_CPP_DECL "struct cv::ocl::internal::ProgramEntry ${cl_filename}_oclsrc={moduleName, \"${cl_filename}\",\n\"${lines}, \"${hash}\", NULL};\n") + set(STR_HPP_DECL "extern struct cv::ocl::internal::ProgramEntry ${cl_filename}_oclsrc;\n") set(STR_CPP "${STR_CPP}${STR_CPP_DECL}") set(STR_HPP "${STR_HPP}${STR_HPP_DECL}") endforeach() -set(STR_CPP "${STR_CPP}}\n${nested_namespace_end}}\n#endif\n") -set(STR_HPP "${STR_HPP}}\n${nested_namespace_end}}\n#endif\n") +set(STR_CPP "${STR_CPP}\n${nested_namespace_end}}}\n#endif\n") +set(STR_HPP "${STR_HPP}\n${nested_namespace_end}}}\n#endif\n") file(WRITE "${OUTPUT}" "${STR_CPP}") @@ -96,7 +88,7 @@ if(EXISTS "${OUTPUT_HPP}") file(READ "${OUTPUT_HPP}" hpp_lines) endif() if("${hpp_lines}" STREQUAL "${STR_HPP}") - message(STATUS "${OUTPUT_HPP} contains same content") + message(STATUS "${OUTPUT_HPP} contains the same content") else() file(WRITE "${OUTPUT_HPP}" "${STR_HPP}") endif() diff --git a/modules/core/include/opencv2/core/ocl.hpp b/modules/core/include/opencv2/core/ocl.hpp index 1a9549df4c..97c5210d25 100644 --- a/modules/core/include/opencv2/core/ocl.hpp +++ b/modules/core/include/opencv2/core/ocl.hpp @@ -627,17 +627,18 @@ protected: class CV_EXPORTS ProgramSource { public: - typedef uint64 hash_t; + typedef uint64 hash_t; // deprecated ProgramSource(); - explicit ProgramSource(const String& prog); - explicit ProgramSource(const char* prog); + explicit ProgramSource(const String& module, const String& name, const String& codeStr, const String& codeHash); + explicit ProgramSource(const String& prog); // deprecated + explicit ProgramSource(const char* prog); // deprecated ~ProgramSource(); ProgramSource(const ProgramSource& prog); ProgramSource& operator = (const ProgramSource& prog); const String& source() const; - hash_t hash() const; + hash_t hash() const; // deprecated protected: struct Impl; diff --git a/modules/core/include/opencv2/core/ocl_genbase.hpp b/modules/core/include/opencv2/core/ocl_genbase.hpp index 5408958bc9..5334cf1f4f 100644 --- a/modules/core/include/opencv2/core/ocl_genbase.hpp +++ b/modules/core/include/opencv2/core/ocl_genbase.hpp @@ -42,23 +42,28 @@ #ifndef OPENCV_OPENCL_GENBASE_HPP #define OPENCV_OPENCL_GENBASE_HPP -namespace cv -{ -namespace ocl -{ - //! @cond IGNORED -struct ProgramEntry +namespace cv { +namespace ocl { + +class ProgramSource; + +namespace internal { + +struct CV_EXPORTS ProgramEntry { + const char* module; const char* name; - const char* programStr; + const char* programCode; const char* programHash; + ProgramSource* pProgramSource; + + operator ProgramSource& () const; }; +} } } // namespace + //! @endcond -} -} - #endif diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 2f51adcfc0..7e03a241af 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -49,6 +49,8 @@ #include #endif +#include "opencv2/core/ocl_genbase.hpp" + #define CV_OPENCL_ALWAYS_SHOW_BUILD_LOG 0 #define CV_OPENCL_SHOW_RUN_ERRORS 0 #define CV_OPENCL_SHOW_SVM_ERROR_LOG 1 @@ -1259,6 +1261,18 @@ static unsigned int getSVMCapabilitiesMask() } // namespace #endif +static size_t getProgramCountLimit() +{ + static bool initialized = false; + static size_t count = 0; + if (!initialized) + { + count = getConfigurationParameterForSize("OPENCV_OPENCL_PROGRAM_CACHE", 64); + initialized = true; + } + return count; +} + struct Context::Impl { static Context::Impl* get(Context& context) { return context.p; } @@ -1378,35 +1392,57 @@ struct Context::Impl Program getProg(const ProgramSource& src, const String& buildflags, String& errmsg) { - String prefix = Program::getPrefix(buildflags); - HashKey k(src.hash(), crc64((const uchar*)prefix.c_str(), prefix.size())); - phash_t::iterator it = phash.find(k); - if( it != phash.end() ) - return it->second; - //String filename = format("%08x%08x_%08x%08x.clb2", + size_t limit = getProgramCountLimit(); + String key = Program::getPrefix(buildflags); + { + cv::AutoLock lock(program_cache_mutex); + phash_t::iterator it = phash.find(key); + if (it != phash.end()) + { + // TODO LRU cache + CacheList::iterator i = std::find(cacheList.begin(), cacheList.end(), key); + if (i != cacheList.end() && i != cacheList.begin()) + { + cacheList.erase(i); + cacheList.push_front(key); + } + return it->second; + } + { // cleanup program cache + size_t sz = phash.size(); + if (limit > 0 && sz >= limit) + { + while (!cacheList.empty()) + { + size_t c = phash.erase(cacheList.back()); + cacheList.pop_back(); + if (c != 0) + break; + } + } + } + } Program prog(src, buildflags, errmsg); if(prog.ptr()) - phash.insert(std::pair(k, prog)); + { + cv::AutoLock lock(program_cache_mutex); + phash.insert(std::pair(key, prog)); + cacheList.push_front(key); + } return prog; } + IMPLEMENT_REFCOUNTABLE(); cl_context handle; std::vector devices; - typedef ProgramSource::hash_t hash_t; - - struct HashKey - { - HashKey(hash_t _a, hash_t _b) : a(_a), b(_b) {} - bool operator < (const HashKey& k) const { return a < k.a || (a == k.a && b < k.b); } - bool operator == (const HashKey& k) const { return a == k.a && b == k.b; } - bool operator != (const HashKey& k) const { return a != k.a || b != k.b; } - hash_t a, b; - }; - typedef std::map phash_t; + cv::Mutex program_cache_mutex; + typedef std::map phash_t; phash_t phash; + typedef std::list CacheList; + CacheList cacheList; #ifdef HAVE_OPENCL_SVM bool svmInitialized; @@ -2580,24 +2616,46 @@ String Program::getPrefix(const String& buildflags) struct ProgramSource::Impl { - Impl(const char* _src) + Impl(const String& src) { - init(String(_src)); + init(cv::String(), cv::String(), src, cv::String()); } - Impl(const String& _src) + Impl(const String& module, const String& name, const String& codeStr, const String& codeHash) { - init(_src); + init(module, name, codeStr, codeHash); } - void init(const String& _src) + void init(const String& module, const String& name, const String& codeStr, const String& codeHash) { refcount = 1; - src = _src; - h = crc64((uchar*)src.c_str(), src.size()); + module_ = module; + name_ = name; + codeStr_ = codeStr; + codeHash_ = codeHash; + + isHashUpdated = false; + if (codeHash_.empty()) + { + updateHash(); + codeHash_ = cv::format("%08llx", hash_); + } + } + + void updateHash() + { + hash_ = crc64((uchar*)codeStr_.c_str(), codeStr_.size()); + isHashUpdated = true; } IMPLEMENT_REFCOUNTABLE(); - String src; - ProgramSource::hash_t h; + + String module_; + String name_; + String codeStr_; + String codeHash_; + // TODO std::vector includes_; + + bool isHashUpdated; + ProgramSource::hash_t hash_; }; @@ -2606,6 +2664,11 @@ ProgramSource::ProgramSource() p = 0; } +ProgramSource::ProgramSource(const String& module, const String& name, const String& codeStr, const String& codeHash) +{ + p = new Impl(module, name, codeStr, codeHash); +} + ProgramSource::ProgramSource(const char* prog) { p = new Impl(prog); @@ -2642,15 +2705,34 @@ ProgramSource& ProgramSource::operator = (const ProgramSource& prog) const String& ProgramSource::source() const { - static String dummy; - return p ? p->src : dummy; + CV_Assert(p); + return p->codeStr_; } ProgramSource::hash_t ProgramSource::hash() const { - return p ? p->h : 0; + CV_Assert(p); + if (!p->isHashUpdated) + p->updateHash(); + return p->hash_; } + +internal::ProgramEntry::operator ProgramSource&() const +{ + if (this->pProgramSource == NULL) + { + cv::AutoLock lock(cv::getInitializationMutex()); + if (this->pProgramSource == NULL) + { + ProgramSource* ps = new ProgramSource(this->module, this->name, this->programCode, this->programHash); + const_cast(this)->pProgramSource = ps; + } + } + return *this->pProgramSource; +} + + //////////////////////////////////////////// OpenCLAllocator ////////////////////////////////////////////////// template From c3e409f9507f1c4c621de6588b228bc5bd50ea47 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 22 Dec 2016 04:52:43 +0300 Subject: [PATCH 003/144] ocl: update program cache defaults --- modules/core/src/ocl.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 7e03a241af..32408c7112 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -1267,7 +1267,7 @@ static size_t getProgramCountLimit() static size_t count = 0; if (!initialized) { - count = getConfigurationParameterForSize("OPENCV_OPENCL_PROGRAM_CACHE", 64); + count = getConfigurationParameterForSize("OPENCV_OPENCL_PROGRAM_CACHE", 0); initialized = true; } return count; @@ -1412,6 +1412,14 @@ struct Context::Impl size_t sz = phash.size(); if (limit > 0 && sz >= limit) { + static bool warningFlag = false; + if (!warningFlag) + { + printf("\nWARNING: OpenCV-OpenCL:\n" + " In-memory cache for OpenCL programs is full, older programs will be unloaded.\n" + " You can change cache size via OPENCV_OPENCL_PROGRAM_CACHE environment variable\n\n"); + warningFlag = true; + } while (!cacheList.empty()) { size_t c = phash.erase(cacheList.back()); From e16227b53cabab1caa4b7aba8ff59a630528348f Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 7 Sep 2016 18:02:36 +0300 Subject: [PATCH 004/144] cmake: support multiple CPU targets --- CMakeLists.txt | 50 +- cmake/OpenCVCompilerOptimizations.cmake | 651 ++++++++++++++++++ cmake/OpenCVCompilerOptions.cmake | 161 +---- cmake/OpenCVGenHeaders.cmake | 4 + cmake/OpenCVModule.cmake | 3 + cmake/OpenCVPCHSupport.cmake | 5 +- cmake/OpenCVUtils.cmake | 50 +- cmake/checks/cpu_avx.cpp | 9 + cmake/checks/cpu_avx2.cpp | 10 + cmake/checks/cpu_avx512.cpp | 10 + cmake/checks/{fp16.cpp => cpu_fp16.cpp} | 2 +- cmake/checks/cpu_popcnt.cpp | 8 + cmake/checks/cpu_sse.cpp | 2 + cmake/checks/cpu_sse2.cpp | 2 + cmake/checks/cpu_sse3.cpp | 7 + cmake/checks/cpu_sse41.cpp | 6 + cmake/checks/cpu_sse42.cpp | 5 + cmake/checks/cpu_ssse3.cpp | 7 + cmake/templates/cv_cpu_config.h.in | 5 + cmake/templates/cvconfig.h.in | 13 + .../include/opencv2/core/cv_cpu_dispatch.h | 166 +++++ .../core/include/opencv2/core/cv_cpu_helper.h | 133 ++++ modules/core/include/opencv2/core/cvdef.h | 153 +--- .../core/include/opencv2/core/fast_math.hpp | 60 +- modules/core/src/system.cpp | 299 ++++++-- modules/highgui/CMakeLists.txt | 2 +- modules/imgproc/src/imgwarp.cpp | 4 +- modules/objdetect/src/haar.cpp | 5 +- 28 files changed, 1439 insertions(+), 393 deletions(-) create mode 100644 cmake/OpenCVCompilerOptimizations.cmake create mode 100644 cmake/checks/cpu_avx.cpp create mode 100644 cmake/checks/cpu_avx2.cpp create mode 100644 cmake/checks/cpu_avx512.cpp rename cmake/checks/{fp16.cpp => cpu_fp16.cpp} (86%) create mode 100644 cmake/checks/cpu_popcnt.cpp create mode 100644 cmake/checks/cpu_sse.cpp create mode 100644 cmake/checks/cpu_sse2.cpp create mode 100644 cmake/checks/cpu_sse3.cpp create mode 100644 cmake/checks/cpu_sse41.cpp create mode 100644 cmake/checks/cpu_sse42.cpp create mode 100644 cmake/checks/cpu_ssse3.cpp create mode 100644 cmake/templates/cv_cpu_config.h.in create mode 100644 modules/core/include/opencv2/core/cv_cpu_dispatch.h create mode 100644 modules/core/include/opencv2/core/cv_cpu_helper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 16e039d324..dadbf1dc31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,10 @@ if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() +if(POLICY CMP0051) + cmake_policy(SET CMP0051 NEW) +endif() + include(cmake/OpenCVUtils.cmake) # must go before the project command @@ -280,16 +284,6 @@ OCV_OPTION(ENABLE_COVERAGE "Enable coverage collection with GCov" OCV_OPTION(ENABLE_OMIT_FRAME_POINTER "Enable -fomit-frame-pointer for GCC" ON IF CMAKE_COMPILER_IS_GNUCXX AND NOT (APPLE AND CMAKE_COMPILER_IS_CLANGCXX) ) OCV_OPTION(ENABLE_POWERPC "Enable PowerPC for GCC" ON IF (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES powerpc.*) ) OCV_OPTION(ENABLE_FAST_MATH "Enable -ffast-math (not recommended for GCC 4.6.x)" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE "Enable SSE instructions" ON IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE2 "Enable SSE2 instructions" ON IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE3 "Enable SSE3 instructions" ON IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX OR CV_ICC) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSSE3 "Enable SSSE3 instructions" OFF IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE41 "Enable SSE4.1 instructions" OFF IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX OR CV_ICC) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE42 "Enable SSE4.2 instructions" OFF IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_POPCNT "Enable POPCNT instructions" OFF IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_AVX "Enable AVX instructions" OFF IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_AVX2 "Enable AVX2 instructions" OFF IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_FMA3 "Enable FMA3 instructions" OFF IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_NEON "Enable NEON instructions" "${NEON}" IF CMAKE_COMPILER_IS_GNUCXX AND (ARM OR AARCH64 OR IOS) ) OCV_OPTION(ENABLE_VFPV3 "Enable VFPv3-D32 instructions" OFF IF CMAKE_COMPILER_IS_GNUCXX AND (ARM OR AARCH64 OR IOS) ) OCV_OPTION(ENABLE_NOISY_WARNINGS "Show all warnings even if they are too noisy" OFF ) @@ -299,6 +293,9 @@ OCV_OPTION(ENABLE_IMPL_COLLECTION "Collect implementation data on function c OCV_OPTION(ENABLE_INSTRUMENTATION "Instrument functions to collect calls trace and performance" OFF ) OCV_OPTION(ENABLE_GNU_STL_DEBUG "Enable GNU STL Debug mode (defines _GLIBCXX_DEBUG)" OFF IF ((NOT CMAKE_VERSION VERSION_LESS "2.8.11") AND CMAKE_COMPILER_IS_GNUCXX) ) OCV_OPTION(GENERATE_ABI_DESCRIPTOR "Generate XML file for abi_compliance_checker tool" OFF IF UNIX) +OCV_OPTION(CV_ENABLE_INTRINSICS "Use intrinsic-based optimized code" ON ) +OCV_OPTION(CV_DISABLE_OPTIMIZATION "Disable explicit optimized code (dispatched code/intrinsics/loop unrolling/etc)" OFF ) + OCV_OPTION(DOWNLOAD_EXTERNAL_TEST_DATA "Download external test data (Python executable and OPENCV_TEST_DATA_PATH environment variable may be required)" OFF ) @@ -499,6 +496,9 @@ if(CMAKE_GENERATOR MATCHES "Makefiles|Ninja" AND "${CMAKE_BUILD_TYPE}" STREQUAL set(CMAKE_BUILD_TYPE Release) endif() +# --- Python Support --- +include(cmake/OpenCVDetectPython.cmake) + include(cmake/OpenCVCompilerOptions.cmake) @@ -576,9 +576,6 @@ else() unset(DOXYGEN_FOUND CACHE) endif() -# --- Python Support --- -include(cmake/OpenCVDetectPython.cmake) - # --- Java Support --- include(cmake/OpenCVDetectApacheAnt.cmake) if(ANDROID) @@ -867,6 +864,33 @@ if(NOT CMAKE_GENERATOR MATCHES "Xcode|Visual Studio") status(" Configuration:" ${CMAKE_BUILD_TYPE}) endif() + +# ========================= CPU code generation mode ========================= +status("") +status(" CPU/HW features:") +status(" Baseline:" "${CPU_BASELINE_FINAL}") +if(NOT CPU_BASELINE STREQUAL CPU_BASELINE_FINAL) + status(" requested:" "${CPU_BASELINE}") +endif() +if(CPU_BASELINE_REQUIRE) + status(" required:" "${CPU_BASELINE_REQUIRE}") +endif() +if(CPU_BASELINE_DISABLE) + status(" disabled:" "${CPU_BASELINE_DISABLE}") +endif() +if(CPU_DISPATCH_FINAL OR CPU_DISPATCH) + status(" Dispatched code generation:" "${CPU_DISPATCH_FINAL}") + if(NOT CPU_DISPATCH STREQUAL CPU_DISPATCH_FINAL) + status(" requested:" "${CPU_DISPATCH}") + endif() + if(CPU_DISPATCH_REQUIRE) + status(" required:" "${CPU_DISPATCH_REQUIRE}") + endif() + foreach(OPT ${CPU_DISPATCH_FINAL}) + status(" ${OPT} (${CPU_${OPT}_USAGE_COUNT} files):" "+ ${CPU_DISPATCH_${OPT}_INCLUDED}") + endforeach() +endif() + # ========================== C/C++ options ========================== if(CMAKE_CXX_COMPILER_VERSION) set(OPENCV_COMPILER_STR "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} (ver ${CMAKE_CXX_COMPILER_VERSION})") diff --git a/cmake/OpenCVCompilerOptimizations.cmake b/cmake/OpenCVCompilerOptimizations.cmake new file mode 100644 index 0000000000..b849f02b14 --- /dev/null +++ b/cmake/OpenCVCompilerOptimizations.cmake @@ -0,0 +1,651 @@ +# x86/x86-64 arch: +# SSE / SSE2 (always available on 64-bit CPUs) +# SSE3 / SSSE3 +# SSE4_1 / SSE4_2 / POPCNT +# AVX / AVX2 / AVX512 +# FMA3 + +# CPU_{opt}_SUPPORTED=ON/OFF - compiler support (possibly with additional flag) +# CPU_{opt}_IMPLIES= +# CPU_{opt}_FORCE= - subset of "implies" list +# CPU_{opt}_FLAGS_ON="" +# CPU_{opt}_FEATURE_ALIAS - mapping to CV_CPU_* HWFeature enum + +# Input variables: +# CPU_BASELINE= - preferred list of baseline optimizations +# CPU_DISPATCH= - preferred list of dispatched optimizations + +# Advanced input variables: +# CPU_BASELINE_REQUIRE= - list of required baseline optimizations +# CPU_DISPATCH_REQUIRE= - list of required dispatched optimizations +# CPU_BASELINE_DISABLE= - list of disabled baseline optimizations + +# Output variables: +# CPU_BASELINE_FINAL= - final list of enabled compiler optimizations +# CPU_DISPATCH_FINAL= - final list of dispatched optimizations +# +# CPU_DISPATCH_FLAGS_${opt} - flags for source files compiled separately (_opt_avx2.cpp) + +set(CPU_ALL_OPTIMIZATIONS "SSE;SSE2;SSE3;SSSE3;SSE4_1;SSE4_2;POPCNT;AVX;FP16;AVX2;FMA3") # without AVX512 +list(APPEND CPU_ALL_OPTIMIZATIONS NEON VFPV3 FP16) +list(REMOVE_DUPLICATES CPU_ALL_OPTIMIZATIONS) + +ocv_update(CPU_VFPV3_FEATURE_ALIAS "") + + +set(HELP_CPU_BASELINE "Specify list of enabled baseline CPU optimizations") +set(HELP_CPU_BASELINE_REQUIRE "Specify list of required baseline CPU optimizations") +set(HELP_CPU_BASELINE_DISABLE "Specify list of forbidden baseline CPU optimizations") +set(HELP_CPU_DISPATCH "Specify list of dispatched CPU optimizations") +set(HELP_CPU_DISPATCH_REQUIRE "Specify list of required dispatched CPU optimizations") + +foreach(var CPU_BASELINE CPU_BASELINE_REQUIRE CPU_BASELINE_DISABLE CPU_DISPATCH CPU_DISPATCH_REQUIRE) + if(DEFINED ${var}) + string(REPLACE "," ";" _list "${${var}}") + set(${var} "${_list}" CACHE STRING "${HELP_${var}}" FORCE) + endif() +endforeach() + +# process legacy flags +macro(ocv_optimization_process_obsolete_option legacy_flag OPT legacy_warn) + if(DEFINED ${legacy_flag}) + if(${legacy_warn}) + message(STATUS "WARNING: Option ${legacy_flag}='${${legacy_flag}}' is deprecated and should not be used anymore") + message(STATUS " Behaviour of this option is not backward compatible") + message(STATUS " Refer to 'CPU_BASELINE'/'CPU_DISPATCH' CMake options documentation") + endif() + if(${legacy_flag}) + if(NOT ";${CPU_BASELINE_REQUIRE};" MATCHES ";${OPT};") + set(CPU_BASELINE_REQUIRE "${CPU_BASELINE_REQUIRE};${OPT}" CACHE STRING "${HELP_CPU_BASELINE_REQUIRE}" FORCE) + endif() + else() + if(NOT ";${CPU_BASELINE_DISABLE};" MATCHES ";${OPT};") + set(CPU_BASELINE_DISABLE "${CPU_BASELINE_DISABLE};${OPT}" CACHE STRING "${HELP_CPU_BASELINE_DISABLE}" FORCE) + endif() + endif() + endif() +endmacro() +ocv_optimization_process_obsolete_option(ENABLE_SSE SSE ON) +ocv_optimization_process_obsolete_option(ENABLE_SSE2 SSE2 ON) +ocv_optimization_process_obsolete_option(ENABLE_SSE3 SSE3 ON) +ocv_optimization_process_obsolete_option(ENABLE_SSSE3 SSSE3 ON) +ocv_optimization_process_obsolete_option(ENABLE_SSE41 SSE4_1 ON) +ocv_optimization_process_obsolete_option(ENABLE_SSE42 SSE4_2 ON) +ocv_optimization_process_obsolete_option(ENABLE_POPCNT POPCNT ON) +ocv_optimization_process_obsolete_option(ENABLE_AVX AVX ON) +ocv_optimization_process_obsolete_option(ENABLE_AVX2 AVX2 ON) +ocv_optimization_process_obsolete_option(ENABLE_FMA3 FMA3 ON) + +ocv_optimization_process_obsolete_option(ENABLE_VFPV3 VFPV3 OFF) +ocv_optimization_process_obsolete_option(ENABLE_NEON NEON OFF) + + +macro(ocv_is_optimization_in_list resultvar check_opt) + set(__checked "") + set(__queue ${ARGN}) + set(${resultvar} 0) + while(__queue AND NOT ${resultvar}) + list(REMOVE_DUPLICATES __queue) + set(__queue_current ${__queue}) + set(__queue "") + foreach(OPT ${__queue_current}) + if("x${OPT}" STREQUAL "x${check_opt}") + set(${resultvar} 1) + break() + elseif(NOT ";${__checked};" MATCHES ";${OPT};") + list(APPEND __queue ${CPU_${OPT}_IMPLIES}) + endif() + list(APPEND __checked ${OPT}) + endforeach() + endwhile() +endmacro() + +macro(ocv_is_optimization_in_force_list resultvar check_opt) + set(__checked "") + set(__queue ${ARGN}) + set(${resultvar} 0) + while(__queue AND NOT ${resultvar}) + list(REMOVE_DUPLICATES __queue) + set(__queue_current ${__queue}) + set(__queue "") + foreach(OPT ${__queue_current}) + if(OPT STREQUAL "${check_opt}") + set(${resultvar} 1) + break() + elseif(NOT ";${__checked};" MATCHES ";${OPT};") + list(APPEND __queue ${CPU_${OPT}_FORCE}) + endif() + list(APPEND __checked ${OPT}) + endforeach() + endwhile() +endmacro() + +macro(ocv_append_optimization_flag var OPT) + if(CPU_${OPT}_FLAGS_CONFLICT) + string(REGEX REPLACE " ${CPU_${OPT}_FLAGS_CONFLICT}" "" ${var} " ${${var}}") + string(REGEX REPLACE "^ +" "" ${var} "${${var}}") + endif() + set(${var} "${${var}} ${CPU_${OPT}_FLAGS_ON}") +endmacro() + +# Support GCC -march=native or Intel Compiler -xHost flags +if(";${CPU_BASELINE};" MATCHES ";NATIVE;" OR ";${CPU_BASELINE};" MATCHES ";HOST;") + set(CPU_BASELINE_DETECT ON) + set(_add_native_flag ON) +elseif(";${CPU_BASELINE};" MATCHES ";DETECT;") + set(CPU_BASELINE_DETECT ON) +elseif(" ${CMAKE_CXX_FLAGS} " MATCHES " -march=native | -xHost | /QxHost ") + if(DEFINED CPU_BASELINE) + message(STATUS "CPU: Detected '-march=native' or '-xHost' compiler flag. Force CPU_BASELINE=DETECT.") + endif() + set(CPU_BASELINE "DETECT" CACHE STRING "${HELP_CPU_BASELINE}") + set(CPU_BASELINE_DETECT ON) +endif() + +if(X86 OR X86_64) + ocv_update(CPU_KNOWN_OPTIMIZATIONS "SSE;SSE2;SSE3;SSSE3;SSE4_1;POPCNT;SSE4_2;FP16;FMA3;AVX;AVX2;AVX512") + + ocv_update(CPU_SSE_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_sse.cpp") + ocv_update(CPU_SSE2_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_sse2.cpp") + ocv_update(CPU_SSE3_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_sse3.cpp") + ocv_update(CPU_SSSE3_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_ssse3.cpp") + ocv_update(CPU_SSE4_1_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_sse41.cpp") + ocv_update(CPU_SSE4_2_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_sse42.cpp") + ocv_update(CPU_POPCNT_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_popcnt.cpp") + ocv_update(CPU_AVX_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx.cpp") + ocv_update(CPU_AVX2_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx2.cpp") + ocv_update(CPU_FP16_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_fp16.cpp") + ocv_update(CPU_AVX512_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx512.cpp") + + if(NOT OPENCV_CPU_OPT_IMPLIES_IGNORE) + ocv_update(CPU_AVX512_IMPLIES "AVX2") + ocv_update(CPU_AVX512_FORCE "") # Don't force other optimizations + ocv_update(CPU_AVX2_IMPLIES "AVX;FMA3;FP16") + ocv_update(CPU_FMA3_IMPLIES "AVX2") + ocv_update(CPU_FMA3_FORCE "") # Don't force other optimizations + ocv_update(CPU_FP16_IMPLIES "AVX") + ocv_update(CPU_FP16_FORCE "") # Don't force other optimizations + ocv_update(CPU_AVX_IMPLIES "SSE4_2") + ocv_update(CPU_SSE4_2_IMPLIES "SSE4_1;POPCNT") + ocv_update(CPU_POPCNT_IMPLIES "SSE4_1") + ocv_update(CPU_POPCNT_FORCE "") # Don't force other optimizations + ocv_update(CPU_SSE4_1_IMPLIES "SSE3;SSSE3") + ocv_update(CPU_SSSE3_IMPLIES "SSE3") + ocv_update(CPU_SSE3_IMPLIES "SSE2") + ocv_update(CPU_SSE2_IMPLIES "SSE") + endif() + + if(CV_ICC) + macro(ocv_intel_compiler_optimization_option name unix_flags msvc_flags) + ocv_update(CPU_${name}_FLAGS_NAME "${name}") + if(MSVC) + set(enable_flags "${msvc_flags}") + set(flags_conflict "/arch:[^ ]+") + else() + set(enable_flags "${unix_flags}") + set(flags_conflict "-msse[^ ]*|-mssse3|-mavx[^ ]*|-march[^ ]+") + endif() + ocv_update(CPU_${name}_FLAGS_ON "${enable_flags}") + if(flags_conflict) + ocv_update(CPU_${name}_FLAGS_CONFLICT "${flags_conflict}") + endif() + endmacro() + ocv_intel_compiler_optimization_option(AVX2 "-march=core-avx2" "/arch:CORE-AVX2") + ocv_intel_compiler_optimization_option(FP16 "-mavx" "/arch:AVX") + ocv_intel_compiler_optimization_option(AVX "-mavx" "/arch:AVX") + ocv_intel_compiler_optimization_option(FMA3 "" "") + ocv_intel_compiler_optimization_option(POPCNT "" "") + ocv_intel_compiler_optimization_option(SSE4_2 "-msse4.2" "/arch:SSE4.2") + ocv_intel_compiler_optimization_option(SSE4_1 "-msse4.1" "/arch:SSE4.1") + ocv_intel_compiler_optimization_option(SSE3 "-msse3" "/arch:SSE3") + ocv_intel_compiler_optimization_option(SSSE3 "-mssse3" "/arch:SSSE3") + ocv_intel_compiler_optimization_option(SSE2 "-msse2" "/arch:SSE2") + if(NOT X86_64) # x64 compiler doesn't support /arch:sse + ocv_intel_compiler_optimization_option(SSE "-msse" "/arch:SSE") + endif() + #ocv_intel_compiler_optimization_option(AVX512 "-march=core-avx512") + elseif(CMAKE_COMPILER_IS_GNUCXX) + ocv_update(CPU_AVX2_FLAGS_ON "-mavx2") + ocv_update(CPU_FP16_FLAGS_ON "-mf16c") + ocv_update(CPU_AVX_FLAGS_ON "-mavx") + ocv_update(CPU_FMA3_FLAGS_ON "-mfma") + ocv_update(CPU_POPCNT_FLAGS_ON "-mpopcnt") + ocv_update(CPU_SSE4_2_FLAGS_ON "-msse4.2") + ocv_update(CPU_SSE4_1_FLAGS_ON "-msse4.1") + ocv_update(CPU_SSE3_FLAGS_ON "-msse3") + ocv_update(CPU_SSSE3_FLAGS_ON "-mssse3") + ocv_update(CPU_SSE2_FLAGS_ON "-msse2") + ocv_update(CPU_SSE_FLAGS_ON "-msse") + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0") + ocv_update(CPU_AVX512_FLAGS_ON "-mavx512f -mavx512pf -mavx512er -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512ifma -mavx512vbmi") + endif() + elseif(MSVC) + ocv_update(CPU_AVX2_FLAGS_ON "/arch:AVX2") + ocv_update(CPU_AVX_FLAGS_ON "/arch:AVX") + if(NOT MSVC64) + # 64-bit MSVC compiler uses SSE/SSE2 by default + ocv_update(CPU_SSE_FLAGS_ON "/arch:SSE") + ocv_update(CPU_SSE_SUPPORTED ON) + ocv_update(CPU_SSE2_FLAGS_ON "/arch:SSE2") + ocv_update(CPU_SSE2_SUPPORTED ON) + else() + ocv_update(CPU_SSE_SUPPORTED ON) + ocv_update(CPU_SSE2_SUPPORTED ON) + endif() + # Other instruction sets are supported by default since MSVC 2008 at least + else() + message(WARNING "TODO: Unsupported compiler") + endif() + + if(NOT DEFINED CPU_DISPATCH) + set(CPU_DISPATCH "SSE4_1;AVX;FP16;AVX2" CACHE STRING "${HELP_CPU_DISPATCH}") + endif() + + if(NOT DEFINED CPU_BASELINE) + if(X86_64) + set(CPU_BASELINE "SSSE3" CACHE STRING "${HELP_CPU_BASELINE}") + else() + set(CPU_BASELINE "SSE2" CACHE STRING "${HELP_CPU_BASELINE}") + endif() + endif() + +elseif(ARM OR AARCH64) + ocv_update(CPU_FP16_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_fp16.cpp") + if(NOT AARCH64) + ocv_update(CPU_KNOWN_OPTIMIZATIONS "VFPV3;NEON;FP16") + ocv_update(CPU_NEON_FLAGS_ON "-mfpu=neon") + ocv_update(CPU_VFPV3_FLAGS_ON "-mfpu=vfpv3") + ocv_update(CPU_FP16_FLAGS_ON "-mfpu=neon-fp16") + set(CPU_BASELINE "DETECT" CACHE STRING "${HELP_CPU_BASELINE}") + else() + ocv_update(CPU_KNOWN_OPTIMIZATIONS "NEON;FP16") + ocv_update(CPU_NEON_FLAGS_ON "") + set(CPU_BASELINE "NEON" CACHE STRING "${HELP_CPU_BASELINE}") + endif() +endif() + +# Helper values for cmake-gui +set(CPU_BASELINE "DETECT" CACHE STRING "${HELP_CPU_BASELINE}") +set(CPU_DISPATCH "" CACHE STRING "${HELP_CPU_DISPATCH}") +set_property(CACHE CPU_BASELINE PROPERTY STRINGS "" ${CPU_KNOWN_OPTIMIZATIONS}) +set_property(CACHE CPU_DISPATCH PROPERTY STRINGS "" ${CPU_KNOWN_OPTIMIZATIONS}) + +set(CPU_BASELINE_FLAGS "") + +set(CPU_BASELINE_FINAL "") +set(CPU_DISPATCH_FINAL "") + +macro(ocv_check_compiler_optimization OPT) + if(NOT DEFINED CPU_${OPT}_SUPPORTED) + if((DEFINED CPU_${OPT}_FLAGS_ON AND NOT "x${CPU_${OPT}_FLAGS_ON}" STREQUAL "x") OR CPU_${OPT}_TEST_FILE) + set(_varname "") + if(CPU_${OPT}_TEST_FILE) + set(__available 0) + if(CPU_BASELINE_DETECT) + set(_varname "HAVE_CPU_${OPT}_SUPPORT") + ocv_check_compiler_flag(CXX "${CPU_BASELINE_FLAGS}" "${_varname}" "${CPU_${OPT}_TEST_FILE}") + if(${_varname}) + list(APPEND CPU_BASELINE_FINAL ${OPT}) + set(__available 1) + endif() + endif() + if(NOT __available) + if(NOT "x${CPU_${OPT}_FLAGS_NAME}" STREQUAL "x") + set(_varname "HAVE_CPU_${CPU_${OPT}_FLAGS_NAME}") + set(_compile_flags "${CPU_BASELINE_FLAGS}") + ocv_append_optimization_flag(_compile_flags ${OPT}) + ocv_check_compiler_flag(CXX "${_compile_flags}" "${_varname}" "${CPU_${OPT}_TEST_FILE}") + elseif(NOT "x${CPU_${OPT}_FLAGS_ON}" STREQUAL "x") + ocv_check_flag_support(CXX "${CPU_${OPT}_FLAGS_ON}" _varname "" "${CPU_${OPT}_TEST_FILE}") + else() + set(_varname "HAVE_CPU_${OPT}_SUPPORT") + set(_compile_flags "${CPU_BASELINE_FLAGS}") + ocv_append_optimization_flag(_compile_flags ${OPT}) + ocv_check_compiler_flag(CXX "${_compile_flags}" "${_varname}" "${CPU_${OPT}_TEST_FILE}") + endif() + endif() + else() + ocv_check_flag_support(CXX "${CPU_${OPT}_FLAGS_ON}" _varname "") + endif() + if(_varname AND ${_varname}) + set(CPU_${OPT}_SUPPORTED ON) + elseif(NOT CPU_${OPT}_SUPPORTED) + message(STATUS "${OPT} is not supported by C++ compiler") + endif() + else() + set(CPU_${OPT}_SUPPORTED ON) + endif() + endif() +endmacro() + +foreach(OPT ${CPU_KNOWN_OPTIMIZATIONS}) + set(CPU_${OPT}_USAGE_COUNT 0 CACHE INTERNAL "" FORCE) + if(NOT DEFINED CPU_${OPT}_FORCE) + set(CPU_${OPT}_FORCE "${CPU_${OPT}_IMPLIES}") + endif() +endforeach() + +if(_add_native_flag) + set(_varname "HAVE_CPU_NATIVE_SUPPORT") + ocv_check_compiler_flag(CXX "-march=native" "${_varname}" "") + if(_varname) + set(CPU_BASELINE_FLAGS "${CPU_BASELINE_FLAGS} -march=native") + else() + set(_varname "HAVE_CPU_HOST_SUPPORT") + if(MSVC) + set(_flag "/QxHost") + else() + set(_flag "-xHost") + endif() + ocv_check_compiler_flag(CXX "${_flag}" "${_varname}" "") + if(_varname) + set(CPU_BASELINE_FLAGS "${CPU_BASELINE_FLAGS} ${flag}") + endif() + endif() +endif() + +foreach(OPT ${CPU_KNOWN_OPTIMIZATIONS}) + set(__is_disabled 0) + foreach(OPT2 ${CPU_BASELINE_DISABLE}) + ocv_is_optimization_in_list(__is_disabled ${OPT2} ${OPT}) + if(__is_disabled) + break() + endif() + endforeach() + if(__is_disabled) + set(__is_from_baseline 0) + else() + ocv_is_optimization_in_list(__is_from_baseline ${OPT} ${CPU_BASELINE_REQUIRE}) + if(NOT __is_from_baseline) + ocv_is_optimization_in_list(__is_from_baseline ${OPT} ${CPU_BASELINE}) + endif() + endif() + ocv_is_optimization_in_list(__is_from_dispatch ${OPT} ${CPU_DISPATCH_REQUIRE}) + if(NOT __is_from_dispatch) + ocv_is_optimization_in_list(__is_from_dispatch ${OPT} ${CPU_DISPATCH}) + endif() + if(__is_from_dispatch OR __is_from_baseline OR CPU_BASELINE_DETECT) + ocv_check_compiler_optimization(${OPT}) + endif() + if(CPU_BASELINE_DETECT AND NOT __is_from_baseline AND NOT __is_disabled) + ocv_is_optimization_in_list(__is_from_baseline ${OPT} ${CPU_BASELINE_FINAL}) + endif() + if(CPU_${OPT}_SUPPORTED) + if(";${CPU_DISPATCH};" MATCHES ";${OPT};" AND NOT __is_from_baseline) + list(APPEND CPU_DISPATCH_FINAL ${OPT}) + elseif(__is_from_baseline AND NOT CPU_BASELINE_DETECT) + list(APPEND CPU_BASELINE_FINAL ${OPT}) + ocv_append_optimization_flag(CPU_BASELINE_FLAGS ${OPT}) + endif() + endif() +endforeach() + +foreach(OPT ${CPU_BASELINE_REQUIRE}) + if(NOT ";${CPU_BASELINE_FINAL};" MATCHES ";${OPT};") + message(SEND_ERROR "Required baseline optimization is not supported: ${OPT} (CPU_BASELINE_REQUIRE=${CPU_BASELINE_REQUIRE})") + endif() +endforeach() + +foreach(OPT ${CPU_BASELINE}) + if(OPT STREQUAL "DETECT" OR OPT STREQUAL "HOST" OR OPT STREQUAL "NATIVE") + # nothing + elseif(NOT ";${CPU_BASELINE_FINAL};" MATCHES ";${OPT};") + message(STATUS "Optimization ${OPT} is not available, skipped") + endif() +endforeach() + +foreach(OPT ${CPU_DISPATCH_REQUIRE}) + if(";${CPU_DISPATCH_FINAL};" MATCHES ";${OPT};") + # OK + elseif(";${CPU_BASELINE_FINAL};" MATCHES ";${OPT};") + message(SEND_ERROR "Dispatched optimization ${OPT} is in baseline list (CPU_DISPATCH_REQUIRE=${CPU_DISPATCH_REQUIRE})") + else() + message(SEND_ERROR "Required dispatch optimization is not supported: ${OPT} (CPU_DISPATCH_REQUIRE=${CPU_DISPATCH_REQUIRE})") + endif() +endforeach() + +foreach(OPT ${CPU_DISPATCH}) + if(";${CPU_DISPATCH_FINAL};" MATCHES ";${OPT};") + # OK + elseif(";${CPU_BASELINE_FINAL};" MATCHES ";${OPT};") + # OK + else() + message(STATUS "Dispatch optimization ${OPT} is not available, skipped") + endif() +endforeach() + +#message(STATUS "CPU_BASELINE_FINAL=${CPU_BASELINE_FINAL}") +#message(STATUS "CPU_DISPATCH_FINAL=${CPU_DISPATCH_FINAL}") + +#if(CPU_DISPATCH_FINAL AND NOT PYTHON_DEFAULT_EXECUTABLE) +# message(FATAL_ERROR "Python is required for CPU dispatched optimization support") +#endif() + +macro(ocv_compiler_optimization_options) + set(__flags "${OPENCV_EXTRA_CXX_FLAGS} ${CPU_BASELINE_FLAGS}") + if(NOT __flags STREQUAL CACHED_CPU_BASELINE_FLAGS) + set(CACHED_CPU_BASELINE_FLAGS "${__flags}" CACHE INTERNAL "" FORCE) + ocv_clear_vars(HAVE_CPU_BASELINE_FLAGS) + endif() + ocv_check_compiler_flag(CXX "${__flags}" HAVE_CPU_BASELINE_FLAGS) + if(NOT HAVE_CPU_BASELINE_FLAGS) + message(FATAL_ERROR "Compiler doesn't support baseline optimization flags: ${CPU_BASELINE_FLAGS}") + endif() + add_extra_compiler_option_force("${CPU_BASELINE_FLAGS}") + + foreach(OPT ${CPU_DISPATCH_FINAL}) + set(__dispatch_flags "") + set(__dispatch_definitions "") + set(__dispatch_opts "") + set(__dispatch_opts_force "") + foreach(OPT2 ${CPU_KNOWN_OPTIMIZATIONS}) + if(NOT CPU_${OPT2}_SUPPORTED) + #continue() + else() + ocv_is_optimization_in_list(__is_from_baseline ${OPT2} ${CPU_BASELINE_FINAL}) + if(NOT __is_from_baseline) + ocv_is_optimization_in_list(__is_active ${OPT2} ${OPT}) + if(__is_active) + ocv_append_optimization_flag(__dispatch_flags ${OPT2}) + list(APPEND __dispatch_definitions "CV_CPU_COMPILE_${OPT2}=1") + list(APPEND __dispatch_opts "${OPT2}") + endif() + ocv_is_optimization_in_force_list(__is_force ${OPT2} ${OPT}) + if(__is_force) + list(APPEND __dispatch_opts_force "${OPT2}") + endif() + endif() + endif() + endforeach() + set(__flags "${OPENCV_EXTRA_CXX_FLAGS} ${__dispatch_flags}") + if(NOT __flags STREQUAL CACHED_CPU_DISPATCH_${OPT}_FLAGS) + set(CACHED_CPU_DISPATCH_${OPT}_FLAGS "${__flags}" CACHE INTERNAL "" FORCE) + ocv_clear_vars(HAVE_CPU_DISPATCH_FLAGS_${OPT}) + endif() + ocv_check_compiler_flag(CXX "${__flags}" HAVE_CPU_DISPATCH_FLAGS_${OPT}) + if(NOT HAVE_CPU_DISPATCH_FLAGS_${OPT}) + message(FATAL_ERROR "Compiler doesn't support optimization flags for ${OPT} dispatch mode: ${__dispatch_flags}") + endif() + set(CPU_DISPATCH_FLAGS_${OPT} "${__dispatch_flags}") + set(CPU_DISPATCH_DEFINITIONS_${OPT} "${__dispatch_definitions}") + set(CPU_DISPATCH_${OPT}_INCLUDED "${__dispatch_opts}") + set(CPU_DISPATCH_${OPT}_FORCED "${__dispatch_opts_force}") + endforeach() + + if(ENABLE_POWERPC) + add_extra_compiler_option("-mcpu=G3 -mtune=G5") + endif() + if(ARM) + add_extra_compiler_option("-mfp16-format=ieee") + endif(ARM) + if(ENABLE_NEON) + add_extra_compiler_option("-mfpu=neon") + endif() + if(ENABLE_VFPV3 AND NOT ENABLE_NEON) + add_extra_compiler_option("-mfpu=vfpv3") + endif() +endmacro() + +macro(ocv_compiler_optimization_options_finalize) + if(CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) + if(NOT APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 4) + if(OPENCV_EXTRA_CXX_FLAGS MATCHES "-m(sse2|avx)") + add_extra_compiler_option(-mfpmath=sse) # !! important - be on the same wave with x64 compilers + else() + add_extra_compiler_option(-mfpmath=387) + endif() + endif() + endif() + + if(MSVC) + # Generate Intrinsic Functions + set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /Oi") + + if((X86 OR X86_64) AND CMAKE_SIZEOF_VOID_P EQUAL 4 AND ";${CPU_BASELINE_FINAL};" MATCHES ";SSE;") + set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /fp:fast") # !! important - be on the same wave with x64 compilers + endif() + endif(MSVC) +endmacro() + +macro(ocv_compiler_optimization_process_sources SOURCES_VAR_NAME LIBS_VAR_NAME TARGET_BASE_NAME) + set(__result "") + set(__result_libs "") + foreach(OPT ${CPU_DISPATCH_FINAL}) + set(__result_${OPT} "") + endforeach() + foreach(fname ${${SOURCES_VAR_NAME}}) + string(TOLOWER "${fname}" fname_LOWER) + if(fname_LOWER MATCHES "[.]opt_.*[.]cpp$") + if(CV_DISABLE_OPTIMIZATION OR NOT CV_ENABLE_INTRINSICS) + message(STATUS "Excluding from source files list: ${fname}") + #continue() + else() + set(__opt_found 0) + foreach(OPT ${CPU_BASELINE_FINAL}) + string(TOLOWER "${OPT}" OPT_LOWER) + if(fname_LOWER MATCHES "_${OPT_LOWER}[.]cpp$") +#message("${fname} BASELINE-${OPT}") + set(__opt_found 1) + list(APPEND __result "${fname}") + break() + endif() + endforeach() + foreach(OPT ${CPU_DISPATCH_FINAL}) + foreach(OPT2 ${CPU_DISPATCH_${OPT}_FORCED}) + string(TOLOWER "${OPT2}" OPT2_LOWER) + if(fname_LOWER MATCHES "_${OPT2_LOWER}[.]cpp$") + list(APPEND __result_${OPT} "${fname}") + math(EXPR CPU_${OPT}_USAGE_COUNT "${CPU_${OPT}_USAGE_COUNT}+1") + set(CPU_${OPT}_USAGE_COUNT "${CPU_${OPT}_USAGE_COUNT}" CACHE INTERNAL "" FORCE) +#message("${fname} ${OPT}") +#message(" ${CPU_DISPATCH_${OPT}_INCLUDED}") +#message(" ${CPU_DISPATCH_DEFINITIONS_${OPT}}") +#message(" ${CPU_DISPATCH_FLAGS_${OPT}}") + set(__opt_found 1) + break() + endif() + endforeach() + if(__opt_found) + set(__opt_found 1) + break() + endif() + endforeach() + if(NOT __opt_found) + message(STATUS "Excluding from source files list: ${fname}") + endif() + endif() + else() + list(APPEND __result "${fname}") + endif() + endforeach() + + foreach(OPT ${CPU_DISPATCH_FINAL}) + if(__result_${OPT}) +#message("${OPT}: ${__result_${OPT}}") + if(CMAKE_GENERATOR MATCHES "^Visual") + # extra flags are added before common flags, so switching between optimizations doesn't work correctly + # Also CMAKE_CXX_FLAGS doesn't work (it is directory-based, so add_subdirectory is required) + add_library(${TARGET_BASE_NAME}_${OPT} OBJECT ${__result_${OPT}}) + ocv_append_dependant_targets(${TARGET_BASE_NAME} ${TARGET_BASE_NAME}_${OPT}) + set_target_properties(${TARGET_BASE_NAME}_${OPT} PROPERTIES COMPILE_DEFINITIONS "${CPU_DISPATCH_DEFINITIONS_${OPT}}") + set_target_properties(${TARGET_BASE_NAME}_${OPT} PROPERTIES COMPILE_FLAGS "${CPU_DISPATCH_FLAGS_${OPT}}") + #list(APPEND __result_libs ${TARGET_BASE_NAME}_${OPT}) + list(APPEND __result "$") + else() + foreach(fname ${__result_${OPT}}) + set_source_files_properties("${fname}" PROPERTIES COMPILE_DEFINITIONS "${CPU_DISPATCH_DEFINITIONS_${OPT}}") + set_source_files_properties("${fname}" PROPERTIES COMPILE_FLAGS "${CPU_DISPATCH_FLAGS_${OPT}}") + endforeach() + list(APPEND __result ${__result_${OPT}}) + endif() + endif() + endforeach() + set(${SOURCES_VAR_NAME} "${__result}") + list(APPEND ${LIBS_VAR_NAME} ${__result_libs}) +endmacro() + +macro(ocv_compiler_optimization_fill_cpu_config) + set(OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE "") + foreach(OPT ${CPU_BASELINE_FINAL}) + set(OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE "${OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE} +#define CV_CPU_COMPILE_${OPT} 1 +#define CV_CPU_BASELINE_COMPILE_${OPT} 1 +") + endforeach() + + set(OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE "${OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE} +#define CV_CPU_BASELINE_FEATURES 0 \\") + foreach(OPT ${CPU_BASELINE_FINAL}) + if(NOT DEFINED CPU_${OPT}_FEATURE_ALIAS OR NOT "x${CPU_${OPT}_FEATURE_ALIAS}" STREQUAL "x") + set(OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE "${OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE} + , CV_CPU_${OPT} \\") + endif() + endforeach() + set(OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE "${OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE}\n") + + set(__dispatch_modes "") + foreach(OPT ${CPU_DISPATCH_FINAL}) + list(APPEND __dispatch_modes ${CPU_DISPATCH_${OPT}_FORCE} ${OPT}) + endforeach() + list(REMOVE_DUPLICATES __dispatch_modes) + set(OPENCV_CPU_DISPATCH_DEFINITIONS_CONFIGMAKE "") + foreach(OPT ${__dispatch_modes}) + set(OPENCV_CPU_DISPATCH_DEFINITIONS_CONFIGMAKE "${OPENCV_CPU_DISPATCH_DEFINITIONS_CONFIGMAKE} +#define CV_CPU_DISPATCH_COMPILE_${OPT} 1") + endforeach() + + set(OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE "// AUTOGENERATED, DO NOT EDIT\n") + foreach(OPT ${CPU_ALL_OPTIMIZATIONS}) + if(NOT DEFINED CPU_${OPT}_FEATURE_ALIAS OR NOT "x${CPU_${OPT}_FEATURE_ALIAS}" STREQUAL "x") + set(OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE "${OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE} +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_${OPT} +# define CV_CPU_HAS_SUPPORT_${OPT} 1 +# define CV_CPU_CALL_${OPT}(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_${OPT} +# define CV_CPU_HAS_SUPPORT_${OPT} (cv::checkHardwareSupport(CV_CPU_${OPT})) +# define CV_CPU_CALL_${OPT}(...) if (CV_CPU_HAS_SUPPORT_${OPT}) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_${OPT} 0 +# define CV_CPU_CALL_${OPT}(...) +#endif +") + endif() + endforeach() + + set(__file "${CMAKE_SOURCE_DIR}/modules/core/include/opencv2/core/cv_cpu_helper.h") + if(EXISTS "${__file}") + file(READ "${__file}" __content) + endif() + if(__content STREQUAL OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE) + #message(STATUS "${__file} contains same content") + else() + file(WRITE "${__file}" "${OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE}") + message(WARNING "${__file} is updated") + endif() +endmacro() + +if(CV_DISABLE_OPTIMIZATION OR CV_ICC) + ocv_update(CV_ENABLE_UNROLLED 0) +else() + ocv_update(CV_ENABLE_UNROLLED 1) +endif() diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake index 5bb0479113..0eb68b656e 100644 --- a/cmake/OpenCVCompilerOptions.cmake +++ b/cmake/OpenCVCompilerOptions.cmake @@ -31,24 +31,21 @@ endif() if(MINGW OR (X86 AND UNIX AND NOT APPLE)) # mingw compiler is known to produce unstable SSE code with -O3 hence we are trying to use -O2 instead if(CMAKE_COMPILER_IS_GNUCXX) - foreach(flags CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) - string(REPLACE "-O3" "-O2" ${flags} "${${flags}}") - endforeach() - endif() - - if(CMAKE_COMPILER_IS_GNUCC) - foreach(flags CMAKE_C_FLAGS CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_DEBUG) + foreach(flags + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG + CMAKE_C_FLAGS CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_DEBUG) string(REPLACE "-O3" "-O2" ${flags} "${${flags}}") endforeach() endif() endif() if(MSVC) - string(REGEX REPLACE "^ *| * $" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - string(REGEX REPLACE "^ *| * $" "" CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT}") + string(STRIP "${CMAKE_CXX_FLAGS}" CMAKE_CXX_FLAGS) + string(STRIP "${CMAKE_CXX_FLAGS_INIT}" CMAKE_CXX_FLAGS_INIT) if(CMAKE_CXX_FLAGS STREQUAL CMAKE_CXX_FLAGS_INIT) # override cmake default exception handling option - string(REPLACE "/EHsc" "/EHa" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHa") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "Flags used by the compiler during all build types." FORCE) endif() endif() @@ -63,9 +60,6 @@ set(OPENCV_EXTRA_EXE_LINKER_FLAGS_RELEASE "") set(OPENCV_EXTRA_EXE_LINKER_FLAGS_DEBUG "") macro(add_extra_compiler_option option) - if(CMAKE_BUILD_TYPE) - set(CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE}) - endif() ocv_check_flag_support(CXX "${option}" _varname "${OPENCV_EXTRA_CXX_FLAGS} ${ARGN}") if(${_varname}) set(OPENCV_EXTRA_CXX_FLAGS "${OPENCV_EXTRA_CXX_FLAGS} ${option}") @@ -77,6 +71,12 @@ macro(add_extra_compiler_option option) endif() endmacro() +macro(add_extra_compiler_option_force option) + set(OPENCV_EXTRA_CXX_FLAGS "${OPENCV_EXTRA_CXX_FLAGS} ${option}") + set(OPENCV_EXTRA_C_FLAGS "${OPENCV_EXTRA_C_FLAGS} ${option}") +endmacro() + + # Gets environment variable and puts its value to the corresponding preprocessor definition # Useful for WINRT that has no access to environment variables macro(add_env_definitions option) @@ -102,7 +102,11 @@ if(MINGW) endif() if(CV_ICC AND NOT ENABLE_FAST_MATH) - add_extra_compiler_option("-fp-model precise") + if(MSVC) + add_extra_compiler_option("/fp:precise") + else() + add_extra_compiler_option("-fp-model precise") + endif() endif() if(CMAKE_COMPILER_IS_GNUCXX) @@ -141,7 +145,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() # We need pthread's - if(UNIX AND NOT ANDROID AND NOT (APPLE AND CMAKE_COMPILER_IS_CLANGCXX)) + if(UNIX AND NOT ANDROID AND NOT (APPLE AND CMAKE_COMPILER_IS_CLANGCXX)) # TODO add_extra_compiler_option(-pthread) endif() @@ -170,83 +174,6 @@ if(CMAKE_COMPILER_IS_GNUCXX) if(ENABLE_FAST_MATH) add_extra_compiler_option(-ffast-math) endif() - if(ENABLE_POWERPC) - add_extra_compiler_option("-mcpu=G3 -mtune=G5") - endif() - if(ENABLE_SSE) - add_extra_compiler_option(-msse) - endif() - if(ENABLE_SSE2) - add_extra_compiler_option(-msse2) - elseif(X86 OR X86_64) - add_extra_compiler_option(-mno-sse2) - endif() - if(ARM) - add_extra_compiler_option("-mfp16-format=ieee") - endif(ARM) - if(ENABLE_NEON) - add_extra_compiler_option("-mfpu=neon") - endif() - if(ENABLE_VFPV3 AND NOT ENABLE_NEON) - add_extra_compiler_option("-mfpu=vfpv3") - endif() - - # SSE3 and further should be disabled under MingW because it generates compiler errors - if(NOT MINGW) - if(ENABLE_AVX) - add_extra_compiler_option(-mavx) - elseif(X86 OR X86_64) - add_extra_compiler_option(-mno-avx) - endif() - if(ENABLE_AVX2) - add_extra_compiler_option(-mavx2) - - if(ENABLE_FMA3) - add_extra_compiler_option(-mfma) - endif() - endif() - - # GCC depresses SSEx instructions when -mavx is used. Instead, it generates new AVX instructions or AVX equivalence for all SSEx instructions when needed. - if(NOT OPENCV_EXTRA_CXX_FLAGS MATCHES "-mavx") - if(ENABLE_SSE3) - add_extra_compiler_option(-msse3) - elseif(X86 OR X86_64) - add_extra_compiler_option(-mno-sse3) - endif() - - if(ENABLE_SSSE3) - add_extra_compiler_option(-mssse3) - elseif(X86 OR X86_64) - add_extra_compiler_option(-mno-ssse3) - endif() - - if(ENABLE_SSE41) - add_extra_compiler_option(-msse4.1) - elseif(X86 OR X86_64) - add_extra_compiler_option(-mno-sse4.1) - endif() - - if(ENABLE_SSE42) - add_extra_compiler_option(-msse4.2) - elseif(X86 OR X86_64) - add_extra_compiler_option(-mno-sse4.2) - endif() - - if(ENABLE_POPCNT) - add_extra_compiler_option(-mpopcnt) - endif() - endif() - endif(NOT MINGW) - - if(X86 OR X86_64) - if(NOT APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 4) - if(OPENCV_EXTRA_CXX_FLAGS MATCHES "-m(sse2|avx)") - add_extra_compiler_option(-mfpmath=sse)# !! important - be on the same wave with x64 compilers - else() - add_extra_compiler_option(-mfpmath=387) - endif() - endif() - endif() # Profiling? if(ENABLE_PROFILING) @@ -257,7 +184,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) string(REPLACE "-fomit-frame-pointer" "" ${flags} "${${flags}}") string(REPLACE "-ffunction-sections" "" ${flags} "${${flags}}") endforeach() - elseif(NOT APPLE AND NOT ANDROID) + elseif(NOT ((IOS OR ANDROID) AND NOT BUILD_SHARED_LIBS)) # Remove unreferenced functions: function level linking add_extra_compiler_option(-ffunction-sections) endif() @@ -296,41 +223,6 @@ if(MSVC) set(OPENCV_EXTRA_FLAGS_RELEASE "${OPENCV_EXTRA_FLAGS_RELEASE} /Zi") endif() - if(ENABLE_AVX2 AND NOT MSVC_VERSION LESS 1800) - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /arch:AVX2") - endif() - if(ENABLE_AVX AND NOT MSVC_VERSION LESS 1600 AND NOT OPENCV_EXTRA_FLAGS MATCHES "/arch:") - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /arch:AVX") - endif() - - if(ENABLE_SSE4_1 AND CV_ICC AND NOT OPENCV_EXTRA_FLAGS MATCHES "/arch:") - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /arch:SSE4.1") - endif() - - if(ENABLE_SSE3 AND CV_ICC AND NOT OPENCV_EXTRA_FLAGS MATCHES "/arch:") - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /arch:SSE3") - endif() - - if(NOT MSVC64) - # 64-bit MSVC compiler uses SSE/SSE2 by default - if(ENABLE_SSE2 AND NOT OPENCV_EXTRA_FLAGS MATCHES "/arch:") - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /arch:SSE2") - endif() - if(ENABLE_SSE AND NOT OPENCV_EXTRA_FLAGS MATCHES "/arch:") - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /arch:SSE") - endif() - endif() - - if(ENABLE_SSE OR ENABLE_SSE2 OR ENABLE_SSE3 OR ENABLE_SSE4_1 OR ENABLE_AVX OR ENABLE_AVX2) - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /Oi") - endif() - - if(X86 OR X86_64) - if(CMAKE_SIZEOF_VOID_P EQUAL 4 AND ENABLE_SSE2) - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /fp:fast") # !! important - be on the same wave with x64 compilers - endif() - endif() - if(OPENCV_WARNINGS_ARE_ERRORS) set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /WX") endif() @@ -353,6 +245,16 @@ if(NOT BUILD_SHARED_LIBS AND CMAKE_COMPILER_IS_GNUCXX AND NOT ANDROID) set(OPENCV_EXTRA_FLAGS "-fPIC ${OPENCV_EXTRA_FLAGS}") endif() +include(cmake/OpenCVCompilerOptimizations.cmake) + +if(COMMAND ocv_compiler_optimization_options) + ocv_compiler_optimization_options() +endif() + +if(COMMAND ocv_compiler_optimization_options_finalize) + ocv_compiler_optimization_options_finalize() +endif() + # Add user supplied extra options (optimization, etc...) # ========================================================== set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS}" CACHE INTERNAL "Extra compiler options") @@ -370,6 +272,7 @@ if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_OPENCV_GCC_VERSION_NUM GREATER 399) add_extra_compiler_option(-fvisibility-inlines-hidden) endif() +# TODO !!!!! if(NOT OPENCV_FP16_DISABLE AND NOT IOS) if(ARM AND ENABLE_NEON) set(FP16_OPTION "-mfpu=neon-fp16") @@ -378,7 +281,7 @@ if(NOT OPENCV_FP16_DISABLE AND NOT IOS) endif() try_compile(__VALID_FP16 "${OpenCV_BINARY_DIR}" - "${OpenCV_SOURCE_DIR}/cmake/checks/fp16.cpp" + "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_fp16.cpp" COMPILE_DEFINITIONS "-DCHECK_FP16" "${FP16_OPTION}" OUTPUT_VARIABLE TRY_OUT ) diff --git a/cmake/OpenCVGenHeaders.cmake b/cmake/OpenCVGenHeaders.cmake index 2988979045..477b910558 100644 --- a/cmake/OpenCVGenHeaders.cmake +++ b/cmake/OpenCVGenHeaders.cmake @@ -3,6 +3,10 @@ configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/cvconfig.h.in" "${OPENCV_CO configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/cvconfig.h.in" "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/opencv2/cvconfig.h") install(FILES "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/cvconfig.h" DESTINATION ${OPENCV_INCLUDE_INSTALL_PATH}/opencv2 COMPONENT dev) +# platform-specific config file +ocv_compiler_optimization_fill_cpu_config() +configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/cv_cpu_config.h.in" "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/cv_cpu_config.h") + # ---------------------------------------------------------------------------- # opencv_modules.hpp based on actual modules list # ---------------------------------------------------------------------------- diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index ce2bc7e08a..10e1f7397c 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -65,6 +65,7 @@ foreach(mod ${OPENCV_MODULES_BUILD} ${OPENCV_MODULES_DISABLED_USER} ${OPENCV_MOD unset(OPENCV_MODULE_${mod}_PRIVATE_OPT_DEPS CACHE) unset(OPENCV_MODULE_${mod}_LINK_DEPS CACHE) unset(OPENCV_MODULE_${mod}_WRAPPERS CACHE) + unset(OPENCV_DEPENDANT_TARGETS_${mod} CACHE) endforeach() # clean modules info which needs to be recalculated @@ -648,6 +649,8 @@ macro(ocv_set_module_sources) # use full paths for module to be independent from the module location ocv_convert_to_full_paths(OPENCV_MODULE_${the_module}_HEADERS) + ocv_compiler_optimization_process_sources(OPENCV_MODULE_${the_module}_SOURCES OPENCV_MODULE_${the_module}_DEPS_EXT ${the_module}) + set(OPENCV_MODULE_${the_module}_HEADERS ${OPENCV_MODULE_${the_module}_HEADERS} CACHE INTERNAL "List of header files for ${the_module}") set(OPENCV_MODULE_${the_module}_SOURCES ${OPENCV_MODULE_${the_module}_SOURCES} CACHE INTERNAL "List of source files for ${the_module}") endmacro() diff --git a/cmake/OpenCVPCHSupport.cmake b/cmake/OpenCVPCHSupport.cmake index 29f21d8015..8db3cb9522 100644 --- a/cmake/OpenCVPCHSupport.cmake +++ b/cmake/OpenCVPCHSupport.cmake @@ -328,7 +328,10 @@ MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _input) get_target_property(_sources ${_targetName} SOURCES) foreach(src ${_sources}) - if(NOT "${src}" MATCHES "\\.mm$") + if(NOT "${src}" MATCHES "\\.mm$" + AND NOT "${src}" MATCHES "\\.h$" AND NOT "${src}" MATCHES "\\.hpp$" # header files + AND NOT "${src}" MATCHES "^\$" # CMake generator expressions + ) get_source_file_property(oldProps "${src}" COMPILE_FLAGS) if(NOT oldProps) set(newProperties "/Yu\"${_input}\" /FI\"${_input}\"") diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 474f7db609..935bfc2a01 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -37,7 +37,11 @@ endmacro() macro(ocv_update VAR) if(NOT DEFINED ${VAR}) - set(${VAR} ${ARGN}) + if("x${ARGN}" STREQUAL "x") + set(${VAR} "") + else() + set(${VAR} ${ARGN}) + endif() else() #ocv_debug_message("Preserve old value for ${VAR}: ${${VAR}}") endif() @@ -151,8 +155,15 @@ function(ocv_append_target_property target prop) endif() endfunction() +function(ocv_append_dependant_targets target) + #ocv_debug_message("ocv_append_dependant_targets(${target} ${ARGN})") + _ocv_fix_target(target) + set(OPENCV_DEPENDANT_TARGETS_${target} "${OPENCV_DEPENDANT_TARGETS_${target}};${ARGN}" CACHE INTERNAL "" FORCE) +endfunction() + # adds include directories in such way that directories from the OpenCV source tree go first function(ocv_target_include_directories target) + #ocv_debug_message("ocv_target_include_directories(${target} ${ARGN})") _ocv_fix_target(target) set(__params "") if(CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0" AND @@ -173,6 +184,11 @@ function(ocv_target_include_directories target) else() if(TARGET ${target}) target_include_directories(${target} PRIVATE ${__params}) + if(OPENCV_DEPENDANT_TARGETS_${target}) + foreach(t ${OPENCV_DEPENDANT_TARGETS_${target}}) + target_include_directories(${t} PRIVATE ${__params}) + endforeach() + endif() else() set(__new_inc "${OCV_TARGET_INCLUDE_DIRS_${target}};${__params}") set(OCV_TARGET_INCLUDE_DIRS_${target} "${__new_inc}" CACHE INTERNAL "") @@ -205,8 +221,11 @@ set(OCV_COMPILER_FAIL_REGEX ) MACRO(ocv_check_compiler_flag LANG FLAG RESULT) + set(_fname "${ARGN}") if(NOT DEFINED ${RESULT}) - if("_${LANG}_" MATCHES "_CXX_") + if(_fname) + # nothing + elseif("_${LANG}_" MATCHES "_CXX_") set(_fname "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx") if("${CMAKE_CXX_FLAGS} ${FLAG} " MATCHES "-Werror " OR "${CMAKE_CXX_FLAGS} ${FLAG} " MATCHES "-Werror=unknown-pragmas ") FILE(WRITE "${_fname}" "int main() { return 0; }\n") @@ -231,7 +250,13 @@ MACRO(ocv_check_compiler_flag LANG FLAG RESULT) unset(_fname) endif() if(_fname) - MESSAGE(STATUS "Performing Test ${RESULT}") + if(NOT "x${ARGN}" STREQUAL "x") + file(RELATIVE_PATH __msg "${CMAKE_SOURCE_DIR}" "${ARGN}") + set(__msg " (check file: ${__msg})") + else() + set(__msg "") + endif() + MESSAGE(STATUS "Performing Test ${RESULT}${__msg}") TRY_COMPILE(${RESULT} "${CMAKE_BINARY_DIR}" "${_fname}" @@ -278,7 +303,11 @@ MACRO(ocv_check_compiler_flag LANG FLAG RESULT) endif() ENDMACRO() -macro(ocv_check_flag_support lang flag varname) +macro(ocv_check_flag_support lang flag varname base_options) + if(CMAKE_BUILD_TYPE) + set(CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE}) + endif() + if("_${lang}_" MATCHES "_CXX_") set(_lang CXX) elseif("_${lang}_" MATCHES "_C_") @@ -293,7 +322,7 @@ macro(ocv_check_flag_support lang flag varname) string(REGEX REPLACE "^(/|-)" "HAVE_${_lang}_" ${varname} "${${varname}}") string(REGEX REPLACE " -|-|=| |\\." "_" ${varname} "${${varname}}") - ocv_check_compiler_flag("${_lang}" "${ARGN} ${flag}" ${${varname}}) + ocv_check_compiler_flag("${_lang}" "${base_options} ${flag}" ${${varname}} ${ARGN}) endmacro() # turns off warnings @@ -327,7 +356,7 @@ macro(ocv_warnings_disable) string(REPLACE "${warning}" "" ${var} "${${var}}") string(REPLACE "-W" "-Wno-" warning "${warning}") endif() - ocv_check_flag_support(${var} "${warning}" _varname) + ocv_check_flag_support(${var} "${warning}" _varname "") if(${_varname}) set(${var} "${${var}} ${warning}") endif() @@ -342,7 +371,7 @@ macro(ocv_warnings_disable) else() string(REPLACE "-wd" "-Qwd" warning "${warning}") endif() - ocv_check_flag_support(${var} "${warning}" _varname) + ocv_check_flag_support(${var} "${warning}" _varname "") if(${_varname}) set(${var} "${${var}} ${warning}") endif() @@ -357,7 +386,7 @@ macro(ocv_warnings_disable) endmacro() macro(add_apple_compiler_options the_module) - ocv_check_flag_support(OBJCXX "-fobjc-exceptions" HAVE_OBJC_EXCEPTIONS) + ocv_check_flag_support(OBJCXX "-fobjc-exceptions" HAVE_OBJC_EXCEPTIONS "") if(HAVE_OBJC_EXCEPTIONS) foreach(source ${OPENCV_MODULE_${the_module}_SOURCES}) if("${source}" MATCHES "\\.mm$") @@ -903,6 +932,11 @@ function(_ocv_append_target_includes target) if (TARGET ${target}_object) target_include_directories(${target}_object PRIVATE ${OCV_TARGET_INCLUDE_DIRS_${target}}) endif() + if(OPENCV_DEPENDANT_TARGETS_${target}) + foreach(t ${OPENCV_DEPENDANT_TARGETS_${target}}) + target_include_directories(${t} PRIVATE ${OCV_TARGET_INCLUDE_DIRS_${target}}) + endforeach() + endif() unset(OCV_TARGET_INCLUDE_DIRS_${target} CACHE) endif() endfunction() diff --git a/cmake/checks/cpu_avx.cpp b/cmake/checks/cpu_avx.cpp new file mode 100644 index 0000000000..05536f443f --- /dev/null +++ b/cmake/checks/cpu_avx.cpp @@ -0,0 +1,9 @@ +#if !defined __AVX__ // MSVC supports this flag since MSVS 2013 +#error "__AVX__ define is missing" +#endif +#include +void test() +{ + __m256 a = _mm256_set1_ps(0.0f); +} +int main() { return 0; } diff --git a/cmake/checks/cpu_avx2.cpp b/cmake/checks/cpu_avx2.cpp new file mode 100644 index 0000000000..3ab1143b8f --- /dev/null +++ b/cmake/checks/cpu_avx2.cpp @@ -0,0 +1,10 @@ +#if !defined __AVX2__ // MSVC supports this flag since MSVS 2013 +#error "__AVX2__ define is missing" +#endif +#include +void test() +{ + int data[8] = {0,0,0,0, 0,0,0,0}; + __m256i a = _mm256_loadu_si256((const __m256i *)data); +} +int main() { return 0; } diff --git a/cmake/checks/cpu_avx512.cpp b/cmake/checks/cpu_avx512.cpp new file mode 100644 index 0000000000..d0898ab3ee --- /dev/null +++ b/cmake/checks/cpu_avx512.cpp @@ -0,0 +1,10 @@ +#if defined __AVX512__ || defined __AVX512F__ +#include +void test() +{ + __m512i zmm = _mm512_setzero_si512(); +} +#else +#error "AVX512 is not supported" +#endif +int main() { return 0; } diff --git a/cmake/checks/fp16.cpp b/cmake/checks/cpu_fp16.cpp similarity index 86% rename from cmake/checks/fp16.cpp rename to cmake/checks/cpu_fp16.cpp index c77c844834..6951f1c4f7 100644 --- a/cmake/checks/fp16.cpp +++ b/cmake/checks/cpu_fp16.cpp @@ -1,6 +1,6 @@ #include -#if defined __F16C__ || (defined _MSC_VER && _MSC_VER >= 1700) +#if defined __F16C__ || (defined _MSC_VER && _MSC_VER >= 1700) || (defined __INTEL_COMPILER && defined __AVX__) #include int test() { diff --git a/cmake/checks/cpu_popcnt.cpp b/cmake/checks/cpu_popcnt.cpp new file mode 100644 index 0000000000..f55c9f3c54 --- /dev/null +++ b/cmake/checks/cpu_popcnt.cpp @@ -0,0 +1,8 @@ +#include +#ifndef _MSC_VER +#include +#endif +int main() { + int i = _mm_popcnt_u64(1); + return 0; +} diff --git a/cmake/checks/cpu_sse.cpp b/cmake/checks/cpu_sse.cpp new file mode 100644 index 0000000000..c6269acdb5 --- /dev/null +++ b/cmake/checks/cpu_sse.cpp @@ -0,0 +1,2 @@ +#include +int main() { return 0; } diff --git a/cmake/checks/cpu_sse2.cpp b/cmake/checks/cpu_sse2.cpp new file mode 100644 index 0000000000..68a69f88cb --- /dev/null +++ b/cmake/checks/cpu_sse2.cpp @@ -0,0 +1,2 @@ +#include +int main() { return 0; } diff --git a/cmake/checks/cpu_sse3.cpp b/cmake/checks/cpu_sse3.cpp new file mode 100644 index 0000000000..98ce2191ec --- /dev/null +++ b/cmake/checks/cpu_sse3.cpp @@ -0,0 +1,7 @@ +#include +int main() { + __m128 u, v; + u = _mm_set1_ps(0.0f); + v = _mm_moveldup_ps(u); // SSE3 + return 0; +} diff --git a/cmake/checks/cpu_sse41.cpp b/cmake/checks/cpu_sse41.cpp new file mode 100644 index 0000000000..ddd835b0e7 --- /dev/null +++ b/cmake/checks/cpu_sse41.cpp @@ -0,0 +1,6 @@ +#include +int main() { + __m128i a = _mm_setzero_si128(), b = _mm_setzero_si128(); + __m128i c = _mm_packus_epi32(a, b); + return 0; +} diff --git a/cmake/checks/cpu_sse42.cpp b/cmake/checks/cpu_sse42.cpp new file mode 100644 index 0000000000..56f56658ab --- /dev/null +++ b/cmake/checks/cpu_sse42.cpp @@ -0,0 +1,5 @@ +#include +int main() { + int i = _mm_popcnt_u64(1); + return 0; +} diff --git a/cmake/checks/cpu_ssse3.cpp b/cmake/checks/cpu_ssse3.cpp new file mode 100644 index 0000000000..e583199bcd --- /dev/null +++ b/cmake/checks/cpu_ssse3.cpp @@ -0,0 +1,7 @@ +#include +const double v = 0; +int main() { + __m128i a = _mm_setzero_si128(); + __m128i b = _mm_abs_epi32(a); + return 0; +} diff --git a/cmake/templates/cv_cpu_config.h.in b/cmake/templates/cv_cpu_config.h.in new file mode 100644 index 0000000000..27b27315cf --- /dev/null +++ b/cmake/templates/cv_cpu_config.h.in @@ -0,0 +1,5 @@ +// OpenCV CPU baseline features +@OPENCV_CPU_BASELINE_DEFINITIONS_CONFIGMAKE@ + +// OpenCV supported CPU dispatched features +@OPENCV_CPU_DISPATCH_DEFINITIONS_CONFIGMAKE@ diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in index 05add9e2c5..658d12c14c 100644 --- a/cmake/templates/cvconfig.h.in +++ b/cmake/templates/cvconfig.h.in @@ -1,6 +1,15 @@ +#ifndef OPENCV_CVCONFIG_H_INCLUDED +#define OPENCV_CVCONFIG_H_INCLUDED + /* OpenCV compiled as static or dynamic libs */ #cmakedefine BUILD_SHARED_LIBS +/* OpenCV intrinsics optimized code */ +#cmakedefine CV_ENABLE_INTRINSICS + +/* OpenCV additional optimized code */ +#cmakedefine CV_DISABLE_OPTIMIZATION + /* Compile for 'real' NVIDIA GPU architectures */ #define CUDA_ARCH_BIN "${OPENCV_CUDA_ARCH_BIN}" @@ -206,3 +215,7 @@ /* OpenVX */ #cmakedefine HAVE_OPENVX + + + +#endif // OPENCV_CVCONFIG_H_INCLUDED diff --git a/modules/core/include/opencv2/core/cv_cpu_dispatch.h b/modules/core/include/opencv2/core/cv_cpu_dispatch.h new file mode 100644 index 0000000000..9a8537f909 --- /dev/null +++ b/modules/core/include/opencv2/core/cv_cpu_dispatch.h @@ -0,0 +1,166 @@ +// 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. + +#if defined __OPENCV_BUILD \ + +#include "cv_cpu_config.h" +#include "cv_cpu_helper.h" + +#if defined CV_ENABLE_INTRINSICS \ + && !defined CV_DISABLE_OPTIMIZATION \ + && !defined __CUDACC__ /* do not include SSE/AVX/NEON headers for NVCC compiler */ \ + +#ifdef CV_CPU_COMPILE_SSE2 +# include +# define CV_MMX 1 +# define CV_SSE 1 +# define CV_SSE2 1 +#endif +#ifdef CV_CPU_COMPILE_SSE3 +# include +# define CV_SSE3 1 +#endif +#ifdef CV_CPU_COMPILE_SSSE3 +# include +# define CV_SSSE3 1 +#endif +#ifdef CV_CPU_COMPILE_SSE4_1 +# include +# define CV_SSE4_1 1 +#endif +#ifdef CV_CPU_COMPILE_SSE4_2 +# include +# define CV_SSE4_2 1 +#endif +#ifdef CV_CPU_COMPILE_POPCNT +# ifdef _MSC_VER +# include +# if defined(_M_X64) +# define CV_POPCNT_U64 _mm_popcnt_u64 +# endif +# define CV_POPCNT_U32 _mm_popcnt_u32 +# else +# include +# if defined(__x86_64__) +# define CV_POPCNT_U64 __builtin_popcountll +# endif +# define CV_POPCNT_U32 __builtin_popcount +# endif +# define CV_POPCNT 1 +#endif +#ifdef CV_CPU_COMPILE_AVX +# include +# define CV_AVX 1 +#endif +#ifdef CV_CPU_COMPILE_AVX2 +# include +# define CV_AVX2 1 +#endif +#ifdef CV_CPU_COMPILE_FMA3 +# define CV_FMA3 1 +#endif + +#if (defined WIN32 || defined _WIN32) && defined(_M_ARM) +# include +# include +# define CV_NEON 1 +#elif defined(__ARM_NEON__) || (defined (__ARM_NEON) && defined(__aarch64__)) +# include +# define CV_NEON 1 +#endif + +#if defined(__ARM_NEON__) || defined(__aarch64__) +# include +#endif + +#endif // CV_ENABLE_INTRINSICS && !CV_DISABLE_OPTIMIZATION && !__CUDACC__ + +#endif // __OPENCV_BUILD + + + +#if !defined __OPENCV_BUILD // Compatibility code + +#if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2) +# include +# define CV_MMX 1 +# define CV_SSE 1 +# define CV_SSE2 1 +#elif (defined WIN32 || defined _WIN32) && defined(_M_ARM) +# include +# include +# define CV_NEON 1 +#elif defined(__ARM_NEON__) || (defined (__ARM_NEON) && defined(__aarch64__)) +# include +# define CV_NEON 1 +#endif + +#endif // !__OPENCV_BUILD (Compatibility code) + + + +#ifndef CV_MMX +# define CV_MMX 0 +#endif +#ifndef CV_SSE +# define CV_SSE 0 +#endif +#ifndef CV_SSE2 +# define CV_SSE2 0 +#endif +#ifndef CV_SSE3 +# define CV_SSE3 0 +#endif +#ifndef CV_SSSE3 +# define CV_SSSE3 0 +#endif +#ifndef CV_SSE4_1 +# define CV_SSE4_1 0 +#endif +#ifndef CV_SSE4_2 +# define CV_SSE4_2 0 +#endif +#ifndef CV_POPCNT +# define CV_POPCNT 0 +#endif +#ifndef CV_AVX +# define CV_AVX 0 +#endif +#ifndef CV_AVX2 +# define CV_AVX2 0 +#endif +#ifndef CV_FMA3 +# define CV_FMA3 0 +#endif +#ifndef CV_AVX_512F +# define CV_AVX_512F 0 +#endif +#ifndef CV_AVX_512BW +# define CV_AVX_512BW 0 +#endif +#ifndef CV_AVX_512CD +# define CV_AVX_512CD 0 +#endif +#ifndef CV_AVX_512DQ +# define CV_AVX_512DQ 0 +#endif +#ifndef CV_AVX_512ER +# define CV_AVX_512ER 0 +#endif +#ifndef CV_AVX_512IFMA512 +# define CV_AVX_512IFMA512 0 +#endif +#ifndef CV_AVX_512PF +# define CV_AVX_512PF 0 +#endif +#ifndef CV_AVX_512VBMI +# define CV_AVX_512VBMI 0 +#endif +#ifndef CV_AVX_512VL +# define CV_AVX_512VL 0 +#endif + +#ifndef CV_NEON +# define CV_NEON 0 +#endif diff --git a/modules/core/include/opencv2/core/cv_cpu_helper.h b/modules/core/include/opencv2/core/cv_cpu_helper.h new file mode 100644 index 0000000000..cb755d615e --- /dev/null +++ b/modules/core/include/opencv2/core/cv_cpu_helper.h @@ -0,0 +1,133 @@ +// AUTOGENERATED, DO NOT EDIT + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE +# define CV_CPU_HAS_SUPPORT_SSE 1 +# define CV_CPU_CALL_SSE(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE +# define CV_CPU_HAS_SUPPORT_SSE (cv::checkHardwareSupport(CV_CPU_SSE)) +# define CV_CPU_CALL_SSE(...) if (CV_CPU_HAS_SUPPORT_SSE) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_SSE 0 +# define CV_CPU_CALL_SSE(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE2 +# define CV_CPU_HAS_SUPPORT_SSE2 1 +# define CV_CPU_CALL_SSE2(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE2 +# define CV_CPU_HAS_SUPPORT_SSE2 (cv::checkHardwareSupport(CV_CPU_SSE2)) +# define CV_CPU_CALL_SSE2(...) if (CV_CPU_HAS_SUPPORT_SSE2) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_SSE2 0 +# define CV_CPU_CALL_SSE2(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE3 +# define CV_CPU_HAS_SUPPORT_SSE3 1 +# define CV_CPU_CALL_SSE3(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE3 +# define CV_CPU_HAS_SUPPORT_SSE3 (cv::checkHardwareSupport(CV_CPU_SSE3)) +# define CV_CPU_CALL_SSE3(...) if (CV_CPU_HAS_SUPPORT_SSE3) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_SSE3 0 +# define CV_CPU_CALL_SSE3(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSSE3 +# define CV_CPU_HAS_SUPPORT_SSSE3 1 +# define CV_CPU_CALL_SSSE3(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSSE3 +# define CV_CPU_HAS_SUPPORT_SSSE3 (cv::checkHardwareSupport(CV_CPU_SSSE3)) +# define CV_CPU_CALL_SSSE3(...) if (CV_CPU_HAS_SUPPORT_SSSE3) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_SSSE3 0 +# define CV_CPU_CALL_SSSE3(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE4_1 +# define CV_CPU_HAS_SUPPORT_SSE4_1 1 +# define CV_CPU_CALL_SSE4_1(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE4_1 +# define CV_CPU_HAS_SUPPORT_SSE4_1 (cv::checkHardwareSupport(CV_CPU_SSE4_1)) +# define CV_CPU_CALL_SSE4_1(...) if (CV_CPU_HAS_SUPPORT_SSE4_1) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_SSE4_1 0 +# define CV_CPU_CALL_SSE4_1(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE4_2 +# define CV_CPU_HAS_SUPPORT_SSE4_2 1 +# define CV_CPU_CALL_SSE4_2(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE4_2 +# define CV_CPU_HAS_SUPPORT_SSE4_2 (cv::checkHardwareSupport(CV_CPU_SSE4_2)) +# define CV_CPU_CALL_SSE4_2(...) if (CV_CPU_HAS_SUPPORT_SSE4_2) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_SSE4_2 0 +# define CV_CPU_CALL_SSE4_2(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_POPCNT +# define CV_CPU_HAS_SUPPORT_POPCNT 1 +# define CV_CPU_CALL_POPCNT(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_POPCNT +# define CV_CPU_HAS_SUPPORT_POPCNT (cv::checkHardwareSupport(CV_CPU_POPCNT)) +# define CV_CPU_CALL_POPCNT(...) if (CV_CPU_HAS_SUPPORT_POPCNT) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_POPCNT 0 +# define CV_CPU_CALL_POPCNT(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX +# define CV_CPU_HAS_SUPPORT_AVX 1 +# define CV_CPU_CALL_AVX(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX +# define CV_CPU_HAS_SUPPORT_AVX (cv::checkHardwareSupport(CV_CPU_AVX)) +# define CV_CPU_CALL_AVX(...) if (CV_CPU_HAS_SUPPORT_AVX) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_AVX 0 +# define CV_CPU_CALL_AVX(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_FP16 +# define CV_CPU_HAS_SUPPORT_FP16 1 +# define CV_CPU_CALL_FP16(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_FP16 +# define CV_CPU_HAS_SUPPORT_FP16 (cv::checkHardwareSupport(CV_CPU_FP16)) +# define CV_CPU_CALL_FP16(...) if (CV_CPU_HAS_SUPPORT_FP16) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_FP16 0 +# define CV_CPU_CALL_FP16(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX2 +# define CV_CPU_HAS_SUPPORT_AVX2 1 +# define CV_CPU_CALL_AVX2(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX2 +# define CV_CPU_HAS_SUPPORT_AVX2 (cv::checkHardwareSupport(CV_CPU_AVX2)) +# define CV_CPU_CALL_AVX2(...) if (CV_CPU_HAS_SUPPORT_AVX2) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_AVX2 0 +# define CV_CPU_CALL_AVX2(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_FMA3 +# define CV_CPU_HAS_SUPPORT_FMA3 1 +# define CV_CPU_CALL_FMA3(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_FMA3 +# define CV_CPU_HAS_SUPPORT_FMA3 (cv::checkHardwareSupport(CV_CPU_FMA3)) +# define CV_CPU_CALL_FMA3(...) if (CV_CPU_HAS_SUPPORT_FMA3) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_FMA3 0 +# define CV_CPU_CALL_FMA3(...) +#endif + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_NEON +# define CV_CPU_HAS_SUPPORT_NEON 1 +# define CV_CPU_CALL_NEON(...) return __VA_ARGS__ +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_NEON +# define CV_CPU_HAS_SUPPORT_NEON (cv::checkHardwareSupport(CV_CPU_NEON)) +# define CV_CPU_CALL_NEON(...) if (CV_CPU_HAS_SUPPORT_NEON) return __VA_ARGS__ +#else +# define CV_CPU_HAS_SUPPORT_NEON 0 +# define CV_CPU_CALL_NEON(...) +#endif diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index 9e2b1ed7fd..faa7ef0a6a 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -48,6 +48,10 @@ //! @addtogroup core_utils //! @{ +#ifdef __OPENCV_BUILD +#include "cvconfig.h" +#endif + #if !defined _CRT_SECURE_NO_DEPRECATE && defined _MSC_VER && _MSC_VER > 1300 # define _CRT_SECURE_NO_DEPRECATE /* to avoid multiple Visual Studio warnings */ #endif @@ -59,10 +63,6 @@ #undef abs #undef Complex -#if !defined _CRT_SECURE_NO_DEPRECATE && defined _MSC_VER && _MSC_VER > 1300 -# define _CRT_SECURE_NO_DEPRECATE /* to avoid multiple Visual Studio warnings */ -#endif - #include #include "opencv2/core/hal/interface.h" @@ -88,7 +88,7 @@ # endif #endif -#if defined CV_ICC && !defined CV_ENABLE_UNROLLED +#if defined CV_DISABLE_OPTIMIZATION || (defined CV_ICC && !defined CV_ENABLE_UNROLLED) # define CV_ENABLE_UNROLLED 0 #else # define CV_ENABLE_UNROLLED 1 @@ -161,150 +161,9 @@ enum CpuFeatures { CPU_NEON = 100 }; -// do not include SSE/AVX/NEON headers for NVCC compiler -#ifndef __CUDACC__ -#if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2) -# include -# define CV_MMX 1 -# define CV_SSE 1 -# define CV_SSE2 1 -# if defined __SSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) -# include -# define CV_SSE3 1 -# endif -# if defined __SSSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) -# include -# define CV_SSSE3 1 -# endif -# if defined __SSE4_1__ || (defined _MSC_VER && _MSC_VER >= 1500) -# include -# define CV_SSE4_1 1 -# endif -# if defined __SSE4_2__ || (defined _MSC_VER && _MSC_VER >= 1500) -# include -# define CV_SSE4_2 1 -# endif -# if defined __POPCNT__ || (defined _MSC_VER && _MSC_VER >= 1500) -# ifdef _MSC_VER -# include -# if defined(_M_X64) -# define CV_POPCNT_U64 _mm_popcnt_u64 -# endif -# define CV_POPCNT_U32 _mm_popcnt_u32 -# else -# include -# if defined(__x86_64__) -# define CV_POPCNT_U64 __builtin_popcountll -# endif -# define CV_POPCNT_U32 __builtin_popcount -# endif -# define CV_POPCNT 1 -# endif -# if defined __AVX__ || (defined _MSC_VER && _MSC_VER >= 1600 && 0) -// MS Visual Studio 2010 (2012?) has no macro pre-defined to identify the use of /arch:AVX -// See: http://connect.microsoft.com/VisualStudio/feedback/details/605858/arch-avx-should-define-a-predefined-macro-in-x64-and-set-a-unique-value-for-m-ix86-fp-in-win32 -# include -# define CV_AVX 1 -# if defined(_XCR_XFEATURE_ENABLED_MASK) -# define __xgetbv() _xgetbv(_XCR_XFEATURE_ENABLED_MASK) -# else -# define __xgetbv() 0 -# endif -# endif -# if defined __AVX2__ || (defined _MSC_VER && _MSC_VER >= 1800 && 0) -# include -# define CV_AVX2 1 -# if defined __FMA__ -# define CV_FMA3 1 -# endif -# endif -#endif +#include "cv_cpu_dispatch.h" -#if (defined WIN32 || defined _WIN32) && defined(_M_ARM) -# include -# include -# define CV_NEON 1 -# define CPU_HAS_NEON_FEATURE (true) -#elif defined(__ARM_NEON__) || (defined (__ARM_NEON) && defined(__aarch64__)) -# include -# define CV_NEON 1 -#endif - -#if defined __GNUC__ && defined __arm__ && (defined __ARM_PCS_VFP || defined __ARM_VFPV3__ || defined __ARM_NEON__) && !defined __SOFTFP__ -# define CV_VFP 1 -#endif - -#endif // __CUDACC__ - -#ifndef CV_POPCNT -#define CV_POPCNT 0 -#endif -#ifndef CV_MMX -# define CV_MMX 0 -#endif -#ifndef CV_SSE -# define CV_SSE 0 -#endif -#ifndef CV_SSE2 -# define CV_SSE2 0 -#endif -#ifndef CV_SSE3 -# define CV_SSE3 0 -#endif -#ifndef CV_SSSE3 -# define CV_SSSE3 0 -#endif -#ifndef CV_SSE4_1 -# define CV_SSE4_1 0 -#endif -#ifndef CV_SSE4_2 -# define CV_SSE4_2 0 -#endif -#ifndef CV_AVX -# define CV_AVX 0 -#endif -#ifndef CV_AVX2 -# define CV_AVX2 0 -#endif -#ifndef CV_FMA3 -# define CV_FMA3 0 -#endif -#ifndef CV_AVX_512F -# define CV_AVX_512F 0 -#endif -#ifndef CV_AVX_512BW -# define CV_AVX_512BW 0 -#endif -#ifndef CV_AVX_512CD -# define CV_AVX_512CD 0 -#endif -#ifndef CV_AVX_512DQ -# define CV_AVX_512DQ 0 -#endif -#ifndef CV_AVX_512ER -# define CV_AVX_512ER 0 -#endif -#ifndef CV_AVX_512IFMA512 -# define CV_AVX_512IFMA512 0 -#endif -#ifndef CV_AVX_512PF -# define CV_AVX_512PF 0 -#endif -#ifndef CV_AVX_512VBMI -# define CV_AVX_512VBMI 0 -#endif -#ifndef CV_AVX_512VL -# define CV_AVX_512VL 0 -#endif - -#ifndef CV_NEON -# define CV_NEON 0 -#endif - -#ifndef CV_VFP -# define CV_VFP 0 -#endif /* fundamental constants */ #define CV_PI 3.1415926535897932384626433832795 diff --git a/modules/core/include/opencv2/core/fast_math.hpp b/modules/core/include/opencv2/core/fast_math.hpp index c76936afe4..31c1062320 100644 --- a/modules/core/include/opencv2/core/fast_math.hpp +++ b/modules/core/include/opencv2/core/fast_math.hpp @@ -47,6 +47,12 @@ #include "opencv2/core/cvdef.h" +#if ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ \ + && defined __SSE2__ && !defined __APPLE__)) && !defined(__CUDACC__) +#include +#endif + + //! @addtogroup core_utils //! @{ @@ -66,7 +72,7 @@ # include "tegra_round.hpp" #endif -#if CV_VFP +#if defined __GNUC__ && defined __arm__ && (defined __ARM_PCS_VFP || defined __ARM_VFPV3__ || defined __ARM_NEON__) && !defined __SOFTFP__ // 1. general scheme #define ARM_ROUND(_value, _asm_string) \ int res; \ @@ -82,7 +88,7 @@ #endif // 3. version for float #define ARM_ROUND_FLT(value) ARM_ROUND(value, "vcvtr.s32.f32 %[temp], %[value]\n vmov %[res], %[temp]") -#endif // CV_VFP +#endif /** @brief Rounds floating-point number to the nearest integer @@ -93,7 +99,7 @@ CV_INLINE int cvRound( double value ) { #if ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ \ - && defined __SSE2__ && !defined __APPLE__)) && !defined(__CUDACC__) + && defined __SSE2__ && !defined __APPLE__) || CV_SSE2) && !defined(__CUDACC__) __m128d t = _mm_set_sd( value ); return _mm_cvtsd_si32(t); #elif defined _MSC_VER && defined _M_IX86 @@ -108,7 +114,7 @@ cvRound( double value ) defined __GNUC__) && defined HAVE_TEGRA_OPTIMIZATION TEGRA_ROUND_DBL(value); #elif defined CV_ICC || defined __GNUC__ -# if CV_VFP +# if defined ARM_ROUND_DBL ARM_ROUND_DBL(value); # else return (int)lrint(value); @@ -130,18 +136,8 @@ cvRound( double value ) */ CV_INLINE int cvFloor( double value ) { -#if (defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__ && !defined __APPLE__)) && !defined(__CUDACC__) - __m128d t = _mm_set_sd( value ); - int i = _mm_cvtsd_si32(t); - return i - _mm_movemask_pd(_mm_cmplt_sd(t, _mm_cvtsi32_sd(t,i))); -#elif defined __GNUC__ int i = (int)value; return i - (i > value); -#else - int i = cvRound(value); - float diff = (float)(value - i); - return i - (diff < 0); -#endif } /** @brief Rounds floating-point number to the nearest integer not smaller than the original. @@ -153,18 +149,8 @@ CV_INLINE int cvFloor( double value ) */ CV_INLINE int cvCeil( double value ) { -#if (defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__&& !defined __APPLE__)) && !defined(__CUDACC__) - __m128d t = _mm_set_sd( value ); - int i = _mm_cvtsd_si32(t); - return i + _mm_movemask_pd(_mm_cmplt_sd(_mm_cvtsi32_sd(t,i), t)); -#elif defined __GNUC__ int i = (int)value; return i + (i < value); -#else - int i = cvRound(value); - float diff = (float)(i - value); - return i + (diff < 0); -#endif } /** @brief Determines if the argument is Not A Number. @@ -200,8 +186,8 @@ CV_INLINE int cvIsInf( double value ) /** @overload */ CV_INLINE int cvRound(float value) { -#if ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ && \ - defined __SSE2__ && !defined __APPLE__)) && !defined(__CUDACC__) +#if ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ \ + && defined __SSE2__ && !defined __APPLE__) || CV_SSE2) && !defined(__CUDACC__) __m128 t = _mm_set_ss( value ); return _mm_cvtss_si32(t); #elif defined _MSC_VER && defined _M_IX86 @@ -216,7 +202,7 @@ CV_INLINE int cvRound(float value) defined __GNUC__) && defined HAVE_TEGRA_OPTIMIZATION TEGRA_ROUND_FLT(value); #elif defined CV_ICC || defined __GNUC__ -# if CV_VFP +# if defined ARM_ROUND_FLT ARM_ROUND_FLT(value); # else return (int)lrintf(value); @@ -237,18 +223,8 @@ CV_INLINE int cvRound( int value ) /** @overload */ CV_INLINE int cvFloor( float value ) { -#if (defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__ && !defined __APPLE__)) && !defined(__CUDACC__) - __m128 t = _mm_set_ss( value ); - int i = _mm_cvtss_si32(t); - return i - _mm_movemask_ps(_mm_cmplt_ss(t, _mm_cvtsi32_ss(t,i))); -#elif defined __GNUC__ int i = (int)value; return i - (i > value); -#else - int i = cvRound(value); - float diff = (float)(value - i); - return i - (diff < 0); -#endif } /** @overload */ @@ -260,18 +236,8 @@ CV_INLINE int cvFloor( int value ) /** @overload */ CV_INLINE int cvCeil( float value ) { -#if (defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__&& !defined __APPLE__)) && !defined(__CUDACC__) - __m128 t = _mm_set_ss( value ); - int i = _mm_cvtss_si32(t); - return i + _mm_movemask_ps(_mm_cmplt_ss(_mm_cvtsi32_ss(t,i), t)); -#elif defined __GNUC__ int i = (int)value; return i + (i < value); -#else - int i = cvRound(value); - float diff = (float)(i - value); - return i + (diff < 0); -#endif } /** @overload */ diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index 3c8f39d74b..a9838382f0 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -237,24 +237,81 @@ void Exception::formatMessage() msg = format("%s:%d: error: (%d) %s\n", file.c_str(), line, code, err.c_str()); } +static const char* g_hwFeatureNames[CV_HARDWARE_MAX_FEATURE] = { NULL }; + +static const char* getHWFeatureName(int id) +{ + return (id < CV_HARDWARE_MAX_FEATURE) ? g_hwFeatureNames[id] : NULL; +} +static const char* getHWFeatureNameSafe(int id) +{ + const char* name = getHWFeatureName(id); + return name ? name : "Unknown feature"; +} + struct HWFeatures { enum { MAX_FEATURE = CV_HARDWARE_MAX_FEATURE }; - HWFeatures(void) + HWFeatures(bool run_initialize = false) { - memset( have, 0, sizeof(have) ); - x86_family = 0; + memset( have, 0, sizeof(have[0]) * MAX_FEATURE ); + if (run_initialize) + initialize(); } - static HWFeatures initialize(void) + static void initializeNames() { - HWFeatures f; + for (int i = 0; i < CV_HARDWARE_MAX_FEATURE; i++) + { + g_hwFeatureNames[i] = 0; + } + g_hwFeatureNames[CPU_MMX] = "MMX"; + g_hwFeatureNames[CPU_SSE] = "SSE"; + g_hwFeatureNames[CPU_SSE2] = "SSE2"; + g_hwFeatureNames[CPU_SSE3] = "SSE3"; + g_hwFeatureNames[CPU_SSSE3] = "SSSE3"; + g_hwFeatureNames[CPU_SSE4_1] = "SSE4.1"; + g_hwFeatureNames[CPU_SSE4_2] = "SSE4.2"; + g_hwFeatureNames[CPU_POPCNT] = "POPCNT"; + g_hwFeatureNames[CPU_FP16] = "FP16"; + g_hwFeatureNames[CPU_AVX] = "AVX"; + g_hwFeatureNames[CPU_AVX2] = "AVX2"; + g_hwFeatureNames[CPU_FMA3] = "FMA3"; + + g_hwFeatureNames[CPU_AVX_512F] = "AVX512F"; + g_hwFeatureNames[CPU_AVX_512BW] = "AVX512BW"; + g_hwFeatureNames[CPU_AVX_512CD] = "AVX512CD"; + g_hwFeatureNames[CPU_AVX_512DQ] = "AVX512DQ"; + g_hwFeatureNames[CPU_AVX_512ER] = "AVX512ER"; + g_hwFeatureNames[CPU_AVX_512IFMA512] = "AVX512IFMA"; + g_hwFeatureNames[CPU_AVX_512PF] = "AVX512PF"; + g_hwFeatureNames[CPU_AVX_512VBMI] = "AVX512VBMI"; + g_hwFeatureNames[CPU_AVX_512VL] = "AVX512VL"; + + g_hwFeatureNames[CPU_NEON] = "NEON"; + } + + void initialize(void) + { +#ifndef WINRT + if (getenv("OPENCV_DUMP_CONFIG")) + { + fprintf(stderr, "\nOpenCV build configuration is:\n%s\n", + cv::getBuildInformation().c_str()); + } +#endif + + initializeNames(); + int cpuid_data[4] = { 0, 0, 0, 0 }; + int cpuid_data_ex[4] = { 0, 0, 0, 0 }; #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64) + #define OPENCV_HAVE_X86_CPUID 1 __cpuid(cpuid_data, 1); #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) + #define OPENCV_HAVE_X86_CPUID 1 #ifdef __x86_64__ asm __volatile__ ( @@ -278,33 +335,36 @@ struct HWFeatures #endif #endif - f.x86_family = (cpuid_data[0] >> 8) & 15; - if( f.x86_family >= 6 ) + #ifdef OPENCV_HAVE_X86_CPUID + int x86_family = (cpuid_data[0] >> 8) & 15; + if( x86_family >= 6 ) { - f.have[CV_CPU_MMX] = (cpuid_data[3] & (1 << 23)) != 0; - f.have[CV_CPU_SSE] = (cpuid_data[3] & (1<<25)) != 0; - f.have[CV_CPU_SSE2] = (cpuid_data[3] & (1<<26)) != 0; - f.have[CV_CPU_SSE3] = (cpuid_data[2] & (1<<0)) != 0; - f.have[CV_CPU_SSSE3] = (cpuid_data[2] & (1<<9)) != 0; - f.have[CV_CPU_FMA3] = (cpuid_data[2] & (1<<12)) != 0; - f.have[CV_CPU_SSE4_1] = (cpuid_data[2] & (1<<19)) != 0; - f.have[CV_CPU_SSE4_2] = (cpuid_data[2] & (1<<20)) != 0; - f.have[CV_CPU_POPCNT] = (cpuid_data[2] & (1<<23)) != 0; - f.have[CV_CPU_AVX] = (((cpuid_data[2] & (1<<28)) != 0)&&((cpuid_data[2] & (1<<27)) != 0));//OS uses XSAVE_XRSTORE and CPU support AVX - f.have[CV_CPU_FP16] = (cpuid_data[2] & (1<<29)) != 0; + have[CV_CPU_MMX] = (cpuid_data[3] & (1<<23)) != 0; + have[CV_CPU_SSE] = (cpuid_data[3] & (1<<25)) != 0; + have[CV_CPU_SSE2] = (cpuid_data[3] & (1<<26)) != 0; + have[CV_CPU_SSE3] = (cpuid_data[2] & (1<<0)) != 0; + have[CV_CPU_SSSE3] = (cpuid_data[2] & (1<<9)) != 0; + have[CV_CPU_FMA3] = (cpuid_data[2] & (1<<12)) != 0; + have[CV_CPU_SSE4_1] = (cpuid_data[2] & (1<<19)) != 0; + have[CV_CPU_SSE4_2] = (cpuid_data[2] & (1<<20)) != 0; + have[CV_CPU_POPCNT] = (cpuid_data[2] & (1<<23)) != 0; + have[CV_CPU_AVX] = (cpuid_data[2] & (1<<28)) != 0; + have[CV_CPU_FP16] = (cpuid_data[2] & (1<<29)) != 0; // make the second call to the cpuid command in order to get // information about extended features like AVX2 #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64) - __cpuidex(cpuid_data, 7, 0); + #define OPENCV_HAVE_X86_CPUID_EX 1 + __cpuidex(cpuid_data_ex, 7, 0); #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) + #define OPENCV_HAVE_X86_CPUID_EX 1 #ifdef __x86_64__ asm __volatile__ ( "movl $7, %%eax\n\t" "movl $0, %%ecx\n\t" "cpuid\n\t" - :[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3]) + :[eax]"=a"(cpuid_data_ex[0]),[ebx]"=b"(cpuid_data_ex[1]),[ecx]"=c"(cpuid_data_ex[2]),[edx]"=d"(cpuid_data_ex[3]) : : "cc" ); @@ -317,29 +377,76 @@ struct HWFeatures "cpuid\n\t" "movl %%ebx, %0\n\t" "popl %%ebx\n\t" - : "=r"(cpuid_data[1]), "=c"(cpuid_data[2]) + : "=r"(cpuid_data_ex[1]), "=c"(cpuid_data_ex[2]) : : "cc" ); #endif #endif - f.have[CV_CPU_AVX2] = (cpuid_data[1] & (1<<5)) != 0; - f.have[CV_CPU_AVX_512F] = (cpuid_data[1] & (1<<16)) != 0; - f.have[CV_CPU_AVX_512DQ] = (cpuid_data[1] & (1<<17)) != 0; - f.have[CV_CPU_AVX_512IFMA512] = (cpuid_data[1] & (1<<21)) != 0; - f.have[CV_CPU_AVX_512PF] = (cpuid_data[1] & (1<<26)) != 0; - f.have[CV_CPU_AVX_512ER] = (cpuid_data[1] & (1<<27)) != 0; - f.have[CV_CPU_AVX_512CD] = (cpuid_data[1] & (1<<28)) != 0; - f.have[CV_CPU_AVX_512BW] = (cpuid_data[1] & (1<<30)) != 0; - f.have[CV_CPU_AVX_512VL] = (cpuid_data[1] & (1<<31)) != 0; - f.have[CV_CPU_AVX_512VBMI] = (cpuid_data[2] & (1<<1)) != 0; + #ifdef OPENCV_HAVE_X86_CPUID_EX + have[CV_CPU_AVX2] = (cpuid_data_ex[1] & (1<<5)) != 0; + + have[CV_CPU_AVX_512F] = (cpuid_data_ex[1] & (1<<16)) != 0; + have[CV_CPU_AVX_512DQ] = (cpuid_data_ex[1] & (1<<17)) != 0; + have[CV_CPU_AVX_512IFMA512] = (cpuid_data_ex[1] & (1<<21)) != 0; + have[CV_CPU_AVX_512PF] = (cpuid_data_ex[1] & (1<<26)) != 0; + have[CV_CPU_AVX_512ER] = (cpuid_data_ex[1] & (1<<27)) != 0; + have[CV_CPU_AVX_512CD] = (cpuid_data_ex[1] & (1<<28)) != 0; + have[CV_CPU_AVX_512BW] = (cpuid_data_ex[1] & (1<<30)) != 0; + have[CV_CPU_AVX_512VL] = (cpuid_data_ex[1] & (1<<31)) != 0; + have[CV_CPU_AVX_512VBMI] = (cpuid_data_ex[2] & (1<<1)) != 0; + #else + CV_UNUSED(cpuid_data_ex); + #endif + + bool have_AVX_OS_support = true; + bool have_AVX512_OS_support = true; + if (!(cpuid_data[2] & (1<<27))) + have_AVX_OS_support = false; // OS uses XSAVE_XRSTORE and CPU support AVX + else + { + int xcr0 = 0; + #ifdef _XCR_XFEATURE_ENABLED_MASK // requires immintrin.h + xcr0 = (int)_xgetbv(_XCR_XFEATURE_ENABLED_MASK); + #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) + __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" ); + #endif + if ((xcr0 & 0x6) != 0x6) + have_AVX_OS_support = false; // YMM registers + if ((xcr0 & 0xe6) != 0xe6) + have_AVX512_OS_support = false; // ZMM registers + } + + if (!have_AVX_OS_support) + { + have[CV_CPU_AVX] = false; + have[CV_CPU_FP16] = false; + have[CV_CPU_AVX2] = false; + have[CV_CPU_FMA3] = false; + } + if (!have_AVX_OS_support || !have_AVX512_OS_support) + { + have[CV_CPU_AVX_512F] = false; + have[CV_CPU_AVX_512BW] = false; + have[CV_CPU_AVX_512CD] = false; + have[CV_CPU_AVX_512DQ] = false; + have[CV_CPU_AVX_512ER] = false; + have[CV_CPU_AVX_512IFMA512] = false; + have[CV_CPU_AVX_512PF] = false; + have[CV_CPU_AVX_512VBMI] = false; + have[CV_CPU_AVX_512VL] = false; + } } + #else + CV_UNUSED(cpuid_data); + CV_UNUSED(cpuid_data_ex); + #endif // OPENCV_HAVE_X86_CPUID #if defined ANDROID || defined __linux__ #ifdef __aarch64__ - f.have[CV_CPU_NEON] = true; - f.have[CV_CPU_FP16] = true; + have[CV_CPU_NEON] = true; + have[CV_CPU_FP16] = true; #elif defined __arm__ int cpufile = open("/proc/self/auxv", O_RDONLY); @@ -352,8 +459,8 @@ struct HWFeatures { if (auxv.a_type == AT_HWCAP) { - f.have[CV_CPU_NEON] = (auxv.a_un.a_val & 4096) != 0; - f.have[CV_CPU_FP16] = (auxv.a_un.a_val & 2) != 0; + have[CV_CPU_NEON] = (auxv.a_un.a_val & 4096) != 0; + have[CV_CPU_FP16] = (auxv.a_un.a_val & 2) != 0; break; } } @@ -363,21 +470,133 @@ struct HWFeatures #endif #elif (defined __clang__ || defined __APPLE__) #if (defined __ARM_NEON__ || (defined __ARM_NEON && defined __aarch64__)) - f.have[CV_CPU_NEON] = true; + have[CV_CPU_NEON] = true; #endif #if (defined __ARM_FP && (((__ARM_FP & 0x2) != 0) && defined __ARM_NEON__)) - f.have[CV_CPU_FP16] = true; + have[CV_CPU_FP16] = true; #endif #endif - return f; + int baseline_features[] = { CV_CPU_BASELINE_FEATURES }; + if (!checkFeatures(baseline_features, sizeof(baseline_features) / sizeof(baseline_features[0]))) + { + fprintf(stderr, "\n" + "******************************************************************\n" + "* FATAL ERROR: *\n" + "* This OpenCV build doesn't support current CPU/HW configuration *\n" + "* *\n" + "* Use OPENCV_DUMP_CONFIG=1 environment variable for details *\n" + "******************************************************************\n"); + fprintf(stderr, "\nRequired baseline features:\n"); + checkFeatures(baseline_features, sizeof(baseline_features) / sizeof(baseline_features[0]), true); + CV_ErrorNoReturn(cv::Error::StsAssert, "Missing support for required CPU baseline features. Check OpenCV build configuration and required CPU/HW setup."); + } + + readSettings(baseline_features, sizeof(baseline_features) / sizeof(baseline_features[0])); + } + + bool checkFeatures(const int* features, int count, bool dump = false) + { + bool result = true; + for (int i = 0; i < count; i++) + { + int feature = features[i]; + if (feature) + { + if (have[feature]) + { + if (dump) fprintf(stderr, "%s - OK\n", getHWFeatureNameSafe(feature)); + } + else + { + result = false; + if (dump) fprintf(stderr, "%s - NOT AVAILABLE\n", getHWFeatureNameSafe(feature)); + } + } + } + return result; + } + + static inline bool isSymbolSeparator(char c) + { + return c == ',' || c == ';' || c == '-'; + } + + void readSettings(const int* baseline_features, int baseline_count) + { + bool dump = true; + const char* disabled_features = +#ifndef WINRT + getenv("OPENCV_CPU_DISABLE"); +#else + NULL; +#endif + if (disabled_features && disabled_features[0] != 0) + { + const char* start = disabled_features; + for (;;) + { + while (start[0] != 0 && isSymbolSeparator(start[0])) + { + start++; + } + if (start[0] == 0) + break; + const char* end = start; + while (end[0] != 0 && !isSymbolSeparator(end[0])) + { + end++; + } + if (end == start) + continue; + cv::String feature(start, end); + start = end; + + CV_Assert(feature.size() > 0); + + bool found = false; + for (int i = 0; i < CV_HARDWARE_MAX_FEATURE; i++) + { + if (!g_hwFeatureNames[i]) continue; + size_t len = strlen(g_hwFeatureNames[i]); + if (len != feature.size()) continue; + if (feature.compare(g_hwFeatureNames[i]) == 0) + { + bool isBaseline = false; + for (int k = 0; k < baseline_count; k++) + { + if (baseline_features[k] == i) + { + isBaseline = true; + break; + } + } + if (isBaseline) + { + if (dump) fprintf(stderr, "OPENCV: Trying to disable baseline CPU feature: '%s'. This has very limited effect, because code optimizations for this feature are executed unconditionally in the most cases.\n", getHWFeatureNameSafe(i)); + } + if (!have[i]) + { + if (dump) fprintf(stderr, "OPENCV: Trying to disable unavailable CPU feature on the current platform: '%s'.\n", getHWFeatureNameSafe(i)); + } + have[i] = false; + + found = true; + break; + } + } + if (!found) + { + if (dump) fprintf(stderr, "OPENCV: Trying to disable unknown CPU feature: '%s'.\n", feature.c_str()); + } + } + } } - int x86_family; bool have[MAX_FEATURE+1]; }; -static HWFeatures featuresEnabled = HWFeatures::initialize(), featuresDisabled = HWFeatures(); +static HWFeatures featuresEnabled(true), featuresDisabled = HWFeatures(false); static HWFeatures* currentFeatures = &featuresEnabled; bool checkHardwareSupport(int feature) diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index b0363c4482..60df4ed7b9 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -65,7 +65,7 @@ elseif(HAVE_QT) list(APPEND HIGHGUI_LIBRARIES ${QT_LIBRARIES}) list(APPEND highgui_srcs ${CMAKE_CURRENT_LIST_DIR}/src/window_QT.cpp ${_MOC_OUTFILES} ${_RCC_OUTFILES}) - ocv_check_flag_support(CXX -Wno-missing-declarations _have_flag) + ocv_check_flag_support(CXX -Wno-missing-declarations _have_flag "") if(${_have_flag}) set_source_files_properties(${_RCC_OUTFILES} PROPERTIES COMPILE_FLAGS -Wno-missing-declarations) endif() diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index 0fa520228e..dcf2e44b5e 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -1649,7 +1649,7 @@ struct VResizeLanczos4 { CastOp castOp; VecOp vecOp; - int k, x = vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width); + int x = vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width); #if CV_ENABLE_UNROLLED for( ; x <= width - 4; x += 4 ) { @@ -1657,7 +1657,7 @@ struct VResizeLanczos4 const WT* S = src[0]; WT s0 = S[x]*b, s1 = S[x+1]*b, s2 = S[x+2]*b, s3 = S[x+3]*b; - for( k = 1; k < 8; k++ ) + for( int k = 1; k < 8; k++ ) { b = beta[k]; S = src[k]; s0 += S[x]*b; s1 += S[x+1]*b; diff --git a/modules/objdetect/src/haar.cpp b/modules/objdetect/src/haar.cpp index 51843fa488..bb37ee91e0 100644 --- a/modules/objdetect/src/haar.cpp +++ b/modules/objdetect/src/haar.cpp @@ -824,10 +824,7 @@ cvRunHaarClassifierCascadeSum( const CvHaarClassifierCascade* _cascade, CvPoint pt, double& stage_sum, int start_stage ) { #ifdef CV_HAAR_USE_AVX - bool haveAVX = false; - if(cv::checkHardwareSupport(CV_CPU_AVX)) - if(__xgetbv()&0x6)// Check if the OS will save the YMM registers - haveAVX = true; + bool haveAVX = cv::checkHardwareSupport(CV_CPU_AVX); #else # ifdef CV_HAAR_USE_SSE bool haveSSE2 = cv::checkHardwareSupport(CV_CPU_SSE2); From 0aadab0941a4fb3d6560ed19cda3b34aa12c0040 Mon Sep 17 00:00:00 2001 From: ziggy90127 Date: Sat, 25 Feb 2017 15:48:09 -0700 Subject: [PATCH 005/144] Add AVMediaTypeMuxed capture devices to AVFoundation, just as QTKit does. --- modules/videoio/src/cap_avfoundation_mac.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/videoio/src/cap_avfoundation_mac.mm b/modules/videoio/src/cap_avfoundation_mac.mm index ce6e3d074c..e7c2e53cac 100644 --- a/modules/videoio/src/cap_avfoundation_mac.mm +++ b/modules/videoio/src/cap_avfoundation_mac.mm @@ -305,7 +305,8 @@ int CvCaptureCAM::startCaptureDevice(int cameraNum) { NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init]; // get capture device - NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]; + NSArray *devices = [[AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo] + arrayByAddingObjectsFromArray:[AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed]]; if ( devices.count == 0 ) { fprintf(stderr, "OpenCV: AVFoundation didn't find any attached Video Input Devices!\n"); From d69b3e385ee8ef93bf8d97214b2d78a87462a2ad Mon Sep 17 00:00:00 2001 From: ziggy90127 Date: Sun, 26 Feb 2017 01:36:26 -0700 Subject: [PATCH 006/144] Add AVMediaTypeMuxed capture devices to AVFoundation, just as QTKit does. --- modules/videoio/src/cap_avfoundation.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/videoio/src/cap_avfoundation.mm b/modules/videoio/src/cap_avfoundation.mm index 867fcfba73..0866782eb9 100644 --- a/modules/videoio/src/cap_avfoundation.mm +++ b/modules/videoio/src/cap_avfoundation.mm @@ -317,7 +317,8 @@ int CvCaptureCAM::startCaptureDevice(int cameraNum) { capture = [[CaptureDelegate alloc] init]; AVCaptureDevice *device; - NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + NSArray* devices = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] + arrayByAddingObjectsFromArray:[AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed]]; if ([devices count] == 0) { std::cout << "AV Foundation didn't find any attached Video Input Devices!" << std::endl; [localpool drain]; From 0a1767a6b5d6755871245c66e6a9091e3adde1fb Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Wed, 8 Mar 2017 19:27:43 -0800 Subject: [PATCH 007/144] Update bgfg_gaussmix2.cpp to avoid divide by zero cases. --- modules/video/src/bgfg_gaussmix2.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/video/src/bgfg_gaussmix2.cpp b/modules/video/src/bgfg_gaussmix2.cpp index ebe449825c..3ee57086a9 100644 --- a/modules/video/src/bgfg_gaussmix2.cpp +++ b/modules/video/src/bgfg_gaussmix2.cpp @@ -693,11 +693,16 @@ public: //go through all modes ////// - //renormalize weights - totalWeight = 1.f/totalWeight; + // Renormalize weights. In the special case that the pixel does + // not agree with any modes, set weights to zero (a new mode will be added below). + float invWeight = 0.f; + if (fabs(totalWeight) > 1e-12f) { + invWeight = 1.f/totalWeight; + } + for( int mode = 0; mode < nmodes; mode++ ) { - gmm[mode].weight *= totalWeight; + gmm[mode].weight *= invWeight; } //make new mode if needed and exit @@ -900,7 +905,10 @@ void BackgroundSubtractorMOG2Impl::getBackgroundImage_intern(OutputArray backgro if(totalWeight > backgroundRatio) break; } - float invWeight = 1.f/totalWeight; + float invWeight = 0.f; + if (fabs(totalWeight) > 1e-12f) { + invWeight = 1.f/totalWeight; + } meanBackground.at >(row, col) = Vec(meanVal * invWeight); meanVal = 0.f; From 3c5d87cbae3cead4b9e73f2d6de5715d0a8648d1 Mon Sep 17 00:00:00 2001 From: "KUANG, Fangjun" Date: Sat, 11 Mar 2017 10:55:50 +0100 Subject: [PATCH 008/144] Add more information to the error code. --- modules/core/include/opencv2/core/base.hpp | 8 ++++---- modules/core/include/opencv2/core/types_c.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index b319df6f38..91720cc88a 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -79,18 +79,18 @@ enum Code { BadImageSize= -10, //!< image size is invalid BadOffset= -11, //!< offset is invalid BadDataPtr= -12, //!< - BadStep= -13, //!< + BadStep= -13, //!< image step is wrong BadModelOrChSeq= -14, //!< - BadNumChannels= -15, //!< + BadNumChannels= -15, //!< bad number of channels BadNumChannel1U= -16, //!< - BadDepth= -17, //!< + BadDepth= -17, //!< input image depth is not supported by function BadAlphaChannel= -18, //!< BadOrder= -19, //!< BadOrigin= -20, //!< BadAlign= -21, //!< BadCallBack= -22, //!< BadTileSize= -23, //!< - BadCOI= -24, //!< + BadCOI= -24, //!< input COI is not supported BadROISize= -25, //!< MaskIsTiled= -26, //!< StsNullPtr= -27, //!< null pointer diff --git a/modules/core/include/opencv2/core/types_c.h b/modules/core/include/opencv2/core/types_c.h index f82a59e812..b1eb75a3bb 100644 --- a/modules/core/include/opencv2/core/types_c.h +++ b/modules/core/include/opencv2/core/types_c.h @@ -130,18 +130,18 @@ enum { CV_BadImageSize= -10, /**< image size is invalid */ CV_BadOffset= -11, /**< offset is invalid */ CV_BadDataPtr= -12, /**/ - CV_BadStep= -13, /**/ + CV_BadStep= -13, /**< image step is wrong */ CV_BadModelOrChSeq= -14, /**/ - CV_BadNumChannels= -15, /**/ + CV_BadNumChannels= -15, /**< bad number of channels */ CV_BadNumChannel1U= -16, /**/ - CV_BadDepth= -17, /**/ + CV_BadDepth= -17, /**< input image depth is not supported by function */ CV_BadAlphaChannel= -18, /**/ CV_BadOrder= -19, /**/ CV_BadOrigin= -20, /**/ CV_BadAlign= -21, /**/ CV_BadCallBack= -22, /**/ CV_BadTileSize= -23, /**/ - CV_BadCOI= -24, /**/ + CV_BadCOI= -24, /**< input COI is not supported */ CV_BadROISize= -25, /**/ CV_MaskIsTiled= -26, /**/ CV_StsNullPtr= -27, /**< null pointer */ From be7d4608fb31c616a305402c354b4d18c9620e89 Mon Sep 17 00:00:00 2001 From: "KUANG, Fangjun" Date: Sun, 12 Mar 2017 16:13:00 +0100 Subject: [PATCH 009/144] Add more comments to the members of CoreTLSData related to OpenCL. --- modules/core/src/precomp.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/src/precomp.hpp b/modules/core/src/precomp.hpp index 69446beb2a..6a63e84ef6 100644 --- a/modules/core/src/precomp.hpp +++ b/modules/core/src/precomp.hpp @@ -272,8 +272,8 @@ struct CoreTLSData RNG rng; //#ifdef HAVE_OPENCL - int device; - ocl::Queue oclQueue; + int device; // device index of an array of devices in a context, see also Device::getDefault + ocl::Queue oclQueue; // the queue used for running a kernel, see also getQueue, Kernel::run int useOpenCL; // 1 - use, 0 - do not use, -1 - auto/not initialized //#endif int useIPP; // 1 - use, 0 - do not use, -1 - auto/not initialized From 7295dd7dece3e4deb255962817ec141b98c62353 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Tue, 14 Mar 2017 16:57:50 -0700 Subject: [PATCH 010/144] Update bgfg_gaussmix2.cpp 1e-12 -> DBL_EPSILON --- modules/video/src/bgfg_gaussmix2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/video/src/bgfg_gaussmix2.cpp b/modules/video/src/bgfg_gaussmix2.cpp index 3ee57086a9..ad81c55eae 100644 --- a/modules/video/src/bgfg_gaussmix2.cpp +++ b/modules/video/src/bgfg_gaussmix2.cpp @@ -696,7 +696,7 @@ public: // Renormalize weights. In the special case that the pixel does // not agree with any modes, set weights to zero (a new mode will be added below). float invWeight = 0.f; - if (fabs(totalWeight) > 1e-12f) { + if (fabs(totalWeight) > DBL_EPSILON) { invWeight = 1.f/totalWeight; } @@ -906,7 +906,7 @@ void BackgroundSubtractorMOG2Impl::getBackgroundImage_intern(OutputArray backgro break; } float invWeight = 0.f; - if (fabs(totalWeight) > 1e-12f) { + if (fabs(totalWeight) > DBL_EPSILON) { invWeight = 1.f/totalWeight; } From a8763c1fec53df63afb67e5e7e454e5768e16e41 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Wed, 15 Mar 2017 17:03:36 +0900 Subject: [PATCH 011/144] Optimize exp32f with AVX2 --- modules/core/src/mathfuncs_core.cpp | 91 ++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/modules/core/src/mathfuncs_core.cpp b/modules/core/src/mathfuncs_core.cpp index e0cc5b58dd..5a1e2fa75c 100644 --- a/modules/core/src/mathfuncs_core.cpp +++ b/modules/core/src/mathfuncs_core.cpp @@ -551,7 +551,96 @@ void exp32f( const float *_x, float *y, int n ) const Cv32suf* x = (const Cv32suf*)_x; Cv32suf buf[4]; -#if CV_SSE2 +#if CV_AVX2 + if( n >= 8 ) + { + static const __m256d prescale4 = _mm256_set1_pd(exp_prescale); + static const __m256 postscale8 = _mm256_set1_ps((float)exp_postscale); + static const __m128 maxval4 = _mm_set1_ps((float)(exp_max_val/exp_prescale)); + static const __m128 minval4 = _mm_set1_ps((float)(-exp_max_val/exp_prescale)); + + static const __m256 mA1 = _mm256_set1_ps(A1); + static const __m256 mA2 = _mm256_set1_ps(A2); + static const __m256 mA3 = _mm256_set1_ps(A3); + static const __m256 mA4 = _mm256_set1_ps(A4); + bool y_aligned = (size_t)(void*)y % 32 == 0; + + ushort CV_DECL_ALIGNED(32) tab_idx[16]; + + for( ; i <= n - 8; i += 8 ) + { + __m256 xf; + __m128i xi0, xi1; + + __m256d xd0 = _mm256_cvtps_pd(_mm_min_ps(_mm_max_ps(_mm_loadu_ps(&x[i].f), minval4), maxval4)); + __m256d xd1 = _mm256_cvtps_pd(_mm_min_ps(_mm_max_ps(_mm_loadu_ps(&x[i+4].f), minval4), maxval4)); + + xd0 = _mm256_mul_pd(xd0, prescale4); + xd1 = _mm256_mul_pd(xd1, prescale4); + + xi0 = _mm256_cvtpd_epi32(xd0); + xi1 = _mm256_cvtpd_epi32(xd1); + + xd0 = _mm256_sub_pd(xd0, _mm256_cvtepi32_pd(xi0)); + xd1 = _mm256_sub_pd(xd1, _mm256_cvtepi32_pd(xi1)); + + // gcc does not support _mm256_set_m128 + //xf = _mm256_set_m128(_mm256_cvtpd_ps(xd1), _mm256_cvtpd_ps(xd0)); + xf = _mm256_insertf128_ps(xf, _mm256_cvtpd_ps(xd0), 0); + xf = _mm256_insertf128_ps(xf, _mm256_cvtpd_ps(xd1), 1); + + xf = _mm256_mul_ps(xf, postscale8); + + xi0 = _mm_packs_epi32(xi0, xi1); + + _mm_store_si128((__m128i*)tab_idx, _mm_and_si128(xi0, _mm_set1_epi16(EXPTAB_MASK))); + + xi0 = _mm_add_epi16(_mm_srai_epi16(xi0, EXPTAB_SCALE), _mm_set1_epi16(127)); + xi0 = _mm_max_epi16(xi0, _mm_setzero_si128()); + xi0 = _mm_min_epi16(xi0, _mm_set1_epi16(255)); + xi1 = _mm_unpackhi_epi16(xi0, _mm_setzero_si128()); + xi0 = _mm_unpacklo_epi16(xi0, _mm_setzero_si128()); + + __m256d yd0 = _mm256_set_pd(expTab[tab_idx[3]], expTab[tab_idx[2]], expTab[tab_idx[1]], expTab[tab_idx[0]]); + __m256d yd1 = _mm256_set_pd(expTab[tab_idx[7]], expTab[tab_idx[6]], expTab[tab_idx[5]], expTab[tab_idx[4]]); + + // gcc does not support _mm256_set_m128 + //__m256 yf = _mm256_set_m128(_mm256_cvtpd_ps(yd1), _mm256_cvtpd_ps(yd0)); + __m256 yf; + yf = _mm256_insertf128_ps(yf, _mm256_cvtpd_ps(yd0), 0); + yf = _mm256_insertf128_ps(yf, _mm256_cvtpd_ps(yd1), 1); + + //_mm256_set_m128i(xi1, xi0) + __m256i temp; + temp = _mm256_inserti128_si256(temp, xi0, 0); + temp = _mm256_inserti128_si256(temp, xi1, 1); + + yf = _mm256_mul_ps(yf, _mm256_castsi256_ps(_mm256_slli_epi32(temp, 23))); + + __m256 zf = _mm256_add_ps(xf, mA1); + +#if CV_FMA3 + zf = _mm256_fmadd_ps(zf, xf, mA2); + zf = _mm256_fmadd_ps(zf, xf, mA3); + zf = _mm256_fmadd_ps(zf, xf, mA4); +#else + zf = _mm256_add_ps(_mm256_mul_ps(zf, xf), mA2); + zf = _mm256_add_ps(_mm256_mul_ps(zf, xf), mA3); + zf = _mm256_add_ps(_mm256_mul_ps(zf, xf), mA4); +#endif + zf = _mm256_mul_ps(zf, yf); + + if( y_aligned ) + { + _mm256_store_ps(y + i, zf); + } + else + { + _mm256_storeu_ps(y + i, zf); + } + } + } +#elif CV_SSE2 if( n >= 8 ) { static const __m128d prescale2 = _mm_set1_pd(exp_prescale); From 27cf6e549e6051533778dd39b4b050a6d08d735b Mon Sep 17 00:00:00 2001 From: Naba Kumar Date: Wed, 15 Mar 2017 11:34:00 +0200 Subject: [PATCH 012/144] Merge pull request #8367 from khnaba:cuda-calchist-with-mask Implement cv::cuda::calcHist with mask support (#8367) * Implement cuda::calcHist with mask * Fix documentation build warning * Have their own step sizes for src and mask. Fix review comment. --- .../include/opencv2/cudaimgproc.hpp | 9 +++ modules/cudaimgproc/src/cuda/hist.cu | 66 +++++++++++++++++++ modules/cudaimgproc/src/histogram.cpp | 14 +++- modules/cudaimgproc/test/test_histogram.cpp | 43 ++++++++++++ 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp b/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp index dc876b744b..25a324a00f 100644 --- a/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp +++ b/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp @@ -201,6 +201,15 @@ CV_EXPORTS void alphaComp(InputArray img1, InputArray img2, OutputArray dst, int */ CV_EXPORTS void calcHist(InputArray src, OutputArray hist, Stream& stream = Stream::Null()); +/** @brief Calculates histogram for one channel 8-bit image confined in given mask. + +@param src Source image with CV_8UC1 type. +@param hist Destination histogram with one row, 256 columns, and the CV_32SC1 type. +@param mask A mask image same size as src and of type CV_8UC1. +@param stream Stream for the asynchronous version. + */ +CV_EXPORTS void calcHist(InputArray src, InputArray mask, OutputArray hist, Stream& stream = Stream::Null()); + /** @brief Equalizes the histogram of a grayscale image. @param src Source image with CV_8UC1 type. diff --git a/modules/cudaimgproc/src/cuda/hist.cu b/modules/cudaimgproc/src/cuda/hist.cu index ba9290c190..be13091f12 100644 --- a/modules/cudaimgproc/src/cuda/hist.cu +++ b/modules/cudaimgproc/src/cuda/hist.cu @@ -105,6 +105,72 @@ namespace hist if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } + + __global__ void histogram256Kernel(const uchar* src, int cols, int rows, size_t srcStep, const uchar* mask, size_t maskStep, int* hist) + { + __shared__ int shist[256]; + + const int y = blockIdx.x * blockDim.y + threadIdx.y; + const int tid = threadIdx.y * blockDim.x + threadIdx.x; + + shist[tid] = 0; + __syncthreads(); + + if (y < rows) + { + const unsigned int* rowPtr = (const unsigned int*) (src + y * srcStep); + const unsigned int* maskRowPtr = (const unsigned int*) (mask + y * maskStep); + + const int cols_4 = cols / 4; + for (int x = threadIdx.x; x < cols_4; x += blockDim.x) + { + unsigned int data = rowPtr[x]; + unsigned int m = maskRowPtr[x]; + + if ((m >> 0) & 0xFFU) + Emulation::smem::atomicAdd(&shist[(data >> 0) & 0xFFU], 1); + + if ((m >> 8) & 0xFFU) + Emulation::smem::atomicAdd(&shist[(data >> 8) & 0xFFU], 1); + + if ((m >> 16) & 0xFFU) + Emulation::smem::atomicAdd(&shist[(data >> 16) & 0xFFU], 1); + + if ((m >> 24) & 0xFFU) + Emulation::smem::atomicAdd(&shist[(data >> 24) & 0xFFU], 1); + } + + if (cols % 4 != 0 && threadIdx.x == 0) + { + for (int x = cols_4 * 4; x < cols; ++x) + { + unsigned int data = ((const uchar*)rowPtr)[x]; + unsigned int m = ((const uchar*)maskRowPtr)[x]; + + if (m) + Emulation::smem::atomicAdd(&shist[data], 1); + } + } + } + + __syncthreads(); + + const int histVal = shist[tid]; + if (histVal > 0) + ::atomicAdd(hist + tid, histVal); + } + + void histogram256(PtrStepSzb src, PtrStepSzb mask, int* hist, cudaStream_t stream) + { + const dim3 block(32, 8); + const dim3 grid(divUp(src.rows, block.y)); + + histogram256Kernel<<>>(src.data, src.cols, src.rows, src.step, mask.data, mask.step, hist); + cudaSafeCall( cudaGetLastError() ); + + if (stream == 0) + cudaSafeCall( cudaDeviceSynchronize() ); + } } ///////////////////////////////////////////////////////////////////////// diff --git a/modules/cudaimgproc/src/histogram.cpp b/modules/cudaimgproc/src/histogram.cpp index 59aa83343a..fce5057590 100644 --- a/modules/cudaimgproc/src/histogram.cpp +++ b/modules/cudaimgproc/src/histogram.cpp @@ -69,20 +69,32 @@ void cv::cuda::histRange(InputArray, GpuMat*, const GpuMat*, Stream&) { throw_no namespace hist { void histogram256(PtrStepSzb src, int* hist, cudaStream_t stream); + void histogram256(PtrStepSzb src, PtrStepSzb mask, int* hist, cudaStream_t stream); } void cv::cuda::calcHist(InputArray _src, OutputArray _hist, Stream& stream) +{ + calcHist(_src, cv::cuda::GpuMat(), _hist, stream); +} + +void cv::cuda::calcHist(InputArray _src, InputArray _mask, OutputArray _hist, Stream& stream) { GpuMat src = _src.getGpuMat(); + GpuMat mask = _mask.getGpuMat(); CV_Assert( src.type() == CV_8UC1 ); + CV_Assert( mask.empty() || mask.type() == CV_8UC1 ); + CV_Assert( mask.empty() || mask.size() == src.size() ); _hist.create(1, 256, CV_32SC1); GpuMat hist = _hist.getGpuMat(); hist.setTo(Scalar::all(0), stream); - hist::histogram256(src, hist.ptr(), StreamAccessor::getStream(stream)); + if (mask.empty()) + hist::histogram256(src, hist.ptr(), StreamAccessor::getStream(stream)); + else + hist::histogram256(src, mask, hist.ptr(), StreamAccessor::getStream(stream)); } //////////////////////////////////////////////////////////////////////// diff --git a/modules/cudaimgproc/test/test_histogram.cpp b/modules/cudaimgproc/test/test_histogram.cpp index 3d3217375e..7fcde85206 100644 --- a/modules/cudaimgproc/test/test_histogram.cpp +++ b/modules/cudaimgproc/test/test_histogram.cpp @@ -136,6 +136,49 @@ INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, CalcHist, testing::Combine( ALL_DEVICES, DIFFERENT_SIZES)); +PARAM_TEST_CASE(CalcHistWithMask, cv::cuda::DeviceInfo, cv::Size) +{ + cv::cuda::DeviceInfo devInfo; + + cv::Size size; + + virtual void SetUp() + { + devInfo = GET_PARAM(0); + size = GET_PARAM(1); + + cv::cuda::setDevice(devInfo.deviceID()); + } +}; + +CUDA_TEST_P(CalcHistWithMask, Accuracy) +{ + cv::Mat src = randomMat(size, CV_8UC1); + cv::Mat mask = randomMat(size, CV_8UC1); + cv::Mat(mask, cv::Rect(0, 0, size.width / 2, size.height / 2)).setTo(0); + + cv::cuda::GpuMat hist; + cv::cuda::calcHist(loadMat(src), loadMat(mask), hist); + + cv::Mat hist_gold; + + const int hbins = 256; + const float hranges[] = {0.0f, 256.0f}; + const int histSize[] = {hbins}; + const float* ranges[] = {hranges}; + const int channels[] = {0}; + + cv::calcHist(&src, 1, channels, mask, hist_gold, 1, histSize, ranges); + hist_gold = hist_gold.reshape(1, 1); + hist_gold.convertTo(hist_gold, CV_32S); + + EXPECT_MAT_NEAR(hist_gold, hist, 0.0); +} + +INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, CalcHistWithMask, testing::Combine( + ALL_DEVICES, + DIFFERENT_SIZES)); + /////////////////////////////////////////////////////////////////////////////////////////////////////// // EqualizeHist From 246d3761cea1eb73e48449f636d9adb0fefc73aa Mon Sep 17 00:00:00 2001 From: Fangjun KUANG Date: Wed, 15 Mar 2017 12:12:59 +0100 Subject: [PATCH 013/144] Merge pull request #8383 from csukuangfj/patch-10 * Improve documentation. * Update imgproc.hpp --- modules/imgproc/include/opencv2/imgproc.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index aeeb1d9a74..5bba3a3891 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -4080,7 +4080,13 @@ CV_EXPORTS Ptr createGeneralizedHoughBallard(); //! Detects position, translation and rotation CV_EXPORTS Ptr createGeneralizedHoughGuil(); -//! Performs linear blending of two images +//! Performs linear blending of two images: +//! \f[ \texttt{dst}(i,j) = \texttt{weights1}(i,j)*\texttt{src1}(i,j) + \texttt{weights2}(i,j)*\texttt{src2}(i,j) \f] +//! @param src1 It has a type of CV_8UC(n) or CV_32FC(n), where n is a positive integer. +//! @param src2 It has the same type and size as src1. +//! @param weights1 It has a type of CV_32FC1 and the same size with src1. +//! @param weights2 It has a type of CV_32FC1 and the same size with src1. +//! @param dst It is created if it does not have the same size and type with src1. CV_EXPORTS void blendLinear(InputArray src1, InputArray src2, InputArray weights1, InputArray weights2, OutputArray dst); //! @addtogroup imgproc_colormap From 9333f82be0d958d756d98789ad49e1af42757270 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Mon, 13 Mar 2017 18:53:52 +0300 Subject: [PATCH 014/144] Reduce dependencies between modules --- modules/features2d/CMakeLists.txt | 2 +- modules/features2d/test/test_precomp.hpp | 1 - modules/highgui/CMakeLists.txt | 2 +- modules/highgui/src/precomp.hpp | 2 -- modules/java/pure_test/CMakeLists.txt | 4 +++- modules/objdetect/CMakeLists.txt | 2 +- modules/objdetect/src/precomp.hpp | 8 -------- modules/stitching/CMakeLists.txt | 2 +- modules/superres/CMakeLists.txt | 1 - 9 files changed, 7 insertions(+), 17 deletions(-) diff --git a/modules/features2d/CMakeLists.txt b/modules/features2d/CMakeLists.txt index bf7d66e433..caae24af04 100644 --- a/modules/features2d/CMakeLists.txt +++ b/modules/features2d/CMakeLists.txt @@ -1,2 +1,2 @@ set(the_description "2D Features Framework") -ocv_define_module(features2d opencv_imgproc opencv_ml opencv_flann OPTIONAL opencv_highgui WRAP java python) +ocv_define_module(features2d opencv_imgproc opencv_flann OPTIONAL opencv_highgui WRAP java python) diff --git a/modules/features2d/test/test_precomp.hpp b/modules/features2d/test/test_precomp.hpp index 893b29b69b..bce72f7296 100644 --- a/modules/features2d/test/test_precomp.hpp +++ b/modules/features2d/test/test_precomp.hpp @@ -13,7 +13,6 @@ #include "opencv2/imgproc.hpp" #include "opencv2/features2d.hpp" #include "opencv2/imgcodecs.hpp" -#include "opencv2/ml.hpp" #include #endif diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index b0363c4482..bba5b8c1da 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -1,5 +1,5 @@ set(the_description "High-level GUI and Media I/O") -ocv_add_module(highgui opencv_imgproc OPTIONAL opencv_imgcodecs opencv_videoio WRAP python) +ocv_add_module(highgui opencv_imgproc opencv_imgcodecs OPTIONAL opencv_videoio WRAP python) # ---------------------------------------------------------------------------- # CMake file for highgui. See root CMakeLists.txt diff --git a/modules/highgui/src/precomp.hpp b/modules/highgui/src/precomp.hpp index d9e7ad8b1c..40af37cd86 100644 --- a/modules/highgui/src/precomp.hpp +++ b/modules/highgui/src/precomp.hpp @@ -50,10 +50,8 @@ #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/highgui/highgui_c.h" -#ifdef HAVE_OPENCV_IMGCODECS #include "opencv2/imgcodecs.hpp" #include "opencv2/imgcodecs/imgcodecs_c.h" -#endif #include #include diff --git a/modules/java/pure_test/CMakeLists.txt b/modules/java/pure_test/CMakeLists.txt index 7d78414994..95b7e47512 100644 --- a/modules/java/pure_test/CMakeLists.txt +++ b/modules/java/pure_test/CMakeLists.txt @@ -1,4 +1,6 @@ -if(NOT ANT_EXECUTABLE) +if(NOT ANT_EXECUTABLE + OR NOT BUILD_opencv_imgcodecs + OR NOT BUILD_opencv_calib3d) return() endif() diff --git a/modules/objdetect/CMakeLists.txt b/modules/objdetect/CMakeLists.txt index d42e9e8f11..862d564cc7 100644 --- a/modules/objdetect/CMakeLists.txt +++ b/modules/objdetect/CMakeLists.txt @@ -1,2 +1,2 @@ set(the_description "Object Detection") -ocv_define_module(objdetect opencv_core opencv_imgproc opencv_ml OPTIONAL opencv_highgui WRAP java python) +ocv_define_module(objdetect opencv_core opencv_imgproc WRAP java python) diff --git a/modules/objdetect/src/precomp.hpp b/modules/objdetect/src/precomp.hpp index 97b976baf2..448d8b19b7 100644 --- a/modules/objdetect/src/precomp.hpp +++ b/modules/objdetect/src/precomp.hpp @@ -46,16 +46,8 @@ #include "opencv2/objdetect.hpp" #include "opencv2/imgproc.hpp" -#include "opencv2/ml.hpp" - #include "opencv2/core/utility.hpp" #include "opencv2/core/ocl.hpp" - -#include "opencv2/opencv_modules.hpp" -#ifdef HAVE_OPENCV_HIGHGUI -# include "opencv2/highgui.hpp" -#endif - #include "opencv2/core/private.hpp" #ifdef HAVE_TEGRA_OPTIMIZATION diff --git a/modules/stitching/CMakeLists.txt b/modules/stitching/CMakeLists.txt index 0e4f39a99d..2802ab8be7 100644 --- a/modules/stitching/CMakeLists.txt +++ b/modules/stitching/CMakeLists.txt @@ -8,6 +8,6 @@ set(STITCHING_CONTRIB_DEPS "opencv_xfeatures2d") if(BUILD_SHARED_LIBS AND BUILD_opencv_world AND OPENCV_WORLD_EXCLUDE_EXTRA_MODULES) set(STITCHING_CONTRIB_DEPS "") endif() -ocv_define_module(stitching opencv_imgproc opencv_features2d opencv_calib3d opencv_objdetect +ocv_define_module(stitching opencv_imgproc opencv_features2d opencv_calib3d OPTIONAL opencv_cudaarithm opencv_cudafilters opencv_cudafeatures2d opencv_cudalegacy ${STITCHING_CONTRIB_DEPS} WRAP python) diff --git a/modules/superres/CMakeLists.txt b/modules/superres/CMakeLists.txt index 7c3fc14a17..34c9297a1b 100644 --- a/modules/superres/CMakeLists.txt +++ b/modules/superres/CMakeLists.txt @@ -3,7 +3,6 @@ if(IOS OR WINRT) endif() set(the_description "Super Resolution") -ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4127 -Wundef -Wshadow) ocv_define_module(superres opencv_imgproc opencv_video OPTIONAL opencv_videoio opencv_cudaarithm opencv_cudafilters opencv_cudawarping opencv_cudaimgproc opencv_cudaoptflow opencv_cudacodec WRAP python) From dcdd5d64b66a378335cdc8721f5e2f571f9f9f48 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 15 Mar 2017 18:23:30 +0300 Subject: [PATCH 015/144] ocl: dump OpenCL driver version in tests --- modules/ts/src/ocl_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/ts/src/ocl_test.cpp b/modules/ts/src/ocl_test.cpp index abc8d95559..9f0acdec82 100644 --- a/modules/ts/src/ocl_test.cpp +++ b/modules/ts/src/ocl_test.cpp @@ -156,6 +156,9 @@ void dumpOpenCLDevice() DUMP_MESSAGE_STDOUT(" Version = " << device.version()); DUMP_PROPERTY_XML("cv_ocl_current_deviceVersion", device.version()); + DUMP_MESSAGE_STDOUT(" Driver version = " << device.driverVersion()); + DUMP_PROPERTY_XML("cv_ocl_current_driverVersion", device.driverVersion()); + DUMP_MESSAGE_STDOUT(" Compute units = "<< device.maxComputeUnits()); DUMP_PROPERTY_XML("cv_ocl_current_maxComputeUnits", device.maxComputeUnits()); From 9a29fc2ce1186f054a1cf2fa226893e03af86ee1 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Thu, 16 Mar 2017 10:13:56 +0900 Subject: [PATCH 016/144] Optimize WarpAffine using AVX2 --- modules/imgproc/src/imgwarp.cpp | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index 7bcf16a394..c429e391ae 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -5523,6 +5523,9 @@ public: const int AB_BITS = MAX(10, (int)INTER_BITS); const int AB_SCALE = 1 << AB_BITS; int round_delta = interpolation == INTER_NEAREST ? AB_SCALE/2 : AB_SCALE/INTER_TAB_SIZE/2, x, y, x1, y1; + #if CV_AVX2 + bool useAVX2 = checkHardwareSupport(CV_CPU_AVX2); + #endif #if CV_SSE2 bool useSSE2 = checkHardwareSupport(CV_CPU_SSE2); #endif @@ -5603,6 +5606,42 @@ public: { short* alpha = A + y1*bw; x1 = 0; + #if CV_AVX2 + if ( useAVX2 ) + { + __m256i fxy_mask = _mm256_set1_epi32(INTER_TAB_SIZE - 1); + __m256i XX = _mm256_set1_epi32(X0), YY = _mm256_set1_epi32(Y0); + for( ; x1 <= bw - 16; x1 += 16 ) + { + __m256i tx0, tx1, ty0, ty1; + tx0 = _mm256_add_epi32(_mm256_loadu_si256((const __m256i*)(adelta + x + x1)), XX); + ty0 = _mm256_add_epi32(_mm256_loadu_si256((const __m256i*)(bdelta + x + x1)), YY); + tx1 = _mm256_add_epi32(_mm256_loadu_si256((const __m256i*)(adelta + x + x1 + 8)), XX); + ty1 = _mm256_add_epi32(_mm256_loadu_si256((const __m256i*)(bdelta + x + x1 + 8)), YY); + + tx0 = _mm256_srai_epi32(tx0, AB_BITS - INTER_BITS); + ty0 = _mm256_srai_epi32(ty0, AB_BITS - INTER_BITS); + tx1 = _mm256_srai_epi32(tx1, AB_BITS - INTER_BITS); + ty1 = _mm256_srai_epi32(ty1, AB_BITS - INTER_BITS); + + __m256i fx_ = _mm256_packs_epi32(_mm256_and_si256(tx0, fxy_mask), + _mm256_and_si256(tx1, fxy_mask)); + __m256i fy_ = _mm256_packs_epi32(_mm256_and_si256(ty0, fxy_mask), + _mm256_and_si256(ty1, fxy_mask)); + tx0 = _mm256_packs_epi32(_mm256_srai_epi32(tx0, INTER_BITS), + _mm256_srai_epi32(tx1, INTER_BITS)); + ty0 = _mm256_packs_epi32(_mm256_srai_epi32(ty0, INTER_BITS), + _mm256_srai_epi32(ty1, INTER_BITS)); + fx_ = _mm256_adds_epi16(fx_, _mm256_slli_epi16(fy_, INTER_BITS)); + fx_ = _mm256_permute4x64_epi64(fx_, (3 << 6) + (1 << 4) + (2 << 2) + 0); + + _mm256_storeu_si256((__m256i*)(xy + x1*2), _mm256_unpacklo_epi16(tx0, ty0)); + _mm256_storeu_si256((__m256i*)(xy + x1*2 + 16), _mm256_unpackhi_epi16(tx0, ty0)); + _mm256_storeu_si256((__m256i*)(alpha + x1), fx_); + } + _mm256_zeroupper(); + } + #endif #if CV_SSE2 if( useSSE2 ) { From 05476d66048d6b8063e193b4aa170cbdbbb42452 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Thu, 16 Mar 2017 13:50:24 +0900 Subject: [PATCH 017/144] Optimize initUndistortRectifyMap with AVX2 --- modules/imgproc/src/undistort.cpp | 149 +++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/src/undistort.cpp b/modules/imgproc/src/undistort.cpp index 127481fe0b..e08cace5d4 100644 --- a/modules/imgproc/src/undistort.cpp +++ b/modules/imgproc/src/undistort.cpp @@ -136,6 +136,10 @@ void cv::initUndistortRectifyMap( InputArray _cameraMatrix, InputArray _distCoef cv::Matx33d matTilt = cv::Matx33d::eye(); cv::detail::computeTiltProjectionMatrix(tauX, tauY, &matTilt); +#if CV_AVX2 + bool USE_AVX2 = cv::checkHardwareSupport(CV_CPU_AVX2); +#endif + for( int i = 0; i < size.height; i++ ) { float* m1f = map1.ptr(i); @@ -144,7 +148,150 @@ void cv::initUndistortRectifyMap( InputArray _cameraMatrix, InputArray _distCoef ushort* m2 = (ushort*)m2f; double _x = i*ir[1] + ir[2], _y = i*ir[4] + ir[5], _w = i*ir[7] + ir[8]; - for( int j = 0; j < size.width; j++, _x += ir[0], _y += ir[3], _w += ir[6] ) + int j = 0; +#if CV_AVX2 +if( USE_AVX2 ) +{ + static const __m256d __one = _mm256_set1_pd(1.0); + static const __m256d __two = _mm256_set1_pd(2.0); + + const __m256d __matTilt_00 = _mm256_set1_pd(matTilt(0, 0)); + const __m256d __matTilt_10 = _mm256_set1_pd(matTilt(1, 0)); + const __m256d __matTilt_20 = _mm256_set1_pd(matTilt(2, 0)); + + const __m256d __matTilt_01 = _mm256_set1_pd(matTilt(0, 1)); + const __m256d __matTilt_11 = _mm256_set1_pd(matTilt(1, 1)); + const __m256d __matTilt_21 = _mm256_set1_pd(matTilt(2, 1)); + + const __m256d __matTilt_02 = _mm256_set1_pd(matTilt(0, 2)); + const __m256d __matTilt_12 = _mm256_set1_pd(matTilt(1, 2)); + const __m256d __matTilt_22 = _mm256_set1_pd(matTilt(2, 2)); + + for( ; j <= size.width - 4; j += 4, _x += 4 * ir[0], _y += 4 * ir[3], _w += 4 * ir[6] ) + { + // Question: Should we load the constants first? + __m256d __w = _mm256_div_pd(__one, _mm256_set_pd(_w + 3 * ir[6], _w + 2 * ir[6], _w + ir[6], _w)); + __m256d __x = _mm256_mul_pd(_mm256_set_pd(_x + 3 * ir[0], _x + 2 * ir[0], _x + ir[0], _x), __w); + __m256d __y = _mm256_mul_pd(_mm256_set_pd(_y + 3 * ir[3], _y + 2 * ir[3], _y + ir[3], _y), __w); + __m256d __x2 = _mm256_mul_pd(__x, __x); + __m256d __y2 = _mm256_mul_pd(__y, __y); + __m256d __r2 = _mm256_add_pd(__x2, __y2); + __m256d __2xy = _mm256_mul_pd(__two, _mm256_mul_pd(__x, __y)); + __m256d __kr = _mm256_div_pd( +#if CV_FMA3 + _mm256_fmadd_pd(_mm256_fmadd_pd(_mm256_fmadd_pd(_mm256_set1_pd(k3), __r2, _mm256_set1_pd(k2)), __r2, _mm256_set1_pd(k1)), __r2, __one), + _mm256_fmadd_pd(_mm256_fmadd_pd(_mm256_fmadd_pd(_mm256_set1_pd(k6), __r2, _mm256_set1_pd(k5)), __r2, _mm256_set1_pd(k4)), __r2, __one) +#else + _mm256_add_pd(__one, _mm256_mul_pd(_mm256_add_pd(_mm256_mul_pd(_mm256_add_pd(_mm256_mul_pd(_mm256_set1_pd(k3), __r2), _mm256_set1_pd(k2)), __r2), _mm256_set1_pd(k1)), __r2)), + _mm256_add_pd(__one, _mm256_mul_pd(_mm256_add_pd(_mm256_mul_pd(_mm256_add_pd(_mm256_mul_pd(_mm256_set1_pd(k6), __r2), _mm256_set1_pd(k5)), __r2), _mm256_set1_pd(k4)), __r2)) +#endif + ); + __m256d __r22 = _mm256_mul_pd(__r2, __r2); +#if CV_FMA3 + __m256d __xd = _mm256_fmadd_pd(__x, __kr, + _mm256_add_pd( + _mm256_fmadd_pd(_mm256_set1_pd(p1), __2xy, _mm256_mul_pd(_mm256_set1_pd(p2), _mm256_fmadd_pd(__two, __x2, __r2))), + _mm256_fmadd_pd(_mm256_set1_pd(s1), __r2, _mm256_mul_pd(_mm256_set1_pd(s2), __r22)))); + __m256d __yd = _mm256_fmadd_pd(__y, __kr, + _mm256_add_pd( + _mm256_fmadd_pd(_mm256_set1_pd(p1), _mm256_fmadd_pd(__two, __y2, __r2), _mm256_mul_pd(_mm256_set1_pd(p2), __2xy)), + _mm256_fmadd_pd(_mm256_set1_pd(s3), __r2, _mm256_mul_pd(_mm256_set1_pd(s4), __r22)))); + + __m256d __vecTilt2 = _mm256_fmadd_pd(__matTilt_20, __xd, _mm256_fmadd_pd(__matTilt_21, __yd, __matTilt_22)); +#else + __m256d __xd = _mm256_add_pd( + _mm256_mul_pd(__x, __kr), + _mm256_add_pd( + _mm256_add_pd( + _mm256_mul_pd(_mm256_set1_pd(p1), __2xy), + _mm256_mul_pd(_mm256_set1_pd(p2), _mm256_add_pd(__r2, _mm256_mul_pd(__two, __x2)))), + _mm256_add_pd( + _mm256_mul_pd(_mm256_set1_pd(s1), __r2), + _mm256_mul_pd(_mm256_set1_pd(s2), __r22)))); + __m256d __yd = _mm256_add_pd( + _mm256_mul_pd(__y, __kr), + _mm256_add_pd( + _mm256_add_pd( + _mm256_mul_pd(_mm256_set1_pd(p1), _mm256_add_pd(__r2, _mm256_mul_pd(__two, __y2))), + _mm256_mul_pd(_mm256_set1_pd(p2), __2xy)), + _mm256_add_pd( + _mm256_mul_pd(_mm256_set1_pd(s3), __r2), + _mm256_mul_pd(_mm256_set1_pd(s4), __r22)))); + + __m256d __vecTilt2 = _mm256_add_pd(_mm256_add_pd( + _mm256_mul_pd(__matTilt_20, __xd), _mm256_mul_pd(__matTilt_21, __yd)), __matTilt_22); +#endif + __m256d __invProj = _mm256_blendv_pd( + __one, _mm256_div_pd(__one, __vecTilt2), + _mm256_cmp_pd(__vecTilt2, _mm256_setzero_pd(), _CMP_EQ_OQ)); + +#if CV_FMA3 + __m256d __u = _mm256_fmadd_pd(__matTilt_00, __xd, _mm256_fmadd_pd(__matTilt_01, __yd, __matTilt_02)); + __u = _mm256_fmadd_pd(_mm256_mul_pd(_mm256_set1_pd(fx), __invProj), __u, _mm256_set1_pd(u0)); + + __m256d __v = _mm256_fmadd_pd(__matTilt_10, __xd, _mm256_fmadd_pd(__matTilt_11, __yd, __matTilt_12)); + __v = _mm256_fmadd_pd(_mm256_mul_pd(_mm256_set1_pd(fy), __invProj), __v, _mm256_set1_pd(v0)); +#else + __m256d __u = _mm256_add_pd(_mm256_add_pd( + _mm256_mul_pd(__matTilt_00, __xd), _mm256_mul_pd(__matTilt_01, __yd)), __matTilt_02); + __u = _mm256_add_pd(_mm256_mul_pd(_mm256_mul_pd(_mm256_set1_pd(fx), __invProj), __u), _mm256_set1_pd(u0)); + + __m256d __v = _mm256_add_pd(_mm256_add_pd( + _mm256_mul_pd(__matTilt_10, __xd), _mm256_mul_pd(__matTilt_11, __yd)), __matTilt_12); + __v = _mm256_add_pd(_mm256_mul_pd(_mm256_mul_pd(_mm256_set1_pd(fy), __invProj), __v), _mm256_set1_pd(v0)); +#endif + + if ( m1type == CV_32FC1 ) + { + _mm_storeu_ps(&m1f[j], _mm256_cvtpd_ps(__u)); + _mm_storeu_ps(&m2f[j], _mm256_cvtpd_ps(__v)); + } + else if ( m1type == CV_32FC2 ) + { + __m128 __u_float = _mm256_cvtpd_ps(__u); + __m128 __v_float = _mm256_cvtpd_ps(__v); + + _mm_storeu_ps(&m1f[j*2], _mm_unpacklo_ps(__u_float, __v_float)); + _mm_storeu_ps(&m1f[j*2 + 4], _mm_unpackhi_ps(__u_float, __v_float)); + } + else // m1type == CV_16SC2 + { + __u = _mm256_mul_pd(__u, _mm256_set1_pd(INTER_TAB_SIZE)); + __v = _mm256_mul_pd(__v, _mm256_set1_pd(INTER_TAB_SIZE)); + + __m128 __u_float = _mm256_cvtpd_ps(__u); + __m128 __v_float = _mm256_cvtpd_ps(__v); + _mm256_zeroupper(); + static const __m128 __int_max = _mm_set1_ps(std::numeric_limits::max()); + static const __m128 __int_min = _mm_set1_ps(std::numeric_limits::min()); + __u_float = _mm_max_ps(_mm_min_ps(__u_float, __int_max), __int_min); + __v_float = _mm_max_ps(_mm_min_ps(__v_float, __int_max), __int_min); + + __m128i __iu = _mm_cvtps_epi32(__u_float); + __m128i __iv = _mm_cvtps_epi32(__v_float); + + static const __m128i __INTER_TAB_SIZE_m1 = _mm_set1_epi32(INTER_TAB_SIZE-1); + __m128i __m2 = _mm_add_epi32( + _mm_mul_epi32(_mm_and_si128(__iv, __INTER_TAB_SIZE_m1), _mm_set1_epi32(INTER_TAB_SIZE)), + _mm_and_si128(__iu, __INTER_TAB_SIZE_m1)); + __m2 = _mm_packus_epi16(__m2, __m2); + _mm_maskstore_epi64((long long int*) &m2[j], _mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF), __m2); + + // gcc4.9 does not support _mm256_set_m128 + // __m256i __m1 = _mm256_set_m128i(__iv, __iu); + __m256i __m1; + __m1 = _mm256_inserti128_si256(__m1, __iu, 0); + __m1 = _mm256_inserti128_si256(__m1, __iv, 1); + __m1 = _mm256_srli_epi32(__m1, INTER_BITS); // v3 v2 v1 v0 u3 u2 u1 u0 (int32_t) + static const __m256i __permute_mask = _mm256_set_epi32(7, 3, 6, 2, 5, 1 ,4, 0); + __m1 = _mm256_permutevar8x32_epi32(__m1, __permute_mask); // v3 u3 v2 u2 v1 u1 v0 u0 (int32_t) + __m1 = _mm256_packs_epi32(__m1, __m1); // x x x x v3 u3 v2 u2 x x x x v1 u1 v0 u0 (int16_t) + _mm_storeu_si128((__m128i*) &m1[j*2], _mm256_extracti128_si256(_mm256_permute4x64_epi64(__m1, (2 << 2) + 0), 0)); + } + } +} +#endif + for( ; j < size.width; j++, _x += ir[0], _y += ir[3], _w += ir[6] ) { double w = 1./_w, x = _x*w, y = _y*w; double x2 = x*x, y2 = y*y; From c370cc10e9e8542eee06671b74f73b614de4bdf7 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Thu, 16 Mar 2017 14:20:41 +0900 Subject: [PATCH 018/144] Optimize normL2Sqr_ with AVX2 --- modules/core/src/stat.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/core/src/stat.cpp b/modules/core/src/stat.cpp index 3c5fb73de4..a2986cc88b 100644 --- a/modules/core/src/stat.cpp +++ b/modules/core/src/stat.cpp @@ -4422,7 +4422,22 @@ int normHamming(const uchar* a, const uchar* b, int n, int cellSize) float normL2Sqr_(const float* a, const float* b, int n) { int j = 0; float d = 0.f; -#if CV_SSE +#if CV_AVX2 + float CV_DECL_ALIGNED(32) buf[8]; + __m256 d0 = _mm256_setzero_ps(); + + for( ; j <= n - 8; j += 8 ) + { + __m256 t0 = _mm256_sub_ps(_mm256_loadu_ps(a + j), _mm256_loadu_ps(b + j)); +#ifdef CV_FMA3 + d0 = _mm256_fmadd_ps(t0, t0, d0); +#else + d0 = _mm256_add_ps(d0, _mm256_mul_ps(t0, t0)); +#endif + } + _mm256_store_ps(buf, d0); + d = buf[0] + buf[1] + buf[2] + buf[3] + buf[4] + buf[5] + buf[6] + buf[7]; +#elif CV_SSE float CV_DECL_ALIGNED(16) buf[4]; __m128 d0 = _mm_setzero_ps(), d1 = _mm_setzero_ps(); From 0b31eca9c28daa047c32946eaeb82512aef0cc56 Mon Sep 17 00:00:00 2001 From: berak Date: Sun, 19 Mar 2017 10:12:50 +0100 Subject: [PATCH 019/144] remove unnessecary print statement #resolves: 7881 remove printf statement and associated variables from invMapPointSpherical() in undistort.cpp --- modules/imgproc/src/undistort.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/modules/imgproc/src/undistort.cpp b/modules/imgproc/src/undistort.cpp index 127481fe0b..6cbb4e2e87 100644 --- a/modules/imgproc/src/undistort.cpp +++ b/modules/imgproc/src/undistort.cpp @@ -476,8 +476,6 @@ static Point2f mapPointSpherical(const Point2f& p, float alpha, Vec4d* J, int pr static Point2f invMapPointSpherical(Point2f _p, float alpha, int projType) { - static int avgiter = 0, avgn = 0; - double eps = 1e-12; Vec2d p(_p.x, _p.y), q(_p.x, _p.y), err; Vec4d J; @@ -502,14 +500,6 @@ static Point2f invMapPointSpherical(Point2f _p, float alpha, int projType) //q -= Vec2d((J.t()*J).inv()*(J.t()*err)); } - if( i < maxiter ) - { - avgiter += i; - avgn++; - if( avgn == 1500 ) - printf("avg iters = %g\n", (double)avgiter/avgn); - } - return i < maxiter ? Point2f((float)q[0], (float)q[1]) : Point2f(-FLT_MAX, -FLT_MAX); } From 11f3c0741ec8ff56236b987498f2f45a22a749a5 Mon Sep 17 00:00:00 2001 From: berak Date: Mon, 20 Mar 2017 09:59:19 +0100 Subject: [PATCH 020/144] imgproc: move ShapeMatchModes enum from c to c++ header --- modules/imgproc/include/opencv2/imgproc.hpp | 16 +++++++++++++++- .../imgproc/include/opencv2/imgproc/types_c.h | 11 ++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 9914f63ff7..03115db2f5 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -452,6 +452,20 @@ enum ContourApproximationModes { CHAIN_APPROX_TC89_KCOS = 4 }; +/** @brief Shape matching methods + +\f$A\f$ denotes object1,\f$B\f$ denotes object2 + +\f$\begin{array}{l} m^A_i = \mathrm{sign} (h^A_i) \cdot \log{h^A_i} \\ m^B_i = \mathrm{sign} (h^B_i) \cdot \log{h^B_i} \end{array}\f$ + +and \f$h^A_i, h^B_i\f$ are the Hu moments of \f$A\f$ and \f$B\f$ , respectively. +*/ +enum ShapeMatchModes { + CONTOURS_MATCH_I1 =1, //!< \f[I_1(A,B) = \sum _{i=1...7} \left | \frac{1}{m^A_i} - \frac{1}{m^B_i} \right |\f] + CONTOURS_MATCH_I2 =2, //!< \f[I_2(A,B) = \sum _{i=1...7} \left | m^A_i - m^B_i \right |\f] + CONTOURS_MATCH_I3 =3 //!< \f[I_3(A,B) = \max _{i=1...7} \frac{ \left| m^A_i - m^B_i \right| }{ \left| m^A_i \right| }\f] +}; + //! @} imgproc_shape //! Variants of a Hough transform @@ -3916,7 +3930,7 @@ The function compares two shapes. All three implemented methods use the Hu invar @param contour1 First contour or grayscale image. @param contour2 Second contour or grayscale image. -@param method Comparison method, see ::ShapeMatchModes +@param method Comparison method, see cv::ShapeMatchModes @param parameter Method-specific parameter (not supported now). */ CV_EXPORTS_W double matchShapes( InputArray contour1, InputArray contour2, diff --git a/modules/imgproc/include/opencv2/imgproc/types_c.h b/modules/imgproc/include/opencv2/imgproc/types_c.h index ca487d2bd4..13ffe1b1a3 100644 --- a/modules/imgproc/include/opencv2/imgproc/types_c.h +++ b/modules/imgproc/include/opencv2/imgproc/types_c.h @@ -501,15 +501,8 @@ enum CV_POLY_APPROX_DP = 0 }; -/** @brief Shape matching methods - -\f$A\f$ denotes object1,\f$B\f$ denotes object2 - -\f$\begin{array}{l} m^A_i = \mathrm{sign} (h^A_i) \cdot \log{h^A_i} \\ m^B_i = \mathrm{sign} (h^B_i) \cdot \log{h^B_i} \end{array}\f$ - -and \f$h^A_i, h^B_i\f$ are the Hu moments of \f$A\f$ and \f$B\f$ , respectively. -*/ -enum ShapeMatchModes +/** Shape matching methods */ +enum { CV_CONTOURS_MATCH_I1 =1, //!< \f[I_1(A,B) = \sum _{i=1...7} \left | \frac{1}{m^A_i} - \frac{1}{m^B_i} \right |\f] CV_CONTOURS_MATCH_I2 =2, //!< \f[I_2(A,B) = \sum _{i=1...7} \left | m^A_i - m^B_i \right |\f] From 3fbe1f8d649ee709858b593bd69a4a85fe3224cb Mon Sep 17 00:00:00 2001 From: vartenkov Date: Thu, 16 Mar 2017 18:50:29 +0300 Subject: [PATCH 021/144] Fix multichannel warping with BORDER_CONSTANT Warping a matrix with more than 4 channels using BORDER_CONSTANT and INTER_NEAREST, INTER_CUBIC or INTER_LANCZOS4 interpolation led to undefined behaviour. This commit changes the behavior of these methods to be similar to that of INTER_LINEAR. Changed the scope of some of the variables to more local. Modified some tests to be able to detect the error described. --- modules/imgproc/src/imgwarp.cpp | 92 +++++++++++++-------------- modules/imgproc/test/test_imgwarp.cpp | 21 ++++-- 2 files changed, 60 insertions(+), 53 deletions(-) diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index 7bcf16a394..c5d2182c2e 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -3533,14 +3533,13 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, int borderType, const Scalar& _borderValue ) { Size ssize = _src.size(), dsize = _dst.size(); - int cn = _src.channels(); + const int cn = _src.channels(); const T* S0 = _src.ptr(); + T cval[CV_CN_MAX]; size_t sstep = _src.step/sizeof(S0[0]); - Scalar_ cval(saturate_cast(_borderValue[0]), - saturate_cast(_borderValue[1]), - saturate_cast(_borderValue[2]), - saturate_cast(_borderValue[3])); - int dx, dy; + + for(int k = 0; k < cn; k++ ) + cval[k] = saturate_cast(_borderValue[k & 3]); unsigned width1 = ssize.width, height1 = ssize.height; @@ -3550,14 +3549,14 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, dsize.height = 1; } - for( dy = 0; dy < dsize.height; dy++ ) + for(int dy = 0; dy < dsize.height; dy++ ) { T* D = _dst.ptr(dy); const short* XY = _xy.ptr(dy); if( cn == 1 ) { - for( dx = 0; dx < dsize.width; dx++ ) + for(int dx = 0; dx < dsize.width; dx++ ) { int sx = XY[dx*2], sy = XY[dx*2+1]; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) @@ -3583,9 +3582,9 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, } else { - for( dx = 0; dx < dsize.width; dx++, D += cn ) + for(int dx = 0; dx < dsize.width; dx++, D += cn ) { - int sx = XY[dx*2], sy = XY[dx*2+1], k; + int sx = XY[dx*2], sy = XY[dx*2+1]; const T *S; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) { @@ -3602,7 +3601,7 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, else { S = S0 + sy*sstep + sx*cn; - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) D[k] = S[k]; } } @@ -3622,7 +3621,7 @@ static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, sy = borderInterpolate(sy, ssize.height, borderType); S = S0 + sy*sstep + sx*cn; } - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) D[k] = S[k]; } } @@ -3852,16 +3851,15 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, typedef typename CastOp::rtype T; typedef typename CastOp::type1 WT; Size ssize = _src.size(), dsize = _dst.size(); - int k, cn = _src.channels(); + const int cn = _src.channels(); const AT* wtab = (const AT*)_wtab; const T* S0 = _src.ptr(); size_t sstep = _src.step/sizeof(S0[0]); T cval[CV_CN_MAX]; - int dx, dy; CastOp castOp; VecOp vecOp; - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) cval[k] = saturate_cast(_borderValue[k & 3]); unsigned width1 = std::max(ssize.width-1, 0), height1 = std::max(ssize.height-1, 0); @@ -3871,7 +3869,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, width1 = std::max(ssize.width-2, 0); #endif - for( dy = 0; dy < dsize.height; dy++ ) + for(int dy = 0; dy < dsize.height; dy++ ) { T* D = _dst.ptr(dy); const short* XY = _xy.ptr(dy); @@ -3879,7 +3877,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, int X0 = 0; bool prevInlier = false; - for( dx = 0; dx <= dsize.width; dx++ ) + for(int dx = 0; dx <= dsize.width; dx++ ) { bool curInlier = dx < dsize.width ? (unsigned)XY[dx*2] < width1 && @@ -3948,7 +3946,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, int sx = XY[dx*2], sy = XY[dx*2+1]; const AT* w = wtab + FXY[dx]*4; const T* S = S0 + sy*sstep + sx*cn; - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) { WT t0 = S[k]*w[0] + S[k+cn]*w[1] + S[sstep+k]*w[2] + S[sstep+k+cn]*w[3]; D[k] = castOp(t0); @@ -4012,7 +4010,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, (sx >= ssize.width || sx+1 < 0 || sy >= ssize.height || sy+1 < 0) ) { - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) D[k] = cval[k]; } else @@ -4046,7 +4044,7 @@ static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, v2 = sx0 >= 0 && sy1 >= 0 ? S0 + sy1*sstep + sx0*cn : &cval[0]; v3 = sx1 >= 0 && sy1 >= 0 ? S0 + sy1*sstep + sx1*cn : &cval[0]; } - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) D[k] = castOp(WT(v0[k]*w[0] + v1[k]*w[1] + v2[k]*w[2] + v3[k]*w[3])); } } @@ -4064,16 +4062,16 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, typedef typename CastOp::rtype T; typedef typename CastOp::type1 WT; Size ssize = _src.size(), dsize = _dst.size(); - int cn = _src.channels(); + const int cn = _src.channels(); const AT* wtab = (const AT*)_wtab; const T* S0 = _src.ptr(); size_t sstep = _src.step/sizeof(S0[0]); - Scalar_ cval(saturate_cast(_borderValue[0]), - saturate_cast(_borderValue[1]), - saturate_cast(_borderValue[2]), - saturate_cast(_borderValue[3])); - int dx, dy; + T cval[CV_CN_MAX]; CastOp castOp; + + for(int k = 0; k < cn; k++ ) + cval[k] = saturate_cast(_borderValue[k & 3]); + int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101; unsigned width1 = std::max(ssize.width-3, 0), height1 = std::max(ssize.height-3, 0); @@ -4084,21 +4082,20 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, dsize.height = 1; } - for( dy = 0; dy < dsize.height; dy++ ) + for(int dy = 0; dy < dsize.height; dy++ ) { T* D = _dst.ptr(dy); const short* XY = _xy.ptr(dy); const ushort* FXY = _fxy.ptr(dy); - for( dx = 0; dx < dsize.width; dx++, D += cn ) + for(int dx = 0; dx < dsize.width; dx++, D += cn ) { int sx = XY[dx*2]-1, sy = XY[dx*2+1]-1; const AT* w = wtab + FXY[dx]*16; - int i, k; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) { const T* S = S0 + sy*sstep + sx*cn; - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) { WT sum = S[0]*w[0] + S[cn]*w[1] + S[cn*2]*w[2] + S[cn*3]*w[3]; S += sstep; @@ -4123,21 +4120,21 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, (sx >= ssize.width || sx+4 <= 0 || sy >= ssize.height || sy+4 <= 0)) { - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) D[k] = cval[k]; continue; } - for( i = 0; i < 4; i++ ) + for(int i = 0; i < 4; i++ ) { x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn; y[i] = borderInterpolate(sy + i, ssize.height, borderType1); } - for( k = 0; k < cn; k++, S0++, w -= 16 ) + for(int k = 0; k < cn; k++, S0++, w -= 16 ) { WT cv = cval[k], sum = cv*ONE; - for( i = 0; i < 4; i++, w += 4 ) + for(int i = 0; i < 4; i++, w += 4 ) { int yi = y[i]; const T* S = S0 + yi*sstep; @@ -4169,16 +4166,16 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, typedef typename CastOp::rtype T; typedef typename CastOp::type1 WT; Size ssize = _src.size(), dsize = _dst.size(); - int cn = _src.channels(); + const int cn = _src.channels(); const AT* wtab = (const AT*)_wtab; const T* S0 = _src.ptr(); size_t sstep = _src.step/sizeof(S0[0]); - Scalar_ cval(saturate_cast(_borderValue[0]), - saturate_cast(_borderValue[1]), - saturate_cast(_borderValue[2]), - saturate_cast(_borderValue[3])); - int dx, dy; + T cval[CV_CN_MAX]; CastOp castOp; + + for(int k = 0; k < cn; k++ ) + cval[k] = saturate_cast(_borderValue[k & 3]); + int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101; unsigned width1 = std::max(ssize.width-7, 0), height1 = std::max(ssize.height-7, 0); @@ -4189,21 +4186,20 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, dsize.height = 1; } - for( dy = 0; dy < dsize.height; dy++ ) + for(int dy = 0; dy < dsize.height; dy++ ) { T* D = _dst.ptr(dy); const short* XY = _xy.ptr(dy); const ushort* FXY = _fxy.ptr(dy); - for( dx = 0; dx < dsize.width; dx++, D += cn ) + for(int dx = 0; dx < dsize.width; dx++, D += cn ) { int sx = XY[dx*2]-3, sy = XY[dx*2+1]-3; const AT* w = wtab + FXY[dx]*64; const T* S = S0 + sy*sstep + sx*cn; - int i, k; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) { - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) { WT sum = 0; for( int r = 0; r < 8; r++, S += sstep, w += 8 ) @@ -4226,21 +4222,21 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, (sx >= ssize.width || sx+8 <= 0 || sy >= ssize.height || sy+8 <= 0)) { - for( k = 0; k < cn; k++ ) + for(int k = 0; k < cn; k++ ) D[k] = cval[k]; continue; } - for( i = 0; i < 8; i++ ) + for(int i = 0; i < 8; i++ ) { x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn; y[i] = borderInterpolate(sy + i, ssize.height, borderType1); } - for( k = 0; k < cn; k++, S0++, w -= 64 ) + for(int k = 0; k < cn; k++, S0++, w -= 64 ) { WT cv = cval[k], sum = cv*ONE; - for( i = 0; i < 8; i++, w += 8 ) + for(int i = 0; i < 8; i++, w += 8 ) { int yi = y[i]; const T* S1 = S0 + yi*sstep; diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index 8246754387..8d7b1f86ea 100644 --- a/modules/imgproc/test/test_imgwarp.cpp +++ b/modules/imgproc/test/test_imgwarp.cpp @@ -1686,22 +1686,33 @@ TEST(Resize, Area_half) TEST(Imgproc_Warp, multichannel) { + static const int inter_types[] = {INTER_NEAREST, INTER_AREA, INTER_CUBIC, + INTER_LANCZOS4, INTER_LINEAR}; + static const int inter_n = sizeof(inter_types) / sizeof(int); + + static const int border_types[] = {BORDER_CONSTANT, BORDER_DEFAULT, + BORDER_REFLECT, BORDER_REPLICATE, + BORDER_WRAP, BORDER_WRAP}; + static const int border_n = sizeof(border_types) / sizeof(int); + RNG& rng = theRNG(); - for( int iter = 0; iter < 30; iter++ ) + for( int iter = 0; iter < 100; iter++ ) { + int inter = inter_types[rng.uniform(0, inter_n)]; + int border = border_types[rng.uniform(0, border_n)]; int width = rng.uniform(3, 333); int height = rng.uniform(3, 333); - int cn = rng.uniform(1, 10); + int cn = rng.uniform(1, 15); Mat src(height, width, CV_8UC(cn)), dst; //randu(src, 0, 256); src.setTo(0.); - Mat rot = getRotationMatrix2D(Point2f(0.f, 0.f), 1, 1); - warpAffine(src, dst, rot, src.size()); + Mat rot = getRotationMatrix2D(Point2f(0.f, 0.f), 1.0, 1.0); + warpAffine(src, dst, rot, src.size(), inter, border); ASSERT_EQ(0.0, norm(dst, NORM_INF)); Mat rot2 = Mat::eye(3, 3, rot.type()); rot.copyTo(rot2.rowRange(0, 2)); - warpPerspective(src, dst, rot2, src.size()); + warpPerspective(src, dst, rot2, src.size(), inter, border); ASSERT_EQ(0.0, norm(dst, NORM_INF)); } } From cdcf44b3ef78958f99c76638b7bb34123e24dfa1 Mon Sep 17 00:00:00 2001 From: Naba Kumar Date: Wed, 15 Mar 2017 15:22:32 +0200 Subject: [PATCH 022/144] Expose BufferPool class for external use also --- modules/core/include/opencv2/core/cuda.hpp | 28 +++++++++++++++++++ .../include/opencv2/core/private.cuda.hpp | 14 ---------- modules/core/src/cuda_stream.cpp | 21 +++++++++++--- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/modules/core/include/opencv2/core/cuda.hpp b/modules/core/include/opencv2/core/cuda.hpp index c538392cbd..4c5c522e24 100644 --- a/modules/core/include/opencv2/core/cuda.hpp +++ b/modules/core/include/opencv2/core/cuda.hpp @@ -327,6 +327,34 @@ The function does not reallocate memory if the matrix has proper attributes alre */ CV_EXPORTS void ensureSizeIsEnough(int rows, int cols, int type, OutputArray arr); +/** @brief BufferPool for use with CUDA streams + + * BufferPool utilizes cuda::Stream's allocator to create new buffers. It is + * particularly useful when BufferPoolUsage is set to true, or a custom + * allocator is specified for the cuda::Stream, and you want to implement your + * own stream based functions utilizing the same underlying GPU memory + * management. + */ +class CV_EXPORTS BufferPool +{ +public: + + //! Gets the BufferPool for the given stream. + explicit BufferPool(Stream& stream); + + //! Allocates a new GpuMat of given size and type. + GpuMat getBuffer(int rows, int cols, int type); + + //! Allocates a new GpuMat of given size and type. + GpuMat getBuffer(Size size, int type) { return getBuffer(size.height, size.width, type); } + + //! Returns the allocator associated with the stream. + Ptr getAllocator() const { return allocator_; } + +private: + Ptr allocator_; +}; + //! BufferPool management (must be called before Stream creation) CV_EXPORTS void setBufferPoolUsage(bool on); CV_EXPORTS void setBufferPoolConfig(int deviceId, size_t stackSize, int stackCount); diff --git a/modules/core/include/opencv2/core/private.cuda.hpp b/modules/core/include/opencv2/core/private.cuda.hpp index 01a4ab3bf9..1214d70304 100644 --- a/modules/core/include/opencv2/core/private.cuda.hpp +++ b/modules/core/include/opencv2/core/private.cuda.hpp @@ -102,20 +102,6 @@ static inline void throw_no_cuda() { CV_Error(cv::Error::StsNotImplemented, "The namespace cv { namespace cuda { - class CV_EXPORTS BufferPool - { - public: - explicit BufferPool(Stream& stream); - - GpuMat getBuffer(int rows, int cols, int type); - GpuMat getBuffer(Size size, int type) { return getBuffer(size.height, size.width, type); } - - GpuMat::Allocator* getAllocator() const { return allocator_; } - - private: - GpuMat::Allocator* allocator_; - }; - static inline void checkNppError(int code, const char* file, const int line, const char* func) { if (code < 0) diff --git a/modules/core/src/cuda_stream.cpp b/modules/core/src/cuda_stream.cpp index 1ea8df37b9..24ecbd4ab0 100644 --- a/modules/core/src/cuda_stream.cpp +++ b/modules/core/src/cuda_stream.cpp @@ -668,20 +668,33 @@ void cv::cuda::setBufferPoolConfig(int deviceId, size_t stackSize, int stackCoun #endif } -#ifdef HAVE_CUDA - -cv::cuda::BufferPool::BufferPool(Stream& stream) : allocator_(stream.impl_->stackAllocator.get()) +#ifndef HAVE_CUDA +cv::cuda::BufferPool::BufferPool(Stream& stream) +{ + (void) stream; + throw_no_cuda(); +} +#else +cv::cuda::BufferPool::BufferPool(Stream& stream) : allocator_(stream.impl_->stackAllocator) { } +#endif GpuMat cv::cuda::BufferPool::getBuffer(int rows, int cols, int type) { +#ifndef HAVE_CUDA + (void) rows; + (void) cols; + (void) type; + throw_no_cuda(); + return GpuMat(); +#else GpuMat buf(allocator_); buf.create(rows, cols, type); return buf; +#endif } -#endif //////////////////////////////////////////////////////////////// // Event From 00f3ad721797d8013657f63142b2451b76556e9c Mon Sep 17 00:00:00 2001 From: Naba Kumar Date: Wed, 15 Mar 2017 08:41:54 +0200 Subject: [PATCH 023/144] Implement DFT as cv::Algorithm to support concurrent streams --- modules/core/include/opencv2/core/base.hpp | 4 + modules/core/src/dxt.cpp | 3 + .../cudaarithm/include/opencv2/cudaarithm.hpp | 30 +++ modules/cudaarithm/src/arithm.cpp | 231 ++++++++++-------- modules/cudaarithm/test/test_arithm.cpp | 27 ++ 5 files changed, 197 insertions(+), 98 deletions(-) diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index b319df6f38..07ca3a51a1 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -239,6 +239,10 @@ enum DftFlags { into a real array and inverse transformation is executed, the function treats the input as a packed complex-conjugate symmetrical array, and the output will also be a real array). */ DFT_REAL_OUTPUT = 32, + /** specifies that input is complex input. If this flag is set, the input must have 2 channels. + On the other hand, for backwards compatibility reason, if input has 2 channels, input is + already considered complex. */ + DFT_COMPLEX_INPUT = 64, /** performs an inverse 1D or 2D transform instead of the default forward transform. */ DCT_INVERSE = DFT_INVERSE, /** performs a forward or inverse transform of every individual row of the input diff --git a/modules/core/src/dxt.cpp b/modules/core/src/dxt.cpp index f553c4f31e..e33b105ba6 100644 --- a/modules/core/src/dxt.cpp +++ b/modules/core/src/dxt.cpp @@ -3342,6 +3342,9 @@ void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows ) CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 ); + // Fail if DFT_COMPLEX_INPUT is specified, but src is not 2 channels. + CV_Assert( !((flags & DFT_COMPLEX_INPUT) && src.channels() != 2) ); + if( !inv && src.channels() == 1 && (flags & DFT_COMPLEX_OUTPUT) ) _dst.create( src.size(), CV_MAKETYPE(depth, 2) ); else if( inv && src.channels() == 2 && (flags & DFT_REAL_OUTPUT) ) diff --git a/modules/cudaarithm/include/opencv2/cudaarithm.hpp b/modules/cudaarithm/include/opencv2/cudaarithm.hpp index f2ee84543f..a482b49fcf 100644 --- a/modules/cudaarithm/include/opencv2/cudaarithm.hpp +++ b/modules/cudaarithm/include/opencv2/cudaarithm.hpp @@ -788,6 +788,7 @@ CV_EXPORTS void mulAndScaleSpectrums(InputArray src1, InputArray src2, OutputArr (obtained from dft_size ). - **DFT_INVERSE** inverts DFT. Use for complex-complex cases (real-complex and complex-real cases are always forward and inverse, respectively). +- **DFT_COMPLEX_INPUT** Specifies that input is complex input with 2 channels. - **DFT_REAL_OUTPUT** specifies the output as real. The source matrix is the result of real-complex transform, so the destination matrix must be real. @param stream Stream for the asynchronous version. @@ -813,6 +814,35 @@ instead of the width. */ CV_EXPORTS void dft(InputArray src, OutputArray dst, Size dft_size, int flags=0, Stream& stream = Stream::Null()); +/** @brief Base class for DFT operator as a cv::Algorithm. : + */ +class CV_EXPORTS DFT : public Algorithm +{ +public: + /** @brief Computes an FFT of a given image. + + @param image Source image. Only CV_32FC1 images are supported for now. + @param result Result image. + @param stream Stream for the asynchronous version. + */ + virtual void compute(InputArray image, OutputArray result, Stream& stream = Stream::Null()) = 0; +}; + +/** @brief Creates implementation for cuda::DFT. + +@param dft_size The image size. +@param flags Optional flags: +- **DFT_ROWS** transforms each individual row of the source matrix. +- **DFT_SCALE** scales the result: divide it by the number of elements in the transform +(obtained from dft_size ). +- **DFT_INVERSE** inverts DFT. Use for complex-complex cases (real-complex and complex-real +cases are always forward and inverse, respectively). +- **DFT_COMPLEX_INPUT** Specifies that inputs will be complex with 2 channels. +- **DFT_REAL_OUTPUT** specifies the output as real. The source matrix is the result of +real-complex transform, so the destination matrix must be real. + */ +CV_EXPORTS Ptr createDFT(Size dft_size, int flags); + /** @brief Base class for convolution (or cross-correlation) operator. : */ class CV_EXPORTS Convolution : public Algorithm diff --git a/modules/cudaarithm/src/arithm.cpp b/modules/cudaarithm/src/arithm.cpp index 08de4e4288..01a0169136 100644 --- a/modules/cudaarithm/src/arithm.cpp +++ b/modules/cudaarithm/src/arithm.cpp @@ -286,111 +286,146 @@ void cv::cuda::gemm(InputArray _src1, InputArray _src2, double alpha, InputArray } ////////////////////////////////////////////////////////////////////////////// -// dft +// DFT function void cv::cuda::dft(InputArray _src, OutputArray _dst, Size dft_size, int flags, Stream& stream) +{ + if (getInputMat(_src, stream).channels() == 2) + flags |= DFT_COMPLEX_INPUT; + + Ptr dft = createDFT(dft_size, flags); + dft->compute(_src, _dst, stream); +} + +////////////////////////////////////////////////////////////////////////////// +// DFT algorithm + +#ifdef HAVE_CUFFT + +namespace +{ + + class DFTImpl : public DFT + { + Size dft_size, dft_size_opt; + bool is_1d_input, is_row_dft, is_scaled_dft, is_inverse, is_complex_input, is_complex_output; + + cufftType dft_type; + cufftHandle plan; + + public: + DFTImpl(Size dft_size, int flags) + : dft_size(dft_size), + dft_size_opt(dft_size), + is_1d_input((dft_size.height == 1) || (dft_size.width == 1)), + is_row_dft((flags & DFT_ROWS) != 0), + is_scaled_dft((flags & DFT_SCALE) != 0), + is_inverse((flags & DFT_INVERSE) != 0), + is_complex_input((flags & DFT_COMPLEX_INPUT) != 0), + is_complex_output(!(flags & DFT_REAL_OUTPUT)), + dft_type(!is_complex_input ? CUFFT_R2C : (is_complex_output ? CUFFT_C2C : CUFFT_C2R)) + { + // We don't support unpacked output (in the case of real input) + CV_Assert( !(flags & DFT_COMPLEX_OUTPUT) ); + + // We don't support real-to-real transform + CV_Assert( is_complex_input || is_complex_output ); + + if (is_1d_input && !is_row_dft) + { + // If the source matrix is single column handle it as single row + dft_size_opt.width = std::max(dft_size.width, dft_size.height); + dft_size_opt.height = std::min(dft_size.width, dft_size.height); + } + + CV_Assert( dft_size_opt.width > 1 ); + + if (is_1d_input || is_row_dft) + cufftSafeCall( cufftPlan1d(&plan, dft_size_opt.width, dft_type, dft_size_opt.height) ); + else + cufftSafeCall( cufftPlan2d(&plan, dft_size_opt.height, dft_size_opt.width, dft_type) ); + } + + ~DFTImpl() + { + cufftSafeCall( cufftDestroy(plan) ); + } + + void compute(InputArray _src, OutputArray _dst, Stream& stream) + { + GpuMat src = getInputMat(_src, stream); + + CV_Assert( src.type() == CV_32FC1 || src.type() == CV_32FC2 ); + CV_Assert( is_complex_input == (src.channels() == 2) ); + + // Make sure here we work with the continuous input, + // as CUFFT can't handle gaps + GpuMat src_cont; + if (src.isContinuous()) + { + src_cont = src; + } + else + { + BufferPool pool(stream); + src_cont.allocator = pool.getAllocator(); + createContinuous(src.rows, src.cols, src.type(), src_cont); + src.copyTo(src_cont, stream); + } + + cufftSafeCall( cufftSetStream(plan, StreamAccessor::getStream(stream)) ); + + if (is_complex_input) + { + if (is_complex_output) + { + createContinuous(dft_size, CV_32FC2, _dst); + GpuMat dst = _dst.getGpuMat(); + + cufftSafeCall(cufftExecC2C( + plan, src_cont.ptr(), dst.ptr(), + is_inverse ? CUFFT_INVERSE : CUFFT_FORWARD)); + } + else + { + createContinuous(dft_size, CV_32F, _dst); + GpuMat dst = _dst.getGpuMat(); + + cufftSafeCall(cufftExecC2R( + plan, src_cont.ptr(), dst.ptr())); + } + } + else + { + // We could swap dft_size for efficiency. Here we must reflect it + if (dft_size == dft_size_opt) + createContinuous(Size(dft_size.width / 2 + 1, dft_size.height), CV_32FC2, _dst); + else + createContinuous(Size(dft_size.width, dft_size.height / 2 + 1), CV_32FC2, _dst); + + GpuMat dst = _dst.getGpuMat(); + + cufftSafeCall(cufftExecR2C( + plan, src_cont.ptr(), dst.ptr())); + } + + if (is_scaled_dft) + cuda::multiply(_dst, Scalar::all(1. / dft_size.area()), _dst, 1, -1, stream); + } + }; +} + +#endif + +Ptr cv::cuda::createDFT(Size dft_size, int flags) { #ifndef HAVE_CUFFT - (void) _src; - (void) _dst; (void) dft_size; (void) flags; - (void) stream; - throw_no_cuda(); + CV_Error(Error::StsNotImplemented, "The library was build without CUFFT"); + return Ptr(); #else - GpuMat src = getInputMat(_src, stream); - - CV_Assert( src.type() == CV_32FC1 || src.type() == CV_32FC2 ); - - // We don't support unpacked output (in the case of real input) - CV_Assert( !(flags & DFT_COMPLEX_OUTPUT) ); - - const bool is_1d_input = (dft_size.height == 1) || (dft_size.width == 1); - const bool is_row_dft = (flags & DFT_ROWS) != 0; - const bool is_scaled_dft = (flags & DFT_SCALE) != 0; - const bool is_inverse = (flags & DFT_INVERSE) != 0; - const bool is_complex_input = src.channels() == 2; - const bool is_complex_output = !(flags & DFT_REAL_OUTPUT); - - // We don't support real-to-real transform - CV_Assert( is_complex_input || is_complex_output ); - - // Make sure here we work with the continuous input, - // as CUFFT can't handle gaps - GpuMat src_cont; - if (src.isContinuous()) - { - src_cont = src; - } - else - { - BufferPool pool(stream); - src_cont.allocator = pool.getAllocator(); - createContinuous(src.rows, src.cols, src.type(), src_cont); - src.copyTo(src_cont, stream); - } - - Size dft_size_opt = dft_size; - if (is_1d_input && !is_row_dft) - { - // If the source matrix is single column handle it as single row - dft_size_opt.width = std::max(dft_size.width, dft_size.height); - dft_size_opt.height = std::min(dft_size.width, dft_size.height); - } - - CV_Assert( dft_size_opt.width > 1 ); - - cufftType dft_type = CUFFT_R2C; - if (is_complex_input) - dft_type = is_complex_output ? CUFFT_C2C : CUFFT_C2R; - - cufftHandle plan; - if (is_1d_input || is_row_dft) - cufftSafeCall( cufftPlan1d(&plan, dft_size_opt.width, dft_type, dft_size_opt.height) ); - else - cufftSafeCall( cufftPlan2d(&plan, dft_size_opt.height, dft_size_opt.width, dft_type) ); - - cufftSafeCall( cufftSetStream(plan, StreamAccessor::getStream(stream)) ); - - if (is_complex_input) - { - if (is_complex_output) - { - createContinuous(dft_size, CV_32FC2, _dst); - GpuMat dst = _dst.getGpuMat(); - - cufftSafeCall(cufftExecC2C( - plan, src_cont.ptr(), dst.ptr(), - is_inverse ? CUFFT_INVERSE : CUFFT_FORWARD)); - } - else - { - createContinuous(dft_size, CV_32F, _dst); - GpuMat dst = _dst.getGpuMat(); - - cufftSafeCall(cufftExecC2R( - plan, src_cont.ptr(), dst.ptr())); - } - } - else - { - // We could swap dft_size for efficiency. Here we must reflect it - if (dft_size == dft_size_opt) - createContinuous(Size(dft_size.width / 2 + 1, dft_size.height), CV_32FC2, _dst); - else - createContinuous(Size(dft_size.width, dft_size.height / 2 + 1), CV_32FC2, _dst); - - GpuMat dst = _dst.getGpuMat(); - - cufftSafeCall(cufftExecR2C( - plan, src_cont.ptr(), dst.ptr())); - } - - cufftSafeCall( cufftDestroy(plan) ); - - if (is_scaled_dft) - cuda::multiply(_dst, Scalar::all(1. / dft_size.area()), _dst, 1, -1, stream); - + return makePtr(dft_size, flags); #endif } diff --git a/modules/cudaarithm/test/test_arithm.cpp b/modules/cudaarithm/test/test_arithm.cpp index 257f5233cc..3e99ed4f3f 100644 --- a/modules/cudaarithm/test/test_arithm.cpp +++ b/modules/cudaarithm/test/test_arithm.cpp @@ -250,6 +250,33 @@ CUDA_TEST_P(Dft, C2C) } } +CUDA_TEST_P(Dft, Algorithm) +{ + int cols = randomInt(2, 100); + int rows = randomInt(2, 100); + + int flags = 0; + cv::Ptr dft = cv::cuda::createDFT(cv::Size(cols, rows), flags); + + for (int i = 0; i < 5; ++i) + { + SCOPED_TRACE("dft algorithm"); + + cv::Mat a = randomMat(cv::Size(cols, rows), CV_32FC2, 0.0, 10.0); + + cv::cuda::GpuMat d_b; + cv::cuda::GpuMat d_b_data; + dft->compute(loadMat(a), d_b); + + cv::Mat b_gold; + cv::dft(a, b_gold, flags); + + ASSERT_EQ(CV_32F, d_b.depth()); + ASSERT_EQ(2, d_b.channels()); + EXPECT_MAT_NEAR(b_gold, cv::Mat(d_b), rows * cols * 1e-4); + } +} + namespace { void testR2CThenC2R(const std::string& hint, int cols, int rows, bool inplace) From 29680100ac10f5ec2f1172efa50431d94be8483b Mon Sep 17 00:00:00 2001 From: Naba Kumar Date: Wed, 15 Mar 2017 08:40:08 +0200 Subject: [PATCH 024/144] Support for creating streams with custom allocator --- modules/core/include/opencv2/core/cuda.hpp | 3 +++ modules/core/src/cuda_stream.cpp | 27 ++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/modules/core/include/opencv2/core/cuda.hpp b/modules/core/include/opencv2/core/cuda.hpp index 4c5c522e24..8856520c1a 100644 --- a/modules/core/include/opencv2/core/cuda.hpp +++ b/modules/core/include/opencv2/core/cuda.hpp @@ -507,6 +507,9 @@ public: //! creates a new asynchronous stream Stream(); + //! creates a new asynchronous stream with custom allocator + Stream(const Ptr& allocator); + /** @brief Returns true if the current stream queue is finished. Otherwise, it returns false. */ bool queryIfComplete() const; diff --git a/modules/core/src/cuda_stream.cpp b/modules/core/src/cuda_stream.cpp index 24ecbd4ab0..696771404c 100644 --- a/modules/core/src/cuda_stream.cpp +++ b/modules/core/src/cuda_stream.cpp @@ -282,9 +282,10 @@ public: cudaStream_t stream; bool ownStream; - Ptr stackAllocator; + Ptr allocator; Impl(); + Impl(const Ptr& allocator); explicit Impl(cudaStream_t stream); ~Impl(); @@ -295,17 +296,23 @@ cv::cuda::Stream::Impl::Impl() : stream(0), ownStream(false) cudaSafeCall( cudaStreamCreate(&stream) ); ownStream = true; - stackAllocator = makePtr(stream); + allocator = makePtr(stream); +} + +cv::cuda::Stream::Impl::Impl(const Ptr& allocator) : stream(0), ownStream(false), allocator(allocator) +{ + cudaSafeCall( cudaStreamCreate(&stream) ); + ownStream = true; } cv::cuda::Stream::Impl::Impl(cudaStream_t stream_) : stream(stream_), ownStream(false) { - stackAllocator = makePtr(stream); + allocator = makePtr(stream); } cv::cuda::Stream::Impl::~Impl() { - stackAllocator.release(); + allocator.release(); if (stream && ownStream) { @@ -417,6 +424,16 @@ cv::cuda::Stream::Stream() #endif } +cv::cuda::Stream::Stream(const Ptr& allocator) +{ +#ifndef HAVE_CUDA + (void) allocator; + throw_no_cuda(); +#else + impl_ = makePtr(allocator); +#endif +} + bool cv::cuda::Stream::queryIfComplete() const { #ifndef HAVE_CUDA @@ -675,7 +692,7 @@ cv::cuda::BufferPool::BufferPool(Stream& stream) throw_no_cuda(); } #else -cv::cuda::BufferPool::BufferPool(Stream& stream) : allocator_(stream.impl_->stackAllocator) +cv::cuda::BufferPool::BufferPool(Stream& stream) : allocator_(stream.impl_->allocator) { } #endif From 2918c3d75a34c307bc3993cb34189757d27b918a Mon Sep 17 00:00:00 2001 From: q Date: Tue, 21 Mar 2017 14:51:19 +0000 Subject: [PATCH 025/144] First occurence of 4-directional version of SGBM. Even without any tests. Next step is parallelising it. --- modules/calib3d/include/opencv2/calib3d.hpp | 3 +- modules/calib3d/src/stereosgbm.cpp | 798 +++++++++++++++++++- 2 files changed, 763 insertions(+), 38 deletions(-) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index 5a0e020d31..dd28d97e7f 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -1809,7 +1809,8 @@ public: { MODE_SGBM = 0, MODE_HH = 1, - MODE_SGBM_3WAY = 2 + MODE_SGBM_3WAY = 2, + MODE_HH4 = 1 }; CV_WRAP virtual int getPreFilterCap() const = 0; diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp index 27ce62e6f9..bedc477e8b 100644 --- a/modules/calib3d/src/stereosgbm.cpp +++ b/modules/calib3d/src/stereosgbm.cpp @@ -301,9 +301,9 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, const CostType MAX_COST = SHRT_MAX; int minD = params.minDisparity, maxD = minD + params.numDisparities; - Size SADWindowSize; - SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; - int ftzero = std::max(params.preFilterCap, 15) | 1; + Size SADWindowSize; //4e: SAD means Sum of Absolute Differences + SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; //4e: and this is always square + int ftzero = std::max(params.preFilterCap, 15) | 1; //4e:ftzero clips x-derivatives. I think, this story with arrays is about non-realized SIMD method int uniquenessRatio = params.uniquenessRatio >= 0 ? params.uniquenessRatio : 10; int disp12MaxDiff = params.disp12MaxDiff > 0 ? params.disp12MaxDiff : 1; int P1 = params.P1 > 0 ? params.P1 : 2, P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); @@ -313,11 +313,11 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, int INVALID_DISP = minD - 1, INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; int SW2 = SADWindowSize.width/2, SH2 = SADWindowSize.height/2; bool fullDP = params.mode == StereoSGBM::MODE_HH; - int npasses = fullDP ? 2 : 1; - const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; + int npasses = fullDP ? 2 : 1; //4e: 2 passes with different behaviour for Hirshmueller method. + const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; //4e: array is such big due to derivative could be +-8*256 in worst cases PixType clipTab[TAB_SIZE]; - for( k = 0; k < TAB_SIZE; k++ ) + for( k = 0; k < TAB_SIZE; k++ ) //4e: If ftzero would = 4, array containment will be = -4 -4 -4 ... -4 -3 -2 -1 0 1 2 3 4 ... 4 4 4 clipTab[k] = (PixType)(std::min(std::max(k - TAB_OFS, -ftzero), ftzero) + ftzero); if( minX1 >= maxX1 ) @@ -330,25 +330,25 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, // NR - the number of directions. the loop on x below that computes Lr assumes that NR == 8. // if you change NR, please, modify the loop as well. - int D2 = D+16, NRD2 = NR2*D2; + int D2 = D+16, NRD2 = NR2*D2; //4e: Somewhere in code we need d+1, so D+1. One of simplest solutuons is increasing D-dimension on 1. But 1 is 16, when storage should be aligned. // the number of L_r(.,.) and min_k L_r(.,.) lines in the buffer: // for 8-way dynamic programming we need the current row and // the previous row, i.e. 2 rows in total - const int NLR = 2; - const int LrBorder = NLR - 1; + const int NLR = 2; //4e: We assume, that we need one or more previous steps in our linear dynamic(one right here). + const int LrBorder = NLR - 1; //4e: for simplification of calculations we need border for taking previous dynamic solutions. // for each possible stereo match (img1(x,y) <=> img2(x-d,y)) // we keep pixel difference cost (C) and the summary cost over NR directions (S). // we also keep all the partial costs for the previous line L_r(x,d) and also min_k L_r(x, k) size_t costBufSize = width1*D; - size_t CSBufSize = costBufSize*(fullDP ? height : 1); - size_t minLrSize = (width1 + LrBorder*2)*NR2, LrSize = minLrSize*D2; + size_t CSBufSize = costBufSize*(fullDP ? height : 1); //4e: For HH mode it's better to keep whole array of costs. + size_t minLrSize = (width1 + LrBorder*2)*NR2, LrSize = minLrSize*D2; //4e: TODO: Understand why NR2 per pass instead od NR2/2 (Probably, without any reason. That doesn't make code wrong) int hsumBufNRows = SH2*2 + 2; size_t totalBufSize = (LrSize + minLrSize)*NLR*sizeof(CostType) + // minLr[] and Lr[] - costBufSize*(hsumBufNRows + 1)*sizeof(CostType) + // hsumBuf, pixdiff - CSBufSize*2*sizeof(CostType) + // C, S - width*16*img1.channels()*sizeof(PixType) + // temp buffer for computing per-pixel cost + costBufSize*(hsumBufNRows + 1)*sizeof(CostType) + // hsumBuf, pixdiff //4e: TODO: Why we should increase sum window height one more time? + CSBufSize*2*sizeof(CostType) + // C, S //4e: C is Block sum of costs, S is multidirectional dynamic sum with same size + width*16*img1.channels()*sizeof(PixType) + // temp buffer for computing per-pixel cost //4e: It is needed for calcPixelCostBT function, as "buffer" value width*(sizeof(CostType) + sizeof(DispType)) + 1024; // disp2cost + disp2 if( buffer.empty() || !buffer.isContinuous() || @@ -361,7 +361,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, CostType* hsumBuf = Sbuf + CSBufSize; CostType* pixDiff = hsumBuf + costBufSize*hsumBufNRows; - CostType* disp2cost = pixDiff + costBufSize + (LrSize + minLrSize)*NLR; + CostType* disp2cost = pixDiff + costBufSize + (LrSize + minLrSize)*NLR; //4e: It is containers for backwards disparity, made by S[d] too, but with other method DispType* disp2ptr = (DispType*)(disp2cost + width); PixType* tempBuf = (PixType*)(disp2ptr + width); @@ -373,21 +373,21 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, { int x1, y1, x2, y2, dx, dy; - if( pass == 1 ) + if( pass == 1 ) //4e: on the first pass, we work down, so calculate directions down, diagdown and right { y1 = 0; y2 = height; dy = 1; x1 = 0; x2 = width1; dx = 1; } - else + else //4e: on the second pass, we work up, so calculate directions up, diagup and up { y1 = height-1; y2 = -1; dy = -1; x1 = width1-1; x2 = -1; dx = -1; } - CostType *Lr[NLR]={0}, *minLr[NLR]={0}; + CostType *Lr[NLR]={0}, *minLr[NLR]={0}; //4e: arrays for L(x,y,r,d) of previous and current rows and minimums of them - for( k = 0; k < NLR; k++ ) - { + for( k = 0; k < NLR; k++ ) //4e: One of them is needed, and one of them is stored. So, we need to swap pointer + { //4e: Yes, and this is done at the end of next cycle, not here. // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, // and will occasionally use negative indices with the arrays // we need to shift Lr[k] pointers by 1, to give the space for d=-1. @@ -408,28 +408,28 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, if( pass == 1 ) // compute C on the first pass, and reuse it on the second pass, if any. { - int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; + int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; //4e: for first line's block sum we need calculate half-window of costs and only one for other for( k = dy1; k <= dy2; k++ ) { - CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; + CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; //4e: Ring buffer for horizontally summed lines if( k < height ) { calcPixelCostBT( img1, img2, k, minD, maxD, pixDiff, tempBuf, clipTab, TAB_OFS, ftzero ); memset(hsumAdd, 0, D*sizeof(CostType)); - for( x = 0; x <= SW2*D; x += D ) + for( x = 0; x <= SW2*D; x += D ) //4e: Calculation summed costs for all disparities in first pixel of line { int scale = x == 0 ? SW2 + 1 : 1; for( d = 0; d < D; d++ ) hsumAdd[d] = (CostType)(hsumAdd[d] + pixDiff[x + d]*scale); } - if( y > 0 ) - { + if( y > 0 ) //4e: We calculate horizontal sums and forming full block sums for y coord by adding this horsums to previous line's sums and subtracting stored lowest + { //4e: horsum in hsumBuf. Exception is case y=0, where we need many iterations per lines to create full blocking sum. const CostType* hsumSub = hsumBuf + (std::max(y - SH2 - 1, 0) % hsumBufNRows)*costBufSize; - const CostType* Cprev = !fullDP || y == 0 ? C : C - costBufSize; + const CostType* Cprev = !fullDP || y == 0 ? C : C - costBufSize; //4e: Well, actually y>0, so we don't need this check: y==0 for( x = D; x < width1*D; x += D ) { @@ -465,8 +465,8 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } else { - for( x = D; x < width1*D; x += D ) - { + for( x = D; x < width1*D; x += D ) //4e: Calcluates horizontal sums if (y==0). This piece of code is calling SH2+1 times and then result is used in different way + { //4e: to create full blocks sum. That's why this code is isolated from upper case. const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); @@ -476,7 +476,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } } - if( y == 0 ) + if( y == 0 ) //4e: Calculating first full block sum. { int scale = k == 0 ? SH2 + 1 : 1; for( x = 0; x < width1*D; x++ ) @@ -485,13 +485,13 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } // also, clear the S buffer - for( k = 0; k < width1*D; k++ ) + for( k = 0; k < width1*D; k++ ) //4e: only on first pass, so it keep old information, don't be confused S[k] = 0; } // clear the left and the right borders - memset( Lr[0] - NRD2*LrBorder - 8, 0, NRD2*LrBorder*sizeof(CostType) ); - memset( Lr[0] + width1*NRD2 - 8, 0, NRD2*LrBorder*sizeof(CostType) ); + memset( Lr[0] - NRD2*LrBorder - 8, 0, NRD2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory + memset( Lr[0] + width1*NRD2 - 8, 0, NRD2*LrBorder*sizeof(CostType) ); //4e: ...00000000|NRD2-16 of real costs value(and some of them are zeroes too)|00000000... memset( minLr[0] - NR2*LrBorder, 0, NR2*LrBorder*sizeof(CostType) ); memset( minLr[0] + width1*NR2, 0, NR2*LrBorder*sizeof(CostType) ); @@ -613,7 +613,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, for( d = 0; d < D; d++ ) { - int Cpd = Cp[d], L0, L1, L2, L3; + int Cpd = Cp[d], L0, L1, L2, L3; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually L0 = Cpd + std::min((int)Lr_p0[d], std::min(Lr_p0[d-1] + P1, std::min(Lr_p0[d+1] + P1, delta0))) - delta0; L1 = Cpd + std::min((int)Lr_p1[d], std::min(Lr_p1[d-1] + P1, std::min(Lr_p1[d+1] + P1, delta1))) - delta1; @@ -654,7 +654,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, CostType* Sp = S + x*D; int minS = MAX_COST, bestDisp = -1; - if( npasses == 1 ) + if( npasses == 1 ) //4e: in this case we could take fifth direction almost for free(direction "left") { int xm = x*NR2, xd = xm*D2; @@ -804,7 +804,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, disp1ptr[x + minX1] = (DispType)(d + minD*DISP_SCALE); } - for( x = minX1; x < maxX1; x++ ) + for( x = minX1; x < maxX1; x++ ) //4e: Left-right check itself { // we round the computed disparity both towards -inf and +inf and check // if either of the corresponding disparities in disp2 is consistent. @@ -815,8 +815,8 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, int _d = d1 >> DISP_SHIFT; int d_ = (d1 + DISP_SCALE-1) >> DISP_SHIFT; int _x = x - _d, x_ = x - d_; - if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && - 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) + if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && //4e: To dismiss disparity, we should assure, that there is no any + 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) //4e: chance to understand this as correct. disp1ptr[x] = (DispType)INVALID_DISP_SCALED; } } @@ -828,8 +828,732 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } } +//////////////////////////////////////////////////////////////////////////////////////////// + +/* + This is new experimential version of disparity calculation, which should be parralled after +TODO: Don't forget to rewrire this commentaries after + + computes disparity for "roi" in img1 w.r.t. img2 and write it to disp1buf. + that is, disp1buf(x, y)=d means that img1(x+roi.x, y+roi.y) ~ img2(x+roi.x-d, y+roi.y). + minD <= d < maxD. + disp2full is the reverse disparity map, that is: + disp2full(x+roi.x,y+roi.y)=d means that img2(x+roi.x, y+roi.y) ~ img1(x+roi.x+d, y+roi.y) + + note that disp1buf will have the same size as the roi and + disp2full will have the same size as img1 (or img2). + On exit disp2buf is not the final disparity, it is an intermediate result that becomes + final after all the tiles are processed. + + the disparity in disp1buf is written with sub-pixel accuracy + (4 fractional bits, see StereoSGBM::DISP_SCALE), + using quadratic interpolation, while the disparity in disp2buf + is written as is, without interpolation. + + disp2cost also has the same size as img1 (or img2). + It contains the minimum current cost, used to find the best disparity, corresponding to the minimal cost. + */ +static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, + Mat& disp1, const StereoSGBMParams& params, + Mat& buffer ) +{ +//#if CV_SIMD128 +// // maxDisparity is supposed to multiple of 16, so we can forget doing else +// static const uchar LSBTab[] = +// { +// 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +// }; +// static const v_uint16x8 v_LSB = v_uint16x8(0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); +// +// bool useSIMD = hasSIMD128(); +//#endif + + const int ALIGN = 16; + const int DISP_SHIFT = StereoMatcher::DISP_SHIFT; + const int DISP_SCALE = (1 << DISP_SHIFT); + const CostType MAX_COST = SHRT_MAX; + + int minD = params.minDisparity, maxD = minD + params.numDisparities; + Size SADWindowSize; //4e: SAD means Sum of Absolute Differences + SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; //4e: and this is always square + int ftzero = std::max(params.preFilterCap, 15) | 1; //4e:ftzero clips x-derivatives. I think, this story with arrays is about non-realized SIMD method + int uniquenessRatio = params.uniquenessRatio >= 0 ? params.uniquenessRatio : 10; + int disp12MaxDiff = params.disp12MaxDiff > 0 ? params.disp12MaxDiff : 1; + int P1 = params.P1 > 0 ? params.P1 : 2, P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion + int k, width = disp1.cols, height = disp1.rows; + int minX1 = std::max(maxD, 0), maxX1 = width + std::min(minD, 0); + int D = maxD - minD, width1 = maxX1 - minX1; + int INVALID_DISP = minD - 1, INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; + int SW2 = SADWindowSize.width/2, SH2 = SADWindowSize.height/2; + const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; //4e: array is such big due to derivative could be +-8*256 in worst cases + PixType clipTab[TAB_SIZE]; + + for( k = 0; k < TAB_SIZE; k++ ) //4e: If ftzero would = 4, array containment will be = -4 -4 -4 ... -4 -3 -2 -1 0 1 2 3 4 ... 4 4 4 + clipTab[k] = (PixType)(std::min(std::max(k - TAB_OFS, -ftzero), ftzero) + ftzero); + + if( minX1 >= maxX1 ) + { + disp1 = Scalar::all(INVALID_DISP_SCALED); + return; + } + + CV_Assert( D % 16 == 0 ); //TODO: Are you sure? By the way, why not 8? + + // NR - the number of directions. the loop on x below that computes Lr assumes that NR == 8. + // if you change NR, please, modify the loop as well. + int D2 = D+16; //4e: Somewhere in code we need d+1, so D+1. One of simplest solutuons is increasing D-dimension on 1. But 1 is 16, when storage should be aligned. + + // the number of L_r(.,.) and min_k L_r(.,.) lines in the buffer: + // for 8-way dynamic programming we need the current row and + // the previous row, i.e. 2 rows in total + const int NLR = 2; //4e: We assume, that we need one or more previous steps in our linear dynamic(one right here). + const int LrBorder = NLR - 1; //4e: for simplification of calculations we need border for taking previous dynamic solutions. + + // for each possible stereo match (img1(x,y) <=> img2(x-d,y)) + // we keep pixel difference cost (C) and the summary cost over NR directions (S). + // we also keep all the partial costs for the previous line L_r(x,d) and also min_k L_r(x, k) + size_t costBufSize = width1*D; + size_t CSBufSize = costBufSize*height; //4e: For HH mode it's better to keep whole array of costs. + size_t minLrSize = (width1 + LrBorder*2), LrSize = minLrSize*D2; //4e: TODO: Understand why NR2 per pass instead od NR2/2 (Probably, without any reason. That doesn't make code wrong) + int hsumBufNRows = SH2*2 + 2; + size_t totalBufSize = (LrSize + minLrSize)*NLR*sizeof(CostType) + // minLr[] and Lr[] + costBufSize*(hsumBufNRows + 1)*sizeof(CostType) + // hsumBuf, pixdiff //4e: TODO: Why we should increase sum window height one more time? + CSBufSize*2*sizeof(CostType) + // C, S //4e: C is Block sum of costs, S is multidirectional dynamic sum with same size + width*16*img1.channels()*sizeof(PixType) + // temp buffer for computing per-pixel cost //4e: It is needed for calcPixelCostBT function, as "buffer" value + width*(sizeof(CostType) + sizeof(DispType)) + 1024; // disp2cost + disp2 + + if( buffer.empty() || !buffer.isContinuous() || + buffer.cols*buffer.rows*buffer.elemSize() < totalBufSize ) + buffer.create(1, (int)totalBufSize, CV_8U); + + // summary cost over different (nDirs) directions + CostType* Cbuf = (CostType*)alignPtr(buffer.ptr(), ALIGN); + CostType* Sbuf = Cbuf + CSBufSize; + CostType* hsumBuf = Sbuf + CSBufSize; + CostType* pixDiff = hsumBuf + costBufSize*hsumBufNRows; + + CostType* disp2cost = pixDiff + costBufSize + (LrSize + minLrSize)*NLR; //4e: It is containers for backwards disparity, made by S[d] too, but with other method + DispType* disp2ptr = (DispType*)(disp2cost + width); + PixType* tempBuf = (PixType*)(disp2ptr + width); + + // add P2 to every C(x,y). it saves a few operations in the inner loops + for(k = 0; k < (int)CSBufSize; k++ ) + Cbuf[k] = (CostType)P2; + + // Two vertical passes - up to down and down to up + for( int pass = 1; pass <= 2; pass++ ) //TODO: rename this magic 2. + { + int y1, y2, dy; + + if( pass == 1 ) + { + y1 = 0; y2 = height; dy = 1; + } + else + { + y1 = height-1; y2 = -1; dy = -1; + } + + CostType *Lr[NLR]={0}, *minLr[NLR]={0}; //4e: arrays for L(x,y,r,d) of previous and current rows and minimums of them + + for( k = 0; k < NLR; k++ ) //4e: One of them is needed, and one of them is stored. So, we need to swap pointer + { //4e: Yes, and this is done at the end of next cycle, not here. + // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, + // and will occasionally use negative indices with the arrays + // we need to shift Lr[k] pointers by 1, to give the space for d=-1. + // however, then the alignment will be imperfect, i.e. bad for SSE, + // thus we shift the pointers by 8 (8*sizeof(short) == 16 - ideal alignment) + Lr[k] = pixDiff + costBufSize + LrSize*k + D2*LrBorder + 8; + memset( Lr[k] - LrBorder*D2 - 8, 0, LrSize*sizeof(CostType) ); + minLr[k] = pixDiff + costBufSize + LrSize*NLR + minLrSize*k + LrBorder; + memset( minLr[k] - LrBorder, 0, minLrSize*sizeof(CostType) ); + } + + for( int y = y1; y != y2; y += dy ) + { + int x, d; + CostType* C = Cbuf + y*costBufSize; + CostType* S = Sbuf + y*costBufSize; + + if( pass == 1 ) // compute C on the first pass, and reuse it on the second pass, if any. + { + int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; //4e: for first line's block sum we need calculate half-window of costs and only one for other + + for( k = dy1; k <= dy2; k++ ) + { + CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; //4e: Ring buffer for horizontally summed lines + + if( k < height ) + { + calcPixelCostBT( img1, img2, k, minD, maxD, pixDiff, tempBuf, clipTab, TAB_OFS, ftzero ); + + memset(hsumAdd, 0, D*sizeof(CostType)); + for( x = 0; x <= SW2*D; x += D ) //4e: Calculation summed costs for all disparities in first pixel of line + { + int scale = x == 0 ? SW2 + 1 : 1; + for( d = 0; d < D; d++ ) + hsumAdd[d] = (CostType)(hsumAdd[d] + pixDiff[x + d]*scale); + } + + if( y > 0 ) //4e: We calculate horizontal sums and forming full block sums for y coord by adding this horsums to previous line's sums and subtracting stored lowest + { //4e: horsum in hsumBuf. Exception is case y=0, where we need many iterations per lines to create full blocking sum. + const CostType* hsumSub = hsumBuf + (std::max(y - SH2 - 1, 0) % hsumBufNRows)*costBufSize; + const CostType* Cprev = !fullDP || y == 0 ? C : C - costBufSize; //4e: Well, actually y>0, so we don't need this check: y==0 + + for( x = D; x < width1*D; x += D ) + { + const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); + const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 hv = v_load(hsumAdd + x - D + d); +// v_int16x8 Cx = v_load(Cprev + x + d); +// v_int16x8 psub = v_load(pixSub + d); +// v_int16x8 padd = v_load(pixAdd + d); +// hv = (hv - psub + padd); +// psub = v_load(hsumSub + x + d); +// Cx = Cx - psub + hv; +// v_store(hsumAdd + x + d, hv); +// v_store(C + x + d, Cx); +// } +// } +// else +// #endif + { + for( d = 0; d < D; d++ ) + { + int hv = hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]); + C[x + d] = (CostType)(Cprev[x + d] + hv - hsumSub[x + d]); + } + } + } + } + else + { + for( x = D; x < width1*D; x += D ) //4e: Calcluates horizontal sums if (y==0). This piece of code is calling SH2+1 times and then result is used in different way + { //4e: to create full blocks sum. That's why this code is isolated from upper case. + const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); + const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); + + for( d = 0; d < D; d++ ) + hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]); + } + } + } + + if( y == 0 ) //4e: Calculating first full block sum. + { + int scale = k == 0 ? SH2 + 1 : 1; + for( x = 0; x < width1*D; x++ ) + C[x] = (CostType)(C[x] + hsumAdd[x]*scale); + } + } + + // also, clear the S buffer + for( k = 0; k < width1*D; k++ ) //4e: only on first pass, so it keep old information, don't be confused + S[k] = 0; + } + + // clear the left and the right borders + memset( Lr[0] - D2*LrBorder - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory + memset( Lr[0] + width1*D2 - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: ...00000000|D2-16 of real costs value(and some of them are zeroes too)|00000000... + memset( minLr[0] - LrBorder, 0, LrBorder*sizeof(CostType) ); + memset( minLr[0] + width1, 0, LrBorder*sizeof(CostType) ); + + /* + [formula 13 in the paper] + compute L_r(p, d) = C(p, d) + + min(L_r(p-r, d), + L_r(p-r, d-1) + P1, + L_r(p-r, d+1) + P1, + min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) + where p = (x,y), r is one of the directions. + we process all the directions at once: + 0: r=(-dx, 0) + 1: r=(-1, -dy) + 2: r=(0, -dy) + 3: r=(1, -dy) + 4: r=(-2, -dy) + 5: r=(-1, -dy*2) + 6: r=(1, -dy*2) + 7: r=(2, -dy) + */ + for( x = 0; x != width; x++ ) + { + int xd = x*D2; + + int delta = minLr[1][x]; + + CostType* Lr_ppr = Lr[1] + xd; + + Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; + + CostType* Lr_p = Lr[0] + xd; + const CostType* Cp = C + x*D; + CostType* Sp = S + x*D; + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _P1 = v_setall_s16((short)P1); +// +// v_int16x8 _delta0 = v_setall_s16((short)delta0); +// v_int16x8 _delta1 = v_setall_s16((short)delta1); +// v_int16x8 _delta2 = v_setall_s16((short)delta2); +// v_int16x8 _delta3 = v_setall_s16((short)delta3); +// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); +// +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 Cpd = v_load(Cp + d); +// v_int16x8 L0, L1, L2, L3; +// +// L0 = v_load(Lr_p0 + d); +// L1 = v_load(Lr_p1 + d); +// L2 = v_load(Lr_ppr + d); +// L3 = v_load(Lr_p3 + d); +// +// L0 = v_min(L0, (v_load(Lr_p0 + d - 1) + _P1)); +// L0 = v_min(L0, (v_load(Lr_p0 + d + 1) + _P1)); +// +// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); +// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); +// +// L2 = v_min(L2, (v_load(Lr_ppr + d - 1) + _P1)); +// L2 = v_min(L2, (v_load(Lr_ppr + d + 1) + _P1)); +// +// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); +// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); +// +// L0 = v_min(L0, _delta0); +// L0 = ((L0 - _delta0) + Cpd); +// +// L1 = v_min(L1, _delta1); +// L1 = ((L1 - _delta1) + Cpd); +// +// L2 = v_min(L2, _delta2); +// L2 = ((L2 - _delta2) + Cpd); +// +// L3 = v_min(L3, _delta3); +// L3 = ((L3 - _delta3) + Cpd); +// +// v_store(Lr_p + d, L0); +// v_store(Lr_p + d + D2, L1); +// v_store(Lr_p + d + D2*2, L2); +// v_store(Lr_p + d + D2*3, L3); +// +// // Get minimum from in L0-L3 +// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; +// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... +// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... +// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... +// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... +// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... +// v_int16x8 t0 = v_min(t0123L, t0123H); +// _minL0 = v_min(_minL0, t0); +// +// v_int16x8 Sval = v_load(Sp + d); +// +// L0 = L0 + L1; +// L2 = L2 + L3; +// Sval = Sval + L0; +// Sval = Sval + L2; +// +// v_store(Sp + d, Sval); +// } +// +// v_int32x4 minL, minH; +// v_expand(_minL0, minL, minH); +// v_pack_store(&minLr[0][x], v_min(minL, minH)); +// } +// else +// #endif + { + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) + { + int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL0 = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L0); + } + minLr[0][x] = (CostType)minL; + } + } + + // now shift the cyclic buffers + std::swap( Lr[0], Lr[1] ); + std::swap( minLr[0], minLr[1] ); + } + } + +// for( int pass = 1; pass <= 2; pass++ ) //pass=1 or left-to-right pass + { + + CostType *Lr, *minLr; + + { //4e: Yes, and this is done at the end of next cycle, not here. + // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, + // and will occasionally use negative indices with the arrays + // we need to shift Lr[k] pointers by 1, to give the space for d=-1. + // however, then the alignment will be imperfect, i.e. bad for SSE, + // thus we shift the pointers by 8 (8*sizeof(short) == 16 - ideal alignment) + Lr = pixDiff + costBufSize + D2*LrBorder + 8; + memset( Lr - LrBorder*D2 - 8, 0, LrSize*sizeof(CostType) ); + minLr = pixDiff + costBufSize + LrSize*NLR + LrBorder; + memset( minLr - LrBorder, 0, minLrSize*sizeof(CostType) ); + } + + for( int y = 0; y != height; y++) + { + int x, d; + DispType* disp1ptr = disp1.ptr(y); + CostType* C = Cbuf + costBufSize; + CostType* S = Sbuf + costBufSize; + + for( x = 0; x < width; x++ ) + { + disp1ptr[x] = disp2ptr[x] = (DispType)INVALID_DISP_SCALED; + disp2cost[x] = MAX_COST; + } + + // clear the left and the right borders //TODO: Well, two of that memsets we could delete, but rest of them is direction-dependent + memset( Lr - D2*LrBorder - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory + memset( Lr + width1*D2 - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: ...00000000|D2-16 of real costs value(and some of them are zeroes too)|00000000... + memset( minLr - LrBorder, 0, LrBorder*sizeof(CostType) ); + memset( minLr + width1, 0, LrBorder*sizeof(CostType) ); + + /* + [formula 13 in the paper] + compute L_r(p, d) = C(p, d) + + min(L_r(p-r, d), + L_r(p-r, d-1) + P1, + L_r(p-r, d+1) + P1, + min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) + where p = (x,y), r is one of the directions. + we process all the directions at once: + 0: r=(-dx, 0) + 1: r=(-1, -dy) + 2: r=(0, -dy) + 3: r=(1, -dy) + 4: r=(-2, -dy) + 5: r=(-1, -dy*2) + 6: r=(1, -dy*2) + 7: r=(2, -dy) + */ + for( x = 0; x != width1; x++) + { + int xd = x*D2; + + int delta = minLr[x - 1]; + + CostType* Lr_ppr = Lr + xd - D2; + + Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; + + CostType* Lr_p = Lr + xd; + const CostType* Cp = C + x*D; + CostType* Sp = S + x*D; + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _P1 = v_setall_s16((short)P1); +// +// v_int16x8 _delta0 = v_setall_s16((short)delta0); +// v_int16x8 _delta1 = v_setall_s16((short)delta1); +// v_int16x8 _delta2 = v_setall_s16((short)delta2); +// v_int16x8 _delta3 = v_setall_s16((short)delta3); +// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); +// +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 Cpd = v_load(Cp + d); +// v_int16x8 L0, L1, L2, L3; +// +// L0 = v_load(Lr_ppr + d); +// L1 = v_load(Lr_p1 + d); +// L2 = v_load(Lr_p2 + d); +// L3 = v_load(Lr_p3 + d); +// +// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); +// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); +// +// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); +// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); +// +// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); +// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); +// +// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); +// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); +// +// L0 = v_min(L0, _delta0); +// L0 = ((L0 - _delta0) + Cpd); +// +// L1 = v_min(L1, _delta1); +// L1 = ((L1 - _delta1) + Cpd); +// +// L2 = v_min(L2, _delta2); +// L2 = ((L2 - _delta2) + Cpd); +// +// L3 = v_min(L3, _delta3); +// L3 = ((L3 - _delta3) + Cpd); +// +// v_store(Lr_p + d, L0); +// v_store(Lr_p + d + D2, L1); +// v_store(Lr_p + d + D2*2, L2); +// v_store(Lr_p + d + D2*3, L3); +// +// // Get minimum from in L0-L3 +// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; +// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... +// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... +// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... +// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... +// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... +// v_int16x8 t0 = v_min(t0123L, t0123H); +// _minL0 = v_min(_minL0, t0); +// +// v_int16x8 Sval = v_load(Sp + d); +// +// L0 = L0 + L1; +// L2 = L2 + L3; +// Sval = Sval + L0; +// Sval = Sval + L2; +// +// v_store(Sp + d, Sval); +// } +// +// v_int32x4 minL, minH; +// v_expand(_minL0, minL, minH); +// v_pack_store(&minLr[x], v_min(minL, minH)); +// } +// else +// #endif + { + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) + { + int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + + L0 = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL0 = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L); + } + minLr[x] = (CostType)minL0; + } + } + + for( x = width1-1; x != -1; x--) + { + int xd = x*D2; + + int delta = minLr[x + 1]; + + CostType* Lr_ppr = Lr + xd + D2; + + Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; + + CostType* Lr_p = Lr + xd; + const CostType* Cp = C + x*D; + CostType* Sp = S + x*D; + int minS = MAX_COST, bestDisp = -1; + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _P1 = v_setall_s16((short)P1); +// +// v_int16x8 _delta0 = v_setall_s16((short)delta0); +// v_int16x8 _delta1 = v_setall_s16((short)delta1); +// v_int16x8 _delta2 = v_setall_s16((short)delta2); +// v_int16x8 _delta3 = v_setall_s16((short)delta3); +// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); +// +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 Cpd = v_load(Cp + d); +// v_int16x8 L0, L1, L2, L3; +// +// L0 = v_load(Lr_ppr + d); +// L1 = v_load(Lr_p1 + d); +// L2 = v_load(Lr_p2 + d); +// L3 = v_load(Lr_p3 + d); +// +// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); +// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); +// +// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); +// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); +// +// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); +// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); +// +// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); +// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); +// +// L0 = v_min(L0, _delta0); +// L0 = ((L0 - _delta0) + Cpd); +// +// L1 = v_min(L1, _delta1); +// L1 = ((L1 - _delta1) + Cpd); +// +// L2 = v_min(L2, _delta2); +// L2 = ((L2 - _delta2) + Cpd); +// +// L3 = v_min(L3, _delta3); +// L3 = ((L3 - _delta3) + Cpd); +// +// v_store(Lr_p + d, L0); +// v_store(Lr_p + d + D2, L1); +// v_store(Lr_p + d + D2*2, L2); +// v_store(Lr_p + d + D2*3, L3); +// +// // Get minimum from in L0-L3 +// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; +// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... +// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... +// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... +// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... +// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... +// v_int16x8 t0 = v_min(t0123L, t0123H); +// _minL0 = v_min(_minL0, t0); +// +// v_int16x8 Sval = v_load(Sp + d); +// +// L0 = L0 + L1; +// L2 = L2 + L3; +// Sval = Sval + L0; +// Sval = Sval + L2; +// +// v_store(Sp + d, Sval); +// } +// +// v_int32x4 minL, minH; +// v_expand(_minL0, minL, minH); +// v_pack_store(&minLr[x], v_min(minL, minH)); +// } +// else +// #endif +//TODO:Next piece of code is came from postprocessing. Be very careful with joining them!!! +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _minS = v_setall_s16(MAX_COST), _bestDisp = v_setall_s16(-1); +// v_int16x8 _d8 = v_int16x8(0, 1, 2, 3, 4, 5, 6, 7), _8 = v_setall_s16(8); +// +// for( d = 0; d < D; d+= 8 ) +// { +// v_int16x8 L0 = v_load(Sp + d); +// v_int16x8 mask = L0 < _minS; +// _minS = v_min( L0, _minS ); +// _bestDisp = _bestDisp ^ ((_bestDisp ^ _d8) & mask); +// _d8 = _d8 + _8; +// } +// v_int32x4 _d0, _d1; +// v_expand(_minS, _d0, _d1); +// minS = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); +// v_int16x8 v_mask = v_setall_s16((short)minS) == _minS; +// +// _bestDisp = (_bestDisp & v_mask) | (v_setall_s16(SHRT_MAX) & ~v_mask); +// v_expand(_bestDisp, _d0, _d1); +// bestDisp = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); +// } +// else +// #endif + { + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) + { + int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + + L0 = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL0 = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L); + if( Sp[d] < minS ) + { + minS = Sp[d]; + bestDisp = d; + } + } + minLr[x] = (CostType)minL0; + } + //Some postprocessing procedures and saving + for( d = 0; d < D; d++ ) + { + if( Sp[d]*(100 - uniquenessRatio) < minS*100 && std::abs(bestDisp - d) > 1 ) + break; + } + if( d < D ) + continue; + d = bestDisp; + int _x2 = x + minX1 - d - minD; + if( disp2cost[_x2] > minS ) + { + disp2cost[_x2] = (CostType)minS; + disp2ptr[_x2] = (DispType)(d + minD); + } + + if( 0 < d && d < D-1 ) + { + // do subpixel quadratic interpolation: + // fit parabola into (x1=d-1, y1=Sp[d-1]), (x2=d, y2=Sp[d]), (x3=d+1, y3=Sp[d+1]) + // then find minimum of the parabola. + int denom2 = std::max(Sp[d-1] + Sp[d+1] - 2*Sp[d], 1); + d = d*DISP_SCALE + ((Sp[d-1] - Sp[d+1])*DISP_SCALE + denom2)/(denom2*2); + } + else + d *= DISP_SCALE; + disp1ptr[x + minX1] = (DispType)(d + minD*DISP_SCALE); + } + //Left-right check sanity procedure + for( x = minX1; x < maxX1; x++ ) + { + // we round the computed disparity both towards -inf and +inf and check + // if either of the corresponding disparities in disp2 is consistent. + // This is to give the computed disparity a chance to look valid if it is. + int d1 = disp1ptr[x]; + if( d1 == INVALID_DISP_SCALED ) + continue; + int _d = d1 >> DISP_SHIFT; + int d_ = (d1 + DISP_SCALE-1) >> DISP_SHIFT; + int _x = x - _d, x_ = x - d_; + if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && //4e: To dismiss disparity, we should assure, that there is no any + 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) //4e: chance to understand this as correct. + disp1ptr[x] = (DispType)INVALID_DISP_SCALED; + } + } + } +} + ////////////////////////////////////////////////////////////////////////////////////////////////////// + void getBufferPointers(Mat& buffer, int width, int width1, int D, int num_ch, int SH2, int P2, CostType*& curCostVolumeLine, CostType*& hsumBuf, CostType*& pixDiff, PixType*& tmpBuf, CostType*& horPassCostVolume, From a56bd1fbba37a9bd9b68d13f688c9cfc855fda63 Mon Sep 17 00:00:00 2001 From: Vladislav Sovrasov Date: Wed, 22 Mar 2017 16:08:25 +0300 Subject: [PATCH 026/144] Make aruco dependency optional for interactive calibration app --- apps/interactive-calibration/CMakeLists.txt | 5 +++- .../frameProcessor.cpp | 12 +++++++--- .../frameProcessor.hpp | 6 ++++- apps/interactive-calibration/main.cpp | 24 ++++++++++++------- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/apps/interactive-calibration/CMakeLists.txt b/apps/interactive-calibration/CMakeLists.txt index 735c4538ef..41abf7c908 100644 --- a/apps/interactive-calibration/CMakeLists.txt +++ b/apps/interactive-calibration/CMakeLists.txt @@ -1,4 +1,7 @@ -set(OPENCV_INTERACTIVECALIBRATION_DEPS opencv_core opencv_imgproc opencv_features2d opencv_aruco opencv_highgui opencv_calib3d opencv_videoio) +set(OPENCV_INTERACTIVECALIBRATION_DEPS opencv_core opencv_imgproc opencv_features2d opencv_highgui opencv_calib3d opencv_videoio) +if(${BUILD_opencv_aruco}) + list(APPEND OPENCV_INTERACTIVECALIBRATION_DEPS opencv_aruco) +endif() ocv_check_dependencies(${OPENCV_INTERACTIVECALIBRATION_DEPS}) if(NOT OCV_DEPENDENCIES_FOUND) diff --git a/apps/interactive-calibration/frameProcessor.cpp b/apps/interactive-calibration/frameProcessor.cpp index 1e672b0c45..07b32dbe12 100644 --- a/apps/interactive-calibration/frameProcessor.cpp +++ b/apps/interactive-calibration/frameProcessor.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -75,6 +74,7 @@ bool CalibProcessor::detectAndParseChessboard(const cv::Mat &frame) bool CalibProcessor::detectAndParseChAruco(const cv::Mat &frame) { +#ifdef HAVE_OPENCV_ARUCO cv::Ptr board = mCharucoBoard.staticCast(); std::vector > corners, rejected; @@ -95,14 +95,16 @@ bool CalibProcessor::detectAndParseChAruco(const cv::Mat &frame) } centerX /= currentCharucoCorners.size[0]; centerY /= currentCharucoCorners.size[0]; - //cv::circle(frame, cv::Point2f(centerX, centerY), 10, cv::Scalar(0, 255, 0), 10); + mTemplateLocations.insert(mTemplateLocations.begin(), cv::Point2f(centerX, centerY)); cv::aruco::drawDetectedCornersCharuco(frame, currentCharucoCorners, currentCharucoIds); mCurrentCharucoCorners = currentCharucoCorners; mCurrentCharucoIds = currentCharucoIds; return true; } - +#else + (void)frame; +#endif return false; } @@ -231,6 +233,7 @@ bool CalibProcessor::checkLastFrame() } } else { +#ifdef HAVE_OPENCV_ARUCO cv::Mat r, t, angles; std::vector allObjPoints; allObjPoints.reserve(mCurrentCharucoIds.total()); @@ -248,6 +251,7 @@ bool CalibProcessor::checkLastFrame() mCalibData->allCharucoCorners.pop_back(); mCalibData->allCharucoIds.pop_back(); } +#endif } return isFrameBad; } @@ -266,10 +270,12 @@ CalibProcessor::CalibProcessor(cv::Ptr data, captureParameters switch(mBoardType) { case chAruco: +#ifdef HAVE_OPENCV_ARUCO mArucoDictionary = cv::aruco::getPredefinedDictionary( cv::aruco::PREDEFINED_DICTIONARY_NAME(capParams.charucoDictName)); mCharucoBoard = cv::aruco::CharucoBoard::create(mBoardSize.width, mBoardSize.height, capParams.charucoSquareLenght, capParams.charucoMarkerSize, mArucoDictionary); +#endif break; case AcirclesGrid: mBlobDetectorPtr = cv::SimpleBlobDetector::create(); diff --git a/apps/interactive-calibration/frameProcessor.hpp b/apps/interactive-calibration/frameProcessor.hpp index 4dbb8ab314..222b83143f 100644 --- a/apps/interactive-calibration/frameProcessor.hpp +++ b/apps/interactive-calibration/frameProcessor.hpp @@ -6,8 +6,10 @@ #define FRAME_PROCESSOR_HPP #include -#include #include +#ifdef HAVE_OPENCV_ARUCO +#include +#endif #include "calibCommon.hpp" #include "calibController.hpp" @@ -37,8 +39,10 @@ protected: cv::Mat mCurrentCharucoIds; cv::Ptr mBlobDetectorPtr; +#ifdef HAVE_OPENCV_ARUCO cv::Ptr mArucoDictionary; cv::Ptr mCharucoBoard; +#endif int mNeededFramesNum; unsigned mDelayBetweenCaptures; diff --git a/apps/interactive-calibration/main.cpp b/apps/interactive-calibration/main.cpp index af62d4ea40..10d3690b89 100644 --- a/apps/interactive-calibration/main.cpp +++ b/apps/interactive-calibration/main.cpp @@ -4,10 +4,13 @@ #include #include -#include #include #include +#ifdef HAVE_OPENCV_ARUCO +#include +#endif + #include #include #include @@ -50,31 +53,27 @@ bool calib::showOverlayMessage(const std::string& message) #endif } -static void deleteButton(int state, void* data) +static void deleteButton(int, void* data) { - state++; //to avoid gcc warnings (static_cast*>(data))->get()->deleteLastFrame(); calib::showOverlayMessage("Last frame deleted"); } -static void deleteAllButton(int state, void* data) +static void deleteAllButton(int, void* data) { - state++; (static_cast*>(data))->get()->deleteAllData(); calib::showOverlayMessage("All frames deleted"); } -static void saveCurrentParamsButton(int state, void* data) +static void saveCurrentParamsButton(int, void* data) { - state++; if((static_cast*>(data))->get()->saveCurrentCameraParameters()) calib::showOverlayMessage("Calibration parameters saved"); } #ifdef HAVE_QT -static void switchVisualizationModeButton(int state, void* data) +static void switchVisualizationModeButton(int, void* data) { - state++; ShowProcessor* processor = static_cast(((cv::Ptr*)data)->get()); processor->switchVisualizationMode(); } @@ -103,6 +102,11 @@ int main(int argc, char** argv) captureParameters capParams = paramsController.getCaptureParameters(); internalParameters intParams = paramsController.getInternalParameters(); +#ifndef HAVE_OPENCV_ARUCO + if(capParams.board == chAruco) + CV_Error(cv::Error::StsNotImplemented, "Aruco module is disabled in current build configuration." + " Consider usage of another calibration pattern\n"); +#endif cv::TermCriteria solverTermCrit = cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, intParams.solverMaxIters, intParams.solverEps); @@ -172,6 +176,7 @@ int main(int argc, char** argv) calibrationFlags, solverTermCrit); } else { +#ifdef HAVE_OPENCV_ARUCO cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(capParams.charucoDictName)); cv::Ptr charucoboard = @@ -183,6 +188,7 @@ int main(int argc, char** argv) globalData->cameraMatrix, globalData->distCoeffs, cv::noArray(), cv::noArray(), globalData->stdDeviations, cv::noArray(), globalData->perViewErrors, calibrationFlags, solverTermCrit); +#endif } dataController->updateUndistortMap(); dataController->printParametersToConsole(std::cout); From 5ebf066dd529aa496c1954f66e8cd89378eb3448 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Tue, 14 Mar 2017 15:24:21 +0300 Subject: [PATCH 027/144] Updated OpenVX detector and wrappers to handle Reference attribute names change --- 3rdparty/openvx/hal/openvx_hal.cpp | 3 ++- 3rdparty/openvx/include/ivx.hpp | 6 ++++++ cmake/FindOpenVX.cmake | 14 ++++++++++++++ cmake/checks/openvx_refenum_test.cpp | 5 +++++ 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 cmake/checks/openvx_refenum_test.cpp diff --git a/3rdparty/openvx/hal/openvx_hal.cpp b/3rdparty/openvx/hal/openvx_hal.cpp index 2999f929c5..cc3e034b3a 100644 --- a/3rdparty/openvx/hal/openvx_hal.cpp +++ b/3rdparty/openvx/hal/openvx_hal.cpp @@ -11,6 +11,7 @@ #include #include #include +#include //================================================================================================== // utility @@ -1076,7 +1077,7 @@ int ovx_hal_integral(int depth, int sdepth, int, const uchar * a, size_t astep, ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U32, ivx::Image::createAddressing(w, h, 4, (vx_int32)bstep), (unsigned int *)(b + bstep + sizeof(unsigned int))); ivx::IVX_CHECK_STATUS(vxuIntegralImage(ctx, ia, ib)); - memset(b, 0, (w + 1) * sizeof(unsigned int)); + std::memset(b, 0, (w + 1) * sizeof(unsigned int)); b += bstep; for (int i = 0; i < h; i++, b += bstep) { diff --git a/3rdparty/openvx/include/ivx.hpp b/3rdparty/openvx/include/ivx.hpp index 47213e6d5c..5c3029d617 100644 --- a/3rdparty/openvx/include/ivx.hpp +++ b/3rdparty/openvx/include/ivx.hpp @@ -32,6 +32,12 @@ static const vx_enum VX_INTERPOLATION_NEAREST_NEIGHBOR = VX_INTERPOLATION_TYPE_N static const vx_enum VX_BORDER_CONSTANT = VX_BORDER_MODE_CONSTANT; static const vx_enum VX_BORDER_REPLICATE = VX_BORDER_MODE_REPLICATE; +#else + + #ifdef IVX_RENAMED_REFS + static const vx_enum VX_REF_ATTRIBUTE_TYPE = VX_REFERENCE_TYPE; + #endif + #endif #ifndef IVX_USE_CXX98 diff --git a/cmake/FindOpenVX.cmake b/cmake/FindOpenVX.cmake index 0a55e951d8..6cba52717c 100644 --- a/cmake/FindOpenVX.cmake +++ b/cmake/FindOpenVX.cmake @@ -25,6 +25,20 @@ endif() if(OPENVX_INCLUDE_DIR AND OPENVX_LIBRARIES) set(HAVE_OPENVX TRUE) + + try_compile(OPENVX_RENAMED_REF + "${OpenCV_BINARY_DIR}" + "${OpenCV_SOURCE_DIR}/cmake/checks/openvx_refenum_test.cpp" + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${OPENVX_INCLUDE_DIR}" + LINK_LIBRARIES ${OPENVX_LIBRARIES} + OUTPUT_VARIABLE OUTPUT + ) + if(OPENVX_RENAMED_REF) + add_definitions(-DIVX_RENAMED_REFS=1) + message(STATUS "OpenVX: Checking reference attribute name convention... New") + else() + message(STATUS "OpenVX: Checking reference attribute name convention... Old") + endif() endif() if(NOT HAVE_OPENVX) diff --git a/cmake/checks/openvx_refenum_test.cpp b/cmake/checks/openvx_refenum_test.cpp new file mode 100644 index 0000000000..f28db050cb --- /dev/null +++ b/cmake/checks/openvx_refenum_test.cpp @@ -0,0 +1,5 @@ +#include +int main() +{ + return VX_REFERENCE_COUNT == VX_REFERENCE_TYPE ? VX_REFERENCE_NAME : 0; +} From eae1ebfd29d1e7a521bec89b3ab0627e714110f2 Mon Sep 17 00:00:00 2001 From: "KUANG, Fangjun" Date: Wed, 22 Mar 2017 22:03:29 +0100 Subject: [PATCH 028/144] fix issue 8411. --- modules/core/include/opencv2/core/mat.hpp | 1 + modules/core/include/opencv2/core/mat.inl.hpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index e3a24032d0..f1a2ee42e0 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -177,6 +177,7 @@ public: template _InputArray(const std::vector<_Tp>& vec); _InputArray(const std::vector& vec); template _InputArray(const std::vector >& vec); + _InputArray(const std::vector >&); template _InputArray(const std::vector >& vec); template _InputArray(const _Tp* vec, int n); template _InputArray(const Matx<_Tp, m, n>& matx); diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index b3b7110cbc..556c3e7a23 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -85,6 +85,10 @@ template inline _InputArray::_InputArray(const std::vector >& vec) { init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); } +inline +_InputArray::_InputArray(const std::vector >&) +{ CV_Error(Error::StsUnsupportedFormat, "std::vector > is not supported!\n"); } + template inline _InputArray::_InputArray(const std::vector >& vec) { init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_READ, &vec); } From 03c4c37969d80ebaa50df32f6b3228380ded524b Mon Sep 17 00:00:00 2001 From: "KUANG, Fangjun" Date: Wed, 22 Mar 2017 22:24:20 +0100 Subject: [PATCH 029/144] fix issue 8189. --- modules/core/src/matrix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 135397aa7d..2e479f7c56 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -1395,7 +1395,7 @@ void _InputArray::getMatVector(std::vector& mv) const { const std::vector& v = *(const std::vector*)obj; - size_t n = v.size(), esz = CV_ELEM_SIZE(flags); + size_t n = size().width, esz = CV_ELEM_SIZE(flags); int t = CV_MAT_DEPTH(flags), cn = CV_MAT_CN(flags); mv.resize(n); From 94521629abfd328e23cd52f8c19f4d0d546ac819 Mon Sep 17 00:00:00 2001 From: Fangjun KUANG Date: Wed, 22 Mar 2017 23:24:47 +0100 Subject: [PATCH 030/144] fix issue 8411. --- modules/core/include/opencv2/core/mat.hpp | 1 + modules/core/include/opencv2/core/mat.inl.hpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index f1a2ee42e0..89369a947d 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -294,6 +294,7 @@ public: template _OutputArray(std::vector<_Tp>& vec); _OutputArray(std::vector& vec); template _OutputArray(std::vector >& vec); + _OutputArray(std::vector >&); template _OutputArray(std::vector >& vec); template _OutputArray(Mat_<_Tp>& m); template _OutputArray(_Tp* vec, int n); diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 556c3e7a23..df8ec483c0 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -161,6 +161,10 @@ template inline _OutputArray::_OutputArray(std::vector >& vec) { init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +inline +_OutputArray::_OutputArray(std::vector >&) +{ CV_Error(Error::StsUnsupportedFormat, "std::vector > cannot be an output array\n"); } + template inline _OutputArray::_OutputArray(std::vector >& vec) { init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_WRITE, &vec); } From 874fb7ae78e64e5f0482954933f2b08caa2b48b3 Mon Sep 17 00:00:00 2001 From: Chaoshuai Lu Date: Wed, 22 Mar 2017 22:04:27 -0700 Subject: [PATCH 031/144] Fix MatToUIImage method crash when the step is not equal to cols * elemSize() --- modules/imgcodecs/src/ios_conversions.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/imgcodecs/src/ios_conversions.mm b/modules/imgcodecs/src/ios_conversions.mm index eed867a790..2db873acd0 100644 --- a/modules/imgcodecs/src/ios_conversions.mm +++ b/modules/imgcodecs/src/ios_conversions.mm @@ -53,7 +53,7 @@ void UIImageToMat(const UIImage* image, cv::Mat& m, bool alphaExist); UIImage* MatToUIImage(const cv::Mat& image) { NSData *data = [NSData dataWithBytes:image.data - length:image.elemSize()*image.total()]; + length:image.step.p[0] * image.rows]; CGColorSpaceRef colorSpace; @@ -73,7 +73,7 @@ UIImage* MatToUIImage(const cv::Mat& image) { // Creating CGImage from cv::Mat CGImageRef imageRef = CGImageCreate(image.cols, image.rows, - 8, + 8 * image.elemSize1(), 8 * image.elemSize(), image.step.p[0], colorSpace, From de7018539de6e213d3cc18d8a62de2c5131cb8b8 Mon Sep 17 00:00:00 2001 From: Chaoshuai Lu Date: Wed, 22 Mar 2017 22:20:42 -0700 Subject: [PATCH 032/144] Fix UIImageToMat method by taking image scale information into account --- modules/imgcodecs/src/ios_conversions.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgcodecs/src/ios_conversions.mm b/modules/imgcodecs/src/ios_conversions.mm index 2db873acd0..202cfe30d1 100644 --- a/modules/imgcodecs/src/ios_conversions.mm +++ b/modules/imgcodecs/src/ios_conversions.mm @@ -97,7 +97,7 @@ UIImage* MatToUIImage(const cv::Mat& image) { void UIImageToMat(const UIImage* image, cv::Mat& m, bool alphaExist) { CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage); - CGFloat cols = image.size.width, rows = image.size.height; + CGFloat cols = CGImageGetWidth(image.CGImage), rows = CGImageGetHeight(image.CGImage); CGContextRef contextRef; CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast; if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelMonochrome) From a321cce5e44ab767c52def328664b47d19dfa1cd Mon Sep 17 00:00:00 2001 From: Egor Pugin Date: Thu, 23 Mar 2017 14:42:23 +0300 Subject: [PATCH 033/144] Fix build under directories with '.cpp' string. --- cmake/cl2cpp.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/cl2cpp.cmake b/cmake/cl2cpp.cmake index ed5dcb8761..dfcc2e6833 100644 --- a/cmake/cl2cpp.cmake +++ b/cmake/cl2cpp.cmake @@ -9,7 +9,7 @@ if (NOT cl_list) message(FATAL_ERROR "Can't find OpenCL kernels in directory: ${CL_DIR}") endif() -string(REPLACE ".cpp" ".hpp" OUTPUT_HPP "${OUTPUT}") +string(REGEX REPLACE "\\.cpp$" ".hpp" OUTPUT_HPP "${OUTPUT}") get_filename_component(OUTPUT_HPP_NAME "${OUTPUT_HPP}" NAME) if("${MODULE_NAME}" STREQUAL "ocl") From f70cc29edb8a606fb859eaa67a4c9609f7f904fa Mon Sep 17 00:00:00 2001 From: Julian Tanke Date: Thu, 23 Mar 2017 14:00:19 +0100 Subject: [PATCH 034/144] export SVM::trainAuto to python #7224 (#8373) * export SVM::trainAuto to python #7224 * workaround for ABI compatibility of SVM::trainAuto * add parameter comments to new SVM::trainAuto function * Export ParamGrid member variables --- modules/ml/include/opencv2/ml.hpp | 66 ++++++++++++++++++++++++++++-- modules/ml/src/inner_functions.cpp | 4 ++ modules/ml/src/svm.cpp | 37 +++++++++++++++++ 3 files changed, 103 insertions(+), 4 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index fc2ce5fec3..a8b7114674 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -104,7 +104,7 @@ enum SampleTypes It is used for optimizing statmodel accuracy by varying model parameters, the accuracy estimate being computed by cross-validation. */ -class CV_EXPORTS ParamGrid +class CV_EXPORTS_W ParamGrid { public: /** @brief Default constructor */ @@ -112,8 +112,8 @@ public: /** @brief Constructor with parameters */ ParamGrid(double _minVal, double _maxVal, double _logStep); - double minVal; //!< Minimum value of the statmodel parameter. Default value is 0. - double maxVal; //!< Maximum value of the statmodel parameter. Default value is 0. + CV_PROP_RW double minVal; //!< Minimum value of the statmodel parameter. Default value is 0. + CV_PROP_RW double maxVal; //!< Maximum value of the statmodel parameter. Default value is 0. /** @brief Logarithmic step for iterating the statmodel parameter. The grid determines the following iteration sequence of the statmodel parameter values: @@ -122,7 +122,15 @@ public: \f[\texttt{minVal} * \texttt{logStep} ^n < \texttt{maxVal}\f] The grid is logarithmic, so logStep must always be greater then 1. Default value is 1. */ - double logStep; + CV_PROP_RW double logStep; + + /** @brief Creates a ParamGrid Ptr that can be given to the %SVM::trainAuto method + + @param minVal minimum value of the parameter grid + @param maxVal maximum value of the parameter grid + @param logstep Logarithmic step for iterating the statmodel parameter + */ + CV_WRAP static Ptr create(double minVal=0., double maxVal=0., double logstep=1.); }; /** @brief Class encapsulating training data. @@ -691,6 +699,46 @@ public: ParamGrid degreeGrid = getDefaultGrid(DEGREE), bool balanced=false) = 0; + /** @brief Trains an %SVM with optimal parameters + + @param samples training samples + @param layout See ml::SampleTypes. + @param responses vector of responses associated with the training samples. + @param kFold Cross-validation parameter. The training set is divided into kFold subsets. One + subset is used to test the model, the others form the train set. So, the %SVM algorithm is + @param Cgrid grid for C + @param gammaGrid grid for gamma + @param pGrid grid for p + @param nuGrid grid for nu + @param coeffGrid grid for coeff + @param degreeGrid grid for degree + @param balanced If true and the problem is 2-class classification then the method creates more + balanced cross-validation subsets that is proportions between classes in subsets are close + to such proportion in the whole train dataset. + + The method trains the %SVM model automatically by choosing the optimal parameters C, gamma, p, + nu, coef0, degree. Parameters are considered optimal when the cross-validation + estimate of the test set error is minimal. + + This function only makes use of SVM::getDefaultGrid for parameter optimization and thus only + offers rudimentary parameter options. + + This function works for the classification (SVM::C_SVC or SVM::NU_SVC) as well as for the + regression (SVM::EPS_SVR or SVM::NU_SVR). If it is SVM::ONE_CLASS, no optimization is made and + the usual %SVM with parameters specified in params is executed. + */ + CV_WRAP bool trainAuto(InputArray samples, + int layout, + InputArray responses, + int kFold = 10, + Ptr Cgrid = SVM::getDefaultGridPtr(SVM::C), + Ptr gammaGrid = SVM::getDefaultGridPtr(SVM::GAMMA), + Ptr pGrid = SVM::getDefaultGridPtr(SVM::P), + Ptr nuGrid = SVM::getDefaultGridPtr(SVM::NU), + Ptr coeffGrid = SVM::getDefaultGridPtr(SVM::COEF), + Ptr degreeGrid = SVM::getDefaultGridPtr(SVM::DEGREE), + bool balanced=false); + /** @brief Retrieves all the support vectors The method returns all the support vectors as a floating-point matrix, where support vectors are @@ -733,6 +781,16 @@ public: */ static ParamGrid getDefaultGrid( int param_id ); + /** @brief Generates a grid for %SVM parameters. + + @param param_id %SVM parameters IDs that must be one of the SVM::ParamTypes. The grid is + generated for the parameter with this ID. + + The function generates a grid pointer for the specified parameter of the %SVM algorithm. + The grid may be passed to the function SVM::trainAuto. + */ + CV_WRAP static Ptr getDefaultGridPtr( int param_id ); + /** Creates empty model. Use StatModel::train to train the model. Since %SVM has several parameters, you may want to find the best parameters for your problem, it can be done with SVM::trainAuto. */ diff --git a/modules/ml/src/inner_functions.cpp b/modules/ml/src/inner_functions.cpp index 3966906823..819d409cd0 100644 --- a/modules/ml/src/inner_functions.cpp +++ b/modules/ml/src/inner_functions.cpp @@ -50,6 +50,10 @@ ParamGrid::ParamGrid(double _minVal, double _maxVal, double _logStep) logStep = std::max(_logStep, 1.); } +Ptr ParamGrid::create(double minval, double maxval, double logstep) { + return makePtr(minval, maxval, logstep); +} + bool StatModel::empty() const { return !isTrained(); } int StatModel::getVarCount() const { return 0; } diff --git a/modules/ml/src/svm.cpp b/modules/ml/src/svm.cpp index 5e5b89163e..d486d26655 100644 --- a/modules/ml/src/svm.cpp +++ b/modules/ml/src/svm.cpp @@ -362,6 +362,12 @@ static void sortSamplesByClasses( const Mat& _samples, const Mat& _responses, //////////////////////// SVM implementation ////////////////////////////// +Ptr SVM::getDefaultGridPtr( int param_id) +{ + ParamGrid grid = getDefaultGrid(param_id); // this is not a nice solution.. + return makePtr(grid.minVal, grid.maxVal, grid.logStep); +} + ParamGrid SVM::getDefaultGrid( int param_id ) { ParamGrid grid; @@ -1920,6 +1926,24 @@ public: bool returnDFVal; }; + bool trainAuto_(InputArray samples, int layout, + InputArray responses, int kfold, Ptr Cgrid, + Ptr gammaGrid, Ptr pGrid, Ptr nuGrid, + Ptr coeffGrid, Ptr degreeGrid, bool balanced) + { + Ptr data = TrainData::create(samples, layout, responses); + return this->trainAuto( + data, kfold, + *Cgrid.get(), + *gammaGrid.get(), + *pGrid.get(), + *nuGrid.get(), + *coeffGrid.get(), + *degreeGrid.get(), + balanced); + } + + float predict( InputArray _samples, OutputArray _results, int flags ) const { float result = 0; @@ -2281,6 +2305,19 @@ Mat SVM::getUncompressedSupportVectors() const return this_->getUncompressedSupportVectors_(); } +bool SVM::trainAuto(InputArray samples, int layout, + InputArray responses, int kfold, Ptr Cgrid, + Ptr gammaGrid, Ptr pGrid, Ptr nuGrid, + Ptr coeffGrid, Ptr degreeGrid, bool balanced) +{ + SVMImpl* this_ = dynamic_cast(this); + if (!this_) { + CV_Error(Error::StsNotImplemented, "the class is not SVMImpl"); + } + return this_->trainAuto_(samples, layout, responses, + kfold, Cgrid, gammaGrid, pGrid, nuGrid, coeffGrid, degreeGrid, balanced); +} + } } From 17e5e4cd5af61a32198f11f768d4bd1d1c47a277 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 22 Mar 2017 14:46:34 +0300 Subject: [PATCH 035/144] core: CPU target dispatcher update - use suffixes like '.avx.cpp' - added CMake-generated files for '.simd.hpp' optimization approach - wrap HAL intrinsic headers into separate namespaces for different build flags - automatic vzeroupper insertion (via CV_INSTRUMENT_REGION macro) --- cmake/OpenCVCompilerOptimizations.cmake | 103 ++++++++++++++++-- cmake/OpenCVModule.cmake | 13 ++- cmake/OpenCVPCHSupport.cmake | 10 +- .../include/opencv2/core/cv_cpu_dispatch.h | 27 +++++ .../core/include/opencv2/core/cv_cpu_helper.h | 87 +++++++++------ modules/core/include/opencv2/core/cvdef.h | 11 ++ .../core/include/opencv2/core/hal/intrin.hpp | 30 +++++ .../include/opencv2/core/hal/intrin_cpp.hpp | 8 +- .../include/opencv2/core/hal/intrin_neon.hpp | 6 +- .../include/opencv2/core/hal/intrin_sse.hpp | 6 +- modules/core/include/opencv2/core/private.hpp | 10 +- .../cv_cpu_include_simd_declarations.hpp | 30 +++++ modules/world/CMakeLists.txt | 1 + 13 files changed, 284 insertions(+), 58 deletions(-) create mode 100644 modules/core/include/opencv2/core/private/cv_cpu_include_simd_declarations.hpp diff --git a/cmake/OpenCVCompilerOptimizations.cmake b/cmake/OpenCVCompilerOptimizations.cmake index b849f02b14..9b48dc857f 100644 --- a/cmake/OpenCVCompilerOptimizations.cmake +++ b/cmake/OpenCVCompilerOptimizations.cmake @@ -275,6 +275,11 @@ set(CPU_BASELINE_FLAGS "") set(CPU_BASELINE_FINAL "") set(CPU_DISPATCH_FINAL "") +if(CV_DISABLE_OPTIMIZATION) + set(CPU_DISPATCH "") + set(CPU_DISPATCH_REQUIRE "") +endif() + macro(ocv_check_compiler_optimization OPT) if(NOT DEFINED CPU_${OPT}_SUPPORTED) if((DEFINED CPU_${OPT}_FLAGS_ON AND NOT "x${CPU_${OPT}_FLAGS_ON}" STREQUAL "x") OR CPU_${OPT}_TEST_FILE) @@ -319,7 +324,7 @@ macro(ocv_check_compiler_optimization OPT) endmacro() foreach(OPT ${CPU_KNOWN_OPTIMIZATIONS}) - set(CPU_${OPT}_USAGE_COUNT 0 CACHE INTERNAL "" FORCE) + set(CPU_${OPT}_USAGE_COUNT 0 CACHE INTERNAL "") if(NOT DEFINED CPU_${OPT}_FORCE) set(CPU_${OPT}_FORCE "${CPU_${OPT}_IMPLIES}") endif() @@ -515,15 +520,27 @@ macro(ocv_compiler_optimization_process_sources SOURCES_VAR_NAME LIBS_VAR_NAME T endforeach() foreach(fname ${${SOURCES_VAR_NAME}}) string(TOLOWER "${fname}" fname_LOWER) - if(fname_LOWER MATCHES "[.]opt_.*[.]cpp$") - if(CV_DISABLE_OPTIMIZATION OR NOT CV_ENABLE_INTRINSICS) - message(STATUS "Excluding from source files list: ${fname}") + if(fname_LOWER MATCHES "\\.(.*)\\.cpp$") + string(TOUPPER "${CMAKE_MATCH_1}" OPT_) + if(OPT_ MATCHES "(CUDA.*|DISPATCH.*|OCL)") # don't touch files like filename.cuda.cpp + list(APPEND __result "${fname}") + #continue() + elseif(CV_DISABLE_OPTIMIZATION OR NOT CV_ENABLE_INTRINSICS) + message(STATUS "Excluding from source files list (optimization is disabled): ${fname}") #continue() else() + get_source_file_property(__definitions "${fname}" COMPILE_DEFINITIONS) + if(__definitions) + list(APPEND __definitions "CV_CPU_DISPATCH_MODE=${OPT_}") + else() + set(__definitions "CV_CPU_DISPATCH_MODE=${OPT_}") + endif() + set_source_files_properties("${fname}" PROPERTIES COMPILE_DEFINITIONS "${__definitions}") + set(__opt_found 0) foreach(OPT ${CPU_BASELINE_FINAL}) string(TOLOWER "${OPT}" OPT_LOWER) - if(fname_LOWER MATCHES "_${OPT_LOWER}[.]cpp$") + if(fname_LOWER MATCHES "\\.${OPT_LOWER}\\.cpp$") #message("${fname} BASELINE-${OPT}") set(__opt_found 1) list(APPEND __result "${fname}") @@ -533,11 +550,11 @@ macro(ocv_compiler_optimization_process_sources SOURCES_VAR_NAME LIBS_VAR_NAME T foreach(OPT ${CPU_DISPATCH_FINAL}) foreach(OPT2 ${CPU_DISPATCH_${OPT}_FORCED}) string(TOLOWER "${OPT2}" OPT2_LOWER) - if(fname_LOWER MATCHES "_${OPT2_LOWER}[.]cpp$") + if(fname_LOWER MATCHES "\\.${OPT2_LOWER}\\.cpp$") list(APPEND __result_${OPT} "${fname}") math(EXPR CPU_${OPT}_USAGE_COUNT "${CPU_${OPT}_USAGE_COUNT}+1") set(CPU_${OPT}_USAGE_COUNT "${CPU_${OPT}_USAGE_COUNT}" CACHE INTERNAL "" FORCE) -#message("${fname} ${OPT}") +#message("(${CPU_${OPT}_USAGE_COUNT})${fname} ${OPT}") #message(" ${CPU_DISPATCH_${OPT}_INCLUDED}") #message(" ${CPU_DISPATCH_DEFINITIONS_${OPT}}") #message(" ${CPU_DISPATCH_FLAGS_${OPT}}") @@ -573,7 +590,13 @@ macro(ocv_compiler_optimization_process_sources SOURCES_VAR_NAME LIBS_VAR_NAME T list(APPEND __result "$") else() foreach(fname ${__result_${OPT}}) - set_source_files_properties("${fname}" PROPERTIES COMPILE_DEFINITIONS "${CPU_DISPATCH_DEFINITIONS_${OPT}}") + get_source_file_property(__definitions "${fname}" COMPILE_DEFINITIONS) + if(__definitions) + list(APPEND __definitions "${CPU_DISPATCH_DEFINITIONS_${OPT}}") + else() + set(__definitions "${CPU_DISPATCH_DEFINITIONS_${OPT}}") + endif() + set_source_files_properties("${fname}" PROPERTIES COMPILE_DEFINITIONS "${__definitions}") set_source_files_properties("${fname}" PROPERTIES COMPILE_FLAGS "${CPU_DISPATCH_FLAGS_${OPT}}") endforeach() list(APPEND __result ${__result_${OPT}}) @@ -620,18 +643,25 @@ macro(ocv_compiler_optimization_fill_cpu_config) set(OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE "${OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE} #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_${OPT} # define CV_CPU_HAS_SUPPORT_${OPT} 1 -# define CV_CPU_CALL_${OPT}(...) return __VA_ARGS__ +# define CV_CPU_CALL_${OPT}(fn, args) return (opt_${OPT}::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_${OPT} # define CV_CPU_HAS_SUPPORT_${OPT} (cv::checkHardwareSupport(CV_CPU_${OPT})) -# define CV_CPU_CALL_${OPT}(...) if (CV_CPU_HAS_SUPPORT_${OPT}) return __VA_ARGS__ +# define CV_CPU_CALL_${OPT}(fn, args) if (CV_CPU_HAS_SUPPORT_${OPT}) return (opt_${OPT}::fn args) #else # define CV_CPU_HAS_SUPPORT_${OPT} 0 -# define CV_CPU_CALL_${OPT}(...) +# define CV_CPU_CALL_${OPT}(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_${OPT}(fn, args, mode, ...) CV_CPU_CALL_${OPT}(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) ") endif() endforeach() + set(OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE "${OPENCV_CPU_CONTROL_DEFINITIONS_CONFIGMAKE} +#define CV_CPU_CALL_BASELINE(fn, args) return (cpu_baseline::fn args) +#define __CV_CPU_DISPATCH_CHAIN_BASELINE(fn, args, mode, ...) CV_CPU_CALL_BASELINE(fn, args) /* last in sequence */ +") + + set(__file "${CMAKE_SOURCE_DIR}/modules/core/include/opencv2/core/cv_cpu_helper.h") if(EXISTS "${__file}") file(READ "${__file}" __content) @@ -644,6 +674,57 @@ macro(ocv_compiler_optimization_fill_cpu_config) endif() endmacro() +macro(ocv_add_dispatched_file filename) + if(NOT OPENCV_INITIAL_PASS) + set(__codestr " +#include \"precomp.hpp\" +#include \"${filename}.simd.hpp\" +") + + set(__declarations_str "#define CV_CPU_SIMD_FILENAME \"${filename}.simd.hpp\"") + set(__dispatch_modes "BASELINE") + + set(__optimizations "${ARGN}") + if(CV_DISABLE_OPTIMIZATION OR NOT CV_ENABLE_INTRINSICS) + set(__optimizations "") + endif() + + foreach(OPT ${__optimizations}) + string(TOLOWER "${OPT}" OPT_LOWER) + set(__file "${CMAKE_CURRENT_BINARY_DIR}/${filename}.${OPT_LOWER}.cpp") + if(EXISTS "${__file}") + file(READ "${__file}" __content) + endif() + if(__content STREQUAL __codestr) + #message(STATUS "${__file} contains up-to-date content") + else() + file(WRITE "${__file}" "${__codestr}") + endif() + list(APPEND OPENCV_MODULE_${the_module}_SOURCES_DISPATCHED "${__file}") + + set(__declarations_str "${__declarations_str} +#define CV_CPU_DISPATCH_MODE ${OPT} +#include \"opencv2/core/private/cv_cpu_include_simd_declarations.hpp\" +") + set(__dispatch_modes "${OPT}, ${__dispatch_modes}") + endforeach() + + set(__declarations_str "${__declarations_str} +#define CV_CPU_DISPATCH_MODES_ALL ${__dispatch_modes} +") + + set(__file "${CMAKE_CURRENT_BINARY_DIR}/${filename}.simd_declarations.hpp") + if(EXISTS "${__file}") + file(READ "${__file}" __content) + endif() + if(__content STREQUAL __declarations_str) + #message(STATUS "${__file} contains up-to-date content") + else() + file(WRITE "${__file}" "${__declarations_str}") + endif() + endif() +endmacro() + if(CV_DISABLE_OPTIMIZATION OR CV_ICC) ocv_update(CV_ENABLE_UNROLLED 0) else() diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 10e1f7397c..2546ac5839 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -314,6 +314,7 @@ macro(ocv_glob_modules) set(OPENCV_INITIAL_PASS OFF) if(${BUILD_opencv_world}) foreach(m ${OPENCV_MODULES_BUILD}) + set(the_module "${m}") if("${m}" STREQUAL opencv_world) add_subdirectory("${OPENCV_MODULE_opencv_world_LOCATION}" "${CMAKE_CURRENT_BINARY_DIR}/world") elseif(NOT OPENCV_MODULE_${m}_IS_PART_OF_WORLD AND NOT ${m} STREQUAL opencv_world) @@ -329,6 +330,7 @@ macro(ocv_glob_modules) endforeach() else() foreach(m ${OPENCV_MODULES_BUILD}) + set(the_module "${m}") if(m MATCHES "^opencv_") string(REGEX REPLACE "^opencv_" "" __shortname "${m}") add_subdirectory("${OPENCV_MODULE_${m}_LOCATION}" "${CMAKE_CURRENT_BINARY_DIR}/${__shortname}") @@ -646,11 +648,13 @@ macro(ocv_set_module_sources) ocv_get_module_external_sources() endif() + if(OPENCV_MODULE_${the_module}_SOURCES_DISPATCHED) + list(APPEND OPENCV_MODULE_${the_module}_SOURCES ${OPENCV_MODULE_${the_module}_SOURCES_DISPATCHED}) + endif() + # use full paths for module to be independent from the module location ocv_convert_to_full_paths(OPENCV_MODULE_${the_module}_HEADERS) - ocv_compiler_optimization_process_sources(OPENCV_MODULE_${the_module}_SOURCES OPENCV_MODULE_${the_module}_DEPS_EXT ${the_module}) - set(OPENCV_MODULE_${the_module}_HEADERS ${OPENCV_MODULE_${the_module}_HEADERS} CACHE INTERNAL "List of header files for ${the_module}") set(OPENCV_MODULE_${the_module}_SOURCES ${OPENCV_MODULE_${the_module}_SOURCES} CACHE INTERNAL "List of source files for ${the_module}") endmacro() @@ -766,6 +770,11 @@ macro(ocv_create_module) endmacro() macro(_ocv_create_module) + + ocv_compiler_optimization_process_sources(OPENCV_MODULE_${the_module}_SOURCES OPENCV_MODULE_${the_module}_DEPS_EXT ${the_module}) + set(OPENCV_MODULE_${the_module}_HEADERS ${OPENCV_MODULE_${the_module}_HEADERS} CACHE INTERNAL "List of header files for ${the_module}") + set(OPENCV_MODULE_${the_module}_SOURCES ${OPENCV_MODULE_${the_module}_SOURCES} CACHE INTERNAL "List of source files for ${the_module}") + # The condition we ought to be testing here is whether ocv_add_precompiled_headers will # be called at some point in the future. We can't look into the future, though, # so this will have to do. diff --git a/cmake/OpenCVPCHSupport.cmake b/cmake/OpenCVPCHSupport.cmake index 6a83218729..659973af81 100644 --- a/cmake/OpenCVPCHSupport.cmake +++ b/cmake/OpenCVPCHSupport.cmake @@ -288,11 +288,12 @@ MACRO(ADD_PRECOMPILED_HEADER _targetName _input) foreach(src ${_sources}) if(NOT "${src}" MATCHES "\\.mm$") get_source_file_property(oldProps "${src}" COMPILE_FLAGS) - if(NOT oldProps) + get_source_file_property(oldProps2 "${src}" COMPILE_DEFINITIONS) + if(NOT oldProps AND NOT oldProps2) set(newProperties "-include \"${CMAKE_CURRENT_BINARY_DIR}/${_name}\"") set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${newProperties}") else() - ocv_debug_message("Skip PCH, flags: ${oldProps} , file: ${src}") + ocv_debug_message("Skip PCH, flags: ${oldProps} defines: ${oldProps2}, file: ${src}") endif() endif() endforeach() @@ -339,11 +340,12 @@ MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _input) AND NOT "${src}" MATCHES "^\$" # CMake generator expressions ) get_source_file_property(oldProps "${src}" COMPILE_FLAGS) - if(NOT oldProps) + get_source_file_property(oldProps2 "${src}" COMPILE_DEFINITIONS) + if(NOT oldProps AND NOT oldProps2) set(newProperties "/Yu\"${_input}\" /FI\"${_input}\"") set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${newProperties}") else() - ocv_debug_message("Skip PCH, flags: ${oldProps} , file: ${src}") + ocv_debug_message("Skip PCH, flags: ${oldProps} defines: ${oldProps2}, file: ${src}") endif() endif() endforeach() diff --git a/modules/core/include/opencv2/core/cv_cpu_dispatch.h b/modules/core/include/opencv2/core/cv_cpu_dispatch.h index 9a8537f909..aaabea38d4 100644 --- a/modules/core/include/opencv2/core/cv_cpu_dispatch.h +++ b/modules/core/include/opencv2/core/cv_cpu_dispatch.h @@ -7,6 +7,23 @@ #include "cv_cpu_config.h" #include "cv_cpu_helper.h" +#ifdef CV_CPU_DISPATCH_MODE +#define CV_CPU_OPTIMIZATION_NAMESPACE __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } +#else +#define CV_CPU_OPTIMIZATION_NAMESPACE cpu_baseline +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace cpu_baseline { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } +#endif + + +#define __CV_CPU_DISPATCH_CHAIN_END(fn, args, mode, ...) /* done */ +#define __CV_CPU_DISPATCH(fn, args, mode, ...) __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) +#define __CV_CPU_DISPATCH_EXPAND(fn, args, ...) __CV_EXPAND(__CV_CPU_DISPATCH(fn, args, __VA_ARGS__)) +#define CV_CPU_DISPATCH(fn, args, ...) __CV_CPU_DISPATCH_EXPAND(fn, args, __VA_ARGS__, END) // expand macros + + #if defined CV_ENABLE_INTRINSICS \ && !defined CV_DISABLE_OPTIMIZATION \ && !defined __CUDACC__ /* do not include SSE/AVX/NEON headers for NVCC compiler */ \ @@ -76,6 +93,16 @@ #endif // CV_ENABLE_INTRINSICS && !CV_DISABLE_OPTIMIZATION && !__CUDACC__ +#if defined CV_CPU_COMPILE_AVX && !defined CV_CPU_BASELINE_COMPILE_AVX +struct VZeroUpperGuard { +#ifdef __GNUC__ + __attribute__((always_inline)) +#endif + inline ~VZeroUpperGuard() { _mm256_zeroupper(); } +}; +#define __CV_AVX_GUARD VZeroUpperGuard __vzeroupper_guard; +#endif + #endif // __OPENCV_BUILD diff --git a/modules/core/include/opencv2/core/cv_cpu_helper.h b/modules/core/include/opencv2/core/cv_cpu_helper.h index cb755d615e..8bd0457242 100644 --- a/modules/core/include/opencv2/core/cv_cpu_helper.h +++ b/modules/core/include/opencv2/core/cv_cpu_helper.h @@ -2,132 +2,147 @@ #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE # define CV_CPU_HAS_SUPPORT_SSE 1 -# define CV_CPU_CALL_SSE(...) return __VA_ARGS__ +# define CV_CPU_CALL_SSE(fn, args) return (opt_SSE::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE # define CV_CPU_HAS_SUPPORT_SSE (cv::checkHardwareSupport(CV_CPU_SSE)) -# define CV_CPU_CALL_SSE(...) if (CV_CPU_HAS_SUPPORT_SSE) return __VA_ARGS__ +# define CV_CPU_CALL_SSE(fn, args) if (CV_CPU_HAS_SUPPORT_SSE) return (opt_SSE::fn args) #else # define CV_CPU_HAS_SUPPORT_SSE 0 -# define CV_CPU_CALL_SSE(...) +# define CV_CPU_CALL_SSE(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_SSE(fn, args, mode, ...) CV_CPU_CALL_SSE(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE2 # define CV_CPU_HAS_SUPPORT_SSE2 1 -# define CV_CPU_CALL_SSE2(...) return __VA_ARGS__ +# define CV_CPU_CALL_SSE2(fn, args) return (opt_SSE2::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE2 # define CV_CPU_HAS_SUPPORT_SSE2 (cv::checkHardwareSupport(CV_CPU_SSE2)) -# define CV_CPU_CALL_SSE2(...) if (CV_CPU_HAS_SUPPORT_SSE2) return __VA_ARGS__ +# define CV_CPU_CALL_SSE2(fn, args) if (CV_CPU_HAS_SUPPORT_SSE2) return (opt_SSE2::fn args) #else # define CV_CPU_HAS_SUPPORT_SSE2 0 -# define CV_CPU_CALL_SSE2(...) +# define CV_CPU_CALL_SSE2(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_SSE2(fn, args, mode, ...) CV_CPU_CALL_SSE2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE3 # define CV_CPU_HAS_SUPPORT_SSE3 1 -# define CV_CPU_CALL_SSE3(...) return __VA_ARGS__ +# define CV_CPU_CALL_SSE3(fn, args) return (opt_SSE3::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE3 # define CV_CPU_HAS_SUPPORT_SSE3 (cv::checkHardwareSupport(CV_CPU_SSE3)) -# define CV_CPU_CALL_SSE3(...) if (CV_CPU_HAS_SUPPORT_SSE3) return __VA_ARGS__ +# define CV_CPU_CALL_SSE3(fn, args) if (CV_CPU_HAS_SUPPORT_SSE3) return (opt_SSE3::fn args) #else # define CV_CPU_HAS_SUPPORT_SSE3 0 -# define CV_CPU_CALL_SSE3(...) +# define CV_CPU_CALL_SSE3(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_SSE3(fn, args, mode, ...) CV_CPU_CALL_SSE3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSSE3 # define CV_CPU_HAS_SUPPORT_SSSE3 1 -# define CV_CPU_CALL_SSSE3(...) return __VA_ARGS__ +# define CV_CPU_CALL_SSSE3(fn, args) return (opt_SSSE3::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSSE3 # define CV_CPU_HAS_SUPPORT_SSSE3 (cv::checkHardwareSupport(CV_CPU_SSSE3)) -# define CV_CPU_CALL_SSSE3(...) if (CV_CPU_HAS_SUPPORT_SSSE3) return __VA_ARGS__ +# define CV_CPU_CALL_SSSE3(fn, args) if (CV_CPU_HAS_SUPPORT_SSSE3) return (opt_SSSE3::fn args) #else # define CV_CPU_HAS_SUPPORT_SSSE3 0 -# define CV_CPU_CALL_SSSE3(...) +# define CV_CPU_CALL_SSSE3(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_SSSE3(fn, args, mode, ...) CV_CPU_CALL_SSSE3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE4_1 # define CV_CPU_HAS_SUPPORT_SSE4_1 1 -# define CV_CPU_CALL_SSE4_1(...) return __VA_ARGS__ +# define CV_CPU_CALL_SSE4_1(fn, args) return (opt_SSE4_1::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE4_1 # define CV_CPU_HAS_SUPPORT_SSE4_1 (cv::checkHardwareSupport(CV_CPU_SSE4_1)) -# define CV_CPU_CALL_SSE4_1(...) if (CV_CPU_HAS_SUPPORT_SSE4_1) return __VA_ARGS__ +# define CV_CPU_CALL_SSE4_1(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_1) return (opt_SSE4_1::fn args) #else # define CV_CPU_HAS_SUPPORT_SSE4_1 0 -# define CV_CPU_CALL_SSE4_1(...) +# define CV_CPU_CALL_SSE4_1(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_SSE4_1(fn, args, mode, ...) CV_CPU_CALL_SSE4_1(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE4_2 # define CV_CPU_HAS_SUPPORT_SSE4_2 1 -# define CV_CPU_CALL_SSE4_2(...) return __VA_ARGS__ +# define CV_CPU_CALL_SSE4_2(fn, args) return (opt_SSE4_2::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE4_2 # define CV_CPU_HAS_SUPPORT_SSE4_2 (cv::checkHardwareSupport(CV_CPU_SSE4_2)) -# define CV_CPU_CALL_SSE4_2(...) if (CV_CPU_HAS_SUPPORT_SSE4_2) return __VA_ARGS__ +# define CV_CPU_CALL_SSE4_2(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_2) return (opt_SSE4_2::fn args) #else # define CV_CPU_HAS_SUPPORT_SSE4_2 0 -# define CV_CPU_CALL_SSE4_2(...) +# define CV_CPU_CALL_SSE4_2(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_SSE4_2(fn, args, mode, ...) CV_CPU_CALL_SSE4_2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_POPCNT # define CV_CPU_HAS_SUPPORT_POPCNT 1 -# define CV_CPU_CALL_POPCNT(...) return __VA_ARGS__ +# define CV_CPU_CALL_POPCNT(fn, args) return (opt_POPCNT::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_POPCNT # define CV_CPU_HAS_SUPPORT_POPCNT (cv::checkHardwareSupport(CV_CPU_POPCNT)) -# define CV_CPU_CALL_POPCNT(...) if (CV_CPU_HAS_SUPPORT_POPCNT) return __VA_ARGS__ +# define CV_CPU_CALL_POPCNT(fn, args) if (CV_CPU_HAS_SUPPORT_POPCNT) return (opt_POPCNT::fn args) #else # define CV_CPU_HAS_SUPPORT_POPCNT 0 -# define CV_CPU_CALL_POPCNT(...) +# define CV_CPU_CALL_POPCNT(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_POPCNT(fn, args, mode, ...) CV_CPU_CALL_POPCNT(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX # define CV_CPU_HAS_SUPPORT_AVX 1 -# define CV_CPU_CALL_AVX(...) return __VA_ARGS__ +# define CV_CPU_CALL_AVX(fn, args) return (opt_AVX::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX # define CV_CPU_HAS_SUPPORT_AVX (cv::checkHardwareSupport(CV_CPU_AVX)) -# define CV_CPU_CALL_AVX(...) if (CV_CPU_HAS_SUPPORT_AVX) return __VA_ARGS__ +# define CV_CPU_CALL_AVX(fn, args) if (CV_CPU_HAS_SUPPORT_AVX) return (opt_AVX::fn args) #else # define CV_CPU_HAS_SUPPORT_AVX 0 -# define CV_CPU_CALL_AVX(...) +# define CV_CPU_CALL_AVX(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_AVX(fn, args, mode, ...) CV_CPU_CALL_AVX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_FP16 # define CV_CPU_HAS_SUPPORT_FP16 1 -# define CV_CPU_CALL_FP16(...) return __VA_ARGS__ +# define CV_CPU_CALL_FP16(fn, args) return (opt_FP16::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_FP16 # define CV_CPU_HAS_SUPPORT_FP16 (cv::checkHardwareSupport(CV_CPU_FP16)) -# define CV_CPU_CALL_FP16(...) if (CV_CPU_HAS_SUPPORT_FP16) return __VA_ARGS__ +# define CV_CPU_CALL_FP16(fn, args) if (CV_CPU_HAS_SUPPORT_FP16) return (opt_FP16::fn args) #else # define CV_CPU_HAS_SUPPORT_FP16 0 -# define CV_CPU_CALL_FP16(...) +# define CV_CPU_CALL_FP16(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_FP16(fn, args, mode, ...) CV_CPU_CALL_FP16(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX2 # define CV_CPU_HAS_SUPPORT_AVX2 1 -# define CV_CPU_CALL_AVX2(...) return __VA_ARGS__ +# define CV_CPU_CALL_AVX2(fn, args) return (opt_AVX2::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX2 # define CV_CPU_HAS_SUPPORT_AVX2 (cv::checkHardwareSupport(CV_CPU_AVX2)) -# define CV_CPU_CALL_AVX2(...) if (CV_CPU_HAS_SUPPORT_AVX2) return __VA_ARGS__ +# define CV_CPU_CALL_AVX2(fn, args) if (CV_CPU_HAS_SUPPORT_AVX2) return (opt_AVX2::fn args) #else # define CV_CPU_HAS_SUPPORT_AVX2 0 -# define CV_CPU_CALL_AVX2(...) +# define CV_CPU_CALL_AVX2(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_AVX2(fn, args, mode, ...) CV_CPU_CALL_AVX2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_FMA3 # define CV_CPU_HAS_SUPPORT_FMA3 1 -# define CV_CPU_CALL_FMA3(...) return __VA_ARGS__ +# define CV_CPU_CALL_FMA3(fn, args) return (opt_FMA3::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_FMA3 # define CV_CPU_HAS_SUPPORT_FMA3 (cv::checkHardwareSupport(CV_CPU_FMA3)) -# define CV_CPU_CALL_FMA3(...) if (CV_CPU_HAS_SUPPORT_FMA3) return __VA_ARGS__ +# define CV_CPU_CALL_FMA3(fn, args) if (CV_CPU_HAS_SUPPORT_FMA3) return (opt_FMA3::fn args) #else # define CV_CPU_HAS_SUPPORT_FMA3 0 -# define CV_CPU_CALL_FMA3(...) +# define CV_CPU_CALL_FMA3(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_FMA3(fn, args, mode, ...) CV_CPU_CALL_FMA3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_NEON # define CV_CPU_HAS_SUPPORT_NEON 1 -# define CV_CPU_CALL_NEON(...) return __VA_ARGS__ +# define CV_CPU_CALL_NEON(fn, args) return (opt_NEON::fn args) #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_NEON # define CV_CPU_HAS_SUPPORT_NEON (cv::checkHardwareSupport(CV_CPU_NEON)) -# define CV_CPU_CALL_NEON(...) if (CV_CPU_HAS_SUPPORT_NEON) return __VA_ARGS__ +# define CV_CPU_CALL_NEON(fn, args) if (CV_CPU_HAS_SUPPORT_NEON) return (opt_NEON::fn args) #else # define CV_CPU_HAS_SUPPORT_NEON 0 -# define CV_CPU_CALL_NEON(...) +# define CV_CPU_CALL_NEON(fn, args) #endif +#define __CV_CPU_DISPATCH_CHAIN_NEON(fn, args, mode, ...) CV_CPU_CALL_NEON(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#define CV_CPU_CALL_BASELINE(fn, args) return (cpu_baseline::fn args) +#define __CV_CPU_DISPATCH_CHAIN_BASELINE(fn, args, mode, ...) CV_CPU_CALL_BASELINE(fn, args) /* last in sequence */ diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index f2212b4217..43f8a02a72 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -52,6 +52,17 @@ #include "cvconfig.h" #endif +#ifndef __CV_EXPAND +#define __CV_EXPAND(x) x +#endif + +#ifndef __CV_CAT +#define __CV_CAT__(x, y) x ## y +#define __CV_CAT_(x, y) __CV_CAT__(x, y) +#define __CV_CAT(x, y) __CV_CAT_(x, y) +#endif + + #if !defined _CRT_SECURE_NO_DEPRECATE && defined _MSC_VER && _MSC_VER > 1300 # define _CRT_SECURE_NO_DEPRECATE /* to avoid multiple Visual Studio warnings */ #endif diff --git a/modules/core/include/opencv2/core/hal/intrin.hpp b/modules/core/include/opencv2/core/hal/intrin.hpp index 34075e3830..9dd1514ea3 100644 --- a/modules/core/include/opencv2/core/hal/intrin.hpp +++ b/modules/core/include/opencv2/core/hal/intrin.hpp @@ -60,6 +60,25 @@ // access from within opencv code more accessible namespace cv { +#ifndef CV_DOXYGEN + +#ifdef CV_CPU_DISPATCH_MODE +#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) +#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) { +#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END } +#else +#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE hal_baseline +#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace hal_baseline { +#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END } +#endif + + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE; +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +#endif + //! @addtogroup core_hal_intrin //! @{ @@ -281,6 +300,9 @@ template struct V_SIMD128Traits //! @} +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +#endif } #ifdef CV_DOXYGEN @@ -323,6 +345,10 @@ template struct V_SIMD128Traits namespace cv { +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +#endif + template struct V_RegTrait128; template <> struct V_RegTrait128 { @@ -407,6 +433,10 @@ template <> struct V_RegTrait128 { }; #endif +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +#endif + } // cv:: //! @endcond diff --git a/modules/core/include/opencv2/core/hal/intrin_cpp.hpp b/modules/core/include/opencv2/core/hal/intrin_cpp.hpp index e15c97d528..e8c166405e 100644 --- a/modules/core/include/opencv2/core/hal/intrin_cpp.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_cpp.hpp @@ -53,6 +53,10 @@ namespace cv { +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +#endif + /** @addtogroup core_hal_intrin "Universal intrinsics" is a types and functions set intended to simplify vectorization of code on @@ -1827,7 +1831,9 @@ static inline bool hasSIMD128() //! @} - +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +#endif } #endif diff --git a/modules/core/include/opencv2/core/hal/intrin_neon.hpp b/modules/core/include/opencv2/core/hal/intrin_neon.hpp index 2bcff2bc15..c7f4e90a36 100644 --- a/modules/core/include/opencv2/core/hal/intrin_neon.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_neon.hpp @@ -53,6 +53,8 @@ namespace cv //! @cond IGNORED +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + #define CV_SIMD128 1 #if defined(__aarch64__) #define CV_SIMD128_64F 1 @@ -1238,11 +1240,13 @@ inline v_float16x4 v_cvt_f16(const v_float32x4& a) //! @brief Check CPU capability of SIMD operation static inline bool hasSIMD128() { - return checkHardwareSupport(CV_CPU_NEON); + return (CV_CPU_HAS_SUPPORT_NEON) ? true : false; } //! @} +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + //! @endcond } diff --git a/modules/core/include/opencv2/core/hal/intrin_sse.hpp b/modules/core/include/opencv2/core/hal/intrin_sse.hpp index 60003082ea..5b9a27fd8a 100644 --- a/modules/core/include/opencv2/core/hal/intrin_sse.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_sse.hpp @@ -56,6 +56,8 @@ namespace cv //! @cond IGNORED +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + struct v_uint8x16 { typedef uchar lane_type; @@ -1791,11 +1793,13 @@ inline v_float16x4 v_cvt_f16(const v_float32x4& a) //! @brief Check CPU capability of SIMD operation static inline bool hasSIMD128() { - return checkHardwareSupport(CV_CPU_SSE2); + return (CV_CPU_HAS_SUPPORT_SSE2) ? true : false; } //! @} +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + //! @endcond } diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp index e428ecf8ad..afbc557166 100644 --- a/modules/core/include/opencv2/core/private.hpp +++ b/modules/core/include/opencv2/core/private.hpp @@ -540,7 +540,7 @@ CV_EXPORTS InstrNode* getCurrentNode(); ///// General instrumentation // General OpenCV region instrumentation macro -#define CV_INSTRUMENT_REGION() CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN) +#define CV_INSTRUMENT_REGION_() CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN) // Custom OpenCV region instrumentation macro #define CV_INSTRUMENT_REGION_NAME(NAME) CV_INSTRUMENT_REGION_CUSTOM_META(NAME, false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN) // Instrumentation for parallel_for_ or other regions which forks and gathers threads @@ -566,7 +566,7 @@ CV_EXPORTS InstrNode* getCurrentNode(); #else #define CV_INSTRUMENT_REGION_META(...) -#define CV_INSTRUMENT_REGION() +#define CV_INSTRUMENT_REGION_() #define CV_INSTRUMENT_REGION_NAME(...) #define CV_INSTRUMENT_REGION_MT_FORK() @@ -580,6 +580,12 @@ CV_EXPORTS InstrNode* getCurrentNode(); #define CV_INSTRUMENT_MARK_OPENCL(...) #endif +#ifdef __CV_AVX_GUARD +#define CV_INSTRUMENT_REGION() __CV_AVX_GUARD CV_INSTRUMENT_REGION_() +#else +#define CV_INSTRUMENT_REGION() CV_INSTRUMENT_REGION_() +#endif + //! @endcond #endif // OPENCV_CORE_PRIVATE_HPP diff --git a/modules/core/include/opencv2/core/private/cv_cpu_include_simd_declarations.hpp b/modules/core/include/opencv2/core/private/cv_cpu_include_simd_declarations.hpp new file mode 100644 index 0000000000..37d06efcd7 --- /dev/null +++ b/modules/core/include/opencv2/core/private/cv_cpu_include_simd_declarations.hpp @@ -0,0 +1,30 @@ +// Helper file to include dispatched functions declaration: +// +// Usage: +// #define CV_CPU_SIMD_FILENAME ".simd.hpp" +// #define CV_CPU_DISPATCH_MODE AVX2 +// #include "opencv2/core/private/cv_cpu_include_simd_declarations.hpp" +// #define CV_CPU_DISPATCH_MODE SSE2 +// #include "opencv2/core/private/cv_cpu_include_simd_declarations.hpp" + +#ifndef CV_DISABLE_OPTIMIZATION +#ifdef _MSC_VER +#pragma warning(disable: 4702) // unreachable code +#endif +#endif + +#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY +#define CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY +#endif + +#undef CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN +#undef CV_CPU_OPTIMIZATION_NAMESPACE_END + +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } + +#include CV_CPU_SIMD_FILENAME + +#undef CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN +#undef CV_CPU_OPTIMIZATION_NAMESPACE_END +#undef CV_CPU_DISPATCH_MODE diff --git a/modules/world/CMakeLists.txt b/modules/world/CMakeLists.txt index dde793fa00..1152cd3ef1 100644 --- a/modules/world/CMakeLists.txt +++ b/modules/world/CMakeLists.txt @@ -24,6 +24,7 @@ if(NOT OPENCV_INITIAL_PASS) message(STATUS "Processing WORLD modules...") foreach(m ${OPENCV_MODULES_BUILD}) + set(the_module ${m}) if(OPENCV_MODULE_${m}_IS_PART_OF_WORLD) message(STATUS " module ${m}...") set(CMAKE_CURRENT_SOURCE_DIR "${OPENCV_MODULE_${m}_LOCATION}") From 1e6ce1d2f827b5c04b0e7797e88c37a955563e31 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 23 Mar 2017 16:09:47 +0300 Subject: [PATCH 036/144] core(mathfuncs_core): cpu optimization dispatched code --- modules/core/CMakeLists.txt | 3 + modules/core/src/mathfuncs_core.dispatch.cpp | 215 ++++++++++++++++++ ...funcs_core.cpp => mathfuncs_core.simd.hpp} | 193 +++------------- 3 files changed, 253 insertions(+), 158 deletions(-) create mode 100644 modules/core/src/mathfuncs_core.dispatch.cpp rename modules/core/src/{mathfuncs_core.cpp => mathfuncs_core.simd.hpp} (91%) diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index 01b272e97e..3d2cc7f594 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -1,4 +1,7 @@ set(the_description "The Core Functionality") + +ocv_add_dispatched_file(mathfuncs_core SSE2 AVX AVX2) + ocv_add_module(core "${OPENCV_HAL_LINKER_LIBS}" OPTIONAL opencv_cudev diff --git a/modules/core/src/mathfuncs_core.dispatch.cpp b/modules/core/src/mathfuncs_core.dispatch.cpp new file mode 100644 index 0000000000..1a462a0635 --- /dev/null +++ b/modules/core/src/mathfuncs_core.dispatch.cpp @@ -0,0 +1,215 @@ +// 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 "mathfuncs_core.simd.hpp" +#include "mathfuncs_core.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX2,...,BASELINE based on CMakeLists.txt content + +namespace cv { namespace hal { + +///////////////////////////////////// ATAN2 //////////////////////////////////// + +void fastAtan32f(const float *Y, const float *X, float *angle, int len, bool angleInDegrees ) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(fastAtan32f, cv_hal_fastAtan32f, Y, X, angle, len, angleInDegrees); + + CV_CPU_DISPATCH(fastAtan32f, (Y, X, angle, len, angleInDegrees), + CV_CPU_DISPATCH_MODES_ALL); +} + +void fastAtan64f(const double *Y, const double *X, double *angle, int len, bool angleInDegrees) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(fastAtan64f, cv_hal_fastAtan64f, Y, X, angle, len, angleInDegrees); + + CV_CPU_DISPATCH(fastAtan64f, (Y, X, angle, len, angleInDegrees), + CV_CPU_DISPATCH_MODES_ALL); +} + +// deprecated +void fastAtan2(const float *Y, const float *X, float *angle, int len, bool angleInDegrees ) +{ + CV_INSTRUMENT_REGION() + + fastAtan32f(Y, X, angle, len, angleInDegrees); +} + +void magnitude32f(const float* x, const float* y, float* mag, int len) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(magnitude32f, cv_hal_magnitude32f, x, y, mag, len); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsMagnitude_32f, x, y, mag, len) >= 0); + + CV_CPU_DISPATCH(magnitude32f, (x, y, mag, len), + CV_CPU_DISPATCH_MODES_ALL); +} + +void magnitude64f(const double* x, const double* y, double* mag, int len) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(magnitude64f, cv_hal_magnitude64f, x, y, mag, len); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsMagnitude_64f, x, y, mag, len) >= 0); + + CV_CPU_DISPATCH(magnitude64f, (x, y, mag, len), + CV_CPU_DISPATCH_MODES_ALL); +} + + +void invSqrt32f(const float* src, float* dst, int len) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(invSqrt32f, cv_hal_invSqrt32f, src, dst, len); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_32f_A21, src, dst, len) >= 0); + + CV_CPU_DISPATCH(invSqrt32f, (src, dst, len), + CV_CPU_DISPATCH_MODES_ALL); +} + + +void invSqrt64f(const double* src, double* dst, int len) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(invSqrt64f, cv_hal_invSqrt64f, src, dst, len); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_64f_A50, src, dst, len) >= 0); + + CV_CPU_DISPATCH(invSqrt64f, (src, dst, len), + CV_CPU_DISPATCH_MODES_ALL); +} + + +void sqrt32f(const float* src, float* dst, int len) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(sqrt32f, cv_hal_sqrt32f, src, dst, len); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsSqrt_32f_A21, src, dst, len) >= 0); + + CV_CPU_DISPATCH(sqrt32f, (src, dst, len), + CV_CPU_DISPATCH_MODES_ALL); +} + + +void sqrt64f(const double* src, double* dst, int len) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(sqrt64f, cv_hal_sqrt64f, src, dst, len); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsSqrt_64f_A50, src, dst, len) >= 0); + + CV_CPU_DISPATCH(sqrt64f, (src, dst, len), + CV_CPU_DISPATCH_MODES_ALL); +} + +void exp32f(const float *src, float *dst, int n) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(exp32f, cv_hal_exp32f, src, dst, n); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_32f_A21, src, dst, n) >= 0); + + CV_CPU_DISPATCH(exp32f, (src, dst, n), + CV_CPU_DISPATCH_MODES_ALL); +} + +void exp64f(const double *src, double *dst, int n) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(exp64f, cv_hal_exp64f, src, dst, n); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_64f_A50, src, dst, n) >= 0); + + CV_CPU_DISPATCH(exp64f, (src, dst, n), + CV_CPU_DISPATCH_MODES_ALL); +} + +void log32f(const float *src, float *dst, int n) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(log32f, cv_hal_log32f, src, dst, n); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_32f_A21, src, dst, n) >= 0); + + CV_CPU_DISPATCH(log32f, (src, dst, n), + CV_CPU_DISPATCH_MODES_ALL); +} + +void log64f(const double *src, double *dst, int n) +{ + CV_INSTRUMENT_REGION() + + CALL_HAL(log64f, cv_hal_log64f, src, dst, n); + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_64f_A50, src, dst, n) >= 0); + + CV_CPU_DISPATCH(log64f, (src, dst, n), + CV_CPU_DISPATCH_MODES_ALL); +} + +//============================================================================= +// for compatibility with 3.0 + +void exp(const float* src, float* dst, int n) +{ + exp32f(src, dst, n); +} + +void exp(const double* src, double* dst, int n) +{ + exp64f(src, dst, n); +} + +void log(const float* src, float* dst, int n) +{ + log32f(src, dst, n); +} + +void log(const double* src, double* dst, int n) +{ + log64f(src, dst, n); +} + +void magnitude(const float* x, const float* y, float* dst, int n) +{ + magnitude32f(x, y, dst, n); +} + +void magnitude(const double* x, const double* y, double* dst, int n) +{ + magnitude64f(x, y, dst, n); +} + +void sqrt(const float* src, float* dst, int len) +{ + sqrt32f(src, dst, len); +} + +void sqrt(const double* src, double* dst, int len) +{ + sqrt64f(src, dst, len); +} + +void invSqrt(const float* src, float* dst, int len) +{ + invSqrt32f(src, dst, len); +} + +void invSqrt(const double* src, double* dst, int len) +{ + invSqrt64f(src, dst, len); +} + +}} // namespace cv::hal:: + +float cv::fastAtan2( float y, float x ) +{ + using namespace cv::hal; + CV_CPU_CALL_BASELINE(fastAtan2, (y, x)); +} diff --git a/modules/core/src/mathfuncs_core.cpp b/modules/core/src/mathfuncs_core.simd.hpp similarity index 91% rename from modules/core/src/mathfuncs_core.cpp rename to modules/core/src/mathfuncs_core.simd.hpp index 5a1e2fa75c..ad5176e192 100644 --- a/modules/core/src/mathfuncs_core.cpp +++ b/modules/core/src/mathfuncs_core.simd.hpp @@ -1,46 +1,29 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's 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. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and 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 the Intel Corporation or 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. -// -//M*/ +// 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" +namespace cv { namespace hal { + +CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN + +// forward declarations +void fastAtan32f(const float *Y, const float *X, float *angle, int len, bool angleInDegrees); +void fastAtan64f(const double *Y, const double *X, double *angle, int len, bool angleInDegrees); +void fastAtan2(const float *Y, const float *X, float *angle, int len, bool angleInDegrees); +void magnitude32f(const float* x, const float* y, float* mag, int len); +void magnitude64f(const double* x, const double* y, double* mag, int len); +void invSqrt32f(const float* src, float* dst, int len); +void invSqrt64f(const double* src, double* dst, int len); +void sqrt32f(const float* src, float* dst, int len); +void sqrt64f(const double* src, double* dst, int len); +void exp32f(const float *src, float *dst, int n); +void exp64f(const double *src, double *dst, int n); +void log32f(const float *src, float *dst, int n); +void log64f(const double *src, double *dst, int n); +float fastAtan2(float y, float x); + + +#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY using namespace std; @@ -197,23 +180,17 @@ static inline void atanImpl(const T *Y, const T *X, T *angle, int len, bool angl } // anonymous:: -namespace cv { namespace hal { - ///////////////////////////////////// ATAN2 //////////////////////////////////// void fastAtan32f(const float *Y, const float *X, float *angle, int len, bool angleInDegrees ) { CV_INSTRUMENT_REGION() - - CALL_HAL(fastAtan32f, cv_hal_fastAtan32f, Y, X, angle, len, angleInDegrees); atanImpl(Y, X, angle, len, angleInDegrees); } void fastAtan64f(const double *Y, const double *X, double *angle, int len, bool angleInDegrees) { CV_INSTRUMENT_REGION() - - CALL_HAL(fastAtan64f, cv_hal_fastAtan64f, Y, X, angle, len, angleInDegrees); atanImpl(Y, X, angle, len, angleInDegrees); } @@ -221,7 +198,6 @@ void fastAtan64f(const double *Y, const double *X, double *angle, int len, bool void fastAtan2(const float *Y, const float *X, float *angle, int len, bool angleInDegrees ) { CV_INSTRUMENT_REGION() - fastAtan32f(Y, X, angle, len, angleInDegrees); } @@ -229,9 +205,6 @@ void magnitude32f(const float* x, const float* y, float* mag, int len) { CV_INSTRUMENT_REGION() - CALL_HAL(magnitude32f, cv_hal_magnitude32f, x, y, mag, len); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsMagnitude_32f, x, y, mag, len) >= 0); - int i = 0; #if CV_SIMD128 @@ -257,9 +230,6 @@ void magnitude64f(const double* x, const double* y, double* mag, int len) { CV_INSTRUMENT_REGION() - CALL_HAL(magnitude64f, cv_hal_magnitude64f, x, y, mag, len); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsMagnitude_64f, x, y, mag, len) >= 0); - int i = 0; #if CV_SIMD128_64F @@ -286,9 +256,6 @@ void invSqrt32f(const float* src, float* dst, int len) { CV_INSTRUMENT_REGION() - CALL_HAL(invSqrt32f, cv_hal_invSqrt32f, src, dst, len); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_32f_A21, src, dst, len) >= 0); - int i = 0; #if CV_SIMD128 @@ -310,9 +277,6 @@ void invSqrt64f(const double* src, double* dst, int len) { CV_INSTRUMENT_REGION() - CALL_HAL(invSqrt64f, cv_hal_invSqrt64f, src, dst, len); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_64f_A50, src, dst, len) >= 0); - int i = 0; #if CV_SSE2 @@ -330,9 +294,6 @@ void sqrt32f(const float* src, float* dst, int len) { CV_INSTRUMENT_REGION() - CALL_HAL(sqrt32f, cv_hal_sqrt32f, src, dst, len); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsSqrt_32f_A21, src, dst, len) >= 0); - int i = 0; #if CV_SIMD128 @@ -354,9 +315,6 @@ void sqrt64f(const double* src, double* dst, int len) { CV_INSTRUMENT_REGION() - CALL_HAL(sqrt64f, cv_hal_sqrt64f, src, dst, len); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsSqrt_64f_A50, src, dst, len) >= 0); - int i = 0; #if CV_SIMD128_64F @@ -381,9 +339,6 @@ void exp32f(const float *src, float *dst, int n) { CV_INSTRUMENT_REGION() - CALL_HAL(exp32f, cv_hal_exp32f, src, dst, n); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_32f_A21, src, dst, n) >= 0); - for (int i = 0; i < n; i++) { dst[i] = std::exp(src[i]); @@ -394,9 +349,6 @@ void exp64f(const double *src, double *dst, int n) { CV_INSTRUMENT_REGION() - CALL_HAL(exp64f, cv_hal_exp64f, src, dst, n); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_64f_A50, src, dst, n) >= 0); - for (int i = 0; i < n; i++) { dst[i] = std::exp(src[i]); @@ -407,9 +359,6 @@ void log32f(const float *src, float *dst, int n) { CV_INSTRUMENT_REGION() - CALL_HAL(log32f, cv_hal_log32f, src, dst, n); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_32f_A21, src, dst, n) >= 0); - for (int i = 0; i < n; i++) { dst[i] = std::log(src[i]); @@ -419,9 +368,6 @@ void log64f(const double *src, double *dst, int n) { CV_INSTRUMENT_REGION() - CALL_HAL(log64f, cv_hal_log64f, src, dst, n); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_64f_A50, src, dst, n) >= 0); - for (int i = 0; i < n; i++) { dst[i] = std::log(src[i]); @@ -534,9 +480,6 @@ void exp32f( const float *_x, float *y, int n ) { CV_INSTRUMENT_REGION() - CALL_HAL(exp32f, cv_hal_exp32f, _x, y, n); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_32f_A21, _x, y, n) >= 0); - static const float A4 = (float)(1.000000000000002438532970795181890933776 / EXPPOLY_32F_A0), A3 = (float)(.6931471805521448196800669615864773144641 / EXPPOLY_32F_A0), @@ -569,7 +512,6 @@ void exp32f( const float *_x, float *y, int n ) for( ; i <= n - 8; i += 8 ) { - __m256 xf; __m128i xi0, xi1; __m256d xd0 = _mm256_cvtps_pd(_mm_min_ps(_mm_max_ps(_mm_loadu_ps(&x[i].f), minval4), maxval4)); @@ -586,8 +528,7 @@ void exp32f( const float *_x, float *y, int n ) // gcc does not support _mm256_set_m128 //xf = _mm256_set_m128(_mm256_cvtpd_ps(xd1), _mm256_cvtpd_ps(xd0)); - xf = _mm256_insertf128_ps(xf, _mm256_cvtpd_ps(xd0), 0); - xf = _mm256_insertf128_ps(xf, _mm256_cvtpd_ps(xd1), 1); + __m256 xf = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm256_cvtpd_ps(xd0)), _mm256_cvtpd_ps(xd1), 1); xf = _mm256_mul_ps(xf, postscale8); @@ -606,14 +547,10 @@ void exp32f( const float *_x, float *y, int n ) // gcc does not support _mm256_set_m128 //__m256 yf = _mm256_set_m128(_mm256_cvtpd_ps(yd1), _mm256_cvtpd_ps(yd0)); - __m256 yf; - yf = _mm256_insertf128_ps(yf, _mm256_cvtpd_ps(yd0), 0); - yf = _mm256_insertf128_ps(yf, _mm256_cvtpd_ps(yd1), 1); + __m256 yf = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm256_cvtpd_ps(yd0)), _mm256_cvtpd_ps(yd1), 1); //_mm256_set_m128i(xi1, xi0) - __m256i temp; - temp = _mm256_inserti128_si256(temp, xi0, 0); - temp = _mm256_inserti128_si256(temp, xi1, 1); + __m256i temp = (__m256i)_mm256_insertf128_ps(_mm256_castps128_ps256((__m128)xi0), (__m128)xi1, 1); yf = _mm256_mul_ps(yf, _mm256_castsi256_ps(_mm256_slli_epi32(temp, 23))); @@ -827,9 +764,6 @@ void exp64f( const double *_x, double *y, int n ) { CV_INSTRUMENT_REGION() - CALL_HAL(exp64f, cv_hal_exp64f, _x, y, n); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_64f_A50, _x, y, n) >= 0); - static const double A5 = .99999999999999999998285227504999 / EXPPOLY_32F_A0, A4 = .69314718055994546743029643825322 / EXPPOLY_32F_A0, @@ -1276,9 +1210,6 @@ void log32f( const float *_x, float *y, int n ) { CV_INSTRUMENT_REGION() - CALL_HAL(log32f, cv_hal_log32f, _x, y, n); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_32f_A21, _x, y, n) >= 0); - static const float shift[] = { 0, -1.f/512 }; static const float A0 = 0.3333333333333333333333333f, @@ -1425,9 +1356,6 @@ void log64f( const double *x, double *y, int n ) { CV_INSTRUMENT_REGION() - CALL_HAL(log64f, cv_hal_log64f, x, y, n); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_64f_A50, x, y, n) >= 0); - static const double shift[] = { 0, -1./512 }; static const double A7 = 1.0, @@ -1613,64 +1541,13 @@ void log64f( const double *x, double *y, int n ) #endif // issue 7795 -//============================================================================= -// for compatibility with 3.0 - -void exp(const float* src, float* dst, int n) -{ - exp32f(src, dst, n); -} - -void exp(const double* src, double* dst, int n) -{ - exp64f(src, dst, n); -} - -void log(const float* src, float* dst, int n) -{ - log32f(src, dst, n); -} - -void log(const double* src, double* dst, int n) -{ - log64f(src, dst, n); -} - -void magnitude(const float* x, const float* y, float* dst, int n) -{ - magnitude32f(x, y, dst, n); -} - -void magnitude(const double* x, const double* y, double* dst, int n) -{ - magnitude64f(x, y, dst, n); -} - -void sqrt(const float* src, float* dst, int len) -{ - sqrt32f(src, dst, len); -} - -void sqrt(const double* src, double* dst, int len) -{ - sqrt64f(src, dst, len); -} - -void invSqrt(const float* src, float* dst, int len) -{ - invSqrt32f(src, dst, len); -} - -void invSqrt(const double* src, double* dst, int len) -{ - invSqrt64f(src, dst, len); -} - - -} // cv::hal:: -} // cv:: - -float cv::fastAtan2( float y, float x ) +float fastAtan2( float y, float x ) { return atanImpl(y, x); } + +#endif // CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY + +CV_CPU_OPTIMIZATION_NAMESPACE_END + +}} // namespace cv::hal From f82d64c6e526488cd75545cf6a0d5dcfc8da17c9 Mon Sep 17 00:00:00 2001 From: Fangjun KUANG Date: Thu, 23 Mar 2017 14:34:24 +0100 Subject: [PATCH 037/144] Add more info to the error code. --- modules/core/include/opencv2/core/base.hpp | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index 91720cc88a..04e28b2c8f 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -73,30 +73,30 @@ enum Code { StsNoMem= -4, //!< insufficient memory StsBadArg= -5, //!< function arg/param is bad StsBadFunc= -6, //!< unsupported function - StsNoConv= -7, //!< iter. didn't converge + StsNoConv= -7, //!< iteration didn't converge StsAutoTrace= -8, //!< tracing HeaderIsNull= -9, //!< image header is NULL BadImageSize= -10, //!< image size is invalid BadOffset= -11, //!< offset is invalid BadDataPtr= -12, //!< - BadStep= -13, //!< image step is wrong + BadStep= -13, //!< image step is wrong, this may happen for a non-continuous matrix. BadModelOrChSeq= -14, //!< - BadNumChannels= -15, //!< bad number of channels + BadNumChannels= -15, //!< bad number of channels, for example, some functions accept only single channel matrices. BadNumChannel1U= -16, //!< - BadDepth= -17, //!< input image depth is not supported by function + BadDepth= -17, //!< input image depth is not supported by the function BadAlphaChannel= -18, //!< - BadOrder= -19, //!< - BadOrigin= -20, //!< - BadAlign= -21, //!< + BadOrder= -19, //!< number of dimensions is out of range + BadOrigin= -20, //!< incorrect input origin + BadAlign= -21, //!< incorrect input align BadCallBack= -22, //!< BadTileSize= -23, //!< BadCOI= -24, //!< input COI is not supported - BadROISize= -25, //!< + BadROISize= -25, //!< incorrect input roi MaskIsTiled= -26, //!< StsNullPtr= -27, //!< null pointer StsVecLengthErr= -28, //!< incorrect vector length - StsFilterStructContentErr= -29, //!< incorr. filter structure content - StsKernelStructContentErr= -30, //!< incorr. transform kernel content + StsFilterStructContentErr= -29, //!< incorrect filter structure content + StsKernelStructContentErr= -30, //!< incorrect transform kernel content StsFilterOffsetErr= -31, //!< incorrect filter offset value StsBadSize= -201, //!< the input/output structure size is incorrect StsDivByZero= -202, //!< division by zero @@ -113,13 +113,13 @@ enum Code { StsNotImplemented= -213, //!< the requested function/feature is not implemented StsBadMemBlock= -214, //!< an allocated block has been corrupted StsAssert= -215, //!< assertion failed - GpuNotSupported= -216, - GpuApiCallError= -217, - OpenGlNotSupported= -218, - OpenGlApiCallError= -219, - OpenCLApiCallError= -220, + GpuNotSupported= -216, //!< no CUDA support + GpuApiCallError= -217, //!< GPU API call error + OpenGlNotSupported= -218, //!< no OpenGL support + OpenGlApiCallError= -219, //!< OpenGL API call error + OpenCLApiCallError= -220, //!< OpenCL API call error OpenCLDoubleNotSupported= -221, - OpenCLInitError= -222, + OpenCLInitError= -222, //!< OpenCL initialization error OpenCLNoAMDBlasFft= -223 }; } //Error From da94d857891625c3b0a7818d33a298bea54012e1 Mon Sep 17 00:00:00 2001 From: Fangjun KUANG Date: Thu, 23 Mar 2017 14:40:34 +0100 Subject: [PATCH 038/144] add more info to the error code. --- modules/core/include/opencv2/core/types_c.h | 34 ++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/modules/core/include/opencv2/core/types_c.h b/modules/core/include/opencv2/core/types_c.h index b1eb75a3bb..f2f0512720 100644 --- a/modules/core/include/opencv2/core/types_c.h +++ b/modules/core/include/opencv2/core/types_c.h @@ -130,24 +130,24 @@ enum { CV_BadImageSize= -10, /**< image size is invalid */ CV_BadOffset= -11, /**< offset is invalid */ CV_BadDataPtr= -12, /**/ - CV_BadStep= -13, /**< image step is wrong */ + CV_BadStep= -13, /**< image step is wrong, this may happen for a non-continuous matrix */ CV_BadModelOrChSeq= -14, /**/ - CV_BadNumChannels= -15, /**< bad number of channels */ + CV_BadNumChannels= -15, /**< bad number of channels, for example, some functions accept only single channel matrices */ CV_BadNumChannel1U= -16, /**/ - CV_BadDepth= -17, /**< input image depth is not supported by function */ + CV_BadDepth= -17, /**< input image depth is not supported by the function */ CV_BadAlphaChannel= -18, /**/ - CV_BadOrder= -19, /**/ - CV_BadOrigin= -20, /**/ - CV_BadAlign= -21, /**/ + CV_BadOrder= -19, /**< number of dimensions is out of range */ + CV_BadOrigin= -20, /**< incorrect input origin */ + CV_BadAlign= -21, /**< incorrect input align */ CV_BadCallBack= -22, /**/ CV_BadTileSize= -23, /**/ - CV_BadCOI= -24, /**< input COI is not supported */ - CV_BadROISize= -25, /**/ + CV_BadCOI= -24, /**< input COI is not supported */ + CV_BadROISize= -25, /**< incorrect input roi */ CV_MaskIsTiled= -26, /**/ CV_StsNullPtr= -27, /**< null pointer */ CV_StsVecLengthErr= -28, /**< incorrect vector length */ - CV_StsFilterStructContentErr= -29, /**< incorr. filter structure content */ - CV_StsKernelStructContentErr= -30, /**< incorr. transform kernel content */ + CV_StsFilterStructContentErr= -29, /**< incorrect filter structure content */ + CV_StsKernelStructContentErr= -30, /**< incorrect transform kernel content */ CV_StsFilterOffsetErr= -31, /**< incorrect filter offset value */ CV_StsBadSize= -201, /**< the input/output structure size is incorrect */ CV_StsDivByZero= -202, /**< division by zero */ @@ -163,14 +163,14 @@ enum { CV_StsParseError= -212, /**< invalid syntax/structure of the parsed file */ CV_StsNotImplemented= -213, /**< the requested function/feature is not implemented */ CV_StsBadMemBlock= -214, /**< an allocated block has been corrupted */ - CV_StsAssert= -215, /**< assertion failed */ - CV_GpuNotSupported= -216, - CV_GpuApiCallError= -217, - CV_OpenGlNotSupported= -218, - CV_OpenGlApiCallError= -219, - CV_OpenCLApiCallError= -220, + CV_StsAssert= -215, /**< assertion failed */ + CV_GpuNotSupported= -216, /**< no CUDA support */ + CV_GpuApiCallError= -217, /**< GPU API call error */ + CV_OpenGlNotSupported= -218, /**< no OpenGL support */ + CV_OpenGlApiCallError= -219, /**< OpenGL API call error */ + CV_OpenCLApiCallError= -220, /**< OpenCL API call error */ CV_OpenCLDoubleNotSupported= -221, - CV_OpenCLInitError= -222, + CV_OpenCLInitError= -222, /**< OpenCL initialization error */ CV_OpenCLNoAMDBlasFft= -223 }; From 69df0eee77a3ec19d37dff0722f1924de37e7fda Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 23 Mar 2017 18:12:48 +0300 Subject: [PATCH 039/144] cmake: fix try_compile() with --coverage flags --- CMakeLists.txt | 4 ++++ cmake/OpenCVCompilerOptions.cmake | 1 + cmake/OpenCVUtils.cmake | 1 + 3 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68fb108423..7d044583bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,10 @@ if(POLICY CMP0051) cmake_policy(SET CMP0051 NEW) endif() +if(POLICY CMP0056) + cmake_policy(SET CMP0056 NEW) +endif() + include(cmake/OpenCVUtils.cmake) # must go before the project command diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake index 0eb68b656e..1656840441 100644 --- a/cmake/OpenCVCompilerOptions.cmake +++ b/cmake/OpenCVCompilerOptions.cmake @@ -192,6 +192,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) if(ENABLE_COVERAGE) set(OPENCV_EXTRA_C_FLAGS "${OPENCV_EXTRA_C_FLAGS} --coverage") set(OPENCV_EXTRA_CXX_FLAGS "${OPENCV_EXTRA_CXX_FLAGS} --coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") endif() if(ENABLE_INSTRUMENTATION) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 935bfc2a01..4c065d66f4 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -260,6 +260,7 @@ MACRO(ocv_check_compiler_flag LANG FLAG RESULT) TRY_COMPILE(${RESULT} "${CMAKE_BINARY_DIR}" "${_fname}" + CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}" # CMP0056 do this on new CMake COMPILE_DEFINITIONS "${FLAG}" OUTPUT_VARIABLE OUTPUT) From c5eb3dfecb425ac2bbf0c3ec8ea3326b55ded216 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Thu, 23 Mar 2017 20:23:56 +0300 Subject: [PATCH 040/144] Restricted OpenVX HAL separable filter implementation to 3x3 kernel size --- 3rdparty/openvx/hal/openvx_hal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/openvx/hal/openvx_hal.cpp b/3rdparty/openvx/hal/openvx_hal.cpp index cc3e034b3a..df2d6788ef 100644 --- a/3rdparty/openvx/hal/openvx_hal.cpp +++ b/3rdparty/openvx/hal/openvx_hal.cpp @@ -601,7 +601,7 @@ int ovx_hal_sepFilterInit(cvhalFilter2D **filter_context, int src_type, int dst_ { if (!filter_context || !kernelx_data || !kernely_data || delta != 0 || src_type != CV_8UC1 || (dst_type != CV_8UC1 && dst_type != CV_16SC1) || - kernelx_length % 2 == 0 || kernely_length % 2 == 0 || anchor_x != kernelx_length / 2 || anchor_y != kernely_length / 2) + kernelx_length != 3 || kernely_length != 3 || anchor_x != 1 || anchor_y != 1) return CV_HAL_ERROR_NOT_IMPLEMENTED; ivx::border_t border; From b45e784bebe318826bb48a41023db3fe1660d91e Mon Sep 17 00:00:00 2001 From: jexner Date: Thu, 23 Mar 2017 18:48:59 +0100 Subject: [PATCH 041/144] Fix segmentation fault in cv::Mat::forEach This issue concerns only matrices with more dimensions than columns. See https://github.com/opencv/opencv/issues/8447 --- modules/core/include/opencv2/core/utility.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp index 93d599ccee..bc33f03f5d 100644 --- a/modules/core/include/opencv2/core/utility.hpp +++ b/modules/core/include/opencv2/core/utility.hpp @@ -507,7 +507,7 @@ void Mat::forEach_impl(const Functor& operation) { this->rowCall2(row, COLS); } } else { - std::vector idx(COLS); /// idx is modified in this->rowCall + std::vector idx(DIMS); /// idx is modified in this->rowCall idx[DIMS - 2] = range.start - 1; for (int line_num = range.start; line_num < range.end; ++line_num) { From e72d353b4506a97a972be7ed22805045089a5d63 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Wed, 15 Mar 2017 13:19:59 +0300 Subject: [PATCH 042/144] Download cache --- .gitignore | 1 + 3rdparty/ffmpeg/ffmpeg.cmake | 54 ++++++++----- 3rdparty/ippicv/.gitignore | 2 - 3rdparty/ippicv/downloader.cmake | 110 ------------------------- 3rdparty/ippicv/ippicv.cmake | 40 ++++++++++ 3rdparty/tbb/CMakeLists.txt | 117 ++++----------------------- CMakeLists.txt | 6 +- cmake/OpenCVDetectTBB.cmake | 4 +- cmake/OpenCVDownload.cmake | 133 +++++++++++++++++++++++++++++++ cmake/OpenCVFindIPP.cmake | 8 +- cmake/OpenCVFindLibsVideo.cmake | 6 +- cmake/OpenCVUtils.cmake | 72 ----------------- modules/videoio/CMakeLists.txt | 9 ++- 13 files changed, 243 insertions(+), 319 deletions(-) delete mode 100644 3rdparty/ippicv/.gitignore delete mode 100644 3rdparty/ippicv/downloader.cmake create mode 100644 3rdparty/ippicv/ippicv.cmake create mode 100644 cmake/OpenCVDownload.cmake diff --git a/.gitignore b/.gitignore index adef6e08d1..0fdd3e81ef 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.user *~ .*.swp +.cache .DS_Store .sw[a-z] Thumbs.db diff --git a/3rdparty/ffmpeg/ffmpeg.cmake b/3rdparty/ffmpeg/ffmpeg.cmake index 3b9f8ba7bf..c26cc7a3c6 100644 --- a/3rdparty/ffmpeg/ffmpeg.cmake +++ b/3rdparty/ffmpeg/ffmpeg.cmake @@ -1,25 +1,37 @@ -# Binary branch name: ffmpeg/master_20161202 -# Binaries were created for OpenCV: 594c136d1fcbb5816c57516e50f9cbeffbd90835 -set(FFMPEG_BINARIES_COMMIT "2a19d0006415955c79431116e4634f04d5eb5a74") -set(FFMPEG_FILE_HASH_BIN32 "f081abd9d6ca7e425d340ce586f9c090") -set(FFMPEG_FILE_HASH_BIN64 "a423363a6eb76d362ca6c406c96c8db6") -set(FFMPEG_FILE_HASH_CMAKE "5346ae1854fc7aa569a722e85af480ec") +function(download_win_ffmpeg script_var) + set(${script_var} "" PARENT_SCOPE) -set(FFMPEG_DOWNLOAD_URL ${OPENCV_FFMPEG_URL};$ENV{OPENCV_FFMPEG_URL};https://raw.githubusercontent.com/opencv/opencv_3rdparty/${FFMPEG_BINARIES_COMMIT}/ffmpeg/) + set(ids BIN32 BIN64 CMAKE) + set(name_BIN32 "opencv_ffmpeg.dll") + set(name_BIN64 "opencv_ffmpeg_64.dll") + set(name_CMAKE "ffmpeg_version.cmake") -ocv_download(PACKAGE opencv_ffmpeg.dll - HASH ${FFMPEG_FILE_HASH_BIN32} - URL ${FFMPEG_DOWNLOAD_URL} - DESTINATION_DIR ${CMAKE_CURRENT_LIST_DIR}) + # Binary branch name: ffmpeg/master_20161202 + # Binaries were created for OpenCV: 594c136d1fcbb5816c57516e50f9cbeffbd90835 + set(FFMPEG_BINARIES_COMMIT "2a19d0006415955c79431116e4634f04d5eb5a74") + set(FFMPEG_FILE_HASH_BIN32 "f081abd9d6ca7e425d340ce586f9c090") + set(FFMPEG_FILE_HASH_BIN64 "a423363a6eb76d362ca6c406c96c8db6") + set(FFMPEG_FILE_HASH_CMAKE "5346ae1854fc7aa569a722e85af480ec") -ocv_download(PACKAGE opencv_ffmpeg_64.dll - HASH ${FFMPEG_FILE_HASH_BIN64} - URL ${FFMPEG_DOWNLOAD_URL} - DESTINATION_DIR ${CMAKE_CURRENT_LIST_DIR}) + set(FFMPEG_BINARIES_COMMIT "2a19d0006415955c79431116e4634f04d5eb5a74") + set(FFMPEG_DOWNLOAD_DIR "${OpenCV_BINARY_DIR}/3rdparty/ffmpeg") -ocv_download(PACKAGE ffmpeg_version.cmake - HASH ${FFMPEG_FILE_HASH_CMAKE} - URL ${FFMPEG_DOWNLOAD_URL} - DESTINATION_DIR ${CMAKE_CURRENT_LIST_DIR}) - -include(${CMAKE_CURRENT_LIST_DIR}/ffmpeg_version.cmake) + set(status TRUE) + foreach(id ${ids}) + ocv_download(FILENAME ${name_${id}} + HASH ${FFMPEG_FILE_HASH_${id}} + URL + "$ENV{OPENCV_FFMPEG_URL}" + "${OPENCV_FFMPEG_URL}" + "https://raw.githubusercontent.com/opencv/opencv_3rdparty/${FFMPEG_BINARIES_COMMIT}/ffmpeg/" + DESTINATION_DIR ${FFMPEG_DOWNLOAD_DIR} + RELATIVE_URL + STATUS res) + if(NOT res) + set(status FALSE) + endif() + endforeach() + if(status) + set(${script_var} "${FFMPEG_DOWNLOAD_DIR}/ffmpeg_version.cmake" PARENT_SCOPE) + endif() +endfunction() diff --git a/3rdparty/ippicv/.gitignore b/3rdparty/ippicv/.gitignore deleted file mode 100644 index ea720dd57d..0000000000 --- a/3rdparty/ippicv/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -downloads/ -unpack/ diff --git a/3rdparty/ippicv/downloader.cmake b/3rdparty/ippicv/downloader.cmake deleted file mode 100644 index 0b186c0946..0000000000 --- a/3rdparty/ippicv/downloader.cmake +++ /dev/null @@ -1,110 +0,0 @@ -# -# The script downloads ICV package -# -# On return this will define: -# OPENCV_ICV_PATH - path to unpacked downloaded package -# - -function(_icv_downloader) - # Commit SHA in the opencv_3rdparty repo - set(IPPICV_BINARIES_COMMIT "81a676001ca8075ada498583e4166079e5744668") - # Define actual ICV versions - if(APPLE) - set(OPENCV_ICV_PACKAGE_NAME "ippicv_macosx_20151201.tgz") - set(OPENCV_ICV_PACKAGE_HASH "4ff1fde9a7cfdfe7250bfcd8334e0f2f") - set(OPENCV_ICV_PLATFORM "macosx") - set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_osx") - elseif(UNIX) - if(ANDROID AND NOT (ANDROID_ABI STREQUAL x86 OR ANDROID_ABI STREQUAL x86_64)) - return() - endif() - set(OPENCV_ICV_PACKAGE_NAME "ippicv_linux_20151201.tgz") - set(OPENCV_ICV_PACKAGE_HASH "808b791a6eac9ed78d32a7666804320e") - set(OPENCV_ICV_PLATFORM "linux") - set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_lnx") - elseif(WIN32 AND NOT ARM) - set(OPENCV_ICV_PACKAGE_NAME "ippicv_windows_20151201.zip") - set(OPENCV_ICV_PACKAGE_HASH "04e81ce5d0e329c3fbc606ae32cad44d") - set(OPENCV_ICV_PLATFORM "windows") - set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_win") - else() - return() # Not supported - endif() - - set(OPENCV_ICV_UNPACK_PATH "${CMAKE_BINARY_DIR}/3rdparty/ippicv") - set(OPENCV_ICV_PATH "${OPENCV_ICV_UNPACK_PATH}${OPENCV_ICV_PACKAGE_SUBDIR}") - - if(DEFINED OPENCV_ICV_PACKAGE_DOWNLOADED - AND OPENCV_ICV_PACKAGE_DOWNLOADED STREQUAL OPENCV_ICV_PACKAGE_HASH - AND EXISTS ${OPENCV_ICV_PATH}) - # Package has been downloaded and checked by the previous build - set(OPENCV_ICV_PATH "${OPENCV_ICV_PATH}" PARENT_SCOPE) - return() - else() - if(EXISTS ${OPENCV_ICV_UNPACK_PATH}) - message(STATUS "ICV: Removing previous unpacked package: ${OPENCV_ICV_UNPACK_PATH}") - file(REMOVE_RECURSE ${OPENCV_ICV_UNPACK_PATH}) - endif() - endif() - unset(OPENCV_ICV_PACKAGE_DOWNLOADED CACHE) - - set(OPENCV_ICV_PACKAGE_ARCHIVE "${CMAKE_CURRENT_LIST_DIR}/downloads/${OPENCV_ICV_PLATFORM}-${OPENCV_ICV_PACKAGE_HASH}/${OPENCV_ICV_PACKAGE_NAME}") - get_filename_component(OPENCV_ICV_PACKAGE_ARCHIVE_DIR "${OPENCV_ICV_PACKAGE_ARCHIVE}" PATH) - if(EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}") - file(MD5 "${OPENCV_ICV_PACKAGE_ARCHIVE}" archive_md5) - if(NOT archive_md5 STREQUAL OPENCV_ICV_PACKAGE_HASH) - message(WARNING "ICV: Local copy of ICV package has invalid MD5 hash: ${archive_md5} (expected: ${OPENCV_ICV_PACKAGE_HASH})") - file(REMOVE "${OPENCV_ICV_PACKAGE_ARCHIVE}") - file(REMOVE_RECURSE "${OPENCV_ICV_PACKAGE_ARCHIVE_DIR}") - endif() - endif() - - if(NOT EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}") - if(NOT DEFINED OPENCV_ICV_URL) - if(DEFINED ENV{OPENCV_ICV_URL}) - set(OPENCV_ICV_URL $ENV{OPENCV_ICV_URL}) - else() - set(OPENCV_ICV_URL "https://raw.githubusercontent.com/opencv/opencv_3rdparty/${IPPICV_BINARIES_COMMIT}/ippicv") - endif() - endif() - - file(MAKE_DIRECTORY ${OPENCV_ICV_PACKAGE_ARCHIVE_DIR}) - message(STATUS "ICV: Downloading ${OPENCV_ICV_PACKAGE_NAME}...") - file(DOWNLOAD "${OPENCV_ICV_URL}/${OPENCV_ICV_PACKAGE_NAME}" "${OPENCV_ICV_PACKAGE_ARCHIVE}" - TIMEOUT 600 STATUS __status - EXPECTED_MD5 ${OPENCV_ICV_PACKAGE_HASH}) - if(NOT __status EQUAL 0) - message(FATAL_ERROR "ICV: Failed to download ICV package: ${OPENCV_ICV_PACKAGE_NAME}. Status=${__status}") - else() - # Don't remove this code, because EXPECTED_MD5 parameter doesn't fail "file(DOWNLOAD)" step - # on wrong hash - file(MD5 "${OPENCV_ICV_PACKAGE_ARCHIVE}" archive_md5) - if(NOT archive_md5 STREQUAL OPENCV_ICV_PACKAGE_HASH) - message(FATAL_ERROR "ICV: Downloaded copy of ICV package has invalid MD5 hash: ${archive_md5} (expected: ${OPENCV_ICV_PACKAGE_HASH})") - endif() - endif() - endif() - - ocv_assert(EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}") - ocv_assert(NOT EXISTS "${OPENCV_ICV_UNPACK_PATH}") - file(MAKE_DIRECTORY ${OPENCV_ICV_UNPACK_PATH}) - ocv_assert(EXISTS "${OPENCV_ICV_UNPACK_PATH}") - - message(STATUS "ICV: Unpacking ${OPENCV_ICV_PACKAGE_NAME} to ${OPENCV_ICV_UNPACK_PATH}...") - execute_process(COMMAND ${CMAKE_COMMAND} -E tar xz "${OPENCV_ICV_PACKAGE_ARCHIVE}" - WORKING_DIRECTORY "${OPENCV_ICV_UNPACK_PATH}" - RESULT_VARIABLE __result) - - if(NOT __result EQUAL 0) - message(FATAL_ERROR "ICV: Failed to unpack ICV package from ${OPENCV_ICV_PACKAGE_ARCHIVE} to ${OPENCV_ICV_UNPACK_PATH} with error ${__result}") - endif() - - ocv_assert(EXISTS "${OPENCV_ICV_PATH}") - - set(OPENCV_ICV_PACKAGE_DOWNLOADED "${OPENCV_ICV_PACKAGE_HASH}" CACHE INTERNAL "ICV package hash") - - message(STATUS "ICV: Package successfully downloaded") - set(OPENCV_ICV_PATH "${OPENCV_ICV_PATH}" PARENT_SCOPE) -endfunction() - -_icv_downloader() diff --git a/3rdparty/ippicv/ippicv.cmake b/3rdparty/ippicv/ippicv.cmake new file mode 100644 index 0000000000..ce100a1ffe --- /dev/null +++ b/3rdparty/ippicv/ippicv.cmake @@ -0,0 +1,40 @@ +function(download_ippicv root_var) + set(${root_var} "" PARENT_SCOPE) + + # Commit SHA in the opencv_3rdparty repo + set(IPPICV_COMMIT "81a676001ca8075ada498583e4166079e5744668") + # Define actual ICV versions + if(APPLE) + set(OPENCV_ICV_NAME "ippicv_macosx_20151201.tgz") + set(OPENCV_ICV_HASH "4ff1fde9a7cfdfe7250bfcd8334e0f2f") + set(OPENCV_ICV_PLATFORM "macosx") + set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_osx") + elseif((UNIX AND NOT ANDROID) OR (UNIX AND ANDROID_ABI MATCHES "x86")) + set(OPENCV_ICV_NAME "ippicv_linux_20151201.tgz") + set(OPENCV_ICV_HASH "808b791a6eac9ed78d32a7666804320e") + set(OPENCV_ICV_PLATFORM "linux") + set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_lnx") + elseif(WIN32 AND NOT ARM) + set(OPENCV_ICV_NAME "ippicv_windows_20151201.zip") + set(OPENCV_ICV_HASH "04e81ce5d0e329c3fbc606ae32cad44d") + set(OPENCV_ICV_PLATFORM "windows") + set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_win") + else() + return() + endif() + + set(THE_ROOT "${OpenCV_BINARY_DIR}/3rdparty/ippicv") + ocv_download(FILENAME ${OPENCV_ICV_NAME} + HASH ${OPENCV_ICV_HASH} + URL + "${OPENCV_IPPICV_URL}" + "$ENV{OPENCV_IPPICV_URL}" + "https://raw.githubusercontent.com/opencv/opencv_3rdparty/${IPPICV_COMMIT}/ippicv/" + DESTINATION_DIR "${THE_ROOT}" + STATUS res + UNPACK RELATIVE_URL) + + if(res) + set(${root_var} "${THE_ROOT}/${OPENCV_ICV_PACKAGE_SUBDIR}" PARENT_SCOPE) + endif() +endfunction() diff --git a/3rdparty/tbb/CMakeLists.txt b/3rdparty/tbb/CMakeLists.txt index 950896309f..fa37cc26fc 100644 --- a/3rdparty/tbb/CMakeLists.txt +++ b/3rdparty/tbb/CMakeLists.txt @@ -6,112 +6,27 @@ if (WIN32 AND NOT ARM) endif() set(tbb_ver "tbb44_20160128oss") -set(tbb_url "http://www.threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb44_20160128oss_src_0.tgz") -set(tbb_md5 "9d8a4cdf43496f1b3f7c473a5248e5cc") +set(tbb_filename "4.4.3.tar.gz") +set(tbb_subdir "tbb-4.4.3") +set(tbb_md5 "8e7200af3ac16e91a0d1535c606a485c") set(tbb_version_file "version_string.ver") ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4702) ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) -# 4.1 update 4 - The first release that supports Windows RT. Hangs on some Android devices -#set(tbb_ver "tbb41_20130613oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130613oss_src.tgz") -#set(tbb_md5 "108c8c1e481b0aaea61878289eb28b6a") -#set(tbb_version_file "version_string.ver") -#ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4702) - -# 4.1 update 2 - works fine -#set(tbb_ver "tbb41_20130116oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130116oss_src.tgz") -#set(tbb_md5 "3809790e1001a1b32d59c9fee590ee85") -#set(tbb_version_file "version_string.ver") -#ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) - -# 4.1 update 3 dev - Hangs on some Android devices -#set(tbb_ver "tbb41_20130401oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130401oss_src.tgz") -#set(tbb_md5 "f2f591a0d2ca8f801e221ce7d9ea84bb") -#set(tbb_version_file "version_string.ver") -#ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) - -# 4.1 update 2 - works fine -#set(tbb_ver "tbb41_20130116oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130116oss_src.tgz") -#set(tbb_md5 "3809790e1001a1b32d59c9fee590ee85") -#set(tbb_version_file "version_string.ver") -#ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) - -# 4.1 update 1 - works fine -#set(tbb_ver "tbb41_20121003oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20121003oss_src.tgz") -#set(tbb_md5 "2a684fefb855d2d0318d1ef09afa75ff") -#set(tbb_version_file "version_string.ver") - -# 4.1 - works fine -#set(tbb_ver "tbb41_20120718oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20120718oss_src.tgz") -#set(tbb_md5 "31b9ec300f3d09da2504d5d882788dd4") -#set(tbb_version_file "version_string.ver") - -# 4.0 update 5 - works fine -#set(tbb_ver "tbb40_20120613oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb40_20120613oss_src.tgz") -#set(tbb_md5 "da01ed74944ec5950cfae3476901a172") -#set(tbb_version_file "version_string.ver") - -# 4.0 update 4 - works fine -#set(tbb_ver "tbb40_20120408oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb40_20120408oss_src.tgz") -#set(tbb_md5 "734b356da7fe0ed308741f3e6018251e") -#set(tbb_version_file "version_string.ver") - -# 4.0 update 3 - build broken -#set(tbb_ver "tbb40_20120201oss") -#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb40_20120201oss_src.tgz") -#set(tbb_md5 "4669e7d4adee018de7a7b8b972987218") -#set(tbb_version_file "version_string.tmp") - -set(tbb_tarball "${CMAKE_CURRENT_SOURCE_DIR}/${tbb_ver}_src.tgz") -set(tbb_src_dir "${CMAKE_CURRENT_BINARY_DIR}/${tbb_ver}") - -if(EXISTS "${tbb_tarball}") - file(MD5 "${tbb_tarball}" tbb_local_md5) - if(NOT tbb_local_md5 STREQUAL tbb_md5) - message(WARNING "Local copy of TBB source tarball has invalid MD5 hash: ${tbb_local_md5} (expected: ${tbb_md5})") - file(REMOVE "${tbb_tarball}") - if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${tbb_ver}") - file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/${tbb_ver}") - endif() - endif() -endif() - -if(NOT EXISTS "${tbb_tarball}") - message(STATUS "Downloading ${tbb_ver}_src.tgz") - file(DOWNLOAD "${tbb_url}" "${tbb_tarball}" TIMEOUT 600 STATUS __statvar) - if(NOT __statvar EQUAL 0) - message(FATAL_ERROR "Failed to download TBB sources (${__statvar}): ${tbb_url}") - endif() - file(MD5 "${tbb_tarball}" tbb_local_md5) - if(NOT tbb_local_md5 STREQUAL tbb_md5) - file(REMOVE "${tbb_tarball}") - message(FATAL_ERROR "Downloaded TBB source tarball has invalid MD5 hash: ${tbb_local_md5} (expected: ${tbb_md5})") - endif() - - if(EXISTS "${tbb_src_dir}") - file(REMOVE_RECURSE "${tbb_src_dir}") - endif() -endif() - -# untar TBB sources -if(NOT EXISTS "${tbb_src_dir}") - message(STATUS "Unpacking ${tbb_ver}_src.tgz to ${tbb_src_dir}") - execute_process(COMMAND ${CMAKE_COMMAND} -E tar xz "${tbb_tarball}" - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - RESULT_VARIABLE tbb_untar_RESULT) - - if(NOT tbb_untar_RESULT EQUAL 0 OR NOT EXISTS "${tbb_src_dir}") - message(FATAL_ERROR "Failed to unpack TBB sources from ${tbb_tarball} to ${tbb_src_dir} with error ${tbb_untar_RESULT}") - endif() +set(tbb_src_dir "${OpenCV_BINARY_DIR}/3rdparty/tbb") +ocv_download(FILENAME ${tbb_filename} + HASH ${tbb_md5} + URL + "${OPENCV_TBB_URL}" + "$ENV{OPENCV_TBB_URL}" + "https://github.com/01org/tbb/archive/" + DESTINATION_DIR ${tbb_src_dir} + STATUS res + UNPACK RELATIVE_URL) +if(NOT res) + return() endif() +set(tbb_src_dir "${tbb_src_dir}/${tbb_subdir}") ocv_include_directories("${tbb_src_dir}/include" "${tbb_src_dir}/src/" diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d044583bd..8c913e0230 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,8 @@ ocv_cmake_eval(DEBUG_PRE ONCE) ocv_clear_vars(OpenCVModules_TARGETS) +include(cmake/OpenCVDownload.cmake) + # ---------------------------------------------------------------------------- # Break in case of popular CMake configuration mistakes # ---------------------------------------------------------------------------- @@ -301,8 +303,6 @@ OCV_OPTION(CV_ENABLE_INTRINSICS "Use intrinsic-based optimized code" ON ) OCV_OPTION(CV_DISABLE_OPTIMIZATION "Disable explicit optimized code (dispatched code/intrinsics/loop unrolling/etc)" OFF ) -OCV_OPTION(DOWNLOAD_EXTERNAL_TEST_DATA "Download external test data (Python executable and OPENCV_TEST_DATA_PATH environment variable may be required)" OFF ) - if(ENABLE_IMPL_COLLECTION) add_definitions(-DCV_COLLECT_IMPL_DATA) @@ -1108,7 +1108,7 @@ endif(DEFINED WITH_1394) if(DEFINED WITH_FFMPEG OR HAVE_FFMPEG) if(WIN32) - status(" FFMPEG:" WITH_FFMPEG THEN "YES (prebuilt binaries)" ELSE NO) + status(" FFMPEG:" HAVE_FFMPEG THEN "YES (prebuilt binaries)" ELSE NO) else() status(" FFMPEG:" HAVE_FFMPEG THEN YES ELSE NO) endif() diff --git a/cmake/OpenCVDetectTBB.cmake b/cmake/OpenCVDetectTBB.cmake index 89e4970b28..426487a88c 100644 --- a/cmake/OpenCVDetectTBB.cmake +++ b/cmake/OpenCVDetectTBB.cmake @@ -68,7 +68,9 @@ endfunction() if(BUILD_TBB) add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/tbb") - message(STATUS "Found TBB: build") + if(NOT TARGET tbb) + return() + endif() set(HAVE_TBB TRUE) endif() diff --git a/cmake/OpenCVDownload.cmake b/cmake/OpenCVDownload.cmake new file mode 100644 index 0000000000..e118e28f87 --- /dev/null +++ b/cmake/OpenCVDownload.cmake @@ -0,0 +1,133 @@ +# +# Download and optionally unpack a file +# +# ocv_download(FILENAME p HASH h URL u1 [u2 ...] DESTINATION_DIR d [STATUS s] [UNPACK] [RELATIVE]) +# FILENAME - filename +# HASH - MD5 hash +# URL - full download url (first nonempty value will be chosen) +# DESTINATION_DIR - file will be copied to this directory +# STATUS - passed variable will be updated in parent scope, +# function will not fail the build in case of download problem if this option is provided, +# but will fail in case when other operations (copy, remove, etc.) failed +# UNPACK - downloaded file will be unpacked to DESTINATION_DIR +# RELATIVE_URL - if set, then URL is treated as a base, and FILENAME will be appended to it +# Note: uses OPENCV_DOWNLOAD_PATH folder as cache, default is /.cache + +set(OPENCV_DOWNLOAD_PATH "${OpenCV_SOURCE_DIR}/.cache" CACHE PATH "Cache directory for downloaded files") +set(OPENCV_DOWNLOAD_LOG "${OpenCV_BINARY_DIR}/CMakeDownloadLog.txt") + +# Init download cache directory and log file +if(NOT EXISTS "${OPENCV_DOWNLOAD_PATH}") + file(MAKE_DIRECTORY ${OPENCV_DOWNLOAD_PATH}) +endif() +file(WRITE "${OPENCV_DOWNLOAD_LOG}" "use_cache \"${OPENCV_DOWNLOAD_PATH}\"\n") + + +function(ocv_download) + cmake_parse_arguments(DL "UNPACK;RELATIVE_URL" "FILENAME;HASH;DESTINATION_DIR;STATUS" "URL" ${ARGN}) + + ocv_assert(DEFINED DL_FILENAME) + ocv_assert(DEFINED DL_HASH) + ocv_assert(DEFINED DL_URL) + ocv_assert(DEFINED DL_DESTINATION_DIR) + + if(DEFINED DL_STATUS) + set(${DL_STATUS} TRUE PARENT_SCOPE) + endif() + + # Select first non-empty url + foreach(url ${DL_URL}) + if(url) + set(DL_URL "${url}") + break() + endif() + endforeach() + + # Append filename to url if needed + if(DL_RELATIVE_URL) + set(DL_URL "${DL_URL}${DL_FILENAME}") + endif() + + set(mode "copy") + if(DL_UNPACK) + set(mode "unpack") + endif() + + # Log all calls to file + file(APPEND "${OPENCV_DOWNLOAD_LOG}" "do_${mode} \"${DL_FILENAME}\" \"${DL_HASH}\" \"${DL_URL}\" \"${DL_DESTINATION_DIR}\"\n") + # ... and to console + message(STATUS "Download: ${DL_FILENAME}") + + # Copy mode: check if copy destination exists and is correct + if(NOT DL_UNPACK) + set(COPY_DESTINATION "${DL_DESTINATION_DIR}/${DL_FILENAME}") + if(EXISTS "${COPY_DESTINATION}") + file(MD5 "${COPY_DESTINATION}" target_md5) + if(target_md5 STREQUAL DL_HASH) + return() + endif() + endif() + endif() + + # Check cache first + set(CACHE_CANDIDATE "${OPENCV_DOWNLOAD_PATH}/${DL_HASH}-${DL_FILENAME}") + if(EXISTS "${CACHE_CANDIDATE}") + file(MD5 "${CACHE_CANDIDATE}" target_md5) + if(NOT target_md5 STREQUAL DL_HASH) + file(REMOVE ${CACHE_CANDIDATE}) + endif() + endif() + + # Download + if(NOT EXISTS "${CACHE_CANDIDATE}") + file(DOWNLOAD "${DL_URL}" "${CACHE_CANDIDATE}" + INACTIVITY_TIMEOUT 60 + TIMEOUT 600 + STATUS status + LOG log) + string(REPLACE "\n" "\n# " log "# ${log}") + file(APPEND "${OPENCV_DOWNLOAD_LOG}" "${log}\n\n") + if(NOT status EQUAL 0) + set(msg_level FATAL_ERROR) + if(DEFINED DL_STATUS) + set(${DL_STATUS} FALSE PARENT_SCOPE) + set(msg_level WARNING) + endif() + message(${msg_level} "Download failed: ${status}") + return() + endif() + + # Don't remove this code, because EXPECTED_MD5 parameter doesn't fail "file(DOWNLOAD)" step on wrong hash + file(MD5 "${CACHE_CANDIDATE}" target_md5) + if(NOT target_md5 STREQUAL DL_HASH) + set(msg_level FATAL_ERROR) + if(DEFINED DL_STATUS) + set(${DL_STATUS} FALSE PARENT_SCOPE) + set(msg_level WARNING) + endif() + message(${msg_level} "Hash mismatch: ${target_md5}") + return() + endif() + endif() + + # Unpack or copy + if(DL_UNPACK) + if(EXISTS "${DL_DESTINATION_DIR}") + file(REMOVE_RECURSE "${DL_DESTINATION_DIR}") + endif() + file(MAKE_DIRECTORY "${DL_DESTINATION_DIR}") + execute_process(COMMAND "${CMAKE_COMMAND}" -E tar xz "${CACHE_CANDIDATE}" + WORKING_DIRECTORY "${DL_DESTINATION_DIR}" + RESULT_VARIABLE res) + if(NOT res EQUAL 0) + message(FATAL_ERROR "Unpack failed: ${res}") + endif() + else() + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CACHE_CANDIDATE}" "${COPY_DESTINATION}" + RESULT_VARIABLE res) + if(NOT res EQUAL 0) + message(FATAL_ERROR "Copy failed: ${res}") + endif() + endif() + +endfunction() diff --git a/cmake/OpenCVFindIPP.cmake b/cmake/OpenCVFindIPP.cmake index ba3f5de118..5e8baee0df 100644 --- a/cmake/OpenCVFindIPP.cmake +++ b/cmake/OpenCVFindIPP.cmake @@ -233,6 +233,7 @@ endmacro() if(DEFINED ENV{OPENCV_IPP_PATH} AND NOT DEFINED IPPROOT) set(IPPROOT "$ENV{OPENCV_IPP_PATH}") endif() + if(NOT DEFINED IPPROOT) if(IOS AND NOT x86_64) # 2016/10: There is an issue with MacOS binary .a file. @@ -240,10 +241,9 @@ if(NOT DEFINED IPPROOT) # So try to ignore i386 version return() endif() - include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/downloader.cmake") - if(DEFINED OPENCV_ICV_PATH) - set(IPPROOT "${OPENCV_ICV_PATH}") - else() + include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/ippicv.cmake") + download_ippicv(IPPROOT) + if(NOT IPPROOT) return() endif() endif() diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake index 1eff03b581..13b62ac4dd 100644 --- a/cmake/OpenCVFindLibsVideo.cmake +++ b/cmake/OpenCVFindLibsVideo.cmake @@ -217,7 +217,11 @@ ocv_clear_vars(HAVE_FFMPEG) if(WITH_FFMPEG) if(WIN32 AND NOT ARM) include("${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/ffmpeg.cmake") - set(HAVE_FFMPEG TRUE) + download_win_ffmpeg(FFMPEG_CMAKE_SCRIPT) + if(FFMPEG_CMAKE_SCRIPT) + set(HAVE_FFMPEG TRUE) + include("${FFMPEG_CMAKE_SCRIPT}") + endif() elseif(PKG_CONFIG_FOUND) ocv_check_modules(FFMPEG libavcodec libavformat libavutil libswscale) ocv_check_modules(FFMPEG_libavresample libavresample) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 4c065d66f4..ccb87311f5 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -1063,78 +1063,6 @@ macro(ocv_get_all_libs _modules _extra _3rdparty) endforeach() endmacro() -function(ocv_download) - cmake_parse_arguments(DL "" "PACKAGE;HASH;URL;DESTINATION_DIR;DOWNLOAD_DIR" "" ${ARGN}) - if(NOT DL_DOWNLOAD_DIR) - set(DL_DOWNLOAD_DIR "${DL_DESTINATION_DIR}/downloads") - endif() - if(DEFINED DL_DESTINATION_DIR) - set(DESTINATION_TARGET "${DL_DESTINATION_DIR}/${DL_PACKAGE}") - if(EXISTS "${DESTINATION_TARGET}") - file(MD5 "${DESTINATION_TARGET}" target_md5) - if(NOT target_md5 STREQUAL DL_HASH) - file(REMOVE "${DESTINATION_TARGET}") - else() - set(DOWNLOAD_PACKAGE_LOCATION "" PARENT_SCOPE) - unset(DOWNLOAD_PACKAGE_LOCATION) - return() - endif() - endif() - endif() - set(DOWNLOAD_TARGET "${DL_DOWNLOAD_DIR}/${DL_HASH}/${DL_PACKAGE}") - get_filename_component(DOWNLOAD_TARGET_DIR "${DOWNLOAD_TARGET}" PATH) - if(EXISTS "${DOWNLOAD_TARGET}") - file(MD5 "${DOWNLOAD_TARGET}" target_md5) - if(NOT target_md5 STREQUAL DL_HASH) - message(WARNING "Download: Local copy of ${DL_PACKAGE} has invalid MD5 hash: ${target_md5} (expected: ${DL_HASH})") - file(REMOVE "${DOWNLOAD_TARGET}") - file(REMOVE_RECURSE "${DOWNLOAD_TARGET_DIR}") - endif() - endif() - - if(NOT EXISTS "${DOWNLOAD_TARGET}") - set(__url "") - foreach(__url_i ${DL_URL}) - if(NOT ("${__url_i}" STREQUAL "")) - set(__url "${__url_i}") - break() - endif() - endforeach() - if("${__url}" STREQUAL "") - message(FATAL_ERROR "Download URL is not specified for package ${DL_PACKAGE}") - endif() - - if(NOT EXISTS "${DOWNLOAD_TARGET_DIR}") - file(MAKE_DIRECTORY ${DOWNLOAD_TARGET_DIR}) - endif() - message(STATUS "Downloading ${DL_PACKAGE}...") - #message(STATUS " ${__url}${DL_PACKAGE}") - file(DOWNLOAD "${__url}${DL_PACKAGE}" "${DOWNLOAD_TARGET}" - TIMEOUT 600 STATUS __status - EXPECTED_MD5 ${DL_HASH}) - if(NOT __status EQUAL 0) - message(FATAL_ERROR "Failed to download ${DL_PACKAGE}. Status=${__status}") - else() - # Don't remove this code, because EXPECTED_MD5 parameter doesn't fail "file(DOWNLOAD)" step on wrong hash - file(MD5 "${DOWNLOAD_TARGET}" target_md5) - if(NOT target_md5 STREQUAL DL_HASH) - message(FATAL_ERROR "Downloaded copy of ${DL_PACKAGE} has invalid MD5 hash: ${target_md5} (expected: ${DL_HASH})") - endif() - endif() - message(STATUS "Downloading ${DL_PACKAGE}... Done") - endif() - - if(DEFINED DL_DESTINATION_DIR) - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DOWNLOAD_TARGET}" "${DL_DESTINATION_DIR}/" - RESULT_VARIABLE __result) - - if(NOT __result EQUAL 0) - message(FATAL_ERROR "Downloader: Failed to copy package from ${DOWNLOAD_TARGET} to ${DL_DESTINATION_DIR} with error ${__result}") - endif() - endif() - - set(DOWNLOAD_PACKAGE_LOCATION ${DOWNLOAD_TARGET} PARENT_SCOPE) -endfunction() function(ocv_add_test_from_target test_name test_kind the_target) if(CMAKE_VERSION VERSION_GREATER "2.8" AND NOT CMAKE_CROSSCOMPILING) diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index cbcb8a1a63..06279a08cf 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -255,15 +255,16 @@ endif() ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated-declarations) -if(WIN32 AND WITH_FFMPEG) +if(WIN32 AND HAVE_FFMPEG) #copy ffmpeg dll to the output folder if(MSVC64 OR MINGW64) set(FFMPEG_SUFFIX _64) endif() + set(ffmpeg_dir "${OpenCV_BINARY_DIR}/3rdparty/ffmpeg") set(ffmpeg_bare_name "opencv_ffmpeg${FFMPEG_SUFFIX}.dll") set(ffmpeg_bare_name_ver "opencv_ffmpeg${OPENCV_DLLVERSION}${FFMPEG_SUFFIX}.dll") - set(ffmpeg_path "${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/${ffmpeg_bare_name}") + set(ffmpeg_path "${ffmpeg_dir}/${ffmpeg_bare_name}") if(MSVC_IDE) add_custom_command(TARGET ${the_module} POST_BUILD @@ -283,8 +284,8 @@ if(WIN32 AND WITH_FFMPEG) install(FILES "${ffmpeg_path}" DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT libs RENAME "${ffmpeg_bare_name_ver}") if(INSTALL_CREATE_DISTRIB) - install(FILES "${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/opencv_ffmpeg.dll" DESTINATION "bin/" COMPONENT libs RENAME "opencv_ffmpeg${OPENCV_DLLVERSION}.dll") - install(FILES "${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/opencv_ffmpeg_64.dll" DESTINATION "bin/" COMPONENT libs RENAME "opencv_ffmpeg${OPENCV_DLLVERSION}_64.dll") + install(FILES "${ffmpeg_dir}/opencv_ffmpeg.dll" DESTINATION "bin/" COMPONENT libs RENAME "opencv_ffmpeg${OPENCV_DLLVERSION}.dll") + install(FILES "${ffmpeg_dir}/opencv_ffmpeg_64.dll" DESTINATION "bin/" COMPONENT libs RENAME "opencv_ffmpeg${OPENCV_DLLVERSION}_64.dll") endif() endif() endmacro() From 30d26acee0ae3a2f5355cddbbdf17b8e40c847c0 Mon Sep 17 00:00:00 2001 From: Alexander Broemmer Date: Thu, 23 Mar 2017 19:16:57 +0100 Subject: [PATCH 043/144] Make stitching panoramas reusable after estimating transform once Stitcher will now make a working copy of the CameraParams object to avoid side effects when composing Panorama. Makes it possible to estimate transform once and then compose multiple panoramas. Useful for setup with fixed cameras. --- modules/stitching/src/stitcher.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/stitching/src/stitcher.cpp b/modules/stitching/src/stitcher.cpp index f7b9172a33..591b5fe883 100644 --- a/modules/stitching/src/stitcher.cpp +++ b/modules/stitching/src/stitcher.cpp @@ -261,6 +261,8 @@ Stitcher::Status Stitcher::composePanorama(InputArrayOfArrays images, OutputArra double compose_scale = 1; bool is_compose_scale_set = false; + std::vector cameras_scaled(cameras_); + UMat full_img, img; for (size_t img_idx = 0; img_idx < imgs_.size(); ++img_idx) { @@ -282,16 +284,16 @@ Stitcher::Status Stitcher::composePanorama(InputArrayOfArrays images, OutputArra compose_work_aspect = compose_scale / work_scale_; // Update warped image scale - warped_image_scale_ *= static_cast(compose_work_aspect); - w = warper_->create((float)warped_image_scale_); + float warp_scale = static_cast(warped_image_scale_ * compose_work_aspect); + w = warper_->create(warp_scale); // Update corners and sizes for (size_t i = 0; i < imgs_.size(); ++i) { // Update intrinsics - cameras_[i].focal *= compose_work_aspect; - cameras_[i].ppx *= compose_work_aspect; - cameras_[i].ppy *= compose_work_aspect; + cameras_scaled[i].ppx *= compose_work_aspect; + cameras_scaled[i].ppy *= compose_work_aspect; + cameras_scaled[i].focal *= compose_work_aspect; // Update corner and size Size sz = full_img_sizes_[i]; @@ -302,8 +304,8 @@ Stitcher::Status Stitcher::composePanorama(InputArrayOfArrays images, OutputArra } Mat K; - cameras_[i].K().convertTo(K, CV_32F); - Rect roi = w->warpRoi(sz, K, cameras_[i].R); + cameras_scaled[i].K().convertTo(K, CV_32F); + Rect roi = w->warpRoi(sz, K, cameras_scaled[i].R); corners[i] = roi.tl(); sizes[i] = roi.size(); } @@ -324,7 +326,7 @@ Stitcher::Status Stitcher::composePanorama(InputArrayOfArrays images, OutputArra LOGLN(" after resize time: " << ((getTickCount() - compositing_t) / getTickFrequency()) << " sec"); Mat K; - cameras_[img_idx].K().convertTo(K, CV_32F); + cameras_scaled[img_idx].K().convertTo(K, CV_32F); #if ENABLE_LOG int64 pt = getTickCount(); From 46af07575e4c7f9bf9597beaacff414a9fe244db Mon Sep 17 00:00:00 2001 From: Julian Exner Date: Fri, 24 Mar 2017 14:54:10 +0100 Subject: [PATCH 044/144] Add test case for cv::Mat::forEach This test case uses a matrix with more dimensions than columns. Without the fix in https://github.com/opencv/opencv/pull/8448/commits/b45e784bebe318826bb48a41023db3fe1660d91e this crashes with a segmentation fault, hangs or simply fails with wrong values. --- modules/core/test/test_mat.cpp | 63 ++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 9a379f468d..98ce812ee9 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -659,6 +659,18 @@ struct InitializerFunctor{ } }; +template +struct InitializerFunctor5D{ + /// Initializer for cv::Mat::forEach test (5 dimensional case) + void operator()(Pixel & pixel, const int * idx) const { + pixel[0] = idx[0]; + pixel[1] = idx[1]; + pixel[2] = idx[2]; + pixel[3] = idx[3]; + pixel[4] = idx[4]; + } +}; + void Core_ArrayOpTest::run( int /* start_from */) { int errcount = 0; @@ -736,6 +748,57 @@ void Core_ArrayOpTest::run( int /* start_from */) } } + // test cv::Mat::forEach + // with a matrix that has more dimensions than columns + // See https://github.com/opencv/opencv/issues/8447 + { + const int dims[5] = { 2, 2, 2, 2, 2 }; + typedef cv::Vec Pixel; + + cv::Mat a = cv::Mat::zeros(5, dims, CV_32SC(5)); + InitializerFunctor5D initializer; + + a.forEach(initializer); + + uint64 total = 0; + bool error_reported = false; + for (int i0 = 0; i0 < dims[0]; ++i0) { + for (int i1 = 0; i1 < dims[1]; ++i1) { + for (int i2 = 0; i2 < dims[2]; ++i2) { + for (int i3 = 0; i3 < dims[3]; ++i3) { + for (int i4 = 0; i4 < dims[4]; ++i4) { + const int i[5] = { i0, i1, i2, i3, i4 }; + Pixel& pixel = a.at(i); + if (pixel[0] != i0 || pixel[1] != i1 || pixel[2] != i2 || pixel[3] != i3 || pixel[4] != i4) { + if (!error_reported) { + ts->printf(cvtest::TS::LOG, "forEach is not correct.\n" + "First error detected at position (%d, %d, %d, %d, %d), got value (%d, %d, %d, %d, %d).\n", + i0, i1, i2, i3, i4, + pixel[0], pixel[1], pixel[2], pixel[3], pixel[4]); + error_reported = true; + } + errcount++; + } + total += pixel[0]; + total += pixel[1]; + total += pixel[2]; + total += pixel[3]; + total += pixel[4]; + } + } + } + } + } + uint64 total2 = 0; + for (size_t i = 0; i < sizeof(dims) / sizeof(dims[0]); ++i) { + total2 += ((dims[i] - 1) * dims[i] / 2) * dims[0] * dims[1] * dims[2] * dims[3] * dims[4] / dims[i]; + } + if (total != total2) { + ts->printf(cvtest::TS::LOG, "forEach is not correct because total is invalid.\n"); + errcount++; + } + } + RNG rng; const int MAX_DIM = 5, MAX_DIM_SZ = 10; // sparse matrix operations From 13540bf7f4d91dacf12d32d6c0864ea180593468 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Fri, 24 Mar 2017 13:26:32 -0700 Subject: [PATCH 045/144] Update bgfg_gaussmix2.cpp Addressed comments. --- modules/video/src/bgfg_gaussmix2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/video/src/bgfg_gaussmix2.cpp b/modules/video/src/bgfg_gaussmix2.cpp index ad81c55eae..977a2581f3 100644 --- a/modules/video/src/bgfg_gaussmix2.cpp +++ b/modules/video/src/bgfg_gaussmix2.cpp @@ -696,7 +696,7 @@ public: // Renormalize weights. In the special case that the pixel does // not agree with any modes, set weights to zero (a new mode will be added below). float invWeight = 0.f; - if (fabs(totalWeight) > DBL_EPSILON) { + if (std::abs(totalWeight) > FLT_EPSILON) { invWeight = 1.f/totalWeight; } @@ -906,7 +906,7 @@ void BackgroundSubtractorMOG2Impl::getBackgroundImage_intern(OutputArray backgro break; } float invWeight = 0.f; - if (fabs(totalWeight) > DBL_EPSILON) { + if (std::abs(totalWeight) > FLT_EPSILON) { invWeight = 1.f/totalWeight; } From 005c4777c780dabca3cd4b24190b9206fc488a86 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sat, 25 Mar 2017 01:28:43 +0300 Subject: [PATCH 046/144] cmake: fix MSVC static builds --- cmake/OpenCVCRTLinkage.cmake | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmake/OpenCVCRTLinkage.cmake b/cmake/OpenCVCRTLinkage.cmake index f5509d83f3..2b6f95cc18 100644 --- a/cmake/OpenCVCRTLinkage.cmake +++ b/cmake/OpenCVCRTLinkage.cmake @@ -38,6 +38,9 @@ if(MSVC AND WINRT) set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO /OPT:NOREF /OPT:NOICF") endif() +# Ignore warning: This object file does not define any previously undefined public symbols, ... +set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221") + if(NOT BUILD_SHARED_LIBS AND BUILD_WITH_STATIC_CRT) foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE @@ -52,9 +55,9 @@ if(NOT BUILD_SHARED_LIBS AND BUILD_WITH_STATIC_CRT) endif() endforeach(flag_var) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:atlthunk.lib /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcrtd.lib") - set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt.lib") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:libcmtd.lib") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:atlthunk.lib") + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:msvcrt.lib") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:libcpmtd.lib /NODEFAULTLIB:msvcrtd.lib") else() foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE From 35f66340d730a50a8a19e61016e9dabfa6696910 Mon Sep 17 00:00:00 2001 From: Claudio Date: Fri, 3 Feb 2017 16:00:16 +0100 Subject: [PATCH 047/144] Add cuda::Stream capability to cuda::HOG::compute In the previous version only the default stream was/could be used, i.e. cv::cuda::Stream::Null(). With this change, HOG::compute() will now run in parallel over different cuda::Streams. The code has been reordered so that all data allocation is completed first, then all the kernels are run in parallel over streams. Fix #8177 --- modules/cudaobjdetect/src/cuda/hog.cu | 77 +++++++++++------------- modules/cudaobjdetect/src/hog.cpp | 87 +++++++++++++-------------- 2 files changed, 77 insertions(+), 87 deletions(-) diff --git a/modules/cudaobjdetect/src/cuda/hog.cu b/modules/cudaobjdetect/src/cuda/hog.cu index c8609e7b03..d7dbd4a3d6 100644 --- a/modules/cudaobjdetect/src/cuda/hog.cu +++ b/modules/cudaobjdetect/src/cuda/hog.cu @@ -52,6 +52,7 @@ namespace cv { namespace cuda { namespace device namespace hog { + __constant__ int cnbins; __constant__ int cblock_stride_x; __constant__ int cblock_stride_y; @@ -99,27 +100,28 @@ namespace cv { namespace cuda { namespace device void set_up_constants(int nbins, int block_stride_x, int block_stride_y, - int nblocks_win_x, int nblocks_win_y, int ncells_block_x, int ncells_block_y) + int nblocks_win_x, int nblocks_win_y, int ncells_block_x, int ncells_block_y, + const cudaStream_t& stream) { - cudaSafeCall( cudaMemcpyToSymbol(cnbins, &nbins, sizeof(nbins)) ); - cudaSafeCall( cudaMemcpyToSymbol(cblock_stride_x, &block_stride_x, sizeof(block_stride_x)) ); - cudaSafeCall( cudaMemcpyToSymbol(cblock_stride_y, &block_stride_y, sizeof(block_stride_y)) ); - cudaSafeCall( cudaMemcpyToSymbol(cnblocks_win_x, &nblocks_win_x, sizeof(nblocks_win_x)) ); - cudaSafeCall( cudaMemcpyToSymbol(cnblocks_win_y, &nblocks_win_y, sizeof(nblocks_win_y)) ); - cudaSafeCall( cudaMemcpyToSymbol(cncells_block_x, &ncells_block_x, sizeof(ncells_block_x)) ); - cudaSafeCall( cudaMemcpyToSymbol(cncells_block_y, &ncells_block_y, sizeof(ncells_block_y)) ); + cudaSafeCall(cudaMemcpyToSymbolAsync(cnbins, &nbins, sizeof(nbins), 0, cudaMemcpyHostToDevice, stream)); + cudaSafeCall(cudaMemcpyToSymbolAsync(cblock_stride_x, &block_stride_x, sizeof(block_stride_x), 0, cudaMemcpyHostToDevice, stream)); + cudaSafeCall(cudaMemcpyToSymbolAsync(cblock_stride_y, &block_stride_y, sizeof(block_stride_y), 0, cudaMemcpyHostToDevice, stream)); + cudaSafeCall(cudaMemcpyToSymbolAsync(cnblocks_win_x, &nblocks_win_x, sizeof(nblocks_win_x), 0, cudaMemcpyHostToDevice, stream)); + cudaSafeCall(cudaMemcpyToSymbolAsync(cnblocks_win_y, &nblocks_win_y, sizeof(nblocks_win_y), 0, cudaMemcpyHostToDevice, stream)); + cudaSafeCall(cudaMemcpyToSymbolAsync(cncells_block_x, &ncells_block_x, sizeof(ncells_block_x), 0, cudaMemcpyHostToDevice, stream)); + cudaSafeCall(cudaMemcpyToSymbolAsync(cncells_block_y, &ncells_block_y, sizeof(ncells_block_y), 0, cudaMemcpyHostToDevice, stream)); int block_hist_size = nbins * ncells_block_x * ncells_block_y; - cudaSafeCall( cudaMemcpyToSymbol(cblock_hist_size, &block_hist_size, sizeof(block_hist_size)) ); + cudaSafeCall(cudaMemcpyToSymbolAsync(cblock_hist_size, &block_hist_size, sizeof(block_hist_size), 0, cudaMemcpyHostToDevice, stream)); int block_hist_size_2up = power_2up(block_hist_size); - cudaSafeCall( cudaMemcpyToSymbol(cblock_hist_size_2up, &block_hist_size_2up, sizeof(block_hist_size_2up)) ); + cudaSafeCall(cudaMemcpyToSymbolAsync(cblock_hist_size_2up, &block_hist_size_2up, sizeof(block_hist_size_2up), 0, cudaMemcpyHostToDevice, stream)); int descr_width = nblocks_win_x * block_hist_size; - cudaSafeCall( cudaMemcpyToSymbol(cdescr_width, &descr_width, sizeof(descr_width)) ); + cudaSafeCall(cudaMemcpyToSymbolAsync(cdescr_width, &descr_width, sizeof(descr_width), 0, cudaMemcpyHostToDevice, stream)); int descr_size = descr_width * nblocks_win_y; - cudaSafeCall( cudaMemcpyToSymbol(cdescr_size, &descr_size, sizeof(descr_size)) ); + cudaSafeCall(cudaMemcpyToSymbolAsync(cdescr_size, &descr_size, sizeof(descr_size), 0, cudaMemcpyHostToDevice, stream)); } @@ -233,7 +235,8 @@ namespace cv { namespace cuda { namespace device void compute_hists(int nbins, int block_stride_x, int block_stride_y, int height, int width, const PtrStepSzf& grad, const PtrStepSzb& qangle, float sigma, float* block_hists, - int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y) + int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y, + const cudaStream_t& stream) { const int ncells_block = ncells_block_x * ncells_block_y; const int patch_side = cell_size_x / 4; @@ -259,20 +262,15 @@ namespace cv { namespace cuda { namespace device int final_hists_size = (nbins * ncells_block * nblocks) * sizeof(float); int smem = hists_size + final_hists_size; if (nblocks == 4) - compute_hists_kernel_many_blocks<4><<>>( - img_block_width, grad, qangle, scale, block_hists, cell_size_x, patch_size, block_patch_size, threads_cell, threads_block, half_cell_size); + compute_hists_kernel_many_blocks<4><<>>(img_block_width, grad, qangle, scale, block_hists, cell_size_x, patch_size, block_patch_size, threads_cell, threads_block, half_cell_size); else if (nblocks == 3) - compute_hists_kernel_many_blocks<3><<>>( - img_block_width, grad, qangle, scale, block_hists, cell_size_x, patch_size, block_patch_size, threads_cell, threads_block, half_cell_size); + compute_hists_kernel_many_blocks<3><<>>(img_block_width, grad, qangle, scale, block_hists, cell_size_x, patch_size, block_patch_size, threads_cell, threads_block, half_cell_size); else if (nblocks == 2) - compute_hists_kernel_many_blocks<2><<>>( - img_block_width, grad, qangle, scale, block_hists, cell_size_x, patch_size, block_patch_size, threads_cell, threads_block, half_cell_size); + compute_hists_kernel_many_blocks<2><<>>(img_block_width, grad, qangle, scale, block_hists, cell_size_x, patch_size, block_patch_size, threads_cell, threads_block, half_cell_size); else - compute_hists_kernel_many_blocks<1><<>>( - img_block_width, grad, qangle, scale, block_hists, cell_size_x, patch_size, block_patch_size, threads_cell, threads_block, half_cell_size); - cudaSafeCall( cudaGetLastError() ); + compute_hists_kernel_many_blocks<1><<>>(img_block_width, grad, qangle, scale, block_hists, cell_size_x, patch_size, block_patch_size, threads_cell, threads_block, half_cell_size); - cudaSafeCall( cudaDeviceSynchronize() ); + cudaSafeCall( cudaGetLastError() ); } @@ -348,7 +346,8 @@ namespace cv { namespace cuda { namespace device void normalize_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, float* block_hists, float threshold, int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y) + int height, int width, float* block_hists, float threshold, int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y, + const cudaStream_t& stream) { const int nblocks = 1; @@ -361,21 +360,19 @@ namespace cv { namespace cuda { namespace device dim3 grid(divUp(img_block_width, nblocks), img_block_height); if (nthreads == 32) - normalize_hists_kernel_many_blocks<32, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); + normalize_hists_kernel_many_blocks<32, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); else if (nthreads == 64) - normalize_hists_kernel_many_blocks<64, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); + normalize_hists_kernel_many_blocks<64, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); else if (nthreads == 128) - normalize_hists_kernel_many_blocks<128, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); + normalize_hists_kernel_many_blocks<128, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); else if (nthreads == 256) - normalize_hists_kernel_many_blocks<256, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); + normalize_hists_kernel_many_blocks<256, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); else if (nthreads == 512) - normalize_hists_kernel_many_blocks<512, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); + normalize_hists_kernel_many_blocks<512, nblocks><<>>(block_hist_size, img_block_width, block_hists, threshold); else CV_Error(cv::Error::StsBadArg, "normalize_hists: histogram's size is too big, try to decrease number of bins"); cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); } @@ -581,7 +578,8 @@ namespace cv { namespace cuda { namespace device void extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, int block_stride_x, int win_stride_y, int win_stride_x, int height, int width, float* block_hists, int cell_size_x, int ncells_block_x, - PtrStepSzf descriptors) + PtrStepSzf descriptors, + const cudaStream_t& stream) { const int nthreads = 256; @@ -593,11 +591,9 @@ namespace cv { namespace cuda { namespace device dim3 grid(img_win_width, img_win_height); int img_block_width = (width - ncells_block_x * cell_size_x + block_stride_x) / block_stride_x; - extract_descrs_by_cols_kernel<<>>( - img_block_width, win_block_stride_x, win_block_stride_y, block_hists, descriptors); - cudaSafeCall( cudaGetLastError() ); + extract_descrs_by_cols_kernel<<>>(img_block_width, win_block_stride_x, win_block_stride_y, block_hists, descriptors); - cudaSafeCall( cudaDeviceSynchronize() ); + cudaSafeCall( cudaGetLastError() ); } //---------------------------------------------------------------------------- @@ -708,7 +704,8 @@ namespace cv { namespace cuda { namespace device void compute_gradients_8UC4(int nbins, int height, int width, const PtrStepSzb& img, - float angle_scale, PtrStepSzf grad, PtrStepSzb qangle, bool correct_gamma) + float angle_scale, PtrStepSzf grad, PtrStepSzb qangle, bool correct_gamma, + const cudaStream_t& stream) { (void)nbins; const int nthreads = 256; @@ -717,13 +714,11 @@ namespace cv { namespace cuda { namespace device dim3 gdim(divUp(width, bdim.x), divUp(height, bdim.y)); if (correct_gamma) - compute_gradients_8UC4_kernel<<>>(height, width, img, angle_scale, grad, qangle); + compute_gradients_8UC4_kernel<<>>(height, width, img, angle_scale, grad, qangle); else - compute_gradients_8UC4_kernel<<>>(height, width, img, angle_scale, grad, qangle); + compute_gradients_8UC4_kernel<<>>(height, width, img, angle_scale, grad, qangle); cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); } template diff --git a/modules/cudaobjdetect/src/hog.cpp b/modules/cudaobjdetect/src/hog.cpp index 3d3b5d336f..a9b4404a67 100644 --- a/modules/cudaobjdetect/src/hog.cpp +++ b/modules/cudaobjdetect/src/hog.cpp @@ -66,15 +66,18 @@ namespace cv { namespace cuda { namespace device { void set_up_constants(int nbins, int block_stride_x, int block_stride_y, int nblocks_win_x, int nblocks_win_y, - int ncells_block_x, int ncells_block_y); + int ncells_block_x, int ncells_block_y, + const cudaStream_t& stream); void compute_hists(int nbins, int block_stride_x, int block_stride_y, int height, int width, const PtrStepSzf& grad, const PtrStepSzb& qangle, float sigma, float* block_hists, - int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y); + int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y, + const cudaStream_t& stream); void normalize_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, float* block_hists, float threshold, int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y); + int height, int width, float* block_hists, float threshold, int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y, + const cudaStream_t& stream); void classify_hists(int win_height, int win_width, int block_stride_y, int block_stride_x, int win_stride_y, int win_stride_x, int height, @@ -90,12 +93,14 @@ namespace cv { namespace cuda { namespace device cv::cuda::PtrStepSzf descriptors); void extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, int block_stride_x, int win_stride_y, int win_stride_x, int height, int width, float* block_hists, int cell_size_x, int ncells_block_x, - cv::cuda::PtrStepSzf descriptors); + cv::cuda::PtrStepSzf descriptors, + const cudaStream_t& stream); void compute_gradients_8UC1(int nbins, int height, int width, const cv::cuda::PtrStepSzb& img, float angle_scale, cv::cuda::PtrStepSzf grad, cv::cuda::PtrStepSzb qangle, bool correct_gamma); void compute_gradients_8UC4(int nbins, int height, int width, const cv::cuda::PtrStepSzb& img, - float angle_scale, cv::cuda::PtrStepSzf grad, cv::cuda::PtrStepSzb qangle, bool correct_gamma); + float angle_scale, cv::cuda::PtrStepSzf grad, cv::cuda::PtrStepSzb qangle, bool correct_gamma, + const cudaStream_t& stream); void resize_8UC1(const cv::cuda::PtrStepSzb& src, cv::cuda::PtrStepSzb dst); void resize_8UC4(const cv::cuda::PtrStepSzb& src, cv::cuda::PtrStepSzb dst); @@ -182,8 +187,8 @@ namespace private: int getTotalHistSize(Size img_size) const; - void computeBlockHistograms(const GpuMat& img, GpuMat& block_hists); - void computeGradient(const GpuMat& img, GpuMat& grad, GpuMat& qangle); + void computeBlockHistograms(const GpuMat& img, GpuMat& block_hists, Stream& stream); +// void computeGradient(const GpuMat& img, GpuMat& grad, GpuMat& qangle, Stream& stream); // Coefficients of the separating plane float free_coef_; @@ -310,7 +315,7 @@ namespace BufferPool pool(Stream::Null()); GpuMat block_hists = pool.getBuffer(1, getTotalHistSize(img.size()), CV_32FC1); - computeBlockHistograms(img, block_hists); + computeBlockHistograms(img, block_hists, Stream::Null()); Size wins_per_img = numPartsWithin(img.size(), win_size_, win_stride_); @@ -458,19 +463,16 @@ namespace CV_Assert( img.type() == CV_8UC1 || img.type() == CV_8UC4 ); CV_Assert( win_stride_.width % block_stride_.width == 0 && win_stride_.height % block_stride_.height == 0 ); - CV_Assert( !stream ); - - BufferPool pool(stream); - - GpuMat block_hists = pool.getBuffer(1, getTotalHistSize(img.size()), CV_32FC1); - computeBlockHistograms(img, block_hists); + BufferPool pool(stream); + GpuMat block_hists = pool.getBuffer(1, getTotalHistSize(img.size()), CV_32FC1); + Size wins_per_img = numPartsWithin(img.size(), win_size_, win_stride_); + Size blocks_per_win = numPartsWithin(win_size_, block_size_, block_stride_); const size_t block_hist_size = getBlockHistogramSize(); - Size blocks_per_win = numPartsWithin(win_size_, block_size_, block_stride_); - Size wins_per_img = numPartsWithin(img.size(), win_size_, win_stride_); - _descriptors.create(wins_per_img.area(), static_cast(blocks_per_win.area() * block_hist_size), CV_32FC1); - GpuMat descriptors = _descriptors.getGpuMat(); + GpuMat descriptors = _descriptors.getGpuMat(); + + computeBlockHistograms(img, block_hists, stream); switch (descr_format_) { @@ -490,7 +492,8 @@ namespace img.rows, img.cols, block_hists.ptr(), cell_size_.width, cells_per_block_.width, - descriptors); + descriptors, + StreamAccessor::getStream(stream)); break; default: CV_Error(cv::Error::StsBadArg, "Unknown descriptor format"); @@ -504,18 +507,25 @@ namespace return static_cast(block_hist_size * blocks_per_img.area()); } - void HOG_Impl::computeBlockHistograms(const GpuMat& img, GpuMat& block_hists) + void HOG_Impl::computeBlockHistograms(const GpuMat& img, GpuMat& block_hists, Stream& stream) { + BufferPool pool(stream); cv::Size blocks_per_win = numPartsWithin(win_size_, block_size_, block_stride_); - hog::set_up_constants(nbins_, block_stride_.width, block_stride_.height, blocks_per_win.width, blocks_per_win.height, cells_per_block_.width, cells_per_block_.height); + float angleScale = static_cast(nbins_ / CV_PI); + GpuMat grad = pool.getBuffer(img.size(), CV_32FC2); + GpuMat qangle = pool.getBuffer(img.size(), CV_8UC2); - BufferPool pool(Stream::Null()); + hog::set_up_constants(nbins_, block_stride_.width, block_stride_.height, blocks_per_win.width, blocks_per_win.height, cells_per_block_.width, cells_per_block_.height, StreamAccessor::getStream(stream)); - GpuMat grad = pool.getBuffer(img.size(), CV_32FC2); - GpuMat qangle = pool.getBuffer(img.size(), CV_8UC2); - computeGradient(img, grad, qangle); - - block_hists.create(1, getTotalHistSize(img.size()), CV_32FC1); + switch (img.type()) + { + case CV_8UC1: + hog::compute_gradients_8UC1(nbins_, img.rows, img.cols, img, angleScale, grad, qangle, gamma_correction_); + break; + case CV_8UC4: + hog::compute_gradients_8UC4(nbins_, img.rows, img.cols, img, angleScale, grad, qangle, gamma_correction_, StreamAccessor::getStream(stream)); + break; + } hog::compute_hists(nbins_, block_stride_.width, block_stride_.height, @@ -524,7 +534,8 @@ namespace (float)getWinSigma(), block_hists.ptr(), cell_size_.width, cell_size_.height, - cells_per_block_.width, cells_per_block_.height); + cells_per_block_.width, cells_per_block_.height, + StreamAccessor::getStream(stream)); hog::normalize_hists(nbins_, block_stride_.width, block_stride_.height, @@ -532,24 +543,8 @@ namespace block_hists.ptr(), (float)threshold_L2hys_, cell_size_.width, cell_size_.height, - cells_per_block_.width, cells_per_block_.height); - } - - void HOG_Impl::computeGradient(const GpuMat& img, GpuMat& grad, GpuMat& qangle) - { - grad.create(img.size(), CV_32FC2); - qangle.create(img.size(), CV_8UC2); - - float angleScale = (float)(nbins_ / CV_PI); - switch (img.type()) - { - case CV_8UC1: - hog::compute_gradients_8UC1(nbins_, img.rows, img.cols, img, angleScale, grad, qangle, gamma_correction_); - break; - case CV_8UC4: - hog::compute_gradients_8UC4(nbins_, img.rows, img.cols, img, angleScale, grad, qangle, gamma_correction_); - break; - } + cells_per_block_.width, cells_per_block_.height, + StreamAccessor::getStream(stream)); } } From dd3655f6a6e4c0af5d93d510ce686a0115315c25 Mon Sep 17 00:00:00 2001 From: Claudio Date: Sat, 25 Mar 2017 15:12:26 +0100 Subject: [PATCH 048/144] Align parameter code style between hog .cu and .cpp files --- modules/cudaobjdetect/src/cuda/hog.cu | 43 +++++++++++++++++++-------- modules/cudaobjdetect/src/hog.cpp | 16 ++++++++-- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/modules/cudaobjdetect/src/cuda/hog.cu b/modules/cudaobjdetect/src/cuda/hog.cu index d7dbd4a3d6..40d2dec89c 100644 --- a/modules/cudaobjdetect/src/cuda/hog.cu +++ b/modules/cudaobjdetect/src/cuda/hog.cu @@ -52,7 +52,6 @@ namespace cv { namespace cuda { namespace device namespace hog { - __constant__ int cnbins; __constant__ int cblock_stride_x; __constant__ int cblock_stride_y; @@ -99,8 +98,10 @@ namespace cv { namespace cuda { namespace device } - void set_up_constants(int nbins, int block_stride_x, int block_stride_y, - int nblocks_win_x, int nblocks_win_y, int ncells_block_x, int ncells_block_y, + void set_up_constants(int nbins, + int block_stride_x, int block_stride_y, + int nblocks_win_x, int nblocks_win_y, + int ncells_block_x, int ncells_block_y, const cudaStream_t& stream) { cudaSafeCall(cudaMemcpyToSymbolAsync(cnbins, &nbins, sizeof(nbins), 0, cudaMemcpyHostToDevice, stream)); @@ -232,10 +233,14 @@ namespace cv { namespace cuda { namespace device } //declaration of variables and invoke the kernel with the calculated number of blocks - void compute_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, const PtrStepSzf& grad, - const PtrStepSzb& qangle, float sigma, float* block_hists, - int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y, + void compute_hists(int nbins, + int block_stride_x, int block_stride_y, + int height, int width, + const PtrStepSzf& grad, const PtrStepSzb& qangle, + float sigma, + float* block_hists, + int cell_size_x, int cell_size_y, + int ncells_block_x, int ncells_block_y, const cudaStream_t& stream) { const int ncells_block = ncells_block_x * ncells_block_y; @@ -345,8 +350,13 @@ namespace cv { namespace cuda { namespace device } - void normalize_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, float* block_hists, float threshold, int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y, + void normalize_hists(int nbins, + int block_stride_x, int block_stride_y, + int height, int width, + float* block_hists, + float threshold, + int cell_size_x, int cell_size_y, + int ncells_block_x, int ncells_block_y, const cudaStream_t& stream) { const int nblocks = 1; @@ -576,8 +586,12 @@ namespace cv { namespace cuda { namespace device } - void extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, int block_stride_x, - int win_stride_y, int win_stride_x, int height, int width, float* block_hists, int cell_size_x, int ncells_block_x, + void extract_descrs_by_cols(int win_height, int win_width, + int block_stride_y, int block_stride_x, + int win_stride_y, int win_stride_x, + int height, int width, + float* block_hists, + int cell_size_x, int ncells_block_x, PtrStepSzf descriptors, const cudaStream_t& stream) { @@ -703,8 +717,11 @@ namespace cv { namespace cuda { namespace device } - void compute_gradients_8UC4(int nbins, int height, int width, const PtrStepSzb& img, - float angle_scale, PtrStepSzf grad, PtrStepSzb qangle, bool correct_gamma, + void compute_gradients_8UC4(int nbins, + int height, int width, const PtrStepSzb& img, + float angle_scale, + PtrStepSzf grad, PtrStepSzb qangle, + bool correct_gamma, const cudaStream_t& stream) { (void)nbins; diff --git a/modules/cudaobjdetect/src/hog.cpp b/modules/cudaobjdetect/src/hog.cpp index a9b4404a67..f59bd0c545 100644 --- a/modules/cudaobjdetect/src/hog.cpp +++ b/modules/cudaobjdetect/src/hog.cpp @@ -515,15 +515,25 @@ namespace GpuMat grad = pool.getBuffer(img.size(), CV_32FC2); GpuMat qangle = pool.getBuffer(img.size(), CV_8UC2); - hog::set_up_constants(nbins_, block_stride_.width, block_stride_.height, blocks_per_win.width, blocks_per_win.height, cells_per_block_.width, cells_per_block_.height, StreamAccessor::getStream(stream)); + hog::set_up_constants(nbins_, + block_stride_.width, block_stride_.height, + blocks_per_win.width, blocks_per_win.height, + cells_per_block_.width, cells_per_block_.height, + StreamAccessor::getStream(stream)); switch (img.type()) { case CV_8UC1: - hog::compute_gradients_8UC1(nbins_, img.rows, img.cols, img, angleScale, grad, qangle, gamma_correction_); + hog::compute_gradients_8UC1(nbins_, img.rows, img.cols, img, + angleScale, grad, qangle, gamma_correction_); break; case CV_8UC4: - hog::compute_gradients_8UC4(nbins_, img.rows, img.cols, img, angleScale, grad, qangle, gamma_correction_, StreamAccessor::getStream(stream)); + hog::compute_gradients_8UC4(nbins_, + img.rows, img.cols, img, + angleScale, + grad, qangle, + gamma_correction_, + StreamAccessor::getStream(stream)); break; } From 4709b9d2d8904bd436c8ebb9fce5bf868ee3f078 Mon Sep 17 00:00:00 2001 From: Claudio Date: Sat, 25 Mar 2017 15:43:56 +0100 Subject: [PATCH 049/144] Add cuda::streams to by_rows and 8UC1 functions Fix #8177 --- modules/cudaobjdetect/src/cuda/hog.cu | 41 +++++++++------ modules/cudaobjdetect/src/hog.cpp | 73 +++++++++++++++++++-------- 2 files changed, 77 insertions(+), 37 deletions(-) diff --git a/modules/cudaobjdetect/src/cuda/hog.cu b/modules/cudaobjdetect/src/cuda/hog.cu index 40d2dec89c..45a3ecb838 100644 --- a/modules/cudaobjdetect/src/cuda/hog.cu +++ b/modules/cudaobjdetect/src/cuda/hog.cu @@ -518,8 +518,10 @@ namespace cv { namespace cuda { namespace device template - __global__ void extract_descrs_by_rows_kernel(const int img_block_width, const int win_block_stride_x, const int win_block_stride_y, - const float* block_hists, PtrStepf descriptors) + __global__ void extract_descrs_by_rows_kernel(const int img_block_width, + const int win_block_stride_x, const int win_block_stride_y, + const float* block_hists, + PtrStepf descriptors) { // Get left top corner of the window in src const float* hist = block_hists + (blockIdx.y * win_block_stride_y * img_block_width + @@ -538,8 +540,14 @@ namespace cv { namespace cuda { namespace device } - void extract_descrs_by_rows(int win_height, int win_width, int block_stride_y, int block_stride_x, int win_stride_y, int win_stride_x, - int height, int width, float* block_hists, int cell_size_x, int ncells_block_x, PtrStepSzf descriptors) + void extract_descrs_by_rows(int win_height, int win_width, + int block_stride_y, int block_stride_x, + int win_stride_y, int win_stride_x, + int height, int width, + float* block_hists, int cell_size_x, + int ncells_block_x, + PtrStepSzf descriptors, + const cudaStream_t& stream) { const int nthreads = 256; @@ -551,17 +559,16 @@ namespace cv { namespace cuda { namespace device dim3 grid(img_win_width, img_win_height); int img_block_width = (width - ncells_block_x * cell_size_x + block_stride_x) / block_stride_x; - extract_descrs_by_rows_kernel<<>>( - img_block_width, win_block_stride_x, win_block_stride_y, block_hists, descriptors); - cudaSafeCall( cudaGetLastError() ); + extract_descrs_by_rows_kernel<<>>(img_block_width, win_block_stride_x, win_block_stride_y, block_hists, descriptors); - cudaSafeCall( cudaDeviceSynchronize() ); + cudaSafeCall( cudaGetLastError() ); } template - __global__ void extract_descrs_by_cols_kernel(const int img_block_width, const int win_block_stride_x, - const int win_block_stride_y, const float* block_hists, + __global__ void extract_descrs_by_cols_kernel(const int img_block_width, + const int win_block_stride_x, const int win_block_stride_y, + const float* block_hists, PtrStepf descriptors) { // Get left top corner of the window in src @@ -792,8 +799,12 @@ namespace cv { namespace cuda { namespace device } - void compute_gradients_8UC1(int nbins, int height, int width, const PtrStepSzb& img, - float angle_scale, PtrStepSzf grad, PtrStepSzb qangle, bool correct_gamma) + void compute_gradients_8UC1(int nbins, + int height, int width, const PtrStepSzb& img, + float angle_scale, + PtrStepSzf grad, PtrStepSzb qangle, + bool correct_gamma, + const cudaStream_t& stream) { (void)nbins; const int nthreads = 256; @@ -802,13 +813,11 @@ namespace cv { namespace cuda { namespace device dim3 gdim(divUp(width, bdim.x), divUp(height, bdim.y)); if (correct_gamma) - compute_gradients_8UC1_kernel<<>>(height, width, img, angle_scale, grad, qangle); + compute_gradients_8UC1_kernel<<>>(height, width, img, angle_scale, grad, qangle); else - compute_gradients_8UC1_kernel<<>>(height, width, img, angle_scale, grad, qangle); + compute_gradients_8UC1_kernel<<>>(height, width, img, angle_scale, grad, qangle); cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); } diff --git a/modules/cudaobjdetect/src/hog.cpp b/modules/cudaobjdetect/src/hog.cpp index f59bd0c545..f06ce363bb 100644 --- a/modules/cudaobjdetect/src/hog.cpp +++ b/modules/cudaobjdetect/src/hog.cpp @@ -64,19 +64,29 @@ namespace cv { namespace cuda { namespace device { namespace hog { - void set_up_constants(int nbins, int block_stride_x, int block_stride_y, + void set_up_constants(int nbins, + int block_stride_x, int block_stride_y, int nblocks_win_x, int nblocks_win_y, int ncells_block_x, int ncells_block_y, const cudaStream_t& stream); - void compute_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, const PtrStepSzf& grad, - const PtrStepSzb& qangle, float sigma, float* block_hists, - int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y, + void compute_hists(int nbins, + int block_stride_x, int block_stride_y, + int height, int width, + const PtrStepSzf& grad, const PtrStepSzb& qangle, + float sigma, + float* block_hists, + int cell_size_x, int cell_size_y, + int ncells_block_x, int ncells_block_y, const cudaStream_t& stream); - void normalize_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, float* block_hists, float threshold, int cell_size_x, int cell_size_y, int ncells_block_x, int ncells_block_y, + void normalize_hists(int nbins, + int block_stride_x, int block_stride_y, + int height, int width, + float* block_hists, + float threshold, + int cell_size_x, int cell_size_y, + int ncells_block_x, int ncells_block_y, const cudaStream_t& stream); void classify_hists(int win_height, int win_width, int block_stride_y, @@ -85,21 +95,37 @@ namespace cv { namespace cuda { namespace device float threshold, int cell_size_x, int ncells_block_x, unsigned char* labels); void compute_confidence_hists(int win_height, int win_width, int block_stride_y, int block_stride_x, - int win_stride_y, int win_stride_x, int height, int width, float* block_hists, - float* coefs, float free_coef, float threshold, int cell_size_x, int ncells_block_x, float *confidences); + int win_stride_y, int win_stride_x, int height, int width, float* block_hists, + float* coefs, float free_coef, float threshold, int cell_size_x, int ncells_block_x, float *confidences); - void extract_descrs_by_rows(int win_height, int win_width, int block_stride_y, int block_stride_x, - int win_stride_y, int win_stride_x, int height, int width, float* block_hists, int cell_size_x, int ncells_block_x, - cv::cuda::PtrStepSzf descriptors); - void extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, int block_stride_x, - int win_stride_y, int win_stride_x, int height, int width, float* block_hists, int cell_size_x, int ncells_block_x, + void extract_descrs_by_rows(int win_height, int win_width, + int block_stride_y, int block_stride_x, + int win_stride_y, int win_stride_x, + int height, int width, + float* block_hists, + int cell_size_x, int ncells_block_x, + cv::cuda::PtrStepSzf descriptors, + const cudaStream_t& stream); + void extract_descrs_by_cols(int win_height, int win_width, + int block_stride_y, int block_stride_x, + int win_stride_y, int win_stride_x, + int height, int width, + float* block_hists, + int cell_size_x, int ncells_block_x, cv::cuda::PtrStepSzf descriptors, const cudaStream_t& stream); - void compute_gradients_8UC1(int nbins, int height, int width, const cv::cuda::PtrStepSzb& img, - float angle_scale, cv::cuda::PtrStepSzf grad, cv::cuda::PtrStepSzb qangle, bool correct_gamma); - void compute_gradients_8UC4(int nbins, int height, int width, const cv::cuda::PtrStepSzb& img, - float angle_scale, cv::cuda::PtrStepSzf grad, cv::cuda::PtrStepSzb qangle, bool correct_gamma, + void compute_gradients_8UC1(int nbins, + int height, int width, const cv::cuda::PtrStepSzb& img, + float angle_scale, + cv::cuda::PtrStepSzf grad, cv::cuda::PtrStepSzb qangle, + bool correct_gamma, + const cudaStream_t& stream); + void compute_gradients_8UC4(int nbins, + int height, int width, const cv::cuda::PtrStepSzb& img, + float angle_scale, + cv::cuda::PtrStepSzf grad, cv::cuda::PtrStepSzb qangle, + bool correct_gamma, const cudaStream_t& stream); void resize_8UC1(const cv::cuda::PtrStepSzb& src, cv::cuda::PtrStepSzb dst); @@ -483,7 +509,8 @@ namespace img.rows, img.cols, block_hists.ptr(), cell_size_.width, cells_per_block_.width, - descriptors); + descriptors, + StreamAccessor::getStream(stream)); break; case DESCR_FORMAT_COL_BY_COL: hog::extract_descrs_by_cols(win_size_.height, win_size_.width, @@ -524,8 +551,12 @@ namespace switch (img.type()) { case CV_8UC1: - hog::compute_gradients_8UC1(nbins_, img.rows, img.cols, img, - angleScale, grad, qangle, gamma_correction_); + hog::compute_gradients_8UC1(nbins_, + img.rows, img.cols, img, + angleScale, + grad, qangle, + gamma_correction_, + StreamAccessor::getStream(stream)); break; case CV_8UC4: hog::compute_gradients_8UC4(nbins_, From 75a489b75b240b6fedfc55a935389ddaa7154e09 Mon Sep 17 00:00:00 2001 From: Sixela David Date: Mon, 27 Mar 2017 11:15:03 +0200 Subject: [PATCH 050/144] Correcting issue #8431 --- .../py_contours_hierarchy/py_contours_hierarchy.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.markdown b/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.markdown index 2f137f5f43..424469a57a 100644 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.markdown +++ b/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.markdown @@ -99,7 +99,7 @@ will have their corresponding values. Just check it yourself and verify it. Below is the result I got, and each row is hierarchy details of corresponding contour. For eg, first row corresponds to contour 0. Next contour is contour 1. So Next = 1. There is no previous contour, -so Previous = 0. And the remaining two, as told before, it is -1. +so Previous = -1. And the remaining two, as told before, it is -1. @code{.py} >>> hierarchy array([[[ 1, -1, -1, -1], @@ -195,7 +195,7 @@ Take contour-0 : It is in hierarchy-0. Next contour in same hierarchy is contour contours. Child is contour-1. And no parent. So array is [7,-1,1,-1]. Take contour-2 : It is in hierarchy-1. No contour in same level. No previous one. Child is -contour-2. Parent is contour-0. So array is [-1,-1,2,0]. +contour-3. Parent is contour-1. So array is [-1,-1,3,1]. And remaining, try yourself. Below is the full answer: @code{.py} From 106413a3ea1c29a5561465d843e1a5055c07eeaf Mon Sep 17 00:00:00 2001 From: Pyotr Chekmaryov <4ekmah@gmail.com> Date: Mon, 27 Mar 2017 21:40:17 +0000 Subject: [PATCH 051/144] Simplest test added and code debuged. --- modules/calib3d/include/opencv2/calib3d.hpp | 2 +- modules/calib3d/src/stereosgbm.cpp | 36 +++++++++++--------- modules/calib3d/test/test_stereomatching.cpp | 30 ++++++++++++++++ 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index dd28d97e7f..46a470bc0f 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -1810,7 +1810,7 @@ public: MODE_SGBM = 0, MODE_HH = 1, MODE_SGBM_3WAY = 2, - MODE_HH4 = 1 + MODE_HH4 = 3 }; CV_WRAP virtual int getPreFilterCap() const = 0; diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp index bedc477e8b..24b3c18ddc 100644 --- a/modules/calib3d/src/stereosgbm.cpp +++ b/modules/calib3d/src/stereosgbm.cpp @@ -513,6 +513,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, 6: r=(1, -dy*2) 7: r=(2, -dy) */ + for( x = x1; x != x2; x += dx ) { int xm = x*NR2, xd = xm*D2; @@ -853,6 +854,7 @@ TODO: Don't forget to rewrire this commentaries after disp2cost also has the same size as img1 (or img2). It contains the minimum current cost, used to find the best disparity, corresponding to the minimal cost. */ +#include //TODO: DUBUG!!! static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, Mat& disp1, const StereoSGBMParams& params, Mat& buffer ) @@ -1005,7 +1007,7 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, if( y > 0 ) //4e: We calculate horizontal sums and forming full block sums for y coord by adding this horsums to previous line's sums and subtracting stored lowest { //4e: horsum in hsumBuf. Exception is case y=0, where we need many iterations per lines to create full blocking sum. const CostType* hsumSub = hsumBuf + (std::max(y - SH2 - 1, 0) % hsumBufNRows)*costBufSize; - const CostType* Cprev = !fullDP || y == 0 ? C : C - costBufSize; //4e: Well, actually y>0, so we don't need this check: y==0 + const CostType* Cprev = C - costBufSize; //4e: Well, actually y>0, so we don't need this check: y==0 for( x = D; x < width1*D; x += D ) { @@ -1089,11 +1091,11 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, 6: r=(1, -dy*2) 7: r=(2, -dy) */ - for( x = 0; x != width; x++ ) + for( x = 0; x != width1; x++ ) { int xd = x*D2; - int delta = minLr[1][x]; + int delta = minLr[1][x] + P2; CostType* Lr_ppr = Lr[1] + xd; @@ -1189,9 +1191,9 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; Lr_p[d] = (CostType)L; - minL0 = std::min(minL, L); + minL = std::min(minL, L); - Sp[d] = saturate_cast(Sp[d] + L0); + Sp[d] = saturate_cast(Sp[d] + L); } minLr[0][x] = (CostType)minL; } @@ -1224,8 +1226,8 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, { int x, d; DispType* disp1ptr = disp1.ptr(y); - CostType* C = Cbuf + costBufSize; - CostType* S = Sbuf + costBufSize; + CostType* C = Cbuf + y*costBufSize; + CostType* S = Sbuf + y*costBufSize; for( x = 0; x < width; x++ ) { @@ -1233,7 +1235,7 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, disp2cost[x] = MAX_COST; } - // clear the left and the right borders //TODO: Well, two of that memsets we could delete, but rest of them is direction-dependent + // clear the left and the right borders memset( Lr - D2*LrBorder - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory memset( Lr + width1*D2 - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: ...00000000|D2-16 of real costs value(and some of them are zeroes too)|00000000... memset( minLr - LrBorder, 0, LrBorder*sizeof(CostType) ); @@ -1261,7 +1263,7 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, { int xd = x*D2; - int delta = minLr[x - 1]; + int delta = minLr[x - 1] + P2; CostType* Lr_ppr = Lr + xd - D2; @@ -1354,14 +1356,14 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, { int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually - L0 = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; Lr_p[d] = (CostType)L; - minL0 = std::min(minL, L); + minL = std::min(minL, L); Sp[d] = saturate_cast(Sp[d] + L); } - minLr[x] = (CostType)minL0; + minLr[x] = (CostType)minL; } } @@ -1369,7 +1371,7 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, { int xd = x*D2; - int delta = minLr[x + 1]; + int delta = minLr[x + 1] + P2; CostType* Lr_ppr = Lr + xd + D2; @@ -1489,10 +1491,10 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, { int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually - L0 = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; Lr_p[d] = (CostType)L; - minL0 = std::min(minL, L); + minL = std::min(minL, L); Sp[d] = saturate_cast(Sp[d] + L); if( Sp[d] < minS ) @@ -1501,7 +1503,7 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, bestDisp = d; } } - minLr[x] = (CostType)minL0; + minLr[x] = (CostType)minL; } //Some postprocessing procedures and saving for( d = 0; d < D; d++ ) @@ -2206,6 +2208,8 @@ public: if(params.mode==MODE_SGBM_3WAY) computeDisparity3WaySGBM( left, right, disp, params, buffers, num_stripes ); + else if(params.mode==MODE_HH4) + computeDisparitySGBMParallel( left, right, disp, params, buffer ); else computeDisparitySGBM( left, right, disp, params, buffer ); diff --git a/modules/calib3d/test/test_stereomatching.cpp b/modules/calib3d/test/test_stereomatching.cpp index 0aee42acee..c51c419334 100644 --- a/modules/calib3d/test/test_stereomatching.cpp +++ b/modules/calib3d/test/test_stereomatching.cpp @@ -784,3 +784,33 @@ protected: TEST(Calib3d_StereoBM, regression) { CV_StereoBMTest test; test.safe_run(); } TEST(Calib3d_StereoSGBM, regression) { CV_StereoSGBMTest test; test.safe_run(); } + +TEST(Calib3d_StereoSGBMPar, idontknowhowtotesthere) +{ +// +// case_teddy_2 teddy "48" "3" "MODE_HH" + +//Ptr StereoSGBM::create(int minDisparity, int numDisparities, int SADWindowSize, +// int P1, int P2, int disp12MaxDiff, +// int preFilterCap, int uniquenessRatio, +// int speckleWindowSize, int speckleRange, +// int mode) + Mat leftImg = imread("/home/q/Work/GitVault/opencv_extra/testdata/cv/stereomatching/datasets/teddy/im2.png"); + Mat rightImg = imread("/home/q/Work/GitVault/opencv_extra/testdata/cv/stereomatching/datasets/teddy/im6.png"); + { + Mat leftDisp; + Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH); + sgbm->compute( leftImg, rightImg, leftDisp ); + CV_Assert( leftDisp.type() == CV_16SC1 ); + leftDisp/=8; + imwrite( "/home/q/Work/GitVault/modehh.jpg", leftDisp); + } + { + Mat leftDisp; + Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH4); + sgbm->compute( leftImg, rightImg, leftDisp ); + CV_Assert( leftDisp.type() == CV_16SC1 ); + leftDisp/=8; + imwrite( "/home/q/Work/GitVault/modehh4.jpg", leftDisp); + } +} From de52887c49072325ba580ee3650502175ceee891 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Fri, 24 Mar 2017 13:29:04 -0700 Subject: [PATCH 052/144] Update circlesgrid.cpp Use identity matrix if homography finding failed. Current behavior zeros out all points. Update circlesgrid.cpp Addressed comments Update circlesgrid.cpp removed whitespace --- modules/calib3d/src/circlesgrid.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/calib3d/src/circlesgrid.cpp b/modules/calib3d/src/circlesgrid.cpp index df85809d41..a90c7f3f5a 100644 --- a/modules/calib3d/src/circlesgrid.cpp +++ b/modules/calib3d/src/circlesgrid.cpp @@ -839,7 +839,11 @@ Mat CirclesGridFinder::rectifyGrid(Size detectedGridSize, const std::vector srcKeypoints; for (size_t i = 0; i < keypoints.size(); i++) From b2524f45717bf66eb78adb83bb7cc755bb3aacab Mon Sep 17 00:00:00 2001 From: Alexander Broemmer Date: Tue, 28 Mar 2017 14:31:00 +0200 Subject: [PATCH 053/144] Clear old CameraParameters in AffineBasedEstimator AffineBasedEstimator crashed when called with an existing CameraParameters. This happens e.g. when using Stitcher in SCANS mode. CameraraParameters is now cleared before any calculation is executed. --- modules/stitching/src/motion_estimators.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/stitching/src/motion_estimators.cpp b/modules/stitching/src/motion_estimators.cpp index f76309f777..925bb44de1 100644 --- a/modules/stitching/src/motion_estimators.cpp +++ b/modules/stitching/src/motion_estimators.cpp @@ -199,7 +199,7 @@ bool AffineBasedEstimator::estimate(const std::vector &features, const std::vector &pairwise_matches, std::vector &cameras) { - cameras.resize(features.size()); + cameras.assign(features.size(), CameraParams()); const int num_images = static_cast(features.size()); // find maximum spaning tree on pairwise matches From 3e0b63f65b63e0270aeadb7dc0a7237a3cd17797 Mon Sep 17 00:00:00 2001 From: berak Date: Thu, 30 Mar 2017 11:07:52 +0200 Subject: [PATCH 054/144] fix comment in optim.hpp --- modules/core/include/opencv2/core/optim.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/optim.hpp b/modules/core/include/opencv2/core/optim.hpp index 7249e0fe75..190d54310f 100644 --- a/modules/core/include/opencv2/core/optim.hpp +++ b/modules/core/include/opencv2/core/optim.hpp @@ -73,7 +73,7 @@ public: /** @brief Getter for the optimized function. The optimized function is represented by Function interface, which requires derivatives to - implement the sole method calc(double*) to evaluate the function. + implement the calc(double*) and getDim() methods to evaluate the function. @return Smart-pointer to an object that implements Function interface - it represents the function that is being optimized. It can be empty, if no function was given so far. From a7de4aca6ab096aa99a57b301875bc16760f37d1 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 28 Mar 2017 18:21:13 +0300 Subject: [PATCH 055/144] cmake: update ocv_download - more aggressive cache for files under CMAKE_BINARY_CACHE * don't re-read files MD5 * don't repack archives - add support for ENV{OPENCV_DOWNLOAD_PATH} - added ID parameter as project/group identifier - non-flat .cache directory (based on ID) - download message prefix based on ID - more detailed logging via ocv_download_log() macro - force .gitignore file for .cache folder (with '*' pattern) --- .gitignore | 1 - 3rdparty/ffmpeg/ffmpeg.cmake | 1 + 3rdparty/ippicv/ippicv.cmake | 1 + 3rdparty/tbb/CMakeLists.txt | 1 + cmake/OpenCVDownload.cmake | 117 ++++++++++++++++++++++++++++++----- 5 files changed, 103 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 0fdd3e81ef..adef6e08d1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ *.user *~ .*.swp -.cache .DS_Store .sw[a-z] Thumbs.db diff --git a/3rdparty/ffmpeg/ffmpeg.cmake b/3rdparty/ffmpeg/ffmpeg.cmake index c26cc7a3c6..b9f5292352 100644 --- a/3rdparty/ffmpeg/ffmpeg.cmake +++ b/3rdparty/ffmpeg/ffmpeg.cmake @@ -25,6 +25,7 @@ function(download_win_ffmpeg script_var) "${OPENCV_FFMPEG_URL}" "https://raw.githubusercontent.com/opencv/opencv_3rdparty/${FFMPEG_BINARIES_COMMIT}/ffmpeg/" DESTINATION_DIR ${FFMPEG_DOWNLOAD_DIR} + ID FFMPEG RELATIVE_URL STATUS res) if(NOT res) diff --git a/3rdparty/ippicv/ippicv.cmake b/3rdparty/ippicv/ippicv.cmake index ce100a1ffe..a477d60b8a 100644 --- a/3rdparty/ippicv/ippicv.cmake +++ b/3rdparty/ippicv/ippicv.cmake @@ -31,6 +31,7 @@ function(download_ippicv root_var) "$ENV{OPENCV_IPPICV_URL}" "https://raw.githubusercontent.com/opencv/opencv_3rdparty/${IPPICV_COMMIT}/ippicv/" DESTINATION_DIR "${THE_ROOT}" + ID IPPICV STATUS res UNPACK RELATIVE_URL) diff --git a/3rdparty/tbb/CMakeLists.txt b/3rdparty/tbb/CMakeLists.txt index fa37cc26fc..41e2cad1a9 100644 --- a/3rdparty/tbb/CMakeLists.txt +++ b/3rdparty/tbb/CMakeLists.txt @@ -21,6 +21,7 @@ ocv_download(FILENAME ${tbb_filename} "$ENV{OPENCV_TBB_URL}" "https://github.com/01org/tbb/archive/" DESTINATION_DIR ${tbb_src_dir} + ID TBB STATUS res UNPACK RELATIVE_URL) if(NOT res) diff --git a/cmake/OpenCVDownload.cmake b/cmake/OpenCVDownload.cmake index e118e28f87..76151bb8ed 100644 --- a/cmake/OpenCVDownload.cmake +++ b/cmake/OpenCVDownload.cmake @@ -1,11 +1,12 @@ # # Download and optionally unpack a file # -# ocv_download(FILENAME p HASH h URL u1 [u2 ...] DESTINATION_DIR d [STATUS s] [UNPACK] [RELATIVE]) +# ocv_download(FILENAME p HASH h URL u1 [u2 ...] DESTINATION_DIR d [ID id] [STATUS s] [UNPACK] [RELATIVE_URL]) # FILENAME - filename # HASH - MD5 hash # URL - full download url (first nonempty value will be chosen) # DESTINATION_DIR - file will be copied to this directory +# ID - identifier for project/group of downloaded files # STATUS - passed variable will be updated in parent scope, # function will not fail the build in case of download problem if this option is provided, # but will fail in case when other operations (copy, remove, etc.) failed @@ -13,28 +14,76 @@ # RELATIVE_URL - if set, then URL is treated as a base, and FILENAME will be appended to it # Note: uses OPENCV_DOWNLOAD_PATH folder as cache, default is /.cache -set(OPENCV_DOWNLOAD_PATH "${OpenCV_SOURCE_DIR}/.cache" CACHE PATH "Cache directory for downloaded files") +set(HELP_OPENCV_DOWNLOAD_PATH "Cache directory for downloaded files") +if(DEFINED ENV{OPENCV_DOWNLOAD_PATH}) + set(OPENCV_DOWNLOAD_PATH "$ENV{OPENCV_DOWNLOAD_PATH}" CACHE PATH "${HELP_OPENCV_DOWNLOAD_PATH}") +endif() +set(OPENCV_DOWNLOAD_PATH "${OpenCV_SOURCE_DIR}/.cache" CACHE PATH "${HELP_OPENCV_DOWNLOAD_PATH}") set(OPENCV_DOWNLOAD_LOG "${OpenCV_BINARY_DIR}/CMakeDownloadLog.txt") # Init download cache directory and log file if(NOT EXISTS "${OPENCV_DOWNLOAD_PATH}") file(MAKE_DIRECTORY ${OPENCV_DOWNLOAD_PATH}) endif() +if(NOT EXISTS "${OPENCV_DOWNLOAD_PATH}/.gitignore") + file(WRITE "${OPENCV_DOWNLOAD_PATH}/.gitignore" "*\n") +endif() file(WRITE "${OPENCV_DOWNLOAD_LOG}" "use_cache \"${OPENCV_DOWNLOAD_PATH}\"\n") function(ocv_download) - cmake_parse_arguments(DL "UNPACK;RELATIVE_URL" "FILENAME;HASH;DESTINATION_DIR;STATUS" "URL" ${ARGN}) + cmake_parse_arguments(DL "UNPACK;RELATIVE_URL" "FILENAME;HASH;DESTINATION_DIR;ID;STATUS" "URL" ${ARGN}) - ocv_assert(DEFINED DL_FILENAME) - ocv_assert(DEFINED DL_HASH) - ocv_assert(DEFINED DL_URL) - ocv_assert(DEFINED DL_DESTINATION_DIR) + macro(ocv_download_log) + file(APPEND "${OPENCV_DOWNLOAD_LOG}" "${ARGN}\n") + endmacro() + + ocv_assert(DL_FILENAME) + ocv_assert(DL_HASH) + ocv_assert(DL_URL) + ocv_assert(DL_DESTINATION_DIR) + if((NOT " ${DL_UNPARSED_ARGUMENTS}" STREQUAL " ") + OR DL_FILENAME STREQUAL "" + OR DL_HASH STREQUAL "" + OR DL_URL STREQUAL "" + OR DL_DESTINATION_DIR STREQUAL "" + ) + set(msg_level FATAL_ERROR) + if(DEFINED DL_STATUS) + set(${DL_STATUS} FALSE PARENT_SCOPE) + set(msg_level WARNING) + endif() + message(${msg_level} "ERROR: ocv_download() unsupported arguments: ${ARGV}") + return() + endif() if(DEFINED DL_STATUS) set(${DL_STATUS} TRUE PARENT_SCOPE) endif() + # Check CMake cache for already processed tasks + string(FIND "${DL_DESTINATION_DIR}" "${CMAKE_BINARY_DIR}" DL_BINARY_PATH_POS) + if(DL_BINARY_PATH_POS EQUAL 0) + set(__file_id "${DL_DESTINATION_DIR}/${DL_FILENAME}") + file(RELATIVE_PATH __file_id "${CMAKE_BINARY_DIR}" "${__file_id}") + string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" __file_id "${__file_id}") + if(DL_ID) + string(TOUPPER ${DL_ID} __id) + string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" __id "${__id}") + set(OCV_DOWNLOAD_HASH_NAME "OCV_DOWNLOAD_${__id}_HASH_${__file_id}") + else() + set(OCV_DOWNLOAD_HASH_NAME "OCV_DOWNLOAD_HASH_${__file_id}") + endif() + if(" ${${OCV_DOWNLOAD_HASH_NAME}}" STREQUAL " ${DL_HASH}") + ocv_download_log("#match_hash_in_cmake_cache \"${OCV_DOWNLOAD_HASH_NAME}\"") + return() + endif() + unset("${OCV_DOWNLOAD_HASH_NAME}" CACHE) + else() + set(OCV_DOWNLOAD_HASH_NAME "") + #message(WARNING "Download destination is not in CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}: ${DL_DESTINATION_DIR}") + endif() + # Select first non-empty url foreach(url ${DL_URL}) if(url) @@ -54,58 +103,85 @@ function(ocv_download) endif() # Log all calls to file - file(APPEND "${OPENCV_DOWNLOAD_LOG}" "do_${mode} \"${DL_FILENAME}\" \"${DL_HASH}\" \"${DL_URL}\" \"${DL_DESTINATION_DIR}\"\n") + ocv_download_log("do_${mode} \"${DL_FILENAME}\" \"${DL_HASH}\" \"${DL_URL}\" \"${DL_DESTINATION_DIR}\"") # ... and to console - message(STATUS "Download: ${DL_FILENAME}") + set(__msg_prefix "") + if(DL_ID) + set(__msg_prefix "${DL_ID}: ") + endif() + message(STATUS "${__msg_prefix}Download: ${DL_FILENAME}") # Copy mode: check if copy destination exists and is correct if(NOT DL_UNPACK) set(COPY_DESTINATION "${DL_DESTINATION_DIR}/${DL_FILENAME}") if(EXISTS "${COPY_DESTINATION}") + ocv_download_log("#check_md5 \"${COPY_DESTINATION}\"") file(MD5 "${COPY_DESTINATION}" target_md5) if(target_md5 STREQUAL DL_HASH) + ocv_download_log("#match_md5 \"${COPY_DESTINATION}\" \"${target_md5}\"") + if(OCV_DOWNLOAD_HASH_NAME) + set(${OCV_DOWNLOAD_HASH_NAME} "${DL_HASH}" CACHE INTERNAL "") + endif() return() endif() + ocv_download_log("#mismatch_md5 \"${COPY_DESTINATION}\" \"${target_md5}\"") + else() + ocv_download_log("#missing \"${COPY_DESTINATION}\"") endif() endif() # Check cache first - set(CACHE_CANDIDATE "${OPENCV_DOWNLOAD_PATH}/${DL_HASH}-${DL_FILENAME}") + if(DL_ID) + string(TOLOWER "${DL_ID}" __id) + string(REGEX REPLACE "[^a-zA-Z0-9_/ ]" "_" __id "${__id}") + set(CACHE_CANDIDATE "${OPENCV_DOWNLOAD_PATH}/${__id}/${DL_HASH}-${DL_FILENAME}") + else() + set(CACHE_CANDIDATE "${OPENCV_DOWNLOAD_PATH}/${DL_HASH}-${DL_FILENAME}") + endif() if(EXISTS "${CACHE_CANDIDATE}") + ocv_download_log("#check_md5 \"${CACHE_CANDIDATE}\"") file(MD5 "${CACHE_CANDIDATE}" target_md5) if(NOT target_md5 STREQUAL DL_HASH) + ocv_download_log("#mismatch_md5 \"${CACHE_CANDIDATE}\" \"${target_md5}\"") + ocv_download_log("#delete \"${CACHE_CANDIDATE}\"") file(REMOVE ${CACHE_CANDIDATE}) endif() endif() # Download if(NOT EXISTS "${CACHE_CANDIDATE}") + ocv_download_log("#cmake_download \"${CACHE_CANDIDATE}\" \"${DL_URL}\"") file(DOWNLOAD "${DL_URL}" "${CACHE_CANDIDATE}" INACTIVITY_TIMEOUT 60 TIMEOUT 600 STATUS status - LOG log) - string(REPLACE "\n" "\n# " log "# ${log}") - file(APPEND "${OPENCV_DOWNLOAD_LOG}" "${log}\n\n") + LOG __log) + string(LENGTH "${__log}" __log_length) + if(__log_length LESS 65536) + string(REPLACE "\n" "\n# " __log "${__log}") + ocv_download_log("# ${__log}\n") + endif() if(NOT status EQUAL 0) set(msg_level FATAL_ERROR) if(DEFINED DL_STATUS) set(${DL_STATUS} FALSE PARENT_SCOPE) set(msg_level WARNING) endif() - message(${msg_level} "Download failed: ${status}") + message(${msg_level} "${__msg_prefix}Download failed: ${status}") return() endif() # Don't remove this code, because EXPECTED_MD5 parameter doesn't fail "file(DOWNLOAD)" step on wrong hash + ocv_download_log("#check_md5 \"${CACHE_CANDIDATE}\"") file(MD5 "${CACHE_CANDIDATE}" target_md5) if(NOT target_md5 STREQUAL DL_HASH) + ocv_download_log("#mismatch_md5 \"${CACHE_CANDIDATE}\" \"${target_md5}\"") set(msg_level FATAL_ERROR) if(DEFINED DL_STATUS) set(${DL_STATUS} FALSE PARENT_SCOPE) set(msg_level WARNING) endif() - message(${msg_level} "Hash mismatch: ${target_md5}") + message(${msg_level} "${__msg_prefix}Hash mismatch: ${target_md5}") return() endif() endif() @@ -113,21 +189,28 @@ function(ocv_download) # Unpack or copy if(DL_UNPACK) if(EXISTS "${DL_DESTINATION_DIR}") + ocv_download_log("#remove_unpack \"${DL_DESTINATION_DIR}\"") file(REMOVE_RECURSE "${DL_DESTINATION_DIR}") endif() + ocv_download_log("#mkdir \"${DL_DESTINATION_DIR}\"") file(MAKE_DIRECTORY "${DL_DESTINATION_DIR}") + ocv_download_log("#unpack \"${DL_DESTINATION_DIR}\" \"${CACHE_CANDIDATE}\"") execute_process(COMMAND "${CMAKE_COMMAND}" -E tar xz "${CACHE_CANDIDATE}" WORKING_DIRECTORY "${DL_DESTINATION_DIR}" RESULT_VARIABLE res) if(NOT res EQUAL 0) - message(FATAL_ERROR "Unpack failed: ${res}") + message(FATAL_ERROR "${__msg_prefix}Unpack failed: ${res}") endif() else() + ocv_download_log("#copy \"${COPY_DESTINATION}\" \"${CACHE_CANDIDATE}\"") execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CACHE_CANDIDATE}" "${COPY_DESTINATION}" RESULT_VARIABLE res) if(NOT res EQUAL 0) - message(FATAL_ERROR "Copy failed: ${res}") + message(FATAL_ERROR "${__msg_prefix}Copy failed: ${res}") endif() endif() + if(OCV_DOWNLOAD_HASH_NAME) + set(${OCV_DOWNLOAD_HASH_NAME} "${DL_HASH}" CACHE INTERNAL "") + endif() endfunction() From 507071cc6ff690f529cb4ae0fcf308385791ff41 Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Fri, 31 Mar 2017 08:20:59 +0900 Subject: [PATCH 056/144] suppress warnings on Jetson TK1 --- modules/core/include/opencv2/core/fast_math.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/fast_math.hpp b/modules/core/include/opencv2/core/fast_math.hpp index 8aae46d9d2..aeeb5e7c51 100644 --- a/modules/core/include/opencv2/core/fast_math.hpp +++ b/modules/core/include/opencv2/core/fast_math.hpp @@ -74,7 +74,7 @@ # include "tegra_round.hpp" #endif -#if defined __GNUC__ && defined __arm__ && (defined __ARM_PCS_VFP || defined __ARM_VFPV3__ || defined __ARM_NEON__) && !defined __SOFTFP__ +#if defined __GNUC__ && defined __arm__ && (defined __ARM_PCS_VFP || defined __ARM_VFPV3__ || defined __ARM_NEON__) && !defined __SOFTFP__ && !defined(__CUDACC__) // 1. general scheme #define ARM_ROUND(_value, _asm_string) \ int res; \ From 98b8c32f30aeac730ded94407ab7a1113130ad46 Mon Sep 17 00:00:00 2001 From: Sergiu Deitsch Date: Fri, 31 Mar 2017 15:44:38 +0200 Subject: [PATCH 057/144] cmake: fixed standalone dynamic IPP detection under win32 --- cmake/OpenCVFindIPP.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVFindIPP.cmake b/cmake/OpenCVFindIPP.cmake index 6913052ff4..c56928f01d 100644 --- a/cmake/OpenCVFindIPP.cmake +++ b/cmake/OpenCVFindIPP.cmake @@ -129,8 +129,13 @@ macro(ipp_detect_version) macro(_ipp_add_library name) # dynamic linking is only supported for standalone version of IPP if (BUILD_WITH_DYNAMIC_IPP AND NOT HAVE_IPP_ICV_ONLY) - set(IPP_LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) - set(IPP_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) + if (WIN32) + set(IPP_LIB_PREFIX ${CMAKE_IMPORT_LIBRARY_PREFIX}) + set(IPP_LIB_SUFFIX ${CMAKE_IMPORT_LIBRARY_SUFFIX}) + else (WIN32) + set(IPP_LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) + set(IPP_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif (WIN32) else () set(IPP_LIB_PREFIX ${CMAKE_STATIC_LIBRARY_PREFIX}) set(IPP_LIB_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX}) From c75b589f898f1635643e49773293350aef7d606a Mon Sep 17 00:00:00 2001 From: Hamdi Sahloul Date: Sat, 1 Apr 2017 03:19:29 +0900 Subject: [PATCH 058/144] Wraps smart pointers properly --- modules/python/src2/cv2.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 9c28c7070f..4788ef1b5e 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -1271,9 +1271,17 @@ PyObject* pyopencv_from(const Moments& m) "nu30", m.nu30, "nu21", m.nu21, "nu12", m.nu12, "nu03", m.nu03); } +template +PyObject* pyopencv_from(const cv::Ptr& p) +{ + if (!p) return Py_None; + return pyopencv_from(*p); +} + template bool pyopencv_to(PyObject *o, Ptr& p, const char *name) { + if (!o || o == Py_None) return true; p = makePtr(); return pyopencv_to(o, *p, name); } From 94d63d4281aeaf7efad7caf7b546159433c57ae9 Mon Sep 17 00:00:00 2001 From: Mark Szumowski Date: Sat, 1 Apr 2017 10:58:07 +1100 Subject: [PATCH 059/144] Update research paper link in Python sample The docstring for one of the Python sample programs includes a link to the research paper describing the main algorithm. That link is no longer valid (results in a 404 error) so this update replaces it with another link from the same institution which is currently valid. --- samples/python/mosse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/python/mosse.py b/samples/python/mosse.py index 46e22d3c06..816c8e4238 100755 --- a/samples/python/mosse.py +++ b/samples/python/mosse.py @@ -18,7 +18,7 @@ Keys: c - clear targets [1] David S. Bolme et al. "Visual Object Tracking using Adaptive Correlation Filters" - http://www.cs.colostate.edu/~bolme/publications/Bolme2010Tracking.pdf + http://www.cs.colostate.edu/~draper/papers/bolme_cvpr10.pdf ''' # Python 2/3 compatibility From 6a856d677c6391dd196d9a2c50cfa4828290b517 Mon Sep 17 00:00:00 2001 From: Hamdi Sahloul Date: Sat, 1 Apr 2017 17:20:03 +0900 Subject: [PATCH 060/144] Wraps cv::EMD for Python and Java --- modules/imgproc/include/opencv2/imgproc.hpp | 4 ++++ modules/imgproc/src/emd.cpp | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 8536e41cc8..4bab109107 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -3280,6 +3280,10 @@ CV_EXPORTS float EMD( InputArray signature1, InputArray signature2, int distType, InputArray cost=noArray(), float* lowerBound = 0, OutputArray flow = noArray() ); +CV_EXPORTS_AS(EMD) float wrapperEMD( InputArray signature1, InputArray signature2, + int distType, InputArray cost=noArray(), + CV_IN_OUT Ptr lowerBound = Ptr(), OutputArray flow = noArray() ); + //! @} imgproc_hist /** @example watershed.cpp diff --git a/modules/imgproc/src/emd.cpp b/modules/imgproc/src/emd.cpp index 96eda61331..7b62c16c6f 100644 --- a/modules/imgproc/src/emd.cpp +++ b/modules/imgproc/src/emd.cpp @@ -1164,4 +1164,11 @@ float cv::EMD( InputArray _signature1, InputArray _signature2, _flow.needed() ? &_cflow : 0, lowerBound, 0 ); } +float cv::wrapperEMD(InputArray _signature1, InputArray _signature2, + int distType, InputArray _cost, + Ptr lowerBound, OutputArray _flow) +{ + return EMD(_signature1, _signature2, distType, _cost, lowerBound.get(), _flow); +} + /* End of file. */ From 89088937a7082674e9cb1b8a1a0906aaa67ec837 Mon Sep 17 00:00:00 2001 From: Hamdi Sahloul Date: Sat, 1 Apr 2017 18:25:04 +0900 Subject: [PATCH 061/144] Avoid memory leakage in smart pointers wrapper --- modules/python/src2/cv2.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 4788ef1b5e..bfd23b7e78 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -1274,14 +1274,16 @@ PyObject* pyopencv_from(const Moments& m) template PyObject* pyopencv_from(const cv::Ptr& p) { - if (!p) return Py_None; + if (!p) + Py_RETURN_NONE; return pyopencv_from(*p); } template bool pyopencv_to(PyObject *o, Ptr& p, const char *name) { - if (!o || o == Py_None) return true; + if (!o || o == Py_None) + return true; p = makePtr(); return pyopencv_to(o, *p, name); } From dd576c89a3f2e5f7dbf7945813a4fd5ed056bfd3 Mon Sep 17 00:00:00 2001 From: Paolo Perkovic Date: Sat, 1 Apr 2017 13:29:44 +0200 Subject: [PATCH 062/144] Fix StereoBM ROI selection - Fix StereoBM ROI (Region of interest) selection for stereo images used by block matching algorithm --- modules/calib3d/src/stereobm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/calib3d/src/stereobm.cpp b/modules/calib3d/src/stereobm.cpp index eb075d8c73..5ed45a4884 100644 --- a/modules/calib3d/src/stereobm.cpp +++ b/modules/calib3d/src/stereobm.cpp @@ -1184,8 +1184,8 @@ public: parallel_for_(Range(0, 2), PrefilterInvoker(left0, right0, left, right, _buf, _buf + bufSize1, ¶ms), 1); Rect validDisparityRect(0, 0, width, height), R1 = params.roi1, R2 = params.roi2; - validDisparityRect = getValidDisparityROI(R1.area() > 0 ? Rect(0, 0, width, height) : validDisparityRect, - R2.area() > 0 ? Rect(0, 0, width, height) : validDisparityRect, + validDisparityRect = getValidDisparityROI(R1.area() > 0 ? R1 : validDisparityRect, + R2.area() > 0 ? R2 : validDisparityRect, params.minDisparity, params.numDisparities, params.SADWindowSize); From 6ab10fc3ace8646f37141615470f17e153849e82 Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Sat, 1 Apr 2017 20:53:50 +0900 Subject: [PATCH 063/144] suppress warnings on GCC 4.9 series - check boundary strictly - initialize the variable before using it --- modules/imgproc/src/contours.cpp | 36 ++++++++++++++++++-------------- modules/imgproc/src/imgwarp.cpp | 9 +------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/modules/imgproc/src/contours.cpp b/modules/imgproc/src/contours.cpp index baa27c4ac3..b7b9a5be45 100644 --- a/modules/imgproc/src/contours.cpp +++ b/modules/imgproc/src/contours.cpp @@ -528,6 +528,7 @@ cvSubstituteContour( CvContourScanner scanner, CvSeq * new_contour ) } } +static const int MAX_SIZE = 16; /* marks domain border with +/- and stores the contour into CvSeq. @@ -544,7 +545,7 @@ icvFetchContour( schar *ptr, int _method ) { const schar nbd = 2; - int deltas[16]; + int deltas[MAX_SIZE]; CvSeqWriter writer; schar *i0 = ptr, *i1, *i3, *i4 = 0; int prev_s = -1, s, s_end; @@ -588,8 +589,9 @@ icvFetchContour( schar *ptr, for( ;; ) { s_end = s; + s = std::min(s, MAX_SIZE - 1); - for( ;; ) + while( s < MAX_SIZE - 1 ) { i4 = i3 + deltas[++s]; if( *i4 != 0 ) @@ -654,8 +656,8 @@ icvFetchContour( schar *ptr, static int icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole ) { - int deltas[16]; - schar *i0 = ptr, *i1, *i3, *i4; + int deltas[MAX_SIZE]; + schar *i0 = ptr, *i1, *i3, *i4 = NULL; int s, s_end; /* initialize local state */ @@ -682,7 +684,8 @@ icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole ) for( ;; ) { - for( ;; ) + s = std::min(s, MAX_SIZE - 1); + while( s < MAX_SIZE - 1 ) { i4 = i3 + deltas[++s]; if( *i4 != 0 ) @@ -709,9 +712,9 @@ icvFetchContourEx( schar* ptr, int nbd, CvRect* _rect ) { - int deltas[16]; + int deltas[MAX_SIZE]; CvSeqWriter writer; - schar *i0 = ptr, *i1, *i3, *i4; + schar *i0 = ptr, *i1, *i3, *i4 = NULL; CvRect rect; int prev_s = -1, s, s_end; int method = _method - 1; @@ -759,8 +762,9 @@ icvFetchContourEx( schar* ptr, for( ;; ) { s_end = s; + s = std::min(s, MAX_SIZE - 1); - for( ;; ) + while( s < MAX_SIZE - 1 ) { i4 = i3 + deltas[++s]; if( *i4 != 0 ) @@ -833,8 +837,8 @@ icvFetchContourEx( schar* ptr, static int icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole ) { - int deltas[16]; - int *i0 = ptr, *i1, *i3, *i4; + int deltas[MAX_SIZE]; + int *i0 = ptr, *i1, *i3, *i4 = NULL; int s, s_end; const int right_flag = INT_MIN; const int new_flag = (int)((unsigned)INT_MIN >> 1); @@ -863,8 +867,9 @@ icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole ) for( ;; ) { s_end = s; + s = std::min(s, MAX_SIZE - 1); - for( ;; ) + while( s < MAX_SIZE - 1 ) { i4 = i3 + deltas[++s]; if( (*i4 & value_mask) == ccomp_val ) @@ -890,7 +895,7 @@ icvFetchContourEx_32s( int* ptr, int _method, CvRect* _rect ) { - int deltas[16]; + int deltas[MAX_SIZE]; CvSeqWriter writer; int *i0 = ptr, *i1, *i3, *i4; CvRect rect; @@ -925,7 +930,7 @@ icvFetchContourEx_32s( int* ptr, s = (s - 1) & 7; i1 = i0 + deltas[s]; } - while( (*i1 & value_mask) != ccomp_val && s != s_end ); + while( (*i1 & value_mask) != ccomp_val && s != s_end && ( s < MAX_SIZE - 1 ) ); if( s == s_end ) /* single pixel domain */ { @@ -945,12 +950,11 @@ icvFetchContourEx_32s( int* ptr, { s_end = s; - for( ;; ) + do { i4 = i3 + deltas[++s]; - if( (*i4 & value_mask) == ccomp_val ) - break; } + while( (*i4 & value_mask) != ccomp_val && ( s < MAX_SIZE - 1 ) ); s &= 7; /* check "right" bound */ diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index c1f38979c4..84a7e5218a 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -1704,10 +1704,6 @@ public: CV_Assert(ksize <= MAX_ESIZE); } -#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Warray-bounds" -#endif virtual void operator() (const Range& range) const { int dy, cn = src.channels(); @@ -1737,7 +1733,7 @@ public: int sy = clip(sy0 - ksize2 + 1 + k, 0, ssize.height); for( k1 = std::max(k1, k); k1 < ksize; k1++ ) { - if( sy == prev_sy[k1] ) // if the sy-th row has been computed already, reuse it. + if( k1 < MAX_ESIZE && sy == prev_sy[k1] ) // if the sy-th row has been computed already, reuse it. { if( k1 > k ) memcpy( rows[k], rows[k1], bufstep*sizeof(rows[0][0]) ); @@ -1756,9 +1752,6 @@ public: vresize( (const WT**)rows, (T*)(dst.data + dst.step*dy), beta, dsize.width ); } } -#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) -# pragma GCC diagnostic pop -#endif private: Mat src; From 4f317599651205e1dc598096d89d3e1a39518bfd Mon Sep 17 00:00:00 2001 From: Sergiu Deitsch Date: Sat, 1 Apr 2017 21:53:30 +0200 Subject: [PATCH 064/144] prevent copying in cv::Mat_ move assignment --- modules/core/include/opencv2/core/mat.inl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 4a32de165a..ad1a366bb2 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -1818,7 +1818,7 @@ Mat_<_Tp>::Mat_(Mat_&& m) template inline Mat_<_Tp>& Mat_<_Tp>::operator = (Mat_&& m) { - Mat::operator = (m); + Mat::operator = (std::move(m)); return *this; } From ef033be59d2c4b3c05615f510a3d3d53a7576fb2 Mon Sep 17 00:00:00 2001 From: vskarlsruhe Date: Mon, 3 Apr 2017 11:58:22 +0200 Subject: [PATCH 065/144] Update py_setup_in_windows.markdown updated links for python, numpy and matplotlib --- .../py_setup_in_windows/py_setup_in_windows.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown b/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown index 3ff4e82e8c..23c5706cd2 100644 --- a/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown +++ b/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown @@ -15,15 +15,15 @@ Installing OpenCV from prebuilt binaries -# Below Python packages are to be downloaded and installed to their default locations. - -# [Python-2.7.x](http://python.org/ftp/python/2.7.5/python-2.7.5.msi). + -# [Python-2.7.x](http://www.python.org/ftp/python/2.7.13/python-2.7.13.msi). - -# [Numpy](http://sourceforge.net/projects/numpy/files/NumPy/1.7.1/numpy-1.7.1-win32-superpack-python2.7.exe/download). + -# [Numpy](https://sourceforge.net/projects/numpy/files/NumPy/1.10.2/numpy-1.10.2-win32-superpack-python2.7.exe/download). - -# [Matplotlib](https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-1.3.0/matplotlib-1.3.0.win32-py2.7.exe) (*Matplotlib is optional, but recommended since we use it a lot in our tutorials*). + -# [Matplotlib](https://sourceforge.net/projects/matplotlib/files/matplotlib/matplotlib-1.5.0/windows/matplotlib-1.5.0.win32-py2.7.exe/download) (*Matplotlib is optional, but recommended since we use it a lot in our tutorials*). -# Install all packages into their default locations. Python will be installed to `C:/Python27/`. --# After installation, open Python IDLE. Enter import numpy and make sure Numpy is working fine. +-# After installation, open Python IDLE. Enter **import numpy** and make sure Numpy is working fine. -# Download latest OpenCV release from [sourceforge site](http://sourceforge.net/projects/opencvlibrary/files/opencv-win/2.4.6/OpenCV-2.4.6.0.exe/download) From d92d82d194376c3c74ea7592c425b0ce00643a31 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Tue, 4 Apr 2017 15:07:02 +0200 Subject: [PATCH 066/144] cap_v4l: SetProperty - do not return false while setting video size --- modules/videoio/src/cap_v4l.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/videoio/src/cap_v4l.cpp b/modules/videoio/src/cap_v4l.cpp index 59202e2927..309dcaaff4 100644 --- a/modules/videoio/src/cap_v4l.cpp +++ b/modules/videoio/src/cap_v4l.cpp @@ -1772,6 +1772,7 @@ static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, switch (property_id) { case CV_CAP_PROP_FRAME_WIDTH: width = cvRound(value); + retval = width != 0; if(width !=0 && height != 0) { capture->width = width; capture->height = height; @@ -1781,6 +1782,7 @@ static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, break; case CV_CAP_PROP_FRAME_HEIGHT: height = cvRound(value); + retval = height != 0; if(width !=0 && height != 0) { capture->width = width; capture->height = height; From 1f86d8564fb6915a6f490cc9a7928c10b208807c Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 4 Apr 2017 19:48:16 +0300 Subject: [PATCH 067/144] cmake: fix GCC precompiled headers warnings --- cmake/OpenCVPCHSupport.cmake | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/cmake/OpenCVPCHSupport.cmake b/cmake/OpenCVPCHSupport.cmake index 659973af81..8cfbe4b7c6 100644 --- a/cmake/OpenCVPCHSupport.cmake +++ b/cmake/OpenCVPCHSupport.cmake @@ -196,18 +196,20 @@ MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use ) _PCH_GET_TARGET_COMPILE_FLAGS(_target_cflags ${_name} ${_pch_output_to_use} ${_dowarn}) #MESSAGE("Add flags ${_target_cflags} to ${_targetName} " ) + if(CMAKE_COMPILER_IS_GNUCXX) + set(_target_cflags "${_target_cflags} -include \"${CMAKE_CURRENT_BINARY_DIR}/${_name}\"") + endif() GET_TARGET_PROPERTY(_sources ${_targetName} SOURCES) FOREACH(src ${_sources}) if(NOT "${src}" MATCHES "\\.mm$") get_source_file_property(_flags "${src}" COMPILE_FLAGS) - if(_flags) - set(_flags "${_flags} ${_target_cflags}") + get_source_file_property(_flags2 "${src}" COMPILE_DEFINITIONS) + if(NOT _flags AND NOT _flags2) + set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${_target_cflags}") else() - set(_flags "${_target_cflags}") + #ocv_debug_message("Skip PCH, flags: ${oldProps} defines: ${oldProps2}, file: ${src}") endif() - - set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${_flags}") endif() ENDFOREACH() @@ -284,20 +286,6 @@ MACRO(ADD_PRECOMPILED_HEADER _targetName _input) DEPENDS ${_targetName}_pch_dephelp ) - get_target_property(_sources ${_targetName} SOURCES) - foreach(src ${_sources}) - if(NOT "${src}" MATCHES "\\.mm$") - get_source_file_property(oldProps "${src}" COMPILE_FLAGS) - get_source_file_property(oldProps2 "${src}" COMPILE_DEFINITIONS) - if(NOT oldProps AND NOT oldProps2) - set(newProperties "-include \"${CMAKE_CURRENT_BINARY_DIR}/${_name}\"") - set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${newProperties}") - else() - ocv_debug_message("Skip PCH, flags: ${oldProps} defines: ${oldProps2}, file: ${src}") - endif() - endif() - endforeach() - ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName} ${_input} ${_output} ${_dowarn}) ENDMACRO(ADD_PRECOMPILED_HEADER) From e5d9b608c47d54e43496041595025fa282fa9de5 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 4 Apr 2017 20:34:58 +0300 Subject: [PATCH 068/144] cmake: fix fp16 support --- cmake/OpenCVCompilerOptions.cmake | 29 ------------------- cmake/templates/cvconfig.h.in | 3 -- .../include/opencv2/core/cv_cpu_dispatch.h | 7 +++++ .../include/opencv2/core/hal/intrin_cpp.hpp | 2 +- .../include/opencv2/core/hal/intrin_neon.hpp | 6 ++-- .../include/opencv2/core/hal/intrin_sse.hpp | 6 ++-- modules/core/include/opencv2/core/private.hpp | 11 ------- modules/core/test/test_intrin.cpp | 6 ++-- 8 files changed, 17 insertions(+), 53 deletions(-) diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake index 1656840441..030837a5d0 100644 --- a/cmake/OpenCVCompilerOptions.cmake +++ b/cmake/OpenCVCompilerOptions.cmake @@ -273,35 +273,6 @@ if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_OPENCV_GCC_VERSION_NUM GREATER 399) add_extra_compiler_option(-fvisibility-inlines-hidden) endif() -# TODO !!!!! -if(NOT OPENCV_FP16_DISABLE AND NOT IOS) - if(ARM AND ENABLE_NEON) - set(FP16_OPTION "-mfpu=neon-fp16") - elseif((X86 OR X86_64) AND NOT MSVC AND ENABLE_AVX) - set(FP16_OPTION "-mf16c") - endif() - try_compile(__VALID_FP16 - "${OpenCV_BINARY_DIR}" - "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_fp16.cpp" - COMPILE_DEFINITIONS "-DCHECK_FP16" "${FP16_OPTION}" - OUTPUT_VARIABLE TRY_OUT - ) - if(NOT __VALID_FP16) - if((X86 OR X86_64) AND NOT MSVC AND NOT ENABLE_AVX) - # GCC enables AVX when mf16c is passed - message(STATUS "FP16: Feature disabled") - else() - message(STATUS "FP16: Compiler support is not available") - endif() - else() - message(STATUS "FP16: Compiler support is available") - set(HAVE_FP16 1) - if(NOT ${FP16_OPTION} STREQUAL "") - add_extra_compiler_option(${FP16_OPTION}) - endif() - endif() -endif() - #combine all "extra" options set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPENCV_EXTRA_FLAGS} ${OPENCV_EXTRA_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENCV_EXTRA_FLAGS} ${OPENCV_EXTRA_CXX_FLAGS}") diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in index 658d12c14c..f20ff0c174 100644 --- a/cmake/templates/cvconfig.h.in +++ b/cmake/templates/cvconfig.h.in @@ -207,9 +207,6 @@ /* Lapack */ #cmakedefine HAVE_LAPACK -/* FP16 */ -#cmakedefine HAVE_FP16 - /* Library was compiled with functions instrumentation */ #cmakedefine ENABLE_INSTRUMENTATION diff --git a/modules/core/include/opencv2/core/cv_cpu_dispatch.h b/modules/core/include/opencv2/core/cv_cpu_dispatch.h index aaabea38d4..c6beacaba8 100644 --- a/modules/core/include/opencv2/core/cv_cpu_dispatch.h +++ b/modules/core/include/opencv2/core/cv_cpu_dispatch.h @@ -70,6 +70,10 @@ # include # define CV_AVX 1 #endif +#ifdef CV_CPU_COMPILE_FP16 +# include +# define CV_FP16 1 +#endif #ifdef CV_CPU_COMPILE_AVX2 # include # define CV_AVX2 1 @@ -154,6 +158,9 @@ struct VZeroUpperGuard { #ifndef CV_AVX # define CV_AVX 0 #endif +#ifndef CV_FP16 +# define CV_FP16 0 +#endif #ifndef CV_AVX2 # define CV_AVX2 0 #endif diff --git a/modules/core/include/opencv2/core/hal/intrin_cpp.hpp b/modules/core/include/opencv2/core/hal/intrin_cpp.hpp index e8c166405e..a5675e4f4d 100644 --- a/modules/core/include/opencv2/core/hal/intrin_cpp.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_cpp.hpp @@ -721,7 +721,7 @@ inline v_reg::abs_type, n> v_absdiff(const v_reg<_Tp, { typedef typename V_TypeTraits<_Tp>::abs_type rtype; v_reg c; - const rtype mask = std::numeric_limits<_Tp>::is_signed ? (1 << (sizeof(rtype)*8 - 1)) : 0; + const rtype mask = (rtype)(std::numeric_limits<_Tp>::is_signed ? (1 << (sizeof(rtype)*8 - 1)) : 0); for( int i = 0; i < n; i++ ) { rtype ua = a.s[i] ^ mask; diff --git a/modules/core/include/opencv2/core/hal/intrin_neon.hpp b/modules/core/include/opencv2/core/hal/intrin_neon.hpp index c7f4e90a36..6dd02bd0db 100644 --- a/modules/core/include/opencv2/core/hal/intrin_neon.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_neon.hpp @@ -278,7 +278,7 @@ struct v_float64x2 }; #endif -#if defined (HAVE_FP16) +#if CV_FP16 // Workaround for old comiplers template static inline int16x4_t vreinterpret_s16_f16(T a) { return (int16x4_t)a; } @@ -775,7 +775,7 @@ OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_float32x4, float, f32) OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_float64x2, double, f64) #endif -#if defined (HAVE_FP16) +#if CV_FP16 // Workaround for old comiplers inline v_float16x4 v_load_f16(const short* ptr) { return v_float16x4(vld1_f16(ptr)); } @@ -1223,7 +1223,7 @@ inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) } #endif -#if defined (HAVE_FP16) +#if CV_FP16 inline v_float32x4 v_cvt_f32(const v_float16x4& a) { return v_float32x4(vcvt_f32_f16(a.val)); diff --git a/modules/core/include/opencv2/core/hal/intrin_sse.hpp b/modules/core/include/opencv2/core/hal/intrin_sse.hpp index 5b9a27fd8a..364f5d76f4 100644 --- a/modules/core/include/opencv2/core/hal/intrin_sse.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_sse.hpp @@ -255,7 +255,7 @@ struct v_float64x2 __m128d val; }; -#if defined(HAVE_FP16) +#if CV_FP16 struct v_float16x4 { typedef short lane_type; @@ -1056,7 +1056,7 @@ inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(v_float32x4, float, ps) OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(v_float64x2, double, pd) -#if defined(HAVE_FP16) +#if CV_FP16 inline v_float16x4 v_load_f16(const short* ptr) { return v_float16x4(_mm_loadl_epi64((const __m128i*)ptr)); } inline void v_store_f16(short* ptr, v_float16x4& a) @@ -1776,7 +1776,7 @@ inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) return v_float64x2(_mm_cvtps_pd(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(a.val),8)))); } -#if defined(HAVE_FP16) +#if CV_FP16 inline v_float32x4 v_cvt_f32(const v_float16x4& a) { return v_float32x4(_mm_cvtph_ps(a.val)); diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp index afbc557166..c43bd727e7 100644 --- a/modules/core/include/opencv2/core/private.hpp +++ b/modules/core/include/opencv2/core/private.hpp @@ -66,17 +66,6 @@ # undef max #endif -#if defined HAVE_FP16 && (defined __F16C__ || (defined _MSC_VER && _MSC_VER >= 1700)) -# include -# define CV_FP16 1 -#elif defined HAVE_FP16 && defined __GNUC__ -# define CV_FP16 1 -#endif - -#ifndef CV_FP16 -# define CV_FP16 0 -#endif - //! @cond IGNORED namespace cv diff --git a/modules/core/test/test_intrin.cpp b/modules/core/test/test_intrin.cpp index 0ec24ef1fb..7d51bd3a6f 100644 --- a/modules/core/test/test_intrin.cpp +++ b/modules/core/test/test_intrin.cpp @@ -743,7 +743,7 @@ template struct TheTest TheTest & test_loadstore_fp16() { -#if CV_FP16 +#if CV_FP16 && CV_SIMD128 AlignedData data; AlignedData out; @@ -775,7 +775,7 @@ template struct TheTest TheTest & test_float_cvt_fp16() { -#if CV_FP16 +#if CV_FP16 && CV_SIMD128 AlignedData data; if(checkHardwareSupport(CV_CPU_FP16)) @@ -1008,7 +1008,7 @@ TEST(hal_intrin, float64x2) { } #endif -#if CV_FP16 +#if CV_FP16 && CV_SIMD128 TEST(hal_intrin, float16x4) { TheTest() .test_loadstore_fp16() From 731b5b206f498c1b9d17937bb2be156506273c5f Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Wed, 5 Apr 2017 08:30:16 +0900 Subject: [PATCH 069/144] suppress warnings from cuda --- modules/superres/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/superres/CMakeLists.txt b/modules/superres/CMakeLists.txt index 34c9297a1b..028274b8eb 100644 --- a/modules/superres/CMakeLists.txt +++ b/modules/superres/CMakeLists.txt @@ -3,6 +3,9 @@ if(IOS OR WINRT) endif() set(the_description "Super Resolution") +if(HAVE_CUDA) + ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wshadow) +endif() ocv_define_module(superres opencv_imgproc opencv_video OPTIONAL opencv_videoio opencv_cudaarithm opencv_cudafilters opencv_cudawarping opencv_cudaimgproc opencv_cudaoptflow opencv_cudacodec WRAP python) From ce50df564cef0452cf1536a99ccae92920e5c03e Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Wed, 5 Apr 2017 11:48:29 +0300 Subject: [PATCH 070/144] Fixed cvtColor OCL compilation issue (BGRA2mBGRA) --- modules/imgproc/src/opencl/cvtcolor.cl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/modules/imgproc/src/opencl/cvtcolor.cl b/modules/imgproc/src/opencl/cvtcolor.cl index daa0483e10..2193541aec 100644 --- a/modules/imgproc/src/opencl/cvtcolor.cl +++ b/modules/imgproc/src/opencl/cvtcolor.cl @@ -132,16 +132,10 @@ enum #define R_COMP z #define G_COMP y #define B_COMP x -#elif bidx == 2 +#else #define R_COMP x #define G_COMP y #define B_COMP z -#elif bidx == 3 -// The only kernel that uses bidx == 3 doesn't use these macros. -// But we still need to make the compiler happy. -#define R_COMP w -#define G_COMP w -#define B_COMP w #endif #ifndef uidx From 8b455e8bb3453e62517ee2d9fb49cb41de66e92b Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Wed, 5 Apr 2017 14:10:03 +0300 Subject: [PATCH 071/144] Fixed Algorithm.save and other methods work in Java --- modules/java/generator/gen_java.py | 4 +-- modules/ml/misc/java/test/MLTest.java | 42 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 modules/ml/misc/java/test/MLTest.java diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index e63df430bd..c18b9d5f18 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -1005,7 +1005,7 @@ class JavaWrapperGenerator(object): type_dict["Ptr_"+name] = \ { "j_type" : classinfo.jname, "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),), - "jni_name" : "Ptr<"+classinfo.fullName(isCPP=True)+">(("+classinfo.fullName(isCPP=True)+"*)%(n)s_nativeObj)", "jni_type" : "jlong", + "jni_name" : "*((Ptr<"+classinfo.fullName(isCPP=True)+">*)%(n)s_nativeObj)", "jni_type" : "jlong", "suffix" : "J" } logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base) @@ -1575,7 +1575,7 @@ JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(j_cls)s_delete # if parents are smart (we hope) then children are! # if not we believe the class is smart if it has "create" method ci.smart = False - if ci.base: + if ci.base or ci.name == 'Algorithm': ci.smart = True else: for fi in ci.methods: diff --git a/modules/ml/misc/java/test/MLTest.java b/modules/ml/misc/java/test/MLTest.java new file mode 100644 index 0000000000..2b08543a84 --- /dev/null +++ b/modules/ml/misc/java/test/MLTest.java @@ -0,0 +1,42 @@ +package org.opencv.test.ml; + +import org.opencv.ml.Ml; +import org.opencv.ml.SVM; +import org.opencv.core.Mat; +import org.opencv.core.MatOfFloat; +import org.opencv.core.MatOfInt; +import org.opencv.core.CvType; +import org.opencv.test.OpenCVTestCase; +import org.opencv.test.OpenCVTestRunner; + +public class MLTest extends OpenCVTestCase { + + public void testSaveLoad() { + Mat samples = new MatOfFloat(new float[] { + 5.1f, 3.5f, 1.4f, 0.2f, + 4.9f, 3.0f, 1.4f, 0.2f, + 4.7f, 3.2f, 1.3f, 0.2f, + 4.6f, 3.1f, 1.5f, 0.2f, + 5.0f, 3.6f, 1.4f, 0.2f, + 7.0f, 3.2f, 4.7f, 1.4f, + 6.4f, 3.2f, 4.5f, 1.5f, + 6.9f, 3.1f, 4.9f, 1.5f, + 5.5f, 2.3f, 4.0f, 1.3f, + 6.5f, 2.8f, 4.6f, 1.5f + }).reshape(1, 10); + Mat responses = new MatOfInt(new int[] { + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 + }).reshape(1, 10); + SVM saved = SVM.create(); + assertFalse(saved.isTrained()); + + saved.train(samples, Ml.ROW_SAMPLE, responses); + assertTrue(saved.isTrained()); + + String filename = OpenCVTestRunner.getTempFileName("yml"); + saved.save(filename); + SVM loaded = SVM.load(filename); + assertTrue(saved.isTrained()); + } + +} From 4d62f1de1e23bb338e541dcbaf3c11f707d5b134 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Wed, 5 Apr 2017 17:50:46 +0300 Subject: [PATCH 072/144] Added javadoc generation --- .../core/misc/java/src/java/core+DMatch.java | 3 --- modules/java/CMakeLists.txt | 2 +- modules/java/build.xml.in | 17 ++++++++++++++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/modules/core/misc/java/src/java/core+DMatch.java b/modules/core/misc/java/src/java/core+DMatch.java index 12bd86ec01..db44d9a0a6 100644 --- a/modules/core/misc/java/src/java/core+DMatch.java +++ b/modules/core/misc/java/src/java/core+DMatch.java @@ -45,9 +45,6 @@ public class DMatch { distance = _distance; } - /** - * Less is better. - */ public boolean lessThan(DMatch it) { return distance < it.distance; } diff --git a/modules/java/CMakeLists.txt b/modules/java/CMakeLists.txt index ed92e0511b..7994332930 100644 --- a/modules/java/CMakeLists.txt +++ b/modules/java/CMakeLists.txt @@ -345,7 +345,7 @@ else(ANDROID) list(APPEND step3_depends "${OpenCV_BINARY_DIR}/build.xml") add_custom_command(OUTPUT "${JAR_FILE}" "${JAR_FILE}.dephelper" - COMMAND ${ANT_EXECUTABLE} -q -noinput -k jar + COMMAND ${ANT_EXECUTABLE} -q -noinput -k jar javadoc COMMAND ${CMAKE_COMMAND} -E touch "${JAR_FILE}.dephelper" WORKING_DIRECTORY "${OpenCV_BINARY_DIR}" DEPENDS ${step3_depends} diff --git a/modules/java/build.xml.in b/modules/java/build.xml.in index c1c1854b7d..954ff6273c 100644 --- a/modules/java/build.xml.in +++ b/modules/java/build.xml.in @@ -2,6 +2,7 @@ + @@ -10,7 +11,21 @@ - + + + + + + + + From 9210cefb36868e201f7e0c8b84e4ee4f91b5432b Mon Sep 17 00:00:00 2001 From: nnorwitz Date: Wed, 5 Apr 2017 10:57:50 -0700 Subject: [PATCH 073/144] Use %% for inline assembly rather than % so this compiles with clang. --- modules/cudev/include/opencv2/cudev/warp/warp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cudev/include/opencv2/cudev/warp/warp.hpp b/modules/cudev/include/opencv2/cudev/warp/warp.hpp index 6860ccf4af..db096c5610 100644 --- a/modules/cudev/include/opencv2/cudev/warp/warp.hpp +++ b/modules/cudev/include/opencv2/cudev/warp/warp.hpp @@ -64,7 +64,7 @@ struct Warp __device__ __forceinline__ static uint laneId() { uint ret; - asm("mov.u32 %0, %laneid;" : "=r"(ret)); + asm("mov.u32 %0, %%laneid;" : "=r"(ret)); return ret; } From 24e8cd1a78a12b5193820dcad52da07208d52fd1 Mon Sep 17 00:00:00 2001 From: nnorwitz Date: Thu, 6 Apr 2017 12:54:56 -0700 Subject: [PATCH 074/144] Use %% for inline assembly rather than % so this compiles with clang. Same as https://github.com/opencv/opencv/pull/8525/commits/9210cefb36868e201f7e0c8b84e4ee4f91b5432b but for this file too. --- modules/core/include/opencv2/core/cuda/warp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/cuda/warp.hpp b/modules/core/include/opencv2/core/cuda/warp.hpp index ae1f8ea5d2..8af7e6a212 100644 --- a/modules/core/include/opencv2/core/cuda/warp.hpp +++ b/modules/core/include/opencv2/core/cuda/warp.hpp @@ -64,7 +64,7 @@ namespace cv { namespace cuda { namespace device static __device__ __forceinline__ unsigned int laneId() { unsigned int ret; - asm("mov.u32 %0, %laneid;" : "=r"(ret) ); + asm("mov.u32 %0, %%laneid;" : "=r"(ret) ); return ret; } From 0a63ab36bb10b133ded9496aca0058ff630fa2a8 Mon Sep 17 00:00:00 2001 From: Tong Ke Date: Fri, 7 Apr 2017 01:48:34 -0500 Subject: [PATCH 075/144] Merge pull request #8301 from tonyke1993:p3p_alg New p3p algorithm (accepted by CVPR 2017) (#8301) * add p3p source code * indent 4 * update publication info * fix filename * interface done * plug in done, test needed * debugging * for test * a working version * clean p3p code * test * test * fix warning, blank line * apply patch from @catree * add reference info * namespace, indent 4 * static solveQuartic * put small functions to anonymous namespace --- doc/opencv.bib | 7 + modules/calib3d/include/opencv2/calib3d.hpp | 4 +- modules/calib3d/src/ap3p.cpp | 383 ++++++++++++++++++ modules/calib3d/src/ap3p.h | 65 +++ modules/calib3d/src/solvepnp.cpp | 16 +- modules/calib3d/test/test_solvepnp_ransac.cpp | 8 +- 6 files changed, 477 insertions(+), 6 deletions(-) create mode 100644 modules/calib3d/src/ap3p.cpp create mode 100644 modules/calib3d/src/ap3p.h diff --git a/doc/opencv.bib b/doc/opencv.bib index 29a2ae4512..f4bb2512d1 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -897,3 +897,10 @@ year={2010}, publisher={Springer} } +@INPROCEEDINGS{Ke17, + author = {Ke, Tong and Roumeliotis, Stergios}, + title = {An Efficient Algebraic Solution to the Perspective-Three-Point Problem}, + booktitle = {Computer Vision and Pattern Recognition (CVPR), 2017 IEEE Conference on}, + year = {2017}, + organization = {IEEE} +} diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index b5a56ec1b6..c58daab027 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -236,8 +236,8 @@ enum { SOLVEPNP_ITERATIVE = 0, SOLVEPNP_EPNP = 1, //!< EPnP: Efficient Perspective-n-Point Camera Pose Estimation @cite lepetit2009epnp SOLVEPNP_P3P = 2, //!< Complete Solution Classification for the Perspective-Three-Point Problem @cite gao2003complete SOLVEPNP_DLS = 3, //!< A Direct Least-Squares (DLS) Method for PnP @cite hesch2011direct - SOLVEPNP_UPNP = 4 //!< Exhaustive Linearization for Robust Camera Pose and Focal Length Estimation @cite penate2013exhaustive - + SOLVEPNP_UPNP = 4, //!< Exhaustive Linearization for Robust Camera Pose and Focal Length Estimation @cite penate2013exhaustive + SOLVEPNP_AP3P = 5 //!< An Efficient Algebraic Solution to the Perspective-Three-Point Problem @cite Ke17 }; enum { CALIB_CB_ADAPTIVE_THRESH = 1, diff --git a/modules/calib3d/src/ap3p.cpp b/modules/calib3d/src/ap3p.cpp new file mode 100644 index 0000000000..ad2841fe98 --- /dev/null +++ b/modules/calib3d/src/ap3p.cpp @@ -0,0 +1,383 @@ +#include "ap3p.h" + +#include +#include + +using namespace std; + +namespace { +void solveQuartic(const double *factors, double *realRoots) { + const double &a4 = factors[0]; + const double &a3 = factors[1]; + const double &a2 = factors[2]; + const double &a1 = factors[3]; + const double &a0 = factors[4]; + + double a4_2 = a4 * a4; + double a3_2 = a3 * a3; + double a4_3 = a4_2 * a4; + double a2a4 = a2 * a4; + + double p4 = (8 * a2a4 - 3 * a3_2) / (8 * a4_2); + double q4 = (a3_2 * a3 - 4 * a2a4 * a3 + 8 * a1 * a4_2) / (8 * a4_3); + double r4 = (256 * a0 * a4_3 - 3 * (a3_2 * a3_2) - 64 * a1 * a3 * a4_2 + 16 * a2a4 * a3_2) / (256 * (a4_3 * a4)); + + double p3 = ((p4 * p4) / 12 + r4) / 3; // /=-3 + double q3 = (72 * r4 * p4 - 2 * p4 * p4 * p4 - 27 * q4 * q4) / 432; // /=2 + + double t; // *=2 + complex w; + if (q3 >= 0) + w = -sqrt(static_cast >(q3 * q3 - p3 * p3 * p3)) - q3; + else + w = sqrt(static_cast >(q3 * q3 - p3 * p3 * p3)) - q3; + if (w.imag() == 0.0) { + w.real(cbrt(w.real())); + t = 2.0 * (w.real() + p3 / w.real()); + } else { + w = pow(w, 1.0 / 3); + t = 4.0 * w.real(); + } + + complex sqrt_2m = sqrt(static_cast >(-2 * p4 / 3 + t)); + double B_4A = -a3 / (4 * a4); + double complex1 = 4 * p4 / 3 + t; + complex complex2 = 2 * q4 / sqrt_2m; + double sqrt_2m_rh = sqrt_2m.real() / 2; + double sqrt1 = sqrt(-(complex1 + complex2)).real() / 2; + realRoots[0] = B_4A + sqrt_2m_rh + sqrt1; + realRoots[1] = B_4A + sqrt_2m_rh - sqrt1; + double sqrt2 = sqrt(-(complex1 - complex2)).real() / 2; + realRoots[2] = B_4A - sqrt_2m_rh + sqrt2; + realRoots[3] = B_4A - sqrt_2m_rh - sqrt2; +} + +void polishQuarticRoots(const double *coeffs, double *roots) { + const int iterations = 2; + for (int i = 0; i < iterations; ++i) { + for (int j = 0; j < 4; ++j) { + double error = + (((coeffs[0] * roots[j] + coeffs[1]) * roots[j] + coeffs[2]) * roots[j] + coeffs[3]) * roots[j] + + coeffs[4]; + double + derivative = + ((4 * coeffs[0] * roots[j] + 3 * coeffs[1]) * roots[j] + 2 * coeffs[2]) * roots[j] + coeffs[3]; + roots[j] -= error / derivative; + } + } +} + +inline void vect_cross(const double *a, const double *b, double *result) { + result[0] = a[1] * b[2] - a[2] * b[1]; + result[1] = -(a[0] * b[2] - a[2] * b[0]); + result[2] = a[0] * b[1] - a[1] * b[0]; +} + +inline double vect_dot(const double *a, const double *b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +inline double vect_norm(const double *a) { + return sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); +} + +inline void vect_scale(const double s, const double *a, double *result) { + result[0] = a[0] * s; + result[1] = a[1] * s; + result[2] = a[2] * s; +} + +inline void vect_sub(const double *a, const double *b, double *result) { + result[0] = a[0] - b[0]; + result[1] = a[1] - b[1]; + result[2] = a[2] - b[2]; +} + +inline void vect_divide(const double *a, const double d, double *result) { + result[0] = a[0] / d; + result[1] = a[1] / d; + result[2] = a[2] / d; +} + +inline void mat_mult(const double a[3][3], const double b[3][3], double result[3][3]) { + result[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0]; + result[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1]; + result[0][2] = a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2]; + + result[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0]; + result[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1]; + result[1][2] = a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2]; + + result[2][0] = a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0]; + result[2][1] = a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1]; + result[2][2] = a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2]; +} +} + +namespace cv { +void ap3p::init_inverse_parameters() { + inv_fx = 1. / fx; + inv_fy = 1. / fy; + cx_fx = cx / fx; + cy_fy = cy / fy; +} + +ap3p::ap3p(cv::Mat cameraMatrix) { + if (cameraMatrix.depth() == CV_32F) + init_camera_parameters(cameraMatrix); + else + init_camera_parameters(cameraMatrix); + init_inverse_parameters(); +} + +ap3p::ap3p(double _fx, double _fy, double _cx, double _cy) { + fx = _fx; + fy = _fy; + cx = _cx; + cy = _cy; + init_inverse_parameters(); +} + +// This algorithm is from "Tong Ke, Stergios Roumeliotis, An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (Accepted by CVPR 2017) +// See https://arxiv.org/pdf/1701.08237.pdf +// featureVectors: The 3 bearing measurements (normalized) stored as column vectors +// worldPoints: The positions of the 3 feature points stored as column vectors +// solutionsR: 4 possible solutions of rotation matrix of the world w.r.t the camera frame +// solutionsT: 4 possible solutions of translation of the world origin w.r.t the camera frame +int ap3p::computePoses(const double featureVectors[3][3], + const double worldPoints[3][3], + double solutionsR[4][3][3], + double solutionsT[4][3]) { + + //world point vectors + double w1[3] = {worldPoints[0][0], worldPoints[1][0], worldPoints[2][0]}; + double w2[3] = {worldPoints[0][1], worldPoints[1][1], worldPoints[2][1]}; + double w3[3] = {worldPoints[0][2], worldPoints[1][2], worldPoints[2][2]}; + // k1 + double u0[3]; + vect_sub(w1, w2, u0); + + double nu0 = vect_norm(u0); + double k1[3]; + vect_divide(u0, nu0, k1); + // bi + double b1[3] = {featureVectors[0][0], featureVectors[1][0], featureVectors[2][0]}; + double b2[3] = {featureVectors[0][1], featureVectors[1][1], featureVectors[2][1]}; + double b3[3] = {featureVectors[0][2], featureVectors[1][2], featureVectors[2][2]}; + // k3,tz + double k3[3]; + vect_cross(b1, b2, k3); + double nk3 = vect_norm(k3); + vect_divide(k3, nk3, k3); + + double tz[3]; + vect_cross(b1, k3, tz); + // ui,vi + double v1[3]; + vect_cross(b1, b3, v1); + double v2[3]; + vect_cross(b2, b3, v2); + + double u1[3]; + vect_sub(w1, w3, u1); + // coefficients related terms + double u1k1 = vect_dot(u1, k1); + double k3b3 = vect_dot(k3, b3); + // f1i + double f11 = k3b3; + double f13 = vect_dot(k3, v1); + double f15 = -u1k1 * f11; + //delta + double nl[3]; + vect_cross(u1, k1, nl); + double delta = vect_norm(nl); + vect_divide(nl, delta, nl); + f11 *= delta; + f13 *= delta; + // f2i + double u2k1 = u1k1 - nu0; + double f21 = vect_dot(tz, v2); + double f22 = nk3 * k3b3; + double f23 = vect_dot(k3, v2); + double f24 = u2k1 * f22; + double f25 = -u2k1 * f21; + f21 *= delta; + f22 *= delta; + f23 *= delta; + double g1 = f13 * f22; + double g2 = f13 * f25 - f15 * f23; + double g3 = f11 * f23 - f13 * f21; + double g4 = -f13 * f24; + double g5 = f11 * f22; + double g6 = f11 * f25 - f15 * f21; + double g7 = -f15 * f24; + double coeffs[5] = {g5 * g5 + g1 * g1 + g3 * g3, + 2 * (g5 * g6 + g1 * g2 + g3 * g4), + g6 * g6 + 2 * g5 * g7 + g2 * g2 + g4 * g4 - g1 * g1 - g3 * g3, + 2 * (g6 * g7 - g1 * g2 - g3 * g4), + g7 * g7 - g2 * g2 - g4 * g4}; + double s[4]; + solveQuartic(coeffs, s); + polishQuarticRoots(coeffs, s); + + double temp[3]; + vect_cross(k1, nl, temp); + + double Ck1nl[3][3] = + {{k1[0], nl[0], temp[0]}, + {k1[1], nl[1], temp[1]}, + {k1[2], nl[2], temp[2]}}; + + double Cb1k3tzT[3][3] = + {{b1[0], b1[1], b1[2]}, + {k3[0], k3[1], k3[2]}, + {tz[0], tz[1], tz[2]}}; + + double b3p[3]; + vect_scale((delta / k3b3), b3, b3p); + + int nb_solutions = 0; + for (int i = 0; i < 4; ++i) { + double ctheta1p = s[i]; + if (abs(ctheta1p) > 1) + continue; + double stheta1p = sqrt(1 - ctheta1p * ctheta1p); + stheta1p = (k3b3 > 0) ? stheta1p : -stheta1p; + double ctheta3 = g1 * ctheta1p + g2; + double stheta3 = g3 * ctheta1p + g4; + double ntheta3 = stheta1p / ((g5 * ctheta1p + g6) * ctheta1p + g7); + ctheta3 *= ntheta3; + stheta3 *= ntheta3; + + double C13[3][3] = + {{ctheta3, 0, -stheta3}, + {stheta1p * stheta3, ctheta1p, stheta1p * ctheta3}, + {ctheta1p * stheta3, -stheta1p, ctheta1p * ctheta3}}; + + double temp_matrix[3][3]; + double R[3][3]; + mat_mult(Ck1nl, C13, temp_matrix); + mat_mult(temp_matrix, Cb1k3tzT, R); + + // R' * p3 + double rp3[3] = + {w3[0] * R[0][0] + w3[1] * R[1][0] + w3[2] * R[2][0], + w3[0] * R[0][1] + w3[1] * R[1][1] + w3[2] * R[2][1], + w3[0] * R[0][2] + w3[1] * R[1][2] + w3[2] * R[2][2]}; + + double pxstheta1p[3]; + vect_scale(stheta1p, b3p, pxstheta1p); + + vect_sub(pxstheta1p, rp3, solutionsT[nb_solutions]); + + solutionsR[nb_solutions][0][0] = R[0][0]; + solutionsR[nb_solutions][1][0] = R[0][1]; + solutionsR[nb_solutions][2][0] = R[0][2]; + solutionsR[nb_solutions][0][1] = R[1][0]; + solutionsR[nb_solutions][1][1] = R[1][1]; + solutionsR[nb_solutions][2][1] = R[1][2]; + solutionsR[nb_solutions][0][2] = R[2][0]; + solutionsR[nb_solutions][1][2] = R[2][1]; + solutionsR[nb_solutions][2][2] = R[2][2]; + + nb_solutions++; + } + + return nb_solutions; +} + +bool ap3p::solve(cv::Mat &R, cv::Mat &tvec, const cv::Mat &opoints, const cv::Mat &ipoints) { + CV_INSTRUMENT_REGION() + + double rotation_matrix[3][3], translation[3]; + std::vector points; + if (opoints.depth() == ipoints.depth()) { + if (opoints.depth() == CV_32F) + extract_points(opoints, ipoints, points); + else + extract_points(opoints, ipoints, points); + } else if (opoints.depth() == CV_32F) + extract_points(opoints, ipoints, points); + else + extract_points(opoints, ipoints, points); + + bool result = solve(rotation_matrix, translation, points[0], points[1], points[2], points[3], points[4], points[5], + points[6], points[7], points[8], points[9], points[10], points[11], points[12], points[13], + points[14], + points[15], points[16], points[17], points[18], points[19]); + cv::Mat(3, 1, CV_64F, translation).copyTo(tvec); + cv::Mat(3, 3, CV_64F, rotation_matrix).copyTo(R); + return result; +} + +bool +ap3p::solve(double R[3][3], double t[3], double mu0, double mv0, double X0, double Y0, double Z0, double mu1, + double mv1, + double X1, double Y1, double Z1, double mu2, double mv2, double X2, double Y2, double Z2, double mu3, + double mv3, double X3, double Y3, double Z3) { + double Rs[4][3][3], ts[4][3]; + + int n = solve(Rs, ts, mu0, mv0, X0, Y0, Z0, mu1, mv1, X1, Y1, Z1, mu2, mv2, X2, Y2, Z2); + if (n == 0) + return false; + + int ns = 0; + double min_reproj = 0; + for (int i = 0; i < n; i++) { + double X3p = Rs[i][0][0] * X3 + Rs[i][0][1] * Y3 + Rs[i][0][2] * Z3 + ts[i][0]; + double Y3p = Rs[i][1][0] * X3 + Rs[i][1][1] * Y3 + Rs[i][1][2] * Z3 + ts[i][1]; + double Z3p = Rs[i][2][0] * X3 + Rs[i][2][1] * Y3 + Rs[i][2][2] * Z3 + ts[i][2]; + double mu3p = cx + fx * X3p / Z3p; + double mv3p = cy + fy * Y3p / Z3p; + double reproj = (mu3p - mu3) * (mu3p - mu3) + (mv3p - mv3) * (mv3p - mv3); + if (i == 0 || min_reproj > reproj) { + ns = i; + min_reproj = reproj; + } + } + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) + R[i][j] = Rs[ns][i][j]; + t[i] = ts[ns][i]; + } + + return true; +} + +int ap3p::solve(double R[4][3][3], double t[4][3], double mu0, double mv0, double X0, double Y0, double Z0, double mu1, + double mv1, double X1, double Y1, double Z1, double mu2, double mv2, double X2, double Y2, double Z2) { + double mk0, mk1, mk2; + double norm; + + mu0 = inv_fx * mu0 - cx_fx; + mv0 = inv_fy * mv0 - cy_fy; + norm = sqrt(mu0 * mu0 + mv0 * mv0 + 1); + mk0 = 1. / norm; + mu0 *= mk0; + mv0 *= mk0; + + mu1 = inv_fx * mu1 - cx_fx; + mv1 = inv_fy * mv1 - cy_fy; + norm = sqrt(mu1 * mu1 + mv1 * mv1 + 1); + mk1 = 1. / norm; + mu1 *= mk1; + mv1 *= mk1; + + mu2 = inv_fx * mu2 - cx_fx; + mv2 = inv_fy * mv2 - cy_fy; + norm = sqrt(mu2 * mu2 + mv2 * mv2 + 1); + mk2 = 1. / norm; + mu2 *= mk2; + mv2 *= mk2; + + double featureVectors[3][3] = {{mu0, mu1, mu2}, + {mv0, mv1, mv2}, + {mk0, mk1, mk2}}; + double worldPoints[3][3] = {{X0, X1, X2}, + {Y0, Y1, Y2}, + {Z0, Z1, Z2}}; + + return computePoses(featureVectors, worldPoints, R, t); +} +} \ No newline at end of file diff --git a/modules/calib3d/src/ap3p.h b/modules/calib3d/src/ap3p.h new file mode 100644 index 0000000000..37c7be12b4 --- /dev/null +++ b/modules/calib3d/src/ap3p.h @@ -0,0 +1,65 @@ +#ifndef P3P_P3P_H +#define P3P_P3P_H + +#include "precomp.hpp" + +namespace cv { +class ap3p { +private: + template + void init_camera_parameters(const cv::Mat &cameraMatrix) { + cx = cameraMatrix.at(0, 2); + cy = cameraMatrix.at(1, 2); + fx = cameraMatrix.at(0, 0); + fy = cameraMatrix.at(1, 1); + } + + template + void extract_points(const cv::Mat &opoints, const cv::Mat &ipoints, std::vector &points) { + points.clear(); + points.resize(20); + for (int i = 0; i < 4; i++) { + points[i * 5] = ipoints.at(i).x * fx + cx; + points[i * 5 + 1] = ipoints.at(i).y * fy + cy; + points[i * 5 + 2] = opoints.at(i).x; + points[i * 5 + 3] = opoints.at(i).y; + points[i * 5 + 4] = opoints.at(i).z; + } + } + + void init_inverse_parameters(); + + double fx, fy, cx, cy; + double inv_fx, inv_fy, cx_fx, cy_fy; +public: + ap3p() {} + + ap3p(double fx, double fy, double cx, double cy); + + ap3p(cv::Mat cameraMatrix); + + bool solve(cv::Mat &R, cv::Mat &tvec, const cv::Mat &opoints, const cv::Mat &ipoints); + + int solve(double R[4][3][3], double t[4][3], + double mu0, double mv0, double X0, double Y0, double Z0, + double mu1, double mv1, double X1, double Y1, double Z1, + double mu2, double mv2, double X2, double Y2, double Z2); + + bool solve(double R[3][3], double t[3], + double mu0, double mv0, double X0, double Y0, double Z0, + double mu1, double mv1, double X1, double Y1, double Z1, + double mu2, double mv2, double X2, double Y2, double Z2, + double mu3, double mv3, double X3, double Y3, double Z3); + + // This algorithm is from "Tong Ke, Stergios Roumeliotis, An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (Accepted by CVPR 2017) + // See https://arxiv.org/pdf/1701.08237.pdf + // featureVectors: 3 bearing measurements (normalized) stored as column vectors + // worldPoints: Positions of the 3 feature points stored as column vectors + // solutionsR: 4 possible solutions of rotation matrix of the world w.r.t the camera frame + // solutionsT: 4 possible solutions of translation of the world origin w.r.t the camera frame + int computePoses(const double featureVectors[3][3], const double worldPoints[3][3], double solutionsR[4][3][3], + double solutionsT[4][3]); + +}; +} +#endif //P3P_P3P_H diff --git a/modules/calib3d/src/solvepnp.cpp b/modules/calib3d/src/solvepnp.cpp index 1e9b8ec6e4..a9be4c848d 100644 --- a/modules/calib3d/src/solvepnp.cpp +++ b/modules/calib3d/src/solvepnp.cpp @@ -45,6 +45,7 @@ #include "dls.h" #include "epnp.h" #include "p3p.h" +#include "ap3p.h" #include "opencv2/calib3d/calib3d_c.h" #include @@ -118,6 +119,18 @@ bool solvePnP( InputArray _opoints, InputArray _ipoints, if (result) Rodrigues(R, rvec); } + else if (flags == SOLVEPNP_AP3P) + { + CV_Assert( npoints == 4); + Mat undistortedPoints; + undistortPoints(ipoints, undistortedPoints, cameraMatrix, distCoeffs); + ap3p P3Psolver(cameraMatrix); + + Mat R; + result = P3Psolver.solve(R, tvec, opoints, undistortedPoints); + if (result) + Rodrigues(R, rvec); + } else if (flags == SOLVEPNP_ITERATIVE) { CvMat c_objectPoints = opoints, c_imagePoints = ipoints; @@ -291,7 +304,8 @@ bool solvePnPRansac(InputArray _opoints, InputArray _ipoints, opoints_inliers.resize(npoints1); ipoints_inliers.resize(npoints1); result = solvePnP(opoints_inliers, ipoints_inliers, cameraMatrix, - distCoeffs, rvec, tvec, false, flags == SOLVEPNP_P3P ? SOLVEPNP_EPNP : flags) ? 1 : -1; + distCoeffs, rvec, tvec, false, + (flags == SOLVEPNP_P3P || flags == SOLVEPNP_AP3P) ? SOLVEPNP_EPNP : flags) ? 1 : -1; } if( result <= 0 || _local_model.rows <= 0) diff --git a/modules/calib3d/test/test_solvepnp_ransac.cpp b/modules/calib3d/test/test_solvepnp_ransac.cpp index e6e9b6b22f..86634a0b45 100644 --- a/modules/calib3d/test/test_solvepnp_ransac.cpp +++ b/modules/calib3d/test/test_solvepnp_ransac.cpp @@ -57,6 +57,7 @@ public: eps[SOLVEPNP_ITERATIVE] = 1.0e-2; eps[SOLVEPNP_EPNP] = 1.0e-2; eps[SOLVEPNP_P3P] = 1.0e-2; + eps[SOLVEPNP_AP3P] = 1.0e-2; eps[SOLVEPNP_DLS] = 1.0e-2; eps[SOLVEPNP_UPNP] = 1.0e-2; totalTestsCount = 10; @@ -161,7 +162,7 @@ protected: points.resize(pointsCount); generate3DPointCloud(points); - const int methodsCount = 5; + const int methodsCount = 6; RNG rng = ts->get_rng(); @@ -189,7 +190,7 @@ protected: } } } - double eps[5]; + double eps[6]; int totalTestsCount; }; @@ -201,6 +202,7 @@ public: eps[SOLVEPNP_ITERATIVE] = 1.0e-6; eps[SOLVEPNP_EPNP] = 1.0e-6; eps[SOLVEPNP_P3P] = 1.0e-4; + eps[SOLVEPNP_AP3P] = 1.0e-4; eps[SOLVEPNP_DLS] = 1.0e-4; eps[SOLVEPNP_UPNP] = 1.0e-4; totalTestsCount = 1000; @@ -222,7 +224,7 @@ protected: generatePose(trueRvec, trueTvec, rng); std::vector opoints; - if (method == 2) + if (method == 2 || method == 5) { opoints = std::vector(points.begin(), points.begin()+4); } From 4065778255a36a1edd7c881cec0096d73e2d8ba0 Mon Sep 17 00:00:00 2001 From: Fangjun KUANG Date: Mon, 10 Apr 2017 09:32:50 +0200 Subject: [PATCH 076/144] fix typos. --- modules/core/include/opencv2/core.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp index 5d18823d58..b6cc6bc7c4 100644 --- a/modules/core/include/opencv2/core.hpp +++ b/modules/core/include/opencv2/core.hpp @@ -2762,7 +2762,7 @@ public: double a1 = rng.uniform((double)0, (double)1); // produces float from [0, 1) - double b = rng.uniform(0.f, 1.f); + float b = rng.uniform(0.f, 1.f); // produces double from [0, 1) double c = rng.uniform(0., 1.); @@ -2778,8 +2778,8 @@ public: want a floating-point random number, but the range boundaries are integer numbers, either put dots in the end, if they are constants, or use explicit type cast operators, as in the a1 initialization above. - @param a lower inclusive boundary of the returned random numbers. - @param b upper non-inclusive boundary of the returned random numbers. + @param a lower inclusive boundary of the returned random number. + @param b upper non-inclusive boundary of the returned random number. */ int uniform(int a, int b); /** @overload */ From 9cd42650dc5287b43f4ca3d6540c198798f53b8a Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Mon, 10 Apr 2017 22:19:17 +0900 Subject: [PATCH 077/144] build with cc 6.2 on Jetson TX2 --- cmake/OpenCVDetectCUDA.cmake | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index 3116d9fd87..282ba3e529 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -88,7 +88,17 @@ if(CUDA_FOUND) set(__cuda_arch_bin "3.2") set(__cuda_arch_ptx "") elseif(AARCH64) - set(__cuda_arch_bin "5.3") + execute_process( COMMAND "${CUDA_NVCC_EXECUTABLE}" "${OpenCV_SOURCE_DIR}/cmake/checks/OpenCVDetectCudaArch.cu" "--run" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" + RESULT_VARIABLE _nvcc_res OUTPUT_VARIABLE _nvcc_out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT _nvcc_res EQUAL 0) + message(STATUS "Automatic detection of CUDA generation failed. Going to build for all known architectures.") + set(__cuda_arch_bin "5.3 6.2") + else() + set(__cuda_arch_bin "${_nvcc_out}") + string(REPLACE "2.1" "2.1(2.0)" __cuda_arch_bin "${__cuda_arch_bin}") + endif() set(__cuda_arch_ptx "") else() if(${CUDA_VERSION} VERSION_LESS "8.0") @@ -96,7 +106,6 @@ if(CUDA_FOUND) else() set(__cuda_arch_bin "2.0 3.0 3.5 3.7 5.0 5.2 6.0 6.1") endif() - set(__cuda_arch_ptx "") endif() endif() From fce74699613e64538c1fd038d828bb4f0f086fa4 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Mon, 10 Apr 2017 12:04:09 -0700 Subject: [PATCH 078/144] Update utility.hpp Adding missing header for ostream decl. in line 384 --- modules/core/include/opencv2/core/utility.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp index bc33f03f5d..87c20f10c7 100644 --- a/modules/core/include/opencv2/core/utility.hpp +++ b/modules/core/include/opencv2/core/utility.hpp @@ -54,6 +54,7 @@ #endif #include "opencv2/core.hpp" +#include namespace cv { From e0fe3cce719b3db03e5fb73c52c4eae1dfb97139 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Mon, 10 Apr 2017 12:07:28 -0700 Subject: [PATCH 079/144] Update autotuned_index.h Add missing sstream header for decl of std::ostringstream in line 104 --- modules/flann/include/opencv2/flann/autotuned_index.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/flann/include/opencv2/flann/autotuned_index.h b/modules/flann/include/opencv2/flann/autotuned_index.h index 6ffb9297c4..30f8b92a81 100644 --- a/modules/flann/include/opencv2/flann/autotuned_index.h +++ b/modules/flann/include/opencv2/flann/autotuned_index.h @@ -30,6 +30,8 @@ #ifndef OPENCV_FLANN_AUTOTUNED_INDEX_H_ #define OPENCV_FLANN_AUTOTUNED_INDEX_H_ +#include + #include "general.h" #include "nn_index.h" #include "ground_truth.h" From b9c2d88e69b507ec05efc2085305696ef279b919 Mon Sep 17 00:00:00 2001 From: Utkarsh Sinha Date: Mon, 10 Apr 2017 20:43:33 -0700 Subject: [PATCH 080/144] If the user passes an empty output matrix, initialize it to identity. --- modules/video/src/ecc.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/video/src/ecc.cpp b/modules/video/src/ecc.cpp index d11419e402..377b775072 100644 --- a/modules/video/src/ecc.cpp +++ b/modules/video/src/ecc.cpp @@ -325,6 +325,16 @@ double cv::findTransformECC(InputArray templateImage, CV_Assert(!src.empty()); CV_Assert(!dst.empty()); + // If the user passed an un-initialized warpMatrix, initialize to identity + if(map.empty()) { + int rowCount = 2; + if(motionType == MOTION_HOMOGRAPHY) + rowCount = 3; + + warpMatrix.create(rowCount, 3, CV_32FC1); + map = warpMatrix.getMat(); + map = Mat::eye(rowCount, 3, CV_32F); + } if( ! (src.type()==dst.type())) CV_Error( Error::StsUnmatchedFormats, "Both input images must have the same data type" ); From ccc8767b55db810e605d0dd2dabb315bef2f975d Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Fri, 7 Apr 2017 19:11:05 +0900 Subject: [PATCH 081/144] suppress warning on Jetson TK1 --- modules/photo/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/photo/CMakeLists.txt b/modules/photo/CMakeLists.txt index 88ac35d83f..c15c01de6c 100644 --- a/modules/photo/CMakeLists.txt +++ b/modules/photo/CMakeLists.txt @@ -1,7 +1,7 @@ set(the_description "Computational Photography") if(HAVE_CUDA) - ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wmissing-declarations) + ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wmissing-declarations -Wshadow) endif() ocv_define_module(photo opencv_imgproc OPTIONAL opencv_cudaarithm opencv_cudaimgproc WRAP java python) From c1ade083d9f74f4af260a6f3e08b65a9ee2ead9b Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 11 Apr 2017 12:35:48 +0300 Subject: [PATCH 082/144] ffmpeg: add __STDC_CONSTANT_MACROS to check code --- cmake/checks/ffmpeg_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/checks/ffmpeg_test.cpp b/cmake/checks/ffmpeg_test.cpp index 7b49c38c7a..81c755632f 100644 --- a/cmake/checks/ffmpeg_test.cpp +++ b/cmake/checks/ffmpeg_test.cpp @@ -1,3 +1,5 @@ +#define __STDC_CONSTANT_MACROS + #include extern "C" { From 0330934c8bf9327e17a71164e88fd93450a3a10e Mon Sep 17 00:00:00 2001 From: Utkarsh Sinha Date: Tue, 11 Apr 2017 06:42:20 -0700 Subject: [PATCH 083/144] Updating documentation. --- modules/video/include/opencv2/video/tracking.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/video/include/opencv2/video/tracking.hpp b/modules/video/include/opencv2/video/tracking.hpp index c6ead3a42c..a96a2e53cf 100644 --- a/modules/video/include/opencv2/video/tracking.hpp +++ b/modules/video/include/opencv2/video/tracking.hpp @@ -297,7 +297,7 @@ row is ignored. Unlike findHomography and estimateRigidTransform, the function findTransformECC implements an area-based alignment that builds on intensity similarities. In essence, the function updates the initial transformation that roughly aligns the images. If this information is missing, the identity -warp (unity matrix) should be given as input. Note that if images undergo strong +warp (unity matrix) is used as an initialization. Note that if images undergo strong displacements/rotations, an initial transformation that roughly aligns the images is necessary (e.g., a simple euclidean/similarity transform that allows for the images showing the same image content approximately). Use inverse warping in the second image to take an image close to the first From 21e698053fb97f755846269e3db6d9800466693d Mon Sep 17 00:00:00 2001 From: Fernando Iglesias Garcia Date: Wed, 12 Apr 2017 10:11:50 +0200 Subject: [PATCH 084/144] Initialize background model in background subtraction KNN. The method does cvCheckPixelBackgroundNP (which reads bgmodel) before it is ever updated (in cvUpdatePixelBackgroundNP). This initialization is thus needed to avoid reads of unitialized values. --- modules/video/src/bgfg_KNN.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/video/src/bgfg_KNN.cpp b/modules/video/src/bgfg_KNN.cpp index 66be34a00f..9dcfe37e78 100755 --- a/modules/video/src/bgfg_KNN.cpp +++ b/modules/video/src/bgfg_KNN.cpp @@ -122,7 +122,7 @@ public: //! computes a background image which are the mean of all background gaussians virtual void getBackgroundImage(OutputArray backgroundImage) const; - //! re-initiaization method + //! re-initialization method void initialize(Size _frameSize, int _frameType) { frameSize = _frameSize; @@ -137,6 +137,7 @@ public: // for each sample of 3 speed pixel models each pixel bg model we store ... // values + flag (nchannels+1 values) bgmodel.create( 1,(nN * 3) * (nchannels+1)* size,CV_8U); + bgmodel = Scalar::all(0); //index through the three circular lists aModelIndexShort.create(1,size,CV_8U); From 550ca10ec653c2cefe46730a5c0913ca11a2a8e8 Mon Sep 17 00:00:00 2001 From: orisano Date: Wed, 12 Apr 2017 12:18:51 +0900 Subject: [PATCH 085/144] Remove stdout log when destructor called. --- modules/videoio/src/cap_qtkit.mm | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/videoio/src/cap_qtkit.mm b/modules/videoio/src/cap_qtkit.mm index ad6037b766..d998b4cbc4 100644 --- a/modules/videoio/src/cap_qtkit.mm +++ b/modules/videoio/src/cap_qtkit.mm @@ -270,8 +270,6 @@ CvCaptureCAM::CvCaptureCAM(int cameraNum) { CvCaptureCAM::~CvCaptureCAM() { stopCaptureDevice(); - - std::cout << "Cleaned up camera." << std::endl; } int CvCaptureCAM::didStart() { From c145f28c710e58f556daf646cb71e60e83a9603f Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Wed, 12 Apr 2017 20:09:00 +0900 Subject: [PATCH 086/144] fix build error on VS2012 --- modules/calib3d/src/ap3p.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/calib3d/src/ap3p.cpp b/modules/calib3d/src/ap3p.cpp index ad2841fe98..db88a02d04 100644 --- a/modules/calib3d/src/ap3p.cpp +++ b/modules/calib3d/src/ap3p.cpp @@ -2,6 +2,9 @@ #include #include +#if defined (_MSC_VER) && (_MSC_VER <= 1700) +static inline double cbrt(double x) { return (double)cv::cubeRoot((float)x); }; +#endif using namespace std; From c90dee668f211783a2929c999501d2f9025ec279 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 12 Apr 2017 18:27:20 +0300 Subject: [PATCH 087/144] cmake: fix optimization filter Check file name only: Excluding from source files list (optimization is disabled): C:/Code/SrcExt/OpenCV/Buildv3.2_x64/modules/core/opencl_kernels_core.cpp --- cmake/OpenCVCompilerOptimizations.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/OpenCVCompilerOptimizations.cmake b/cmake/OpenCVCompilerOptimizations.cmake index 9b48dc857f..6758fdf628 100644 --- a/cmake/OpenCVCompilerOptimizations.cmake +++ b/cmake/OpenCVCompilerOptimizations.cmake @@ -520,6 +520,7 @@ macro(ocv_compiler_optimization_process_sources SOURCES_VAR_NAME LIBS_VAR_NAME T endforeach() foreach(fname ${${SOURCES_VAR_NAME}}) string(TOLOWER "${fname}" fname_LOWER) + get_filename_component(fname_LOWER "${fname_LOWER}" NAME) if(fname_LOWER MATCHES "\\.(.*)\\.cpp$") string(TOUPPER "${CMAKE_MATCH_1}" OPT_) if(OPT_ MATCHES "(CUDA.*|DISPATCH.*|OCL)") # don't touch files like filename.cuda.cpp From d873fe66ab371abdf9bb93d4e3dfee1d3dcd9906 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Thu, 13 Apr 2017 17:45:42 +0300 Subject: [PATCH 088/144] Fixed size estimation for copyFrom/To vector in vx_matrix and vx_convolution wrappers --- 3rdparty/openvx/include/ivx.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/3rdparty/openvx/include/ivx.hpp b/3rdparty/openvx/include/ivx.hpp index 5c3029d617..5f8423fa61 100644 --- a/3rdparty/openvx/include/ivx.hpp +++ b/3rdparty/openvx/include/ivx.hpp @@ -2508,10 +2508,10 @@ public: { if (!areTypesCompatible(TypeToEnum::value, dataType())) throw WrapperError(std::string(__func__) + "(): destination type is wrong"); - if (data.size() != size()) + if (data.size()*sizeof(T) != size()) { if (data.size() == 0) - data.resize(size()); + data.resize(size()/sizeof(T)); else throw WrapperError(std::string(__func__) + "(): destination size is wrong"); } @@ -2522,7 +2522,7 @@ public: { if (!areTypesCompatible(TypeToEnum::value, dataType())) throw WrapperError(std::string(__func__) + "(): source type is wrong"); - if (data.size() != size()) throw WrapperError(std::string(__func__) + "(): source size is wrong"); + if (data.size()*sizeof(T) != size()) throw WrapperError(std::string(__func__) + "(): source size is wrong"); copyFrom(&data[0]); } @@ -2670,10 +2670,10 @@ public: { if (!areTypesCompatible(TypeToEnum::value, dataType())) throw WrapperError(std::string(__func__) + "(): destination type is wrong"); - if (data.size() != size()) + if (data.size()*sizeof(T) != size()) { if (data.size() == 0) - data.resize(size()); + data.resize(size()/sizeof(T)); else throw WrapperError(std::string(__func__) + "(): destination size is wrong"); } @@ -2684,7 +2684,7 @@ public: { if (!areTypesCompatible(TypeToEnum::value, dataType())) throw WrapperError(std::string(__func__) + "(): source type is wrong"); - if (data.size() != size()) throw WrapperError(std::string(__func__) + "(): source size is wrong"); + if (data.size()*sizeof(T) != size()) throw WrapperError(std::string(__func__) + "(): source size is wrong"); copyFrom(&data[0]); } From 1fc60e6d64dc8ffec72891d9ca73c8fe6bba1b8e Mon Sep 17 00:00:00 2001 From: zongwave Date: Wed, 21 Dec 2016 16:12:08 +0800 Subject: [PATCH 089/144] Add method KeypointBasedMotionEstimator::estimate(InputArray, InputArray) to support both cpu & opencl algorithm processing the orignal estimate function has input parameters defined as "Mat", this prevent users to call into algorithm opencl path --- .../videostab/include/opencv2/videostab/global_motion.hpp | 1 + modules/videostab/src/global_motion.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/modules/videostab/include/opencv2/videostab/global_motion.hpp b/modules/videostab/include/opencv2/videostab/global_motion.hpp index 80b147a6b5..8250654c2c 100644 --- a/modules/videostab/include/opencv2/videostab/global_motion.hpp +++ b/modules/videostab/include/opencv2/videostab/global_motion.hpp @@ -236,6 +236,7 @@ public: Ptr outlierRejector() const { return outlierRejector_; } virtual Mat estimate(const Mat &frame0, const Mat &frame1, bool *ok = 0); + Mat estimate(InputArray frame0, InputArray frame1, bool *ok = 0); private: Ptr motionEstimator_; diff --git a/modules/videostab/src/global_motion.cpp b/modules/videostab/src/global_motion.cpp index 53603382ad..e0302ced2c 100644 --- a/modules/videostab/src/global_motion.cpp +++ b/modules/videostab/src/global_motion.cpp @@ -710,6 +710,14 @@ KeypointBasedMotionEstimator::KeypointBasedMotionEstimator(Ptrdetect(frame0, keypointsPrev_); From 26ccc09c4686a753b9ed9a41d60c499979ce5f7c Mon Sep 17 00:00:00 2001 From: Yuriy Solovyov Date: Fri, 14 Apr 2017 17:16:00 +0300 Subject: [PATCH 090/144] Fix zlib issue on iOS --- modules/core/src/persistence.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp index 66b318d328..2e834f67fd 100644 --- a/modules/core/src/persistence.cpp +++ b/modules/core/src/persistence.cpp @@ -50,15 +50,6 @@ #define USE_ZLIB 1 -#ifdef __APPLE__ -# include "TargetConditionals.h" -# if (defined TARGET_OS_IPHONE && TARGET_OS_IPHONE) || (defined TARGET_IPHONE_SIMULATOR && TARGET_IPHONE_SIMULATOR) -# undef USE_ZLIB -# define USE_ZLIB 0 - typedef void* gzFile; -# endif -#endif - #if USE_ZLIB # ifndef _LFS64_LARGEFILE # define _LFS64_LARGEFILE 0 From 9e054d3880ff445aac6fa95a53e05f0dce7880d9 Mon Sep 17 00:00:00 2001 From: brian-armstrong-discord Date: Fri, 14 Apr 2017 13:12:07 -0700 Subject: [PATCH 091/144] Merge pull request #8492 from brian-armstrong-discord:exif_inmemory autorotate in-memory jpegs (#8492) * autorotate in-memory jpegs * correct indentation (4 spaces) * imgcodecs: don't apply EXIF rotation for unloaded images * videoio: don't try to rotate MJPEG stream * imgcodecs: ByteStreamBuffer::seekoff support all seek "dir" * imgcodecs: fix condition: "off == egptr() - eback()" is valid offset --- modules/imgcodecs/src/exif.cpp | 51 ++++------ modules/imgcodecs/src/exif.hpp | 10 +- modules/imgcodecs/src/loadsave.cpp | 117 ++++++++++++++++++---- modules/videoio/src/cap_mjpeg_decoder.cpp | 2 +- 4 files changed, 128 insertions(+), 52 deletions(-) diff --git a/modules/imgcodecs/src/exif.cpp b/modules/imgcodecs/src/exif.cpp index 8a4f3f4b86..e057f8ce53 100644 --- a/modules/imgcodecs/src/exif.cpp +++ b/modules/imgcodecs/src/exif.cpp @@ -61,7 +61,7 @@ ExifEntry_t::ExifEntry_t() : /** * @brief ExifReader constructor */ -ExifReader::ExifReader(std::string filename) : m_filename(filename), m_format(NONE) +ExifReader::ExifReader(std::istream& stream) : m_stream(stream), m_format(NONE) { } @@ -121,29 +121,18 @@ ExifEntry_t ExifReader::getTag(const ExifTagName tag) */ std::map ExifReader::getExif() { - const size_t markerSize = 2; - const size_t offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header + const std::streamsize markerSize = 2; + const std::streamsize offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header unsigned char appMarker[markerSize]; m_exif.erase( m_exif.begin(), m_exif.end() ); - size_t count; - - if (m_filename.size() == 0) - { - return m_exif; - } - - FILE* f = fopen( m_filename.c_str(), "rb" ); - - if( !f ) - { - return m_exif; //Until this moment the map is empty - } + std::streamsize count; bool exifFound = false, stopSearch = false; - while( ( !feof( f ) ) && !exifFound && !stopSearch ) + while( ( !m_stream.eof() ) && !exifFound && !stopSearch ) { - count = fread( appMarker, sizeof(unsigned char), markerSize, f ); + m_stream.read( reinterpret_cast(appMarker), markerSize ); + count = m_stream.gcount(); if( count < markerSize ) { break; @@ -159,12 +148,14 @@ std::map ExifReader::getExif() case APP0: case APP2: case APP3: case APP4: case APP5: case APP6: case APP7: case APP8: case APP9: case APP10: case APP11: case APP12: case APP13: case APP14: case APP15: case COM: - bytesToSkip = getFieldSize( f ); + bytesToSkip = getFieldSize(); if (bytesToSkip < markerSize) { - fclose(f); throw ExifParsingError(); } - fseek( f, static_cast( bytesToSkip - markerSize ), SEEK_CUR ); + m_stream.seekg( static_cast( bytesToSkip - markerSize ), m_stream.cur ); + if ( m_stream.fail() ) { + throw ExifParsingError(); + } break; //SOI and EOI don't have the size field after the marker @@ -172,14 +163,17 @@ std::map ExifReader::getExif() break; case APP1: //actual Exif Marker - exifSize = getFieldSize(f); + exifSize = getFieldSize(); if (exifSize <= offsetToTiffHeader) { - fclose(f); throw ExifParsingError(); } m_data.resize( exifSize - offsetToTiffHeader ); - fseek(f, static_cast( offsetToTiffHeader ), SEEK_CUR); - count = fread( &m_data[0], sizeof( unsigned char ), exifSize - offsetToTiffHeader, f ); + m_stream.seekg( static_cast( offsetToTiffHeader ), m_stream.cur ); + if ( m_stream.fail() ) { + throw ExifParsingError(); + } + m_stream.read( reinterpret_cast(&m_data[0]), exifSize - offsetToTiffHeader ); + count = m_stream.gcount(); exifFound = true; break; @@ -189,8 +183,6 @@ std::map ExifReader::getExif() } } - fclose(f); - if( !exifFound ) { return m_exif; @@ -207,10 +199,11 @@ std::map ExifReader::getExif() * * @return size of exif field in the file */ -size_t ExifReader::getFieldSize (FILE* f) const +size_t ExifReader::getFieldSize () { unsigned char fieldSize[2]; - size_t count = fread ( fieldSize, sizeof( char ), 2, f ); + m_stream.read( reinterpret_cast(fieldSize), 2 ); + std::streamsize count = m_stream.gcount(); if (count < 2) { return 0; diff --git a/modules/imgcodecs/src/exif.hpp b/modules/imgcodecs/src/exif.hpp index 43c2857f3c..094236be40 100644 --- a/modules/imgcodecs/src/exif.hpp +++ b/modules/imgcodecs/src/exif.hpp @@ -51,6 +51,7 @@ #include #include #include +#include namespace cv { @@ -168,9 +169,9 @@ public: /** * @brief ExifReader constructor. Constructs an object of exif reader * - * @param [in]filename The name of file to look exif info in + * @param [in]stream An istream to look for EXIF bytes from */ - explicit ExifReader( std::string filename ); + explicit ExifReader( std::istream& stream ); ~ExifReader(); @@ -190,7 +191,7 @@ public: ExifEntry_t getTag( const ExifTagName tag ); private: - std::string m_filename; + std::istream& m_stream; std::vector m_data; std::map m_exif; Endianess_t m_format; @@ -198,7 +199,7 @@ private: void parseExif(); bool checkTagMark() const; - size_t getFieldSize ( FILE* f ) const; + size_t getFieldSize (); size_t getNumDirEntry() const; uint32_t getStartOffset() const; uint16_t getExifTag( const size_t offset ) const; @@ -247,7 +248,6 @@ private: }; - } #endif /* _OPENCV_EXIF_HPP_ */ diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index 493ccab457..4ceccd196e 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -50,10 +50,50 @@ #undef min #undef max #include +#include /****************************************************************************************\ * Image Codecs * \****************************************************************************************/ +namespace { + +class ByteStreamBuffer: public std::streambuf +{ +public: + ByteStreamBuffer(char* base, size_t length) + { + setg(base, base, base + length); + } + +protected: + virtual pos_type seekoff( off_type offset, + std::ios_base::seekdir dir, + std::ios_base::openmode ) + { + // get absolute offset + off_type off = offset; + if (dir == std::ios_base::cur) + { + off += gptr() - eback(); + } + else if (dir == std::ios_base::end) + { + off += egptr() - eback(); + } + + // check limits + if (off >= (off_type)0 && off <= egptr() - eback()) + { + setg(eback(), gptr() + off, egptr()); + return gptr() - eback(); + } + + return -1; + } +}; + +} + namespace cv { @@ -232,23 +272,8 @@ static ImageEncoder findEncoder( const String& _ext ) enum { LOAD_CVMAT=0, LOAD_IMAGE=1, LOAD_MAT=2 }; -static void ApplyExifOrientation(const String& filename, Mat& img) +static void ExifTransform(int orientation, Mat& img) { - int orientation = IMAGE_ORIENTATION_TL; - - if (filename.size() > 0) - { - ExifReader reader( filename ); - if( reader.parse() ) - { - ExifEntry_t entry = reader.getTag( ORIENTATION ); - if (entry.tag != INVALID_TAG) - { - orientation = entry.field_u16; //orientation is unsigned short, so check field_u16 - } - } - } - switch( orientation ) { case IMAGE_ORIENTATION_TL: //0th row == visual top, 0th column == visual left-hand side @@ -284,6 +309,50 @@ static void ApplyExifOrientation(const String& filename, Mat& img) } } +static void ApplyExifOrientation(const String& filename, Mat& img) +{ + int orientation = IMAGE_ORIENTATION_TL; + + if (filename.size() > 0) + { + std::ifstream stream( filename.c_str(), std::ios_base::in | std::ios_base::binary ); + ExifReader reader( stream ); + if( reader.parse() ) + { + ExifEntry_t entry = reader.getTag( ORIENTATION ); + if (entry.tag != INVALID_TAG) + { + orientation = entry.field_u16; //orientation is unsigned short, so check field_u16 + } + } + stream.close(); + } + + ExifTransform(orientation, img); +} + +static void ApplyExifOrientation(const Mat& buf, Mat& img) +{ + int orientation = IMAGE_ORIENTATION_TL; + + if( buf.isContinuous() ) + { + ByteStreamBuffer bsb( reinterpret_cast(buf.data), buf.total() * buf.elemSize() ); + std::istream stream( &bsb ); + ExifReader reader( stream ); + if( reader.parse() ) + { + ExifEntry_t entry = reader.getTag( ORIENTATION ); + if (entry.tag != INVALID_TAG) + { + orientation = entry.field_u16; //orientation is unsigned short, so check field_u16 + } + } + } + + ExifTransform(orientation, img); +} + /** * Read an image into memory and return the information * @@ -494,7 +563,7 @@ Mat imread( const String& filename, int flags ) imread_( filename, flags, LOAD_MAT, &img ); /// optionally rotate the data if EXIF' orientation flag says so - if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED ) + if( !img.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED ) { ApplyExifOrientation(filename, img); } @@ -658,6 +727,13 @@ Mat imdecode( InputArray _buf, int flags ) { Mat buf = _buf.getMat(), img; imdecode_( buf, flags, LOAD_MAT, &img ); + + /// optionally rotate the data if EXIF' orientation flag says so + if( !img.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED ) + { + ApplyExifOrientation(buf, img); + } + return img; } @@ -666,6 +742,13 @@ Mat imdecode( InputArray _buf, int flags, Mat* dst ) Mat buf = _buf.getMat(), img; dst = dst ? dst : &img; imdecode_( buf, flags, LOAD_MAT, dst ); + + /// optionally rotate the data if EXIF' orientation flag says so + if( !dst->empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED ) + { + ApplyExifOrientation(buf, *dst); + } + return *dst; } diff --git a/modules/videoio/src/cap_mjpeg_decoder.cpp b/modules/videoio/src/cap_mjpeg_decoder.cpp index 7abce2004e..2ded72e72f 100644 --- a/modules/videoio/src/cap_mjpeg_decoder.cpp +++ b/modules/videoio/src/cap_mjpeg_decoder.cpp @@ -821,7 +821,7 @@ bool MotionJpegCapture::retrieveFrame(int, OutputArray output_frame) if(data.size()) { - m_current_frame = imdecode(data, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_COLOR); + m_current_frame = imdecode(data, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_COLOR | IMREAD_IGNORE_ORIENTATION); } m_current_frame.copyTo(output_frame); From a07d8a89b6b38b1a1f35ac808955dab97985becb Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sat, 15 Apr 2017 06:55:46 +0300 Subject: [PATCH 092/144] cmake: disallow in-source builds --- CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c913e0230..c4df1fb073 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,13 @@ # # ---------------------------------------------------------------------------- +# Disable in-source builds to prevent source tree corruption. +if(" ${CMAKE_SOURCE_DIR}" STREQUAL " ${CMAKE_BINARY_DIR}") + message(FATAL_ERROR " +FATAL: In-source builds are not allowed. + You should create separate directory for build files. +") +endif() include(cmake/OpenCVMinDepVersions.cmake) @@ -1386,13 +1393,6 @@ status("") ocv_finalize_status() -# ---------------------------------------------------------------------------- -# Warn in the case of in-source build -# ---------------------------------------------------------------------------- -if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") - message(WARNING "The source directory is the same as binary directory. \"make clean\" may damage the source tree") -endif() - # ---------------------------------------------------------------------------- # CPack stuff # ---------------------------------------------------------------------------- From 20036b82d39bac0a7cd45d6bfc2af3be41d930a2 Mon Sep 17 00:00:00 2001 From: Pyotr Chekmaryov <4ekmah@gmail.com> Date: Sat, 15 Apr 2017 21:51:15 +0000 Subject: [PATCH 093/144] There added parallel realization of vertical passes for MODE_HH4. --- modules/calib3d/include/opencv2/calib3d.hpp | 3 +- modules/calib3d/src/stereosgbm.cpp | 830 ++++++++++++++++++- modules/calib3d/test/test_stereomatching.cpp | 27 +- 3 files changed, 838 insertions(+), 22 deletions(-) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index 46a470bc0f..f2915850f9 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -1810,7 +1810,8 @@ public: MODE_SGBM = 0, MODE_HH = 1, MODE_SGBM_3WAY = 2, - MODE_HH4 = 3 + MODE_HH4 = 3, + MODE_HH4_OLD = 4 }; CV_WRAP virtual int getPreFilterCap() const = 0; diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp index 24b3c18ddc..8a6bfebc67 100644 --- a/modules/calib3d/src/stereosgbm.cpp +++ b/modules/calib3d/src/stereosgbm.cpp @@ -110,6 +110,7 @@ struct StereoSGBMParams int mode; }; +static const int DEFAULT_RIGHT_BORDER = -1; /* For each pixel row1[x], max(maxD, 0) <= minX <= x < maxX <= width - max(0, -minD), and for each disparity minD<=d width1) ? width1 : xrange_max; + maxX1 = minX1 + xrange_max; + minX1 += xrange_min; + width1 = maxX1 - minX1; int minX2 = std::max(minX1 - maxD, 0), maxX2 = std::min(maxX1 - minD, width); - int D = maxD - minD, width1 = maxX1 - minX1, width2 = maxX2 - minX2; + int width2 = maxX2 - minX2; const PixType *row1 = img1.ptr(y), *row2 = img2.ptr(y); PixType *prow1 = buffer + width2*2, *prow2 = prow1 + width*cn*2; #if CV_SIMD128 @@ -179,10 +189,10 @@ static void calcPixelCostBT( const Mat& img1, const Mat& img2, int y, } } - memset( cost, 0, width1*D*sizeof(cost[0]) ); + memset( cost + xrange_min*D, 0, width1*D*sizeof(cost[0]) ); - buffer -= minX2; - cost -= minX1*D + minD; // simplify the cost indices inside the loop + buffer -= width-1-maxX2; + cost -= (minX1-xrange_min)*D + minD; // simplify the cost indices inside the loop for( c = 0; c < cn*2; c++, prow1 += width, prow2 += width ) { @@ -191,7 +201,7 @@ static void calcPixelCostBT( const Mat& img1, const Mat& img2, int y, // precompute // v0 = min(row2[x-1/2], row2[x], row2[x+1/2]) and // v1 = max(row2[x-1/2], row2[x], row2[x+1/2]) and - for( x = minX2; x < maxX2; x++ ) + for( x = width-1-maxX2; x < width-1- minX2; x++ ) { int v = prow2[x]; int vl = x > 0 ? (v + prow2[x-1])/2 : v; @@ -830,6 +840,335 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } //////////////////////////////////////////////////////////////////////////////////////////// +//TODO: Assumation: Let's pretend, that we allocate memory for pixDiff and tempBuf independently in each thread, with full size, needed for original calcBT +//TODO: Redo size of this arrays even if situation with independent allocation will still. +struct CalcVerticalSums: public ParallelLoopBody +{ + CalcVerticalSums(const Mat& _img1, const Mat& _img2, const StereoSGBMParams& params, + CostType* alignedBuf, PixType* _clipTab): img1(_img1), img2(_img2), clipTab(_clipTab) + { + minD = params.minDisparity; + maxD = minD + params.numDisparities; + SW2 = SH2 = (params.SADWindowSize > 0 ? params.SADWindowSize : 5)/2; + ftzero = std::max(params.preFilterCap, 15) | 1; + P1 = params.P1 > 0 ? params.P1 : 2; + P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion + height = img1.rows; + width = img1.cols; + int minX1 = std::max(maxD, 0), maxX1 = width + std::min(minD, 0); + D = maxD - minD; + width1 = maxX1 - minX1; + D2 = D + 16; + costBufSize = width1*D; + CSBufSize = costBufSize*height; + minLrSize = (width1 + LrBorder*2); + LrSize = minLrSize*D2; + hsumBufNRows = SH2*2 + 2; + Cbuf = alignedBuf; + Sbuf = Cbuf + CSBufSize; + hsumBuf = Sbuf + CSBufSize; + } + + void operator()( const Range& range ) const + { + static const CostType MAX_COST = SHRT_MAX; + static const int ALIGN = 16; + static const int TAB_OFS = 256*4; + int x1 = range.start, x2 = range.end, k; + size_t pixDiffSize = ((x2 - x1) + 2*SW2)*D; + size_t auxBufsSize = pixDiffSize*sizeof(CostType) + //pixdiff size + width*16*img1.channels()*sizeof(PixType) + 32; //tempBuf //TODO: Probably it's better 6 instead of 16(alignment?) + Mat auxBuff; + auxBuff.create(1, (int)auxBufsSize, CV_8U); + CostType* pixDiff = (CostType*)alignPtr(auxBuff.ptr(), ALIGN); + PixType* tempBuf = (PixType*)(pixDiff + pixDiffSize); + + // Simplification of index calculation + pixDiff -= (x1>SW2 ? (x1 - SW2): 0)*D; + + for( int pass = 1; pass <= 2; pass++ ) //TODO: rename this magic 2. + { + int y1, y2, dy; + + if( pass == 1 ) + { + y1 = 0; y2 = height; dy = 1; + } + else + { + y1 = height-1; y2 = -1; dy = -1; + } + + CostType *Lr[NLR]={0}, *minLr[NLR]={0}; //4e: arrays for L(x,y,r,d) of previous and current rows and minimums of them + + for( k = 0; k < NLR; k++ ) //4e: One of them is needed, and one of them is stored. So, we need to swap pointer + { //4e: Yes, and this is done at the end of next cycle, not here. + // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, + // and will occasionally use negative indices with the arrays + // we need to shift Lr[k] pointers by 1, to give the space for d=-1. + // however, then the alignment will be imperfect, i.e. bad for SSE, + // thus we shift the pointers by 8 (8*sizeof(short) == 16 - ideal alignment) + Lr[k] = hsumBuf + costBufSize*hsumBufNRows + LrSize*k + D2*LrBorder + 8; + memset( Lr[k] + x1*D2 - 8, 0, (x2-x1)*D2*sizeof(CostType) ); + minLr[k] = hsumBuf + costBufSize*hsumBufNRows + LrSize*NLR + minLrSize*k + LrBorder; + memset( minLr[k] + x1, 0, (x2-x1)*sizeof(CostType) ); + } + + for( int y = y1; y != y2; y += dy ) + { + int x, d; + CostType* C = Cbuf + y*costBufSize; + CostType* S = Sbuf + y*costBufSize; + + if( pass == 1 ) // compute C on the first pass, and reuse it on the second pass, if any. + { + int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; //4e: for first line's block sum we need calculate half-window of costs and only one for other + + for( k = dy1; k <= dy2; k++ ) + { + CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; //4e: Ring buffer for horizontally summed lines + + if( k < height ) + { + calcPixelCostBT( img1, img2, k, minD, maxD, pixDiff, tempBuf, clipTab, TAB_OFS, ftzero, x1 - SW2, x2 + SW2); + + memset(hsumAdd + x1*D, 0, D*sizeof(CostType)); + for( x = (x1 - SW2)*D; x <= (x1 + SW2)*D; x += D ) //4e: Calculation summed costs for all disparities in first pixel of line + { + int xbord = x <= 0 ? 0 : (x > (width1 - 1)*D? (width1 - 1)*D : x); + for( d = 0; d < D; d++ ) + hsumAdd[x1*D + d] = (CostType)(hsumAdd[x1*D + d] + pixDiff[xbord + d]); + } + + if( y > 0 ) //4e: We calculate horizontal sums and forming full block sums for y coord by adding this horsums to previous line's sums and subtracting stored lowest + { //4e: horsum in hsumBuf. Exception is case y=0, where we need many iterations per lines to create full blocking sum. + const CostType* hsumSub = hsumBuf + (std::max(y - SH2 - 1, 0) % hsumBufNRows)*costBufSize; + const CostType* Cprev = C - costBufSize; + + // We need to calculate C[x1] in different way, because hsumadd is already calculated + // We don't doing then for x==0, because original function has forgotten to do this //TODO: Check: does this original still exist? + if(x1!=0) + { + for( d = 0; d < D; d++ ) + C[x1*D + d] = (CostType)(Cprev[x1*D + d] + hsumAdd[x1*D + d] - hsumSub[x1*D + d]); + } + + for( x = (x1+1)*D; x < x2*D; x += D ) + { + const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); + const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 hv = v_load(hsumAdd + x - D + d); +// v_int16x8 Cx = v_load(Cprev + x + d); +// v_int16x8 psub = v_load(pixSub + d); +// v_int16x8 padd = v_load(pixAdd + d); +// hv = (hv - psub + padd); +// psub = v_load(hsumSub + x + d); +// Cx = Cx - psub + hv; +// v_store(hsumAdd + x + d, hv); +// v_store(C + x + d, Cx); +// } +// } +// else +// #endif + { + for( d = 0; d < D; d++ ) + { + int hv = hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]); + C[x + d] = (CostType)(Cprev[x + d] + hv - hsumSub[x + d]); + } + } + } + } + else + { + for( x = (x1+1)*D; x < x2*D; x += D ) //4e: Calcluates horizontal sums if (y==0). This piece of code is calling SH2+1 times and then result is used in different way + { //4e: to create full blocks sum. That's why this code is isolated from upper case. + const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); + const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); + + for( d = 0; d < D; d++ ) + hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]); + } + } + // Return to coordinates, which is needed by CalcCostBT + } + + if( y == 0 ) //4e: Calculating first full block sum. + { + int scale = k == 0 ? SH2 + 1 : 1; + for( x = x1*D; x < x2*D; x++ ) + C[x] = (CostType)(C[x] + hsumAdd[x]*scale); + } + } + + // also, clear the S buffer + for( k = x1*D; k < x2*D; k++ ) //4e: only on first pass, so it keep old information, don't be confused + S[k] = 0; + } + +// [formula 13 in the paper] +// compute L_r(p, d) = C(p, d) + +// min(L_r(p-r, d), +// L_r(p-r, d-1) + P1, +// L_r(p-r, d+1) + P1, +// min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) +// where p = (x,y), r is one of the directions. +// we process all the directions at once: +// 0: r=(-dx, 0) +// 1: r=(-1, -dy) +// 2: r=(0, -dy) +// 3: r=(1, -dy) +// 4: r=(-2, -dy) +// 5: r=(-1, -dy*2) +// 6: r=(1, -dy*2) +// 7: r=(2, -dy) + + for( x = x1; x != x2; x++ ) + { + int xd = x*D2; + + int delta = minLr[1][x] + P2; + + CostType* Lr_ppr = Lr[1] + xd; + + Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; + + CostType* Lr_p = Lr[0] + xd; + const CostType* Cp = C + x*D; + CostType* Sp = S + x*D; + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _P1 = v_setall_s16((short)P1); +// +// v_int16x8 _delta0 = v_setall_s16((short)delta0); +// v_int16x8 _delta1 = v_setall_s16((short)delta1); +// v_int16x8 _delta2 = v_setall_s16((short)delta2); +// v_int16x8 _delta3 = v_setall_s16((short)delta3); +// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); +// +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 Cpd = v_load(Cp + d); +// v_int16x8 L0, L1, L2, L3; +// +// L0 = v_load(Lr_p0 + d); +// L1 = v_load(Lr_p1 + d); +// L2 = v_load(Lr_ppr + d); +// L3 = v_load(Lr_p3 + d); +// +// L0 = v_min(L0, (v_load(Lr_p0 + d - 1) + _P1)); +// L0 = v_min(L0, (v_load(Lr_p0 + d + 1) + _P1)); +// +// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); +// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); +// +// L2 = v_min(L2, (v_load(Lr_ppr + d - 1) + _P1)); +// L2 = v_min(L2, (v_load(Lr_ppr + d + 1) + _P1)); +// +// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); +// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); +// +// L0 = v_min(L0, _delta0); +// L0 = ((L0 - _delta0) + Cpd); +// +// L1 = v_min(L1, _delta1); +// L1 = ((L1 - _delta1) + Cpd); +// +// L2 = v_min(L2, _delta2); +// L2 = ((L2 - _delta2) + Cpd); +// +// L3 = v_min(L3, _delta3); +// L3 = ((L3 - _delta3) + Cpd); +// +// v_store(Lr_p + d, L0); +// v_store(Lr_p + d + D2, L1); +// v_store(Lr_p + d + D2*2, L2); +// v_store(Lr_p + d + D2*3, L3); +// +// // Get minimum from in L0-L3 +// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; +// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... +// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... +// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... +// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... +// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... +// v_int16x8 t0 = v_min(t0123L, t0123H); +// _minL0 = v_min(_minL0, t0); +// +// v_int16x8 Sval = v_load(Sp + d); +// +// L0 = L0 + L1; +// L2 = L2 + L3; +// Sval = Sval + L0; +// Sval = Sval + L2; +// +// v_store(Sp + d, Sval); +// } +// +// v_int32x4 minL, minH; +// v_expand(_minL0, minL, minH); +// v_pack_store(&minLr[0][x], v_min(minL, minH)); +// } +// else +// #endif + { + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) + { + int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L); + } + minLr[0][x] = (CostType)minL; + } + } + + // now shift the cyclic buffers + std::swap( Lr[0], Lr[1] ); + std::swap( minLr[0], minLr[1] ); + } + } + } + static const int NLR = 2; + static const int LrBorder = NLR - 1; + const Mat& img1; + const Mat& img2; + CostType* Cbuf; + CostType* Sbuf; + CostType* hsumBuf; + PixType* clipTab; + int minD; + int maxD; + int D; + int D2; + int SH2; + int SW2; + int width; + int width1; + int height; + int P1; + int P2; + size_t costBufSize; + size_t CSBufSize; + size_t minLrSize; + size_t LrSize; + size_t hsumBufNRows; + int ftzero; +}; /* This is new experimential version of disparity calculation, which should be parralled after @@ -854,7 +1193,6 @@ TODO: Don't forget to rewrire this commentaries after disp2cost also has the same size as img1 (or img2). It contains the minimum current cost, used to find the best disparity, corresponding to the minimal cost. */ -#include //TODO: DUBUG!!! static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, Mat& disp1, const StereoSGBMParams& params, Mat& buffer ) @@ -882,6 +1220,472 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, const int DISP_SCALE = (1 << DISP_SHIFT); const CostType MAX_COST = SHRT_MAX; + int minD = params.minDisparity, maxD = minD + params.numDisparities; + Size SADWindowSize; //4e: SAD means Sum of Absolute Differences + SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; //4e: and this is always square + int ftzero = std::max(params.preFilterCap, 15) | 1; //4e:ftzero clips x-derivatives. I think, this story with arrays is about non-realized SIMD method + int uniquenessRatio = params.uniquenessRatio >= 0 ? params.uniquenessRatio : 10; + int disp12MaxDiff = params.disp12MaxDiff > 0 ? params.disp12MaxDiff : 1; + int P1 = params.P1 > 0 ? params.P1 : 2, P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion + int k, width = disp1.cols, height = disp1.rows; + int minX1 = std::max(maxD, 0), maxX1 = width + std::min(minD, 0); + int D = maxD - minD, width1 = maxX1 - minX1; + int INVALID_DISP = minD - 1, INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; + int SH2 = SADWindowSize.height/2; + const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; //4e: array is such big due to derivative could be +-8*256 in worst cases + PixType clipTab[TAB_SIZE]; + + for( k = 0; k < TAB_SIZE; k++ ) //4e: If ftzero would = 4, array containment will be = -4 -4 -4 ... -4 -3 -2 -1 0 1 2 3 4 ... 4 4 4 + clipTab[k] = (PixType)(std::min(std::max(k - TAB_OFS, -ftzero), ftzero) + ftzero); + + if( minX1 >= maxX1 ) + { + disp1 = Scalar::all(INVALID_DISP_SCALED); + return; + } + + CV_Assert( D % 16 == 0 ); //TODO: Are you sure? By the way, why not 8? + + // NR - the number of directions. the loop on x below that computes Lr assumes that NR == 8. + // if you change NR, please, modify the loop as well. + int D2 = D+16; //4e: Somewhere in code we need d+1, so D+1. One of simplest solutuons is increasing D-dimension on 1. But 1 is 16, when storage should be aligned. + + // the number of L_r(.,.) and min_k L_r(.,.) lines in the buffer: + // for 8-way dynamic programming we need the current row and + // the previous row, i.e. 2 rows in total + const int NLR = 2; //4e: We assume, that we need one or more previous steps in our linear dynamic(one right here). + const int LrBorder = NLR - 1; //4e: for simplification of calculations we need border for taking previous dynamic solutions. + + // for each possible stereo match (img1(x,y) <=> img2(x-d,y)) + // we keep pixel difference cost (C) and the summary cost over NR directions (S). + // we also keep all the partial costs for the previous line L_r(x,d) and also min_k L_r(x, k) + size_t costBufSize = width1*D; + size_t CSBufSize = costBufSize*height; + size_t minLrSize = (width1 + LrBorder*2), LrSize = minLrSize*D2; //TODO: We don't need LrBorder for vertical passes and we don't need Lr buffer for horizontal passes. + int hsumBufNRows = SH2*2 + 2; + size_t totalBufSize = (LrSize + minLrSize)*NLR*sizeof(CostType) + // minLr[] and Lr[] + costBufSize*hsumBufNRows*sizeof(CostType) + // hsumBuf //4e: TODO: Why we should increase sum window height one more time? + CSBufSize*2*sizeof(CostType) + // C, S //4e: C is Block sum of costs, S is multidirectional dynamic sum with same size + width*(sizeof(CostType) + sizeof(DispType)) + 1024; // disp2cost + disp2 + + if( buffer.empty() || !buffer.isContinuous() || + buffer.cols*buffer.rows*buffer.elemSize() < totalBufSize ) + buffer.create(1, (int)totalBufSize, CV_8U); + + // summary cost over different (nDirs) directions + CostType* Cbuf = (CostType*)alignPtr(buffer.ptr(), ALIGN); + CostType* Sbuf = Cbuf + CSBufSize; + CostType* hsumBuf = Sbuf + CSBufSize; + + CostType* disp2cost = hsumBuf + costBufSize*hsumBufNRows + (LrSize + minLrSize)*NLR; //4e: It is containers for backwards disparity, made by S[d] too, but with other method + DispType* disp2ptr = (DispType*)(disp2cost + width); + + // add P2 to every C(x,y). it saves a few operations in the inner loops + for(k = 0; k < (int)CSBufSize; k++ ) + Cbuf[k] = (CostType)P2; + + parallel_for_(Range(0,width1),CalcVerticalSums(img1, img2, params, Cbuf, clipTab)); + +// for( int pass = 1; pass <= 2; pass++ ) //pass=1 or left-to-right pass + { + + CostType *Lr, *minLr; + + { //4e: Yes, and this is done at the end of next cycle, not here. + // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, + // and will occasionally use negative indices with the arrays + // we need to shift Lr[k] pointers by 1, to give the space for d=-1. + // however, then the alignment will be imperfect, i.e. bad for SSE, + // thus we shift the pointers by 8 (8*sizeof(short) == 16 - ideal alignment) + Lr = hsumBuf + costBufSize*hsumBufNRows + D2*LrBorder + 8; + memset( Lr - LrBorder*D2 - 8, 0, LrSize*sizeof(CostType) ); + minLr = hsumBuf + costBufSize*hsumBufNRows + LrSize*NLR + LrBorder; + memset( minLr - LrBorder, 0, minLrSize*sizeof(CostType) ); + } + + for( int y = 0; y != height; y++) + { + int x, d; + DispType* disp1ptr = disp1.ptr(y); + CostType* C = Cbuf + y*costBufSize; + CostType* S = Sbuf + y*costBufSize; + + for( x = 0; x < width; x++ ) + { + disp1ptr[x] = disp2ptr[x] = (DispType)INVALID_DISP_SCALED; + disp2cost[x] = MAX_COST; + } + + // clear the left and the right borders + memset( Lr - D2*LrBorder - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory + memset( Lr + width1*D2 - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: ...00000000|D2-16 of real costs value(and some of them are zeroes too)|00000000... + memset( minLr - LrBorder, 0, LrBorder*sizeof(CostType) ); + memset( minLr + width1, 0, LrBorder*sizeof(CostType) ); + + /* + [formula 13 in the paper] + compute L_r(p, d) = C(p, d) + + min(L_r(p-r, d), + L_r(p-r, d-1) + P1, + L_r(p-r, d+1) + P1, + min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) + where p = (x,y), r is one of the directions. + we process all the directions at once: + 0: r=(-dx, 0) + 1: r=(-1, -dy) + 2: r=(0, -dy) + 3: r=(1, -dy) + 4: r=(-2, -dy) + 5: r=(-1, -dy*2) + 6: r=(1, -dy*2) + 7: r=(2, -dy) + */ + for( x = 0; x != width1; x++) + { + int xd = x*D2; + + int delta = minLr[x - 1] + P2; + + CostType* Lr_ppr = Lr + xd - D2; + + Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; + + CostType* Lr_p = Lr + xd; + const CostType* Cp = C + x*D; + CostType* Sp = S + x*D; + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _P1 = v_setall_s16((short)P1); +// +// v_int16x8 _delta0 = v_setall_s16((short)delta0); +// v_int16x8 _delta1 = v_setall_s16((short)delta1); +// v_int16x8 _delta2 = v_setall_s16((short)delta2); +// v_int16x8 _delta3 = v_setall_s16((short)delta3); +// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); +// +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 Cpd = v_load(Cp + d); +// v_int16x8 L0, L1, L2, L3; +// +// L0 = v_load(Lr_ppr + d); +// L1 = v_load(Lr_p1 + d); +// L2 = v_load(Lr_p2 + d); +// L3 = v_load(Lr_p3 + d); +// +// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); +// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); +// +// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); +// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); +// +// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); +// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); +// +// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); +// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); +// +// L0 = v_min(L0, _delta0); +// L0 = ((L0 - _delta0) + Cpd); +// +// L1 = v_min(L1, _delta1); +// L1 = ((L1 - _delta1) + Cpd); +// +// L2 = v_min(L2, _delta2); +// L2 = ((L2 - _delta2) + Cpd); +// +// L3 = v_min(L3, _delta3); +// L3 = ((L3 - _delta3) + Cpd); +// +// v_store(Lr_p + d, L0); +// v_store(Lr_p + d + D2, L1); +// v_store(Lr_p + d + D2*2, L2); +// v_store(Lr_p + d + D2*3, L3); +// +// // Get minimum from in L0-L3 +// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; +// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... +// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... +// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... +// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... +// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... +// v_int16x8 t0 = v_min(t0123L, t0123H); +// _minL0 = v_min(_minL0, t0); +// +// v_int16x8 Sval = v_load(Sp + d); +// +// L0 = L0 + L1; +// L2 = L2 + L3; +// Sval = Sval + L0; +// Sval = Sval + L2; +// +// v_store(Sp + d, Sval); +// } +// +// v_int32x4 minL, minH; +// v_expand(_minL0, minL, minH); +// v_pack_store(&minLr[x], v_min(minL, minH)); +// } +// else +// #endif + { + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) + { + int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L); + } + minLr[x] = (CostType)minL; + } + } + + for( x = width1-1; x != -1; x--) + { + int xd = x*D2; + + int delta = minLr[x + 1] + P2; + + CostType* Lr_ppr = Lr + xd + D2; + + Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; + + CostType* Lr_p = Lr + xd; + const CostType* Cp = C + x*D; + CostType* Sp = S + x*D; + int minS = MAX_COST, bestDisp = -1; + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _P1 = v_setall_s16((short)P1); +// +// v_int16x8 _delta0 = v_setall_s16((short)delta0); +// v_int16x8 _delta1 = v_setall_s16((short)delta1); +// v_int16x8 _delta2 = v_setall_s16((short)delta2); +// v_int16x8 _delta3 = v_setall_s16((short)delta3); +// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); +// +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 Cpd = v_load(Cp + d); +// v_int16x8 L0, L1, L2, L3; +// +// L0 = v_load(Lr_ppr + d); +// L1 = v_load(Lr_p1 + d); +// L2 = v_load(Lr_p2 + d); +// L3 = v_load(Lr_p3 + d); +// +// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); +// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); +// +// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); +// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); +// +// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); +// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); +// +// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); +// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); +// +// L0 = v_min(L0, _delta0); +// L0 = ((L0 - _delta0) + Cpd); +// +// L1 = v_min(L1, _delta1); +// L1 = ((L1 - _delta1) + Cpd); +// +// L2 = v_min(L2, _delta2); +// L2 = ((L2 - _delta2) + Cpd); +// +// L3 = v_min(L3, _delta3); +// L3 = ((L3 - _delta3) + Cpd); +// +// v_store(Lr_p + d, L0); +// v_store(Lr_p + d + D2, L1); +// v_store(Lr_p + d + D2*2, L2); +// v_store(Lr_p + d + D2*3, L3); +// +// // Get minimum from in L0-L3 +// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; +// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... +// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... +// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... +// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... +// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... +// v_int16x8 t0 = v_min(t0123L, t0123H); +// _minL0 = v_min(_minL0, t0); +// +// v_int16x8 Sval = v_load(Sp + d); +// +// L0 = L0 + L1; +// L2 = L2 + L3; +// Sval = Sval + L0; +// Sval = Sval + L2; +// +// v_store(Sp + d, Sval); +// } +// +// v_int32x4 minL, minH; +// v_expand(_minL0, minL, minH); +// v_pack_store(&minLr[x], v_min(minL, minH)); +// } +// else +// #endif +//TODO:Next piece of code is came from postprocessing. Be very careful with joining them!!! +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _minS = v_setall_s16(MAX_COST), _bestDisp = v_setall_s16(-1); +// v_int16x8 _d8 = v_int16x8(0, 1, 2, 3, 4, 5, 6, 7), _8 = v_setall_s16(8); +// +// for( d = 0; d < D; d+= 8 ) +// { +// v_int16x8 L0 = v_load(Sp + d); +// v_int16x8 mask = L0 < _minS; +// _minS = v_min( L0, _minS ); +// _bestDisp = _bestDisp ^ ((_bestDisp ^ _d8) & mask); +// _d8 = _d8 + _8; +// } +// v_int32x4 _d0, _d1; +// v_expand(_minS, _d0, _d1); +// minS = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); +// v_int16x8 v_mask = v_setall_s16((short)minS) == _minS; +// +// _bestDisp = (_bestDisp & v_mask) | (v_setall_s16(SHRT_MAX) & ~v_mask); +// v_expand(_bestDisp, _d0, _d1); +// bestDisp = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); +// } +// else +// #endif + { + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) + { + int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L); + if( Sp[d] < minS ) + { + minS = Sp[d]; + bestDisp = d; + } + } + minLr[x] = (CostType)minL; + } + //Some postprocessing procedures and saving + for( d = 0; d < D; d++ ) + { + if( Sp[d]*(100 - uniquenessRatio) < minS*100 && std::abs(bestDisp - d) > 1 ) + break; + } + if( d < D ) + continue; + d = bestDisp; + int _x2 = x + minX1 - d - minD; + if( disp2cost[_x2] > minS ) + { + disp2cost[_x2] = (CostType)minS; + disp2ptr[_x2] = (DispType)(d + minD); + } + + if( 0 < d && d < D-1 ) + { + // do subpixel quadratic interpolation: + // fit parabola into (x1=d-1, y1=Sp[d-1]), (x2=d, y2=Sp[d]), (x3=d+1, y3=Sp[d+1]) + // then find minimum of the parabola. + int denom2 = std::max(Sp[d-1] + Sp[d+1] - 2*Sp[d], 1); + d = d*DISP_SCALE + ((Sp[d-1] - Sp[d+1])*DISP_SCALE + denom2)/(denom2*2); + } + else + d *= DISP_SCALE; + disp1ptr[x + minX1] = (DispType)(d + minD*DISP_SCALE); + } + //Left-right check sanity procedure + for( x = minX1; x < maxX1; x++ ) + { + // we round the computed disparity both towards -inf and +inf and check + // if either of the corresponding disparities in disp2 is consistent. + // This is to give the computed disparity a chance to look valid if it is. + int d1 = disp1ptr[x]; + if( d1 == INVALID_DISP_SCALED ) + continue; + int _d = d1 >> DISP_SHIFT; + int d_ = (d1 + DISP_SCALE-1) >> DISP_SHIFT; + int _x = x - _d, x_ = x - d_; + if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && //4e: To dismiss disparity, we should assure, that there is no any + 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) //4e: chance to understand this as correct. + disp1ptr[x] = (DispType)INVALID_DISP_SCALED; + } + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* + This is new experimential version of disparity calculation, which should be parralled after +TODO: Don't forget to rewrire this commentaries after + + computes disparity for "roi" in img1 w.r.t. img2 and write it to disp1buf. + that is, disp1buf(x, y)=d means that img1(x+roi.x, y+roi.y) ~ img2(x+roi.x-d, y+roi.y). + minD <= d < maxD. + disp2full is the reverse disparity map, that is: + disp2full(x+roi.x,y+roi.y)=d means that img2(x+roi.x, y+roi.y) ~ img1(x+roi.x+d, y+roi.y) + + note that disp1buf will have the same size as the roi and + disp2full will have the same size as img1 (or img2). + On exit disp2buf is not the final disparity, it is an intermediate result that becomes + final after all the tiles are processed. + + the disparity in disp1buf is written with sub-pixel accuracy + (4 fractional bits, see StereoSGBM::DISP_SCALE), + using quadratic interpolation, while the disparity in disp2buf + is written as is, without interpolation. + + disp2cost also has the same size as img1 (or img2). + It contains the minimum current cost, used to find the best disparity, corresponding to the minimal cost. + */ +static void computeDisparitySGBMParallelOld( const Mat& img1, const Mat& img2, + Mat& disp1, const StereoSGBMParams& params, + Mat& buffer ) +{ +//#if CV_SIMD128 +// // maxDisparity is supposed to multiple of 16, so we can forget doing else +// static const uchar LSBTab[] = +// { +// 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +// }; +// static const v_uint16x8 v_LSB = v_uint16x8(0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); +// +// bool useSIMD = hasSIMD128(); +//#endif + + const int ALIGN = 16; + const int DISP_SHIFT = StereoMatcher::DISP_SHIFT; + const int DISP_SCALE = (1 << DISP_SHIFT); + const CostType MAX_COST = SHRT_MAX; + int minD = params.minDisparity, maxD = minD + params.numDisparities; Size SADWindowSize; //4e: SAD means Sum of Absolute Differences SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; //4e: and this is always square @@ -1204,6 +2008,14 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, std::swap( minLr[0], minLr[1] ); } } +// for(int y = 0; y sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH); - sgbm->compute( leftImg, rightImg, leftDisp ); - CV_Assert( leftDisp.type() == CV_16SC1 ); - leftDisp/=8; - imwrite( "/home/q/Work/GitVault/modehh.jpg", leftDisp); - } + Mat leftDisp_old, leftDisp_new; { Mat leftDisp; Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH4); - sgbm->compute( leftImg, rightImg, leftDisp ); - CV_Assert( leftDisp.type() == CV_16SC1 ); - leftDisp/=8; - imwrite( "/home/q/Work/GitVault/modehh4.jpg", leftDisp); + sgbm->compute( leftImg, rightImg, leftDisp_new ); + CV_Assert( leftDisp_new.type() == CV_16SC1 ); +// leftDisp/=8; +// imwrite( "/home/q/Work/GitVault/modehh4_new.jpg", leftDisp); } + { + Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH4_OLD); + sgbm->compute( leftImg, rightImg, leftDisp_old ); + CV_Assert( leftDisp_old.type() == CV_16SC1 ); +// leftDisp/=8; +// imwrite( "/home/q/Work/GitVault/modehh4_old.jpg", leftDisp); + } + Mat diff; + absdiff(leftDisp_old,leftDisp_new,diff); + CV_Assert( countNonZero(diff)==0); } From 3d52661400baa4ea673a82a58bbfd4bc99138a66 Mon Sep 17 00:00:00 2001 From: Kyle Fleming Date: Sun, 16 Apr 2017 14:39:26 -0700 Subject: [PATCH 094/144] Set Mac OS X deployment target to 10.9 Without it set, the build will choose the current OS version as the deployment target. 10.9 is the earliest usable, since that is when OS X introduced libc++. --- platforms/osx/build_framework.py | 1 + 1 file changed, 1 insertion(+) diff --git a/platforms/osx/build_framework.py b/platforms/osx/build_framework.py index 64e73c5490..6e23931266 100644 --- a/platforms/osx/build_framework.py +++ b/platforms/osx/build_framework.py @@ -18,6 +18,7 @@ class OSXBuilder(Builder): def getBuildCommand(self, archs, target): buildcmd = [ "xcodebuild", + "MACOSX_DEPLOYMENT_TARGET=10.9", "ARCHS=%s" % archs[0], "-sdk", target.lower(), "-configuration", "Release", From 62c17dc3cf0e2b6aea8d7eaad4cdf2399d2d6114 Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Mon, 17 Apr 2017 08:32:08 +0900 Subject: [PATCH 095/144] fix typo and align white spaces --- modules/calib3d/test/test_fisheye.cpp | 91 +++++++++++++-------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/modules/calib3d/test/test_fisheye.cpp b/modules/calib3d/test/test_fisheye.cpp index 9ad8c64d91..af466cacc1 100644 --- a/modules/calib3d/test/test_fisheye.cpp +++ b/modules/calib3d/test/test_fisheye.cpp @@ -245,13 +245,13 @@ TEST_F(fisheyeTest, Calibration) cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ); CV_Assert(fs_left.isOpened()); for(int i = 0; i < n_images; ++i) - fs_left[cv::format("image_%d", i )] >> imagePoints[i]; + fs_left[cv::format("image_%d", i )] >> imagePoints[i]; fs_left.release(); cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ); CV_Assert(fs_object.isOpened()); for(int i = 0; i < n_images; ++i) - fs_object[cv::format("image_%d", i )] >> objectPoints[i]; + fs_object[cv::format("image_%d", i )] >> objectPoints[i]; fs_object.release(); int flag = 0; @@ -280,13 +280,13 @@ TEST_F(fisheyeTest, Homography) cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ); CV_Assert(fs_left.isOpened()); for(int i = 0; i < n_images; ++i) - fs_left[cv::format("image_%d", i )] >> imagePoints[i]; + fs_left[cv::format("image_%d", i )] >> imagePoints[i]; fs_left.release(); cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ); CV_Assert(fs_object.isOpened()); for(int i = 0; i < n_images; ++i) - fs_object[cv::format("image_%d", i )] >> objectPoints[i]; + fs_object[cv::format("image_%d", i )] >> objectPoints[i]; fs_object.release(); cv::internal::IntrinsicParams param; @@ -330,7 +330,7 @@ TEST_F(fisheyeTest, Homography) EXPECT_MAT_NEAR(std_err, correct_std_err, 1e-12); } -TEST_F(fisheyeTest, EtimateUncertainties) +TEST_F(fisheyeTest, EstimateUncertainties) { const int n_images = 34; @@ -341,13 +341,13 @@ TEST_F(fisheyeTest, EtimateUncertainties) cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ); CV_Assert(fs_left.isOpened()); for(int i = 0; i < n_images; ++i) - fs_left[cv::format("image_%d", i )] >> imagePoints[i]; + fs_left[cv::format("image_%d", i )] >> imagePoints[i]; fs_left.release(); cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ); CV_Assert(fs_object.isOpened()); for(int i = 0; i < n_images; ++i) - fs_object[cv::format("image_%d", i )] >> objectPoints[i]; + fs_object[cv::format("image_%d", i )] >> objectPoints[i]; fs_object.release(); int flag = 0; @@ -435,9 +435,9 @@ TEST_F(fisheyeTest, rectify) if (correct.empty()) cv::imwrite(combine(datasets_repository_path, cv::format("rectification_AB_%03d.png", i)), rectification); - else - EXPECT_MAT_NEAR(correct, rectification, 1e-10); - } + else + EXPECT_MAT_NEAR(correct, rectification, 1e-10); + } } TEST_F(fisheyeTest, stereoCalibrate) @@ -453,19 +453,19 @@ TEST_F(fisheyeTest, stereoCalibrate) cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ); CV_Assert(fs_left.isOpened()); for(int i = 0; i < n_images; ++i) - fs_left[cv::format("image_%d", i )] >> leftPoints[i]; + fs_left[cv::format("image_%d", i )] >> leftPoints[i]; fs_left.release(); cv::FileStorage fs_right(combine(folder, "right.xml"), cv::FileStorage::READ); CV_Assert(fs_right.isOpened()); for(int i = 0; i < n_images; ++i) - fs_right[cv::format("image_%d", i )] >> rightPoints[i]; + fs_right[cv::format("image_%d", i )] >> rightPoints[i]; fs_right.release(); cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ); CV_Assert(fs_object.isOpened()); for(int i = 0; i < n_images; ++i) - fs_object[cv::format("image_%d", i )] >> objectPoints[i]; + fs_object[cv::format("image_%d", i )] >> objectPoints[i]; fs_object.release(); cv::Matx33d K1, K2, theR; @@ -476,7 +476,6 @@ TEST_F(fisheyeTest, stereoCalibrate) flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC; flag |= cv::fisheye::CALIB_CHECK_COND; flag |= cv::fisheye::CALIB_FIX_SKEW; - // flag |= cv::fisheye::CALIB_FIX_INTRINSIC; cv::fisheye::stereoCalibrate(objectPoints, leftPoints, rightPoints, K1, D1, K2, D2, imageSize, theR, theT, flag, @@ -521,19 +520,19 @@ TEST_F(fisheyeTest, stereoCalibrateFixIntrinsic) cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ); CV_Assert(fs_left.isOpened()); for(int i = 0; i < n_images; ++i) - fs_left[cv::format("image_%d", i )] >> leftPoints[i]; + fs_left[cv::format("image_%d", i )] >> leftPoints[i]; fs_left.release(); cv::FileStorage fs_right(combine(folder, "right.xml"), cv::FileStorage::READ); CV_Assert(fs_right.isOpened()); for(int i = 0; i < n_images; ++i) - fs_right[cv::format("image_%d", i )] >> rightPoints[i]; + fs_right[cv::format("image_%d", i )] >> rightPoints[i]; fs_right.release(); cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ); CV_Assert(fs_object.isOpened()); for(int i = 0; i < n_images; ++i) - fs_object[cv::format("image_%d", i )] >> objectPoints[i]; + fs_object[cv::format("image_%d", i )] >> objectPoints[i]; fs_object.release(); cv::Matx33d theR; @@ -572,44 +571,44 @@ TEST_F(fisheyeTest, stereoCalibrateFixIntrinsic) TEST_F(fisheyeTest, CalibrationWithDifferentPointsNumber) { - const int n_images = 2; + const int n_images = 2; - std::vector > imagePoints(n_images); - std::vector > objectPoints(n_images); + std::vector > imagePoints(n_images); + std::vector > objectPoints(n_images); - std::vector imgPoints1(10); - std::vector imgPoints2(15); + std::vector imgPoints1(10); + std::vector imgPoints2(15); - std::vector objectPoints1(imgPoints1.size()); - std::vector objectPoints2(imgPoints2.size()); + std::vector objectPoints1(imgPoints1.size()); + std::vector objectPoints2(imgPoints2.size()); - for (size_t i = 0; i < imgPoints1.size(); i++) - { - imgPoints1[i] = cv::Point2d((double)i, (double)i); - objectPoints1[i] = cv::Point3d((double)i, (double)i, 10.0); - } + for (size_t i = 0; i < imgPoints1.size(); i++) + { + imgPoints1[i] = cv::Point2d((double)i, (double)i); + objectPoints1[i] = cv::Point3d((double)i, (double)i, 10.0); + } - for (size_t i = 0; i < imgPoints2.size(); i++) - { - imgPoints2[i] = cv::Point2d(i + 0.5, i + 0.5); - objectPoints2[i] = cv::Point3d(i + 0.5, i + 0.5, 10.0); - } + for (size_t i = 0; i < imgPoints2.size(); i++) + { + imgPoints2[i] = cv::Point2d(i + 0.5, i + 0.5); + objectPoints2[i] = cv::Point3d(i + 0.5, i + 0.5, 10.0); + } - imagePoints[0] = imgPoints1; - imagePoints[1] = imgPoints2; - objectPoints[0] = objectPoints1; - objectPoints[1] = objectPoints2; + imagePoints[0] = imgPoints1; + imagePoints[1] = imgPoints2; + objectPoints[0] = objectPoints1; + objectPoints[1] = objectPoints2; - cv::Matx33d theK = cv::Matx33d::eye(); - cv::Vec4d theD; + cv::Matx33d theK = cv::Matx33d::eye(); + cv::Vec4d theD; - int flag = 0; - flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC; - flag |= cv::fisheye::CALIB_USE_INTRINSIC_GUESS; - flag |= cv::fisheye::CALIB_FIX_SKEW; + int flag = 0; + flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC; + flag |= cv::fisheye::CALIB_USE_INTRINSIC_GUESS; + flag |= cv::fisheye::CALIB_FIX_SKEW; - cv::fisheye::calibrate(objectPoints, imagePoints, cv::Size(100, 100), theK, theD, - cv::noArray(), cv::noArray(), flag, cv::TermCriteria(3, 20, 1e-6)); + cv::fisheye::calibrate(objectPoints, imagePoints, cv::Size(100, 100), theK, theD, + cv::noArray(), cv::noArray(), flag, cv::TermCriteria(3, 20, 1e-6)); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// From 7ce6895a2c71d0174662efbf0bd5853346a959ce Mon Sep 17 00:00:00 2001 From: berak Date: Mon, 17 Apr 2017 09:10:10 +0200 Subject: [PATCH 096/144] Update tvl1_optical_flow.cpp repair broken cmdline param for cpu/gpu mode --- samples/tapi/tvl1_optical_flow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/tapi/tvl1_optical_flow.cpp b/samples/tapi/tvl1_optical_flow.cpp index 5efa4e2352..925745fd7f 100644 --- a/samples/tapi/tvl1_optical_flow.cpp +++ b/samples/tapi/tvl1_optical_flow.cpp @@ -105,7 +105,7 @@ int main(int argc, const char* argv[]) string fname1 = cmd.get("r"); string vdofile = cmd.get("v"); string outpath = cmd.get("o"); - bool useCPU = cmd.get("s"); + bool useCPU = cmd.get("m"); bool useCamera = cmd.get("c"); int inputName = cmd.get("c"); From bacc21060603460f0422fc8e81972671b6dda1e7 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 17 Apr 2017 11:28:14 +0000 Subject: [PATCH 097/144] fixing segfaults occuring when launching those unit tests --- modules/calib3d/test/test_cameracalibration.cpp | 3 ++- modules/ml/src/lr.cpp | 3 +++ modules/ml/test/test_emknearestkmeans.cpp | 1 + modules/ml/test/test_lr.cpp | 5 +++++ modules/shape/test/test_shape.cpp | 3 +++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/calib3d/test/test_cameracalibration.cpp b/modules/calib3d/test/test_cameracalibration.cpp index 0f0740510b..d738341eeb 100644 --- a/modules/calib3d/test/test_cameracalibration.cpp +++ b/modules/calib3d/test/test_cameracalibration.cpp @@ -1570,7 +1570,8 @@ void CV_StereoCalibrationTest::run( int ) { ts->printf( cvtest::TS::LOG, "The file %s can not be opened or has invalid content\n", filepath.c_str() ); ts->set_failed_test_info( f ? cvtest::TS::FAIL_INVALID_TEST_DATA : cvtest::TS::FAIL_MISSING_TEST_DATA ); - fclose(f); + if (f) + fclose(f); return; } diff --git a/modules/ml/src/lr.cpp b/modules/ml/src/lr.cpp index 8198003da5..f930014bf5 100644 --- a/modules/ml/src/lr.cpp +++ b/modules/ml/src/lr.cpp @@ -138,6 +138,9 @@ bool LogisticRegressionImpl::train(const Ptr& trainData, int) // return value bool ok = false; + if (trainData.empty()) { + return false; + } clear(); Mat _data_i = trainData->getSamples(); Mat _labels_i = trainData->getResponses(); diff --git a/modules/ml/test/test_emknearestkmeans.cpp b/modules/ml/test/test_emknearestkmeans.cpp index 65371755ab..2764876ff5 100644 --- a/modules/ml/test/test_emknearestkmeans.cpp +++ b/modules/ml/test/test_emknearestkmeans.cpp @@ -618,6 +618,7 @@ protected: { ts->printf(cvtest::TS::LOG, "File with spambase dataset cann't be read.\n"); ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + return; } Mat samples = data->getSamples(); diff --git a/modules/ml/test/test_lr.cpp b/modules/ml/test/test_lr.cpp index 1bca9051df..125fd8b5b1 100644 --- a/modules/ml/test/test_lr.cpp +++ b/modules/ml/test/test_lr.cpp @@ -95,6 +95,11 @@ void CV_LRTest::run( int /*start_from*/ ) string dataFileName = ts->get_data_path() + "iris.data"; Ptr tdata = TrainData::loadFromCSV(dataFileName, 0); + if (tdata.empty()) { + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + return; + } + // run LR classifier train classifier Ptr p = LogisticRegression::create(); p->setLearningRate(1.0); diff --git a/modules/shape/test/test_shape.cpp b/modules/shape/test/test_shape.cpp index 97a621e4b5..2495320ed8 100644 --- a/modules/shape/test/test_shape.cpp +++ b/modules/shape/test/test_shape.cpp @@ -83,6 +83,9 @@ protected: vector convertContourType(const Mat& currentQuery) const { + if (currentQuery.empty()) { + return vector(); + } vector > _contoursQuery; findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE); From ebf13b39e5cd9d09a2fe44b9ff16b174fae25356 Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Tue, 18 Apr 2017 19:31:57 +0900 Subject: [PATCH 098/144] fix build error on ODROID-X2 --- cmake/OpenCVFindLAPACK.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/OpenCVFindLAPACK.cmake b/cmake/OpenCVFindLAPACK.cmake index 09cd66cdae..e281b4b78c 100644 --- a/cmake/OpenCVFindLAPACK.cmake +++ b/cmake/OpenCVFindLAPACK.cmake @@ -136,6 +136,10 @@ if(WITH_LAPACK) unset(LAPACK_LIBRARIES) unset(LAPACK_LIBRARIES CACHE) endif() + else() + # LAPACK not found + unset(LAPACK_LIBRARIES) + unset(LAPACK_LIBRARIES CACHE) endif() endif() From a8a1838615830ab9d1db8d79be4474322731fb24 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 18 Apr 2017 22:12:34 +0300 Subject: [PATCH 099/144] update FFmpeg Windows wrapper ffmpeg 3.2.1 -> 3.3 libvpx 1.6.0 -> 1.6.1 --- 3rdparty/ffmpeg/ffmpeg.cmake | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/3rdparty/ffmpeg/ffmpeg.cmake b/3rdparty/ffmpeg/ffmpeg.cmake index b9f5292352..c47d2a83fe 100644 --- a/3rdparty/ffmpeg/ffmpeg.cmake +++ b/3rdparty/ffmpeg/ffmpeg.cmake @@ -1,3 +1,10 @@ +# Binary branch name: ffmpeg/master_20170418 +# Binaries were created for OpenCV: b993b9b7c7f6f5f37d10acacb2962812228410ba +set(FFMPEG_BINARIES_COMMIT "86c4a841055f2612774e85b4292bb20e5fe8a783") +set(FFMPEG_FILE_HASH_BIN32 "3dea5f7f009b44601fe95728328e0f9e") +set(FFMPEG_FILE_HASH_BIN64 "9debe701975ef074bd6661981f3f0716") +set(FFMPEG_FILE_HASH_CMAKE "208c00f03d2f6f39fa6262649e0bfc8d") + function(download_win_ffmpeg script_var) set(${script_var} "" PARENT_SCOPE) @@ -6,14 +13,6 @@ function(download_win_ffmpeg script_var) set(name_BIN64 "opencv_ffmpeg_64.dll") set(name_CMAKE "ffmpeg_version.cmake") - # Binary branch name: ffmpeg/master_20161202 - # Binaries were created for OpenCV: 594c136d1fcbb5816c57516e50f9cbeffbd90835 - set(FFMPEG_BINARIES_COMMIT "2a19d0006415955c79431116e4634f04d5eb5a74") - set(FFMPEG_FILE_HASH_BIN32 "f081abd9d6ca7e425d340ce586f9c090") - set(FFMPEG_FILE_HASH_BIN64 "a423363a6eb76d362ca6c406c96c8db6") - set(FFMPEG_FILE_HASH_CMAKE "5346ae1854fc7aa569a722e85af480ec") - - set(FFMPEG_BINARIES_COMMIT "2a19d0006415955c79431116e4634f04d5eb5a74") set(FFMPEG_DOWNLOAD_DIR "${OpenCV_BINARY_DIR}/3rdparty/ffmpeg") set(status TRUE) From dd304dbe05f83edd9d04be41312b38f7b93bb6a8 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 18 Apr 2017 22:25:00 +0300 Subject: [PATCH 100/144] test: fix min/max name mismatching --- modules/core/test/ocl/test_arithm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/core/test/ocl/test_arithm.cpp b/modules/core/test/ocl/test_arithm.cpp index 435cbf66f5..b6b249865f 100644 --- a/modules/core/test/ocl/test_arithm.cpp +++ b/modules/core/test/ocl/test_arithm.cpp @@ -447,8 +447,8 @@ OCL_TEST_P(Min, Mat) { generateTestData(); - OCL_OFF(cv::max(src1_roi, src2_roi, dst1_roi)); - OCL_ON(cv::max(usrc1_roi, usrc2_roi, udst1_roi)); + OCL_OFF(cv::min(src1_roi, src2_roi, dst1_roi)); + OCL_ON(cv::min(usrc1_roi, usrc2_roi, udst1_roi)); Near(0); } } @@ -461,8 +461,8 @@ OCL_TEST_P(Max, Mat) { generateTestData(); - OCL_OFF(cv::min(src1_roi, src2_roi, dst1_roi)); - OCL_ON(cv::min(usrc1_roi, usrc2_roi, udst1_roi)); + OCL_OFF(cv::max(src1_roi, src2_roi, dst1_roi)); + OCL_ON(cv::max(usrc1_roi, usrc2_roi, udst1_roi)); Near(0); } } From 2922738b6dd8211236baacc0b25ec5e6d86e939f Mon Sep 17 00:00:00 2001 From: insoow Date: Wed, 19 Apr 2017 02:57:54 -0700 Subject: [PATCH 101/144] Merge pull request #8104 from insoow:master Gemm kernels for Intel GPU (#8104) * Fix an issue with Kernel object reset release when consecutive Kernel::run calls Kernel::run launch OCL gpu kernels and set a event callback function to decreate the ref count of UMat or remove UMat when the lauched workloads are completed. However, for some OCL kernels requires multiple call of Kernel::run function with some kernel parameter changes (e.g., input and output buffer offset) to get the final computation result. In the case, the current implementation requires unnecessary synchronization and cleanupMat. This fix requires the user to specify whether there will be more work or not. If there is no remaining computation, the Kernel::run will reset the kernel object Signed-off-by: Woo, Insoo * GEMM kernel optimization for Intel GEN The optimized kernels uses cl_intel_subgroups extension for better performance. Note: This optimized kernels will be part of ISAAC in a code generation way under MIT license. Signed-off-by: Woo, Insoo * Fix API compatibility error This patch fixes a OCV API compatibility error. The error was reported due to the interface changes of Kernel::run. To resolve the issue, An overloaded function of Kernel::run is added. It take a flag indicating whether there are more work to be done with the kernel object without releasing resources related to it. Signed-off-by: Woo, Insoo * Renaming intel_gpu_gemm.cpp to intel_gpu_gemm.inl.hpp Signed-off-by: Woo, Insoo * Revert "Fix API compatibility error" This reverts commit 2ef427db91b6c4aec170f691c5d2e6c47d6520d7. Conflicts: modules/core/src/intel_gpu_gemm.inl.hpp * Revert "Fix an issue with Kernel object reset release when consecutive Kernel::run calls" This reverts commit cc7f9f54695dc293598addce9b9d7e345225bede. * Fix the case of uninitialization D When C is null and beta is non-zero, D is used without initialization. This resloves the issue Signed-off-by: Woo, Insoo * fix potential output error due to 0 * nan Signed-off-by: Woo, Insoo * whitespace fix, eliminate non-ASCII symbols * fix build warning --- modules/core/include/opencv2/core/ocl.hpp | 2 + modules/core/src/intel_gpu_gemm.inl.hpp | 147 +++ modules/core/src/matmul.cpp | 104 +- modules/core/src/ocl.cpp | 18 + modules/core/src/opencl/intel_gemm.cl | 1082 +++++++++++++++++++++ 5 files changed, 1315 insertions(+), 38 deletions(-) create mode 100644 modules/core/src/intel_gpu_gemm.inl.hpp create mode 100644 modules/core/src/opencl/intel_gemm.cl diff --git a/modules/core/include/opencv2/core/ocl.hpp b/modules/core/include/opencv2/core/ocl.hpp index 1a9549df4c..72378e2b56 100644 --- a/modules/core/include/opencv2/core/ocl.hpp +++ b/modules/core/include/opencv2/core/ocl.hpp @@ -160,6 +160,8 @@ public: uint imagePitchAlignment() const; uint imageBaseAddressAlignment() const; + bool intelSubgroupsSupport() const; + size_t image2DMaxWidth() const; size_t image2DMaxHeight() const; diff --git a/modules/core/src/intel_gpu_gemm.inl.hpp b/modules/core/src/intel_gpu_gemm.inl.hpp new file mode 100644 index 0000000000..04b5ffc3cd --- /dev/null +++ b/modules/core/src/intel_gpu_gemm.inl.hpp @@ -0,0 +1,147 @@ +/* +* Copyright 2015-2017 Philippe Tillet +* Copyright (c) 2017, Intel Corporation +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files +* (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, +* and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifdef HAVE_OPENCL + +#include +#include "precomp.hpp" +#include "opencl_kernels_core.hpp" +#include "opencv2/core/opencl/runtime/opencl_clamdblas.hpp" +#include "opencv2/core/opencl/runtime/opencl_core.hpp" + +namespace cv +{ + +static bool intel_gpu_gemm( + UMat A, Size sizeA, + UMat B, Size sizeB, + UMat D, Size sizeD, + double alpha, double beta, + bool atrans, bool btrans) +{ + CV_UNUSED(sizeB); + + int M = sizeD.height, N = sizeD.width, K = ((atrans)? sizeA.height : sizeA.width); + + std::string kernelName; + bool ret = true; + + size_t lx = 8, ly = 4; + size_t dx = 4, dy = 8; + + if(!atrans && !btrans) + { + + if (M % 32 == 0 && N % 32 == 0 && K % 16 == 0) + { + kernelName = "intelblas_gemm_buffer_NN_sp"; + } + else + { + kernelName = "intelblas_gemm_buffer_NN"; + } + } + else if(atrans && !btrans) + { + kernelName = "intelblas_gemm_buffer_TN"; + } + else if(!atrans && btrans) + { + kernelName = "intelblas_gemm_buffer_NT"; + ly = 16; + dx = 1; + } + else + { + kernelName = "intelblas_gemm_buffer_TT"; + } + + const size_t gx = (size_t)(N + dx - 1) / dx; + const size_t gy = (size_t)(M + dy - 1) / dy; + + size_t local[] = {lx, ly, 1}; + size_t global[] = {(gx + lx - 1) / lx * lx, (gy + ly - 1) / ly * ly, 1}; + + int stride = (M * N < 1024 * 1024) ? 10000000 : 256; + + ocl::Queue q; + String errmsg; + const ocl::Program program = ocl::Context::getDefault().getProg(ocl::core::intel_gemm_oclsrc, "", errmsg); + + if(!atrans && btrans) + { + ocl::Kernel k(kernelName.c_str(), program); + if (k.empty()) + { + return false; + } + + k.args(ocl::KernelArg::PtrReadOnly(A), + (int) (A.offset / sizeof(float)), + ocl::KernelArg::PtrReadOnly(B), + (int) (B.offset / sizeof(float)), + ocl::KernelArg::PtrWriteOnly(D), + (int) (D.offset / sizeof(float)), + M, N, K, + (float)alpha, + (float)beta, + (int)(A.step / sizeof(float)), + (int)(B.step / sizeof(float)), + (int)(D.step / sizeof(float)), + (int) 0, // 14 start_index + stride); + + ret = k.run(2, global, local, false, q); + } + else + { + for(int start_index = 0; start_index < K; start_index += stride) + { + ocl::Kernel k(kernelName.c_str(), program); + k.args(ocl::KernelArg::PtrReadOnly(A), + (int) (A.offset / sizeof(float)), + ocl::KernelArg::PtrReadOnly(B), + (int) (B.offset / sizeof(float)), + ocl::KernelArg::PtrWriteOnly(D), + (int) (D.offset / sizeof(float)), + M, N, K, + (float)alpha, + (float)beta, + (int)(A.step / sizeof(float)), + (int)(B.step / sizeof(float)), + (int)(D.step / sizeof(float)), + (int) start_index, // 14 start_index + stride); + + ret = k.run(2, global, local, false, q); + if (!ret) return ret; + } + } + + return ret; +} + +} // namespace cv + +#endif diff --git a/modules/core/src/matmul.cpp b/modules/core/src/matmul.cpp index 477d4ab9e6..3b4b8bd1ad 100644 --- a/modules/core/src/matmul.cpp +++ b/modules/core/src/matmul.cpp @@ -41,9 +41,12 @@ // //M*/ +#include #include "precomp.hpp" #include "opencl_kernels_core.hpp" #include "opencv2/core/opencl/runtime/opencl_clamdblas.hpp" +#include "opencv2/core/opencl/runtime/opencl_core.hpp" +#include "intel_gpu_gemm.inl.hpp" namespace cv { @@ -787,7 +790,6 @@ static bool ocl_gemm_amdblas( InputArray matA, InputArray matB, double alpha, #endif #ifdef HAVE_OPENCL - static bool ocl_gemm( InputArray matA, InputArray matB, double alpha, InputArray matC, double beta, OutputArray matD, int flags ) { @@ -806,62 +808,88 @@ static bool ocl_gemm( InputArray matA, InputArray matB, double alpha, Size sizeA = matA.size(), sizeB = matB.size(), sizeC = haveC ? matC.size() : Size(0, 0); bool atrans = (flags & GEMM_1_T) != 0, btrans = (flags & GEMM_2_T) != 0, ctrans = (flags & GEMM_3_T) != 0; - if (atrans) - sizeA = Size(sizeA.height, sizeA.width); - if (btrans) - sizeB = Size(sizeB.height, sizeB.width); - if (haveC && ctrans) - sizeC = Size(sizeC.height, sizeC.width); - - Size sizeD(sizeB.width, sizeA.height); - CV_Assert( !haveC || matC.type() == type ); - CV_Assert( sizeA.width == sizeB.height && (!haveC || sizeC == sizeD) ); - - int max_wg_size = (int)dev.maxWorkGroupSize(); - int block_size = (max_wg_size / (32*cn) < 32) ? (max_wg_size / (16*cn) < 16) ? (max_wg_size / (8*cn) < 8) ? 1 : 8 : 16 : 32; + Size sizeD(((btrans)? sizeB.height : sizeB.width), + ((atrans)? sizeA.width : sizeA.height)); matD.create(sizeD, type); UMat A = matA.getUMat(), B = matB.getUMat(), D = matD.getUMat(); - if (atrans) - A = A.t(); - if (btrans) - B = B.t(); + if (!dev.intelSubgroupsSupport() || (depth == CV_64F) || cn != 1) + { + String opts; - if (haveC) - ctrans ? transpose(matC, D) : matC.copyTo(D); + if (atrans) + sizeA = Size(sizeA.height, sizeA.width); + if (btrans) + sizeB = Size(sizeB.height, sizeB.width); + if (haveC && ctrans) + sizeC = Size(sizeC.height, sizeC.width); - int vectorWidths[] = { 4, 4, 2, 2, 1, 4, cn, -1 }; - int kercn = ocl::checkOptimalVectorWidth(vectorWidths, B, D); + CV_Assert( sizeA.width == sizeB.height && (!haveC || sizeC == sizeD) ); - String opts = format("-D T=%s -D T1=%s -D WT=%s -D cn=%d -D kercn=%d -D LOCAL_SIZE=%d %s %s %s", + int max_wg_size = (int)dev.maxWorkGroupSize(); + int block_size = (max_wg_size / (32*cn) < 32) ? (max_wg_size / (16*cn) < 16) ? (max_wg_size / (8*cn) < 8) ? 1 : 8 : 16 : 32; + + if (atrans) + A = A.t(); + + if (btrans) + B = B.t(); + + if (haveC) + ctrans ? transpose(matC, D) : matC.copyTo(D); + + int vectorWidths[] = { 4, 4, 2, 2, 1, 4, cn, -1 }; + int kercn = ocl::checkOptimalVectorWidth(vectorWidths, B, D); + + opts += format(" -D T=%s -D T1=%s -D WT=%s -D cn=%d -D kercn=%d -D LOCAL_SIZE=%d %s %s %s", ocl::typeToStr(type), ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), cn, kercn, block_size, (sizeA.width % block_size !=0) ? "-D NO_MULT" : "", haveC ? "-D HAVE_C" : "", doubleSupport ? " -D DOUBLE_SUPPORT" : ""); - ocl::Kernel k("gemm", cv::ocl::core::gemm_oclsrc, opts); - if (k.empty()) - return false; + ocl::Kernel k("gemm", cv::ocl::core::gemm_oclsrc, opts); + if (k.empty()) + return false; - if (depth == CV_64F) - k.args(ocl::KernelArg::ReadOnlyNoSize(A), - ocl::KernelArg::ReadOnlyNoSize(B, cn, kercn), - ocl::KernelArg::ReadWrite(D, cn, kercn), - sizeA.width, alpha, beta); + if (depth == CV_64F) + k.args(ocl::KernelArg::ReadOnlyNoSize(A), + ocl::KernelArg::ReadOnlyNoSize(B, cn, kercn), + ocl::KernelArg::ReadWrite(D, cn, kercn), + sizeA.width, alpha, beta); + else + k.args(ocl::KernelArg::ReadOnlyNoSize(A), + ocl::KernelArg::ReadOnlyNoSize(B, cn, kercn), + ocl::KernelArg::ReadWrite(D, cn, kercn), + sizeA.width, (float)alpha, (float)beta); + + size_t globalsize[2] = { (size_t)sizeD.width * cn / kercn, (size_t)sizeD.height}; + size_t localsize[2] = { (size_t)block_size, (size_t)block_size}; + + return k.run(2, globalsize, block_size!=1 ? localsize : NULL, false); + } else - k.args(ocl::KernelArg::ReadOnlyNoSize(A), - ocl::KernelArg::ReadOnlyNoSize(B, cn, kercn), - ocl::KernelArg::ReadWrite(D, cn, kercn), - sizeA.width, (float)alpha, (float)beta); + { + if (haveC && beta != 0.0) + { + ctrans ? transpose(matC, D) : matC.copyTo(D); + } + else + { + beta = 0.0; + } - size_t globalsize[2] = { (size_t)sizeD.width * cn / kercn, (size_t)sizeD.height}; - size_t localsize[2] = { (size_t)block_size, (size_t)block_size}; - return k.run(2, globalsize, block_size!=1 ? localsize : NULL, false); + return intel_gpu_gemm(A, sizeA, + B, sizeB, + D, sizeD, + alpha, + beta, + atrans, btrans); + } } #endif diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 64314a2206..47ba1b8b28 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -1812,6 +1812,8 @@ struct Device::Impl String deviceVersion_ = getStrProp(CL_DEVICE_VERSION); parseDeviceVersion(deviceVersion_, deviceVersionMajor_, deviceVersionMinor_); + intelSubgroupsSupport_ = isExtensionSupported("cl_intel_subgroups"); + vendorName_ = getStrProp(CL_DEVICE_VENDOR); if (vendorName_ == "Advanced Micro Devices, Inc." || vendorName_ == "AMD") @@ -1851,6 +1853,18 @@ struct Device::Impl sz < sizeof(buf) ? String(buf) : String(); } + bool isExtensionSupported(const String& extensionName) const + { + bool ret = false; + size_t pos = getStrProp(CL_DEVICE_EXTENSIONS).find(extensionName); + if (pos != String::npos) + { + ret = true; + } + return ret; + } + + IMPLEMENT_REFCOUNTABLE(); cl_device_id handle; @@ -1866,6 +1880,7 @@ struct Device::Impl String driverVersion_; String vendorName_; int vendorID_; + bool intelSubgroupsSupport_; }; @@ -2072,6 +2087,9 @@ size_t Device::imageMaxArraySize() const { CV_REQUIRE_OPENCL_1_2_ERROR; } #endif +bool Device::intelSubgroupsSupport() const +{ return p ? p->intelSubgroupsSupport_ : false; } + int Device::maxClockFrequency() const { return p ? p->getProp(CL_DEVICE_MAX_CLOCK_FREQUENCY) : 0; } diff --git a/modules/core/src/opencl/intel_gemm.cl b/modules/core/src/opencl/intel_gemm.cl new file mode 100644 index 0000000000..6cea8d7efd --- /dev/null +++ b/modules/core/src/opencl/intel_gemm.cl @@ -0,0 +1,1082 @@ +// Copyright (c) 2017, Intel Corporation +// +// The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if defined(cl_intel_subgroups) +#pragma OPENCL EXTENSION cl_intel_subgroups : enable +#endif + +#if defined(cl_intel_subgroups) + +#define VEC_SIZE 4 +#define LWG_HEIGHT 4 +#define TILE_M 8 +#define TILE_K 16 +#define TILE_N 32 + +__attribute__((reqd_work_group_size(8, LWG_HEIGHT, 1))) +__kernel void intelblas_gemm_buffer_NN_sp( + const __global float *src0, int off0, + const __global float *src1, int off1, + __global float *dst, int offd, + int M, + int N, + int K, + float alpha, + float beta, + int ldA, + int ldB, + int ldC, + int start_index, + int stride) +{ + const int group_x = get_group_id(0); + const int group_y = get_group_id(1); + const int local_x = get_local_id(0); + const int local_y = get_local_id(1); + const int global_x = get_global_id(0); + const int global_y = get_global_id(1); + + float4 brow; + float2 arow0, arow1, arow2, arow3, arow4, arow5, arow6, arow7; + + __global float *dst_write0 = dst + local_x * VEC_SIZE + ( group_x * TILE_N ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M) * ldC + offd; + + const __global float *src0_read = src0 + local_x * ( TILE_K / 8 ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M ) * ldA + start_index + off0; + + const __global float *src1_read0 = src1 + local_x * VEC_SIZE + ( group_x * TILE_N ) + start_index * ldB + off1; + + float4 dot00 = (start_index != 0) ? vload4(0, dst_write0) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 )) : (float4)(0.0)); + float4 dot01 = (start_index != 0) ? vload4(0, dst_write0 + 1 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 1 * ldC)) : (float4)(0.0)); + float4 dot02 = (start_index != 0) ? vload4(0, dst_write0 + 2 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 2 * ldC)) : (float4)(0.0)); + float4 dot03 = (start_index != 0) ? vload4(0, dst_write0 + 3 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 3 * ldC)) : (float4)(0.0)); + float4 dot04 = (start_index != 0) ? vload4(0, dst_write0 + 4 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 4 * ldC)) : (float4)(0.0)); + float4 dot05 = (start_index != 0) ? vload4(0, dst_write0 + 5 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 5 * ldC)) : (float4)(0.0)); + float4 dot06 = (start_index != 0) ? vload4(0, dst_write0 + 6 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 6 * ldC)) : (float4)(0.0)); + float4 dot07 = (start_index != 0) ? vload4(0, dst_write0 + 7 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 7 * ldC)) : (float4)(0.0)); + + int end_index = min(start_index + stride, K); + int w = start_index; + while( w + TILE_K <= end_index ) { + arow0 = (float)alpha * vload2(0, src0_read + 0 * ldA); + arow1 = (float)alpha * vload2(0, src0_read + 1 * ldA); + arow2 = (float)alpha * vload2(0, src0_read + 2 * ldA); + arow3 = (float)alpha * vload2(0, src0_read + 3 * ldA); + arow4 = (float)alpha * vload2(0, src0_read + 4 * ldA); + arow5 = (float)alpha * vload2(0, src0_read + 5 * ldA); + arow6 = (float)alpha * vload2(0, src0_read + 6 * ldA); + arow7 = (float)alpha * vload2(0, src0_read + 7 * ldA); + +#define MM_DOT_PRODUCT(index, suffix) \ + brow = vload4(0, src1_read0); src1_read0 += ldB; \ + dot00 = mad((float4)(intel_sub_group_shuffle(arow0.s##suffix,index)),brow,dot00); \ + dot01 = mad((float4)(intel_sub_group_shuffle(arow1.s##suffix,index)),brow,dot01); \ + dot02 = mad((float4)(intel_sub_group_shuffle(arow2.s##suffix,index)),brow,dot02); \ + dot03 = mad((float4)(intel_sub_group_shuffle(arow3.s##suffix,index)),brow,dot03); \ + dot04 = mad((float4)(intel_sub_group_shuffle(arow4.s##suffix,index)),brow,dot04); \ + dot05 = mad((float4)(intel_sub_group_shuffle(arow5.s##suffix,index)),brow,dot05); \ + dot06 = mad((float4)(intel_sub_group_shuffle(arow6.s##suffix,index)),brow,dot06); \ + dot07 = mad((float4)(intel_sub_group_shuffle(arow7.s##suffix,index)),brow,dot07); + + MM_DOT_PRODUCT(0,0); + MM_DOT_PRODUCT(0,1); + MM_DOT_PRODUCT(1,0); + MM_DOT_PRODUCT(1,1); + MM_DOT_PRODUCT(2,0); + MM_DOT_PRODUCT(2,1); + MM_DOT_PRODUCT(3,0); + MM_DOT_PRODUCT(3,1); + MM_DOT_PRODUCT(4,0); + MM_DOT_PRODUCT(4,1); + MM_DOT_PRODUCT(5,0); + MM_DOT_PRODUCT(5,1); + MM_DOT_PRODUCT(6,0); + MM_DOT_PRODUCT(6,1); + MM_DOT_PRODUCT(7,0); + MM_DOT_PRODUCT(7,1); +#undef MM_DOT_PRODUCT + + src0_read += TILE_K; + w += TILE_K; + } + + vstore4(dot00, 0, dst_write0); dst_write0 += ldC; + vstore4(dot01, 0, dst_write0); dst_write0 += ldC; + vstore4(dot02, 0, dst_write0); dst_write0 += ldC; + vstore4(dot03, 0, dst_write0); dst_write0 += ldC; + vstore4(dot04, 0, dst_write0); dst_write0 += ldC; + vstore4(dot05, 0, dst_write0); dst_write0 += ldC; + vstore4(dot06, 0, dst_write0); dst_write0 += ldC; + vstore4(dot07, 0, dst_write0); dst_write0 += ldC; +} + +#undef VEC_SIZE +#undef LWG_HEIGHT +#undef TILE_M +#undef TILE_K +#undef TILE_N + +#define VEC_SIZE 4 +#define LWG_HEIGHT 4 +#define TILE_M 8 +#define TILE_K 16 +#define TILE_N 32 + +__attribute__((reqd_work_group_size(8, LWG_HEIGHT, 1))) +__kernel void intelblas_gemm_buffer_NN( + const __global float *src0, int off0, + const __global float *src1, int off1, + __global float *dst, int offd, + int M, + int N, + int K, + float alpha, + float beta, + int ldA, + int ldB, + int ldC, + int start_index, + int stride) +{ + const int group_x = get_group_id(0); + const int group_y = get_group_id(1); + const int local_x = get_local_id(0); + const int local_y = get_local_id(1); + const int global_x = get_global_id(0); + const int global_y = get_global_id(1); + + float4 brow; + float2 arow0, arow1, arow2, arow3, arow4, arow5, arow6, arow7; + + __global float *dst_write0 = dst + local_x * VEC_SIZE + ( group_x * TILE_N ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M) * ldC + offd; + + const __global float *src0_read = src0 + local_x * ( TILE_K / 8 ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M ) * ldA + start_index + off0; + + const __global float *src1_read0 = src1 + local_x * VEC_SIZE + ( group_x * TILE_N ) + start_index * ldB + off1; + + int border = -(group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M); + + int row0 = mad24(global_y, TILE_M, 0) < M ? 0 : border; + int row1 = mad24(global_y, TILE_M, 1) < M ? 1 : border; + int row2 = mad24(global_y, TILE_M, 2) < M ? 2 : border; + int row3 = mad24(global_y, TILE_M, 3) < M ? 3 : border; + int row4 = mad24(global_y, TILE_M, 4) < M ? 4 : border; + int row5 = mad24(global_y, TILE_M, 5) < M ? 5 : border; + int row6 = mad24(global_y, TILE_M, 6) < M ? 6 : border; + int row7 = mad24(global_y, TILE_M, 7) < M ? 7 : border; + + float4 dot00 = (start_index != 0) ? vload4(0, dst_write0) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 )) : (float4)(0.0)); + float4 dot01 = (start_index != 0) ? vload4(0, dst_write0 + 1 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 1 * ldC)) : (float4)(0.0)); + float4 dot02 = (start_index != 0) ? vload4(0, dst_write0 + 2 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 2 * ldC)) : (float4)(0.0)); + float4 dot03 = (start_index != 0) ? vload4(0, dst_write0 + 3 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 3 * ldC)) : (float4)(0.0)); + float4 dot04 = (start_index != 0) ? vload4(0, dst_write0 + 4 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 4 * ldC)) : (float4)(0.0)); + float4 dot05 = (start_index != 0) ? vload4(0, dst_write0 + 5 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 5 * ldC)) : (float4)(0.0)); + float4 dot06 = (start_index != 0) ? vload4(0, dst_write0 + 6 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 6 * ldC)) : (float4)(0.0)); + float4 dot07 = (start_index != 0) ? vload4(0, dst_write0 + 7 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 7 * ldC)) : (float4)(0.0)); + + int end_index = min(start_index + stride, K); + int w = start_index; + while( w + TILE_K <= end_index ) { + arow0 = (float)alpha * vload2(0, src0_read + row0 * ldA); + arow1 = (float)alpha * vload2(0, src0_read + row1 * ldA); + arow2 = (float)alpha * vload2(0, src0_read + row2 * ldA); + arow3 = (float)alpha * vload2(0, src0_read + row3 * ldA); + arow4 = (float)alpha * vload2(0, src0_read + row4 * ldA); + arow5 = (float)alpha * vload2(0, src0_read + row5 * ldA); + arow6 = (float)alpha * vload2(0, src0_read + row6 * ldA); + arow7 = (float)alpha * vload2(0, src0_read + row7 * ldA); + +#define MM_DOT_PRODUCT(index,suffix) \ + brow = vload4(0, src1_read0); src1_read0 += ldB; \ + dot00 = mad((float4)(intel_sub_group_shuffle(arow0.s##suffix,index)),brow,dot00); \ + dot01 = mad((float4)(intel_sub_group_shuffle(arow1.s##suffix,index)),brow,dot01); \ + dot02 = mad((float4)(intel_sub_group_shuffle(arow2.s##suffix,index)),brow,dot02); \ + dot03 = mad((float4)(intel_sub_group_shuffle(arow3.s##suffix,index)),brow,dot03); \ + dot04 = mad((float4)(intel_sub_group_shuffle(arow4.s##suffix,index)),brow,dot04); \ + dot05 = mad((float4)(intel_sub_group_shuffle(arow5.s##suffix,index)),brow,dot05); \ + dot06 = mad((float4)(intel_sub_group_shuffle(arow6.s##suffix,index)),brow,dot06); \ + dot07 = mad((float4)(intel_sub_group_shuffle(arow7.s##suffix,index)),brow,dot07); + + MM_DOT_PRODUCT(0,0); + MM_DOT_PRODUCT(0,1); + MM_DOT_PRODUCT(1,0); + MM_DOT_PRODUCT(1,1); + MM_DOT_PRODUCT(2,0); + MM_DOT_PRODUCT(2,1); + MM_DOT_PRODUCT(3,0); + MM_DOT_PRODUCT(3,1); + MM_DOT_PRODUCT(4,0); + MM_DOT_PRODUCT(4,1); + MM_DOT_PRODUCT(5,0); + MM_DOT_PRODUCT(5,1); + MM_DOT_PRODUCT(6,0); + MM_DOT_PRODUCT(6,1); + MM_DOT_PRODUCT(7,0); + MM_DOT_PRODUCT(7,1); +#undef MM_DOT_PRODUCT + + src0_read += TILE_K; + w += TILE_K; + } + + if(w < end_index) { + arow0.x = ((w + local_x * 2) < K) ? (float)alpha * (src0_read + row0 * ldA)[0] : 0.0f; + arow0.y = ((w + local_x * 2 + 1) < K) ? (float)alpha * (src0_read + row0 * ldA)[1] : 0.0f; + arow1.x = ((w + local_x * 2) < K) ? (float)alpha * (src0_read + row1 * ldA)[0] : 0.0f; + arow1.y = ((w + local_x * 2 + 1) < K) ? (float)alpha * (src0_read + row1 * ldA)[1] : 0.0f; + arow2.x = ((w + local_x * 2) < K) ? (float)alpha * (src0_read + row2 * ldA)[0] : 0.0f; + arow2.y = ((w + local_x * 2 + 1) < K) ? (float)alpha * (src0_read + row2 * ldA)[1] : 0.0f; + arow3.x = ((w + local_x * 2) < K) ? (float)alpha * (src0_read + row3 * ldA)[0] : 0.0f; + arow3.y = ((w + local_x * 2 + 1) < K) ? (float)alpha * (src0_read + row3 * ldA)[1] : 0.0f; + arow4.x = ((w + local_x * 2) < K) ? (float)alpha * (src0_read + row4 * ldA)[0] : 0.0f; + arow4.y = ((w + local_x * 2 + 1) < K) ? (float)alpha * (src0_read + row4 * ldA)[1] : 0.0f; + arow5.x = ((w + local_x * 2) < K) ? (float)alpha * (src0_read + row5 * ldA)[0] : 0.0f; + arow5.y = ((w + local_x * 2 + 1) < K) ? (float)alpha * (src0_read + row5 * ldA)[1] : 0.0f; + arow6.x = ((w + local_x * 2) < K) ? (float)alpha * (src0_read + row6 * ldA)[0] : 0.0f; + arow6.y = ((w + local_x * 2 + 1) < K) ? (float)alpha * (src0_read + row6 * ldA)[1] : 0.0f; + arow7.x = ((w + local_x * 2) < K) ? (float)alpha * (src0_read + row7 * ldA)[0] : 0.0f; + arow7.y = ((w + local_x * 2 + 1) < K) ? (float)alpha * (src0_read + row7 * ldA)[1] : 0.0f; + +#define MM_DOT_PRODUCT(index,suffix) \ + brow = (w < K) ? vload4(0, src1_read0) : (float)0.0f; src1_read0 += ldB; w++; \ + dot00 = mad((float4)(intel_sub_group_shuffle( arow0.s##suffix, index )),brow,dot00 ); \ + dot01 = mad((float4)(intel_sub_group_shuffle( arow1.s##suffix, index )),brow,dot01 ); \ + dot02 = mad((float4)(intel_sub_group_shuffle( arow2.s##suffix, index )),brow,dot02 ); \ + dot03 = mad((float4)(intel_sub_group_shuffle( arow3.s##suffix, index )),brow,dot03 ); \ + dot04 = mad((float4)(intel_sub_group_shuffle( arow4.s##suffix, index )),brow,dot04 ); \ + dot05 = mad((float4)(intel_sub_group_shuffle( arow5.s##suffix, index )),brow,dot05 ); \ + dot06 = mad((float4)(intel_sub_group_shuffle( arow6.s##suffix, index )),brow,dot06 ); \ + dot07 = mad((float4)(intel_sub_group_shuffle( arow7.s##suffix, index )),brow,dot07 ); + + MM_DOT_PRODUCT(0,0); + MM_DOT_PRODUCT(0,1); + MM_DOT_PRODUCT(1,0); + MM_DOT_PRODUCT(1,1); + MM_DOT_PRODUCT(2,0); + MM_DOT_PRODUCT(2,1); + MM_DOT_PRODUCT(3,0); + MM_DOT_PRODUCT(3,1); + MM_DOT_PRODUCT(4,0); + MM_DOT_PRODUCT(4,1); + MM_DOT_PRODUCT(5,0); + MM_DOT_PRODUCT(5,1); + MM_DOT_PRODUCT(6,0); + MM_DOT_PRODUCT(6,1); + MM_DOT_PRODUCT(7,0); + MM_DOT_PRODUCT(7,1); +#undef MM_DOT_PRODUCT + } + + if(global_x * 4 < N && global_y * 8 < M) { + if(mad24(global_x, 4, 3) < N) { + vstore4(dot00, 0, dst_write0); dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { vstore4(dot01, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { vstore4(dot02, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { vstore4(dot03, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { vstore4(dot04, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { vstore4(dot05, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { vstore4(dot06, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { vstore4(dot07, 0, dst_write0); } + } else if(mad24(global_x, 4, 2) < N) { + vstore2(dot00.xy, 0, dst_write0); + dst_write0[2] = dot00.z; + dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { + vstore2(dot01.xy, 0, dst_write0); + dst_write0[2] = dot01.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 2) < M) { + vstore2(dot02.xy, 0, dst_write0); + dst_write0[2] = dot02.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 3) < M) { + vstore2(dot03.xy, 0, dst_write0); + dst_write0[2] = dot03.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 4) < M) { + vstore2(dot04.xy, 0, dst_write0); + dst_write0[2] = dot04.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 5) < M) { + vstore2(dot05.xy, 0, dst_write0); + dst_write0[2] = dot05.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 6) < M) { + vstore2(dot06.xy, 0, dst_write0); + dst_write0[2] = dot06.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 7) < M) { + vstore2(dot07.xy, 0, dst_write0); + dst_write0[2] = dot07.z; + } + } else if(mad24(global_x, 4, 1) < N) { + vstore2(dot00.xy, 0, dst_write0); dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { vstore2(dot01.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { vstore2(dot02.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { vstore2(dot03.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { vstore2(dot04.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { vstore2(dot05.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { vstore2(dot06.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { vstore2(dot07.xy, 0, dst_write0); } + } else { + dst_write0[0] = dot00.x; dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { dst_write0[0] = dot01.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { dst_write0[0] = dot02.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { dst_write0[0] = dot03.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { dst_write0[0] = dot04.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { dst_write0[0] = dot05.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { dst_write0[0] = dot06.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { dst_write0[0] = dot07.x; } + } + } +} + +#undef VEC_SIZE +#undef LWG_HEIGHT +#undef TILE_M +#undef TILE_K +#undef TILE_N + +#define VEC_SIZE 1 +#define LWG_HEIGHT 16 +#define TILE_M 8 +#define TILE_K 32 +#define TILE_N 8 +#define SLM_BLOCK 512 + +__attribute__((reqd_work_group_size(8, LWG_HEIGHT, 1))) +__kernel void intelblas_gemm_buffer_NT( + const __global float *src0, int off0, + const __global float *src1, int off1, + __global float *dst, int offd, + int M, + int N, + int K, + float alpha, + float beta, + int ldA, + int ldB, + int ldC) +{ + const int group_x = get_group_id(0); + const int group_y = get_group_id(1); + const int local_x = get_local_id(0); + const int local_y = get_local_id(1); + const int global_x = get_global_id(0); + const int global_y = get_global_id(1); + + float8 dot00 = 0.f; + float8 dot01 = 0.f; + float8 dot02 = 0.f; + float8 dot03 = 0.f; + float8 dot04 = 0.f; + float8 dot05 = 0.f; + float8 dot06 = 0.f; + float8 dot07 = 0.f; + + float4 brow0; + float4 brow1; + float4 brow2; + float4 brow3; + float4 brow4; + float4 brow5; + float4 brow6; + float4 brow7; + + __global float *dst_write0 = dst + local_x * VEC_SIZE + ( group_x * TILE_N ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M) * ldC + offd; + + const __global float *src0_read = src0 + local_x * ( TILE_K / 8 ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M ) * ldA + off0; + + const __global float *src1_read0 = src1 + ( group_x * TILE_N ) * ldB + off1; + + __local float slm_brow[8 * SLM_BLOCK]; + __local float* slm_brow0; + + int local_index = mad24(local_y, 8, local_x) * 4; + int w; + for(int b_tile = 0; b_tile < K; b_tile += SLM_BLOCK) { + barrier(CLK_LOCAL_MEM_FENCE); + vstore4(vload4(0, src1_read0 + mad24(0, ldB, local_index)), 0, slm_brow + mad24(0, SLM_BLOCK, local_index)); + vstore4(vload4(0, src1_read0 + mad24(1, ldB, local_index)), 0, slm_brow + mad24(1, SLM_BLOCK, local_index)); + vstore4(vload4(0, src1_read0 + mad24(2, ldB, local_index)), 0, slm_brow + mad24(2, SLM_BLOCK, local_index)); + vstore4(vload4(0, src1_read0 + mad24(3, ldB, local_index)), 0, slm_brow + mad24(3, SLM_BLOCK, local_index)); + vstore4(vload4(0, src1_read0 + mad24(4, ldB, local_index)), 0, slm_brow + mad24(4, SLM_BLOCK, local_index)); + vstore4(vload4(0, src1_read0 + mad24(5, ldB, local_index)), 0, slm_brow + mad24(5, SLM_BLOCK, local_index)); + vstore4(vload4(0, src1_read0 + mad24(6, ldB, local_index)), 0, slm_brow + mad24(6, SLM_BLOCK, local_index)); + vstore4(vload4(0, src1_read0 + mad24(7, ldB, local_index)), 0, slm_brow + mad24(7, SLM_BLOCK, local_index)); + barrier(CLK_LOCAL_MEM_FENCE); + + slm_brow0 = slm_brow + local_x * (TILE_K / 8); + w = b_tile; + int end_w = min(b_tile + SLM_BLOCK, K); + while( w + TILE_K <= end_w ) { + float4 arow; + + brow0 = vload4(0, slm_brow0 + 0 * SLM_BLOCK); + brow1 = vload4(0, slm_brow0 + 1 * SLM_BLOCK); + brow2 = vload4(0, slm_brow0 + 2 * SLM_BLOCK); + brow3 = vload4(0, slm_brow0 + 3 * SLM_BLOCK); + brow4 = vload4(0, slm_brow0 + 4 * SLM_BLOCK); + brow5 = vload4(0, slm_brow0 + 5 * SLM_BLOCK); + brow6 = vload4(0, slm_brow0 + 6 * SLM_BLOCK); + brow7 = vload4(0, slm_brow0 + 7 * SLM_BLOCK); + +#define MM_DOT_PRODUCT(_row,_dot) \ + arow = vload4(0, src0_read + _row * ldA); \ + _dot = mad( (float8)(arow.x), (float8)(brow0.x, brow1.x, brow2.x, brow3.x, brow4.x, brow5.x, brow6.x, brow7.x), _dot ); \ + _dot = mad( (float8)(arow.y), (float8)(brow0.y, brow1.y, brow2.y, brow3.y, brow4.y, brow5.y, brow6.y, brow7.y), _dot ); \ + _dot = mad( (float8)(arow.z), (float8)(brow0.z, brow1.z, brow2.z, brow3.z, brow4.z, brow5.z, brow6.z, brow7.z), _dot ); \ + _dot = mad( (float8)(arow.w), (float8)(brow0.w, brow1.w, brow2.w, brow3.w, brow4.w, brow5.w, brow6.w, brow7.w), _dot ); + + MM_DOT_PRODUCT(0,dot00); + MM_DOT_PRODUCT(1,dot01); + MM_DOT_PRODUCT(2,dot02); + MM_DOT_PRODUCT(3,dot03); + MM_DOT_PRODUCT(4,dot04); + MM_DOT_PRODUCT(5,dot05); + MM_DOT_PRODUCT(6,dot06); + MM_DOT_PRODUCT(7,dot07); +#undef MM_DOT_PRODUCT + + src0_read += TILE_K; + slm_brow0 += TILE_K; + w += TILE_K; + } + src1_read0 += SLM_BLOCK; + } + + if(w < K) { + float4 arow; + +#define READ_BROW(_brow,_row) \ + _brow = vload4(0, slm_brow0 + _row * SLM_BLOCK); \ + _brow.x = (mad24(local_x, 4, w) < K) ? _brow.x : 0.0f; \ + _brow.y = (mad24(local_x, 4, w + 1) < K) ? _brow.y : 0.0f; \ + _brow.z = (mad24(local_x, 4, w + 2) < K) ? _brow.z : 0.0f; \ + _brow.w = (mad24(local_x, 4, w + 3) < K) ? _brow.w : 0.0f; + + READ_BROW(brow0,0); + READ_BROW(brow1,1); + READ_BROW(brow2,2); + READ_BROW(brow3,3); + READ_BROW(brow4,4); + READ_BROW(brow5,5); + READ_BROW(brow6,6); + READ_BROW(brow7,7); + +#define MM_DOT_PRODUCT(_row,_dot) \ + arow = vload4(0, src0_read + _row * ldA); \ + arow.x = (mad24(local_x, 4, w) < K) ? arow.x : 0.0f; \ + arow.y = (mad24(local_x, 4, w + 1) < K) ? arow.y : 0.0f; \ + arow.z = (mad24(local_x, 4, w + 2) < K) ? arow.z : 0.0f; \ + arow.w = (mad24(local_x, 4, w + 3) < K) ? arow.w : 0.0f; \ + _dot = mad( (float8)(arow.x), (float8)(brow0.x, brow1.x, brow2.x, brow3.x, brow4.x, brow5.x, brow6.x, brow7.x), _dot ); \ + _dot = mad( (float8)(arow.y), (float8)(brow0.y, brow1.y, brow2.y, brow3.y, brow4.y, brow5.y, brow6.y, brow7.y), _dot ); \ + _dot = mad( (float8)(arow.z), (float8)(brow0.z, brow1.z, brow2.z, brow3.z, brow4.z, brow5.z, brow6.z, brow7.z), _dot ); \ + _dot = mad( (float8)(arow.w), (float8)(brow0.w, brow1.w, brow2.w, brow3.w, brow4.w, brow5.w, brow6.w, brow7.w), _dot ); + + MM_DOT_PRODUCT(0,dot00); + MM_DOT_PRODUCT(1,dot01); + MM_DOT_PRODUCT(2,dot02); + MM_DOT_PRODUCT(3,dot03); + MM_DOT_PRODUCT(4,dot04); + MM_DOT_PRODUCT(5,dot05); + MM_DOT_PRODUCT(6,dot06); + MM_DOT_PRODUCT(7,dot07); +#undef MM_DOT_PRODUCT + } + +#define REDUCE(_dot) \ + _dot.s0 = intel_sub_group_shuffle(_dot.s0, 0) + intel_sub_group_shuffle(_dot.s0, 1) + intel_sub_group_shuffle(_dot.s0, 2) + intel_sub_group_shuffle(_dot.s0, 3) + \ + intel_sub_group_shuffle(_dot.s0, 4) + intel_sub_group_shuffle(_dot.s0, 5) + intel_sub_group_shuffle(_dot.s0, 6) + intel_sub_group_shuffle(_dot.s0, 7); \ + _dot.s1 = intel_sub_group_shuffle(_dot.s1, 0) + intel_sub_group_shuffle(_dot.s1, 1) + intel_sub_group_shuffle(_dot.s1, 2) + intel_sub_group_shuffle(_dot.s1, 3) + \ + intel_sub_group_shuffle(_dot.s1, 4) + intel_sub_group_shuffle(_dot.s1, 5) + intel_sub_group_shuffle(_dot.s1, 6) + intel_sub_group_shuffle(_dot.s1, 7); \ + _dot.s2 = intel_sub_group_shuffle(_dot.s2, 0) + intel_sub_group_shuffle(_dot.s2, 1) + intel_sub_group_shuffle(_dot.s2, 2) + intel_sub_group_shuffle(_dot.s2, 3) + \ + intel_sub_group_shuffle(_dot.s2, 4) + intel_sub_group_shuffle(_dot.s2, 5) + intel_sub_group_shuffle(_dot.s2, 6) + intel_sub_group_shuffle(_dot.s2, 7); \ + _dot.s3 = intel_sub_group_shuffle(_dot.s3, 0) + intel_sub_group_shuffle(_dot.s3, 1) + intel_sub_group_shuffle(_dot.s3, 2) + intel_sub_group_shuffle(_dot.s3, 3) + \ + intel_sub_group_shuffle(_dot.s3, 4) + intel_sub_group_shuffle(_dot.s3, 5) + intel_sub_group_shuffle(_dot.s3, 6) + intel_sub_group_shuffle(_dot.s3, 7); \ + _dot.s4 = intel_sub_group_shuffle(_dot.s4, 0) + intel_sub_group_shuffle(_dot.s4, 1) + intel_sub_group_shuffle(_dot.s4, 2) + intel_sub_group_shuffle(_dot.s4, 3) + \ + intel_sub_group_shuffle(_dot.s4, 4) + intel_sub_group_shuffle(_dot.s4, 5) + intel_sub_group_shuffle(_dot.s4, 6) + intel_sub_group_shuffle(_dot.s4, 7); \ + _dot.s5 = intel_sub_group_shuffle(_dot.s5, 0) + intel_sub_group_shuffle(_dot.s5, 1) + intel_sub_group_shuffle(_dot.s5, 2) + intel_sub_group_shuffle(_dot.s5, 3) + \ + intel_sub_group_shuffle(_dot.s5, 4) + intel_sub_group_shuffle(_dot.s5, 5) + intel_sub_group_shuffle(_dot.s5, 6) + intel_sub_group_shuffle(_dot.s5, 7); \ + _dot.s6 = intel_sub_group_shuffle(_dot.s6, 0) + intel_sub_group_shuffle(_dot.s6, 1) + intel_sub_group_shuffle(_dot.s6, 2) + intel_sub_group_shuffle(_dot.s6, 3) + \ + intel_sub_group_shuffle(_dot.s6, 4) + intel_sub_group_shuffle(_dot.s6, 5) + intel_sub_group_shuffle(_dot.s6, 6) + intel_sub_group_shuffle(_dot.s6, 7); \ + _dot.s7 = intel_sub_group_shuffle(_dot.s7, 0) + intel_sub_group_shuffle(_dot.s7, 1) + intel_sub_group_shuffle(_dot.s7, 2) + intel_sub_group_shuffle(_dot.s7, 3) + \ + intel_sub_group_shuffle(_dot.s7, 4) + intel_sub_group_shuffle(_dot.s7, 5) + intel_sub_group_shuffle(_dot.s7, 6) + intel_sub_group_shuffle(_dot.s7, 7); + + REDUCE(dot00); + REDUCE(dot01); + REDUCE(dot02); + REDUCE(dot03); + REDUCE(dot04); + REDUCE(dot05); + REDUCE(dot06); + REDUCE(dot07); +#undef REDUCE + + float output = 0.0f; +#define OUTPUT(_dot) \ + output = (local_x == 0) ? _dot.s0 : output; \ + output = (local_x == 1) ? _dot.s1 : output; \ + output = (local_x == 2) ? _dot.s2 : output; \ + output = (local_x == 3) ? _dot.s3 : output; \ + output = (local_x == 4) ? _dot.s4 : output; \ + output = (local_x == 5) ? _dot.s5 : output; \ + output = (local_x == 6) ? _dot.s6 : output; \ + output = (local_x == 7) ? _dot.s7 : output; \ + if (beta != 0.0) \ + dst_write0[0] = mad(output, (float)alpha, ((float)beta * dst_write0[0])); \ + else \ + dst_write0[0] = output * (float)alpha; \ + dst_write0 += ldC; + + if(global_x < N && global_y * 8 < M) { + OUTPUT(dot00); + if(mad24(global_y, 8, 1) < M) { OUTPUT(dot01); } + if(mad24(global_y, 8, 2) < M) { OUTPUT(dot02); } + if(mad24(global_y, 8, 3) < M) { OUTPUT(dot03); } + if(mad24(global_y, 8, 4) < M) { OUTPUT(dot04); } + if(mad24(global_y, 8, 5) < M) { OUTPUT(dot05); } + if(mad24(global_y, 8, 6) < M) { OUTPUT(dot06); } + if(mad24(global_y, 8, 7) < M) { OUTPUT(dot07); } + } +#undef OUTPUT +} + +#undef VEC_SIZE +#undef LWG_HEIGHT +#undef TILE_M +#undef TILE_K +#undef TILE_N +#undef SLM_BLOCK + +#define VEC_SIZE 4 +#define LWG_HEIGHT 4 +#define TILE_M 8 +#define TILE_K 16 +#define TILE_N 32 + +__attribute__((reqd_work_group_size(8, LWG_HEIGHT, 1))) +__kernel void intelblas_gemm_buffer_TN( + const __global float *src0, int off0, + const __global float *src1, int off1, + __global float *dst, int offd, + int M, + int N, + int K, + float alpha, + float beta, + int ldA, + int ldB, + int ldC, + int start_index, + int stride) + +{ + const int group_x = get_group_id(0); + const int group_y = get_group_id(1); + const int local_x = get_local_id(0); + const int local_y = get_local_id(1); + const int global_x = get_global_id(0); + const int global_y = get_global_id(1); + + float4 brow; + + __global float *dst_write0 = dst + local_x * VEC_SIZE + ( group_x * TILE_N ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M) * ldC + offd; + + const __global float *src0_read = src0 + (local_x * ( TILE_K / 8 ) + start_index) * ldA + group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M + off0; + + const __global float *src1_read0 = src1 + local_x * VEC_SIZE + ( group_x * TILE_N ) + start_index * ldB + off1; + + float4 dot00 = (start_index != 0) ? vload4(0, dst_write0) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 )) : (float4)(0.0)); + float4 dot01 = (start_index != 0) ? vload4(0, dst_write0 + 1 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 1 * ldC)) : (float4)(0.0)); + float4 dot02 = (start_index != 0) ? vload4(0, dst_write0 + 2 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 2 * ldC)) : (float4)(0.0)); + float4 dot03 = (start_index != 0) ? vload4(0, dst_write0 + 3 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 3 * ldC)) : (float4)(0.0)); + float4 dot04 = (start_index != 0) ? vload4(0, dst_write0 + 4 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 4 * ldC)) : (float4)(0.0)); + float4 dot05 = (start_index != 0) ? vload4(0, dst_write0 + 5 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 5 * ldC)) : (float4)(0.0)); + float4 dot06 = (start_index != 0) ? vload4(0, dst_write0 + 6 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 6 * ldC)) : (float4)(0.0)); + float4 dot07 = (start_index != 0) ? vload4(0, dst_write0 + 7 * ldC) : ((beta != 0.0) ? ((float)beta * vload4(0, dst_write0 + 7 * ldC)) : (float4)(0.0)); + + int end_index = min(start_index + stride, K); + while( start_index + TILE_K <= end_index ) { + float8 arow0 = (float)alpha * vload8(0, src0_read); + float8 arow1 = (float)alpha * vload8(0, src0_read + ldA); + +#define MM_DOT_PRODUCT(_arow,index) \ + brow = vload4(0, src1_read0); src1_read0 += ldB; \ + dot00 = mad( (float4)(intel_sub_group_shuffle(_arow.s0, index)), brow, dot00 ); \ + dot01 = mad( (float4)(intel_sub_group_shuffle(_arow.s1, index)), brow, dot01 ); \ + dot02 = mad( (float4)(intel_sub_group_shuffle(_arow.s2, index)), brow, dot02 ); \ + dot03 = mad( (float4)(intel_sub_group_shuffle(_arow.s3, index)), brow, dot03 ); \ + dot04 = mad( (float4)(intel_sub_group_shuffle(_arow.s4, index)), brow, dot04 ); \ + dot05 = mad( (float4)(intel_sub_group_shuffle(_arow.s5, index)), brow, dot05 ); \ + dot06 = mad( (float4)(intel_sub_group_shuffle(_arow.s6, index)), brow, dot06 ); \ + dot07 = mad( (float4)(intel_sub_group_shuffle(_arow.s7, index)), brow, dot07 ); + + MM_DOT_PRODUCT(arow0,0); + MM_DOT_PRODUCT(arow1,0); + MM_DOT_PRODUCT(arow0,1); + MM_DOT_PRODUCT(arow1,1); + MM_DOT_PRODUCT(arow0,2); + MM_DOT_PRODUCT(arow1,2); + MM_DOT_PRODUCT(arow0,3); + MM_DOT_PRODUCT(arow1,3); + MM_DOT_PRODUCT(arow0,4); + MM_DOT_PRODUCT(arow1,4); + MM_DOT_PRODUCT(arow0,5); + MM_DOT_PRODUCT(arow1,5); + MM_DOT_PRODUCT(arow0,6); + MM_DOT_PRODUCT(arow1,6); + MM_DOT_PRODUCT(arow0,7); + MM_DOT_PRODUCT(arow1,7); +#undef MM_DOT_PRODUCT + + src0_read += TILE_K * ldA; + start_index += TILE_K; + } + + if(start_index < end_index) { + float8 arow0 = ((start_index + local_x * 2) < K) ? ((float)alpha * vload8(0, src0_read)) : (float)0.0f; + float8 arow1 = ((start_index + local_x * 2 + 1) < K) ? ((float)alpha * vload8(0, src0_read + ldA)) : (float)0.0f; + +#define MM_DOT_PRODUCT(_arow,index) \ + brow = (start_index < K) ? vload4(0, src1_read0) : (float)0.0f; src1_read0 += ldB; start_index++; \ + dot00 = mad( (float4)(intel_sub_group_shuffle(_arow.s0, index)), brow, dot00 ); \ + dot01 = mad( (float4)(intel_sub_group_shuffle(_arow.s1, index)), brow, dot01 ); \ + dot02 = mad( (float4)(intel_sub_group_shuffle(_arow.s2, index)), brow, dot02 ); \ + dot03 = mad( (float4)(intel_sub_group_shuffle(_arow.s3, index)), brow, dot03 ); \ + dot04 = mad( (float4)(intel_sub_group_shuffle(_arow.s4, index)), brow, dot04 ); \ + dot05 = mad( (float4)(intel_sub_group_shuffle(_arow.s5, index)), brow, dot05 ); \ + dot06 = mad( (float4)(intel_sub_group_shuffle(_arow.s6, index)), brow, dot06 ); \ + dot07 = mad( (float4)(intel_sub_group_shuffle(_arow.s7, index)), brow, dot07 ); + + MM_DOT_PRODUCT(arow0,0); + MM_DOT_PRODUCT(arow1,0); + MM_DOT_PRODUCT(arow0,1); + MM_DOT_PRODUCT(arow1,1); + MM_DOT_PRODUCT(arow0,2); + MM_DOT_PRODUCT(arow1,2); + MM_DOT_PRODUCT(arow0,3); + MM_DOT_PRODUCT(arow1,3); + MM_DOT_PRODUCT(arow0,4); + MM_DOT_PRODUCT(arow1,4); + MM_DOT_PRODUCT(arow0,5); + MM_DOT_PRODUCT(arow1,5); + MM_DOT_PRODUCT(arow0,6); + MM_DOT_PRODUCT(arow1,6); + MM_DOT_PRODUCT(arow0,7); + MM_DOT_PRODUCT(arow1,7); +#undef MM_DOT_PRODUCT + } + + if(global_x * 4 < N && global_y * 8 < M) { + if(mad24(global_x, 4, 3) < N) { + vstore4(dot00, 0, dst_write0); dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { vstore4(dot01, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { vstore4(dot02, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { vstore4(dot03, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { vstore4(dot04, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { vstore4(dot05, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { vstore4(dot06, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { vstore4(dot07, 0, dst_write0); } + } else if(mad24(global_x, 4, 2) < N) { + vstore2(dot00.xy, 0, dst_write0); + dst_write0[2] = dot00.z; + dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { + vstore2(dot01.xy, 0, dst_write0); + dst_write0[2] = dot01.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 2) < M) { + vstore2(dot02.xy, 0, dst_write0); + dst_write0[2] = dot02.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 3) < M) { + vstore2(dot03.xy, 0, dst_write0); + dst_write0[2] = dot03.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 4) < M) { + vstore2(dot04.xy, 0, dst_write0); + dst_write0[2] = dot04.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 5) < M) { + vstore2(dot05.xy, 0, dst_write0); + dst_write0[2] = dot05.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 6) < M) { + vstore2(dot06.xy, 0, dst_write0); + dst_write0[2] = dot06.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 7) < M) { + vstore2(dot07.xy, 0, dst_write0); + dst_write0[2] = dot07.z; + } + } else if(mad24(global_x, 4, 1) < N) { + vstore2(dot00.xy, 0, dst_write0); dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { vstore2(dot01.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { vstore2(dot02.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { vstore2(dot03.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { vstore2(dot04.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { vstore2(dot05.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { vstore2(dot06.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { vstore2(dot07.xy, 0, dst_write0); } + } else { + dst_write0[0] = dot00.x; dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { dst_write0[0] = dot01.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { dst_write0[0] = dot02.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { dst_write0[0] = dot03.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { dst_write0[0] = dot04.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { dst_write0[0] = dot05.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { dst_write0[0] = dot06.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { dst_write0[0] = dot07.x; } + } + } +} + +#undef VEC_SIZE +#undef LWG_HEIGHT +#undef TILE_M +#undef TILE_K +#undef TILE_N + +#define VEC_SIZE 4 +#define LWG_HEIGHT 4 +#define TILE_M 8 +#define TILE_K 16 +#define TILE_N 32 + +__attribute__((reqd_work_group_size(8, LWG_HEIGHT, 1))) +__kernel void intelblas_gemm_buffer_TT( + const __global float *src0, int off0, + const __global float *src1, int off1, + __global float *dst, int offd, + int M, + int N, + int K, + float alpha, + float beta, + int ldA, + int ldB, + int ldC, + int start_index, + int stride) +{ + const int group_x = get_group_id(0); + const int group_y = get_group_id(1); + const int local_x = get_local_id(0); + const int local_y = get_local_id(1); + const int global_x = get_global_id(0); + const int global_y = get_global_id(1); + + float8 dot0 = 0.f; + float8 dot1 = 0.f; + float8 dot2 = 0.f; + float8 dot3 = 0.f; + + float16 brow0; + float16 brow1; + float16 brow2; + float16 brow3; + + __global float *dst_write0 = dst + local_x * VEC_SIZE + ( group_x * TILE_N ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M) * ldC + offd; + + const __global float *src0_read = src0 + (local_x * ( TILE_K / 8 ) + start_index) * ldA + group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M + off0; + + const __global float *src1_read0 = src1 + (local_x * VEC_SIZE + ( group_x * TILE_N )) * ldB + start_index + off1; + + float4 dot00 = (start_index != 0) ? vload4(0, dst_write0) : ((beta != 0.0)? ((float)beta * vload4(0, dst_write0 )) : (float4)(0.0)); + float4 dot01 = (start_index != 0) ? vload4(0, dst_write0 + ldC) : ((beta != 0.0)? ((float)beta * vload4(0, dst_write0 + ldC )) : (float4)(0.0)); + float4 dot02 = (start_index != 0) ? vload4(0, dst_write0 + 2 * ldC) : ((beta != 0.0)? ((float)beta * vload4(0, dst_write0 + 2 * ldC)) : (float4)(0.0)); + float4 dot03 = (start_index != 0) ? vload4(0, dst_write0 + 3 * ldC) : ((beta != 0.0)? ((float)beta * vload4(0, dst_write0 + 3 * ldC)) : (float4)(0.0)); + float4 dot04 = (start_index != 0) ? vload4(0, dst_write0 + 4 * ldC) : ((beta != 0.0)? ((float)beta * vload4(0, dst_write0 + 4 * ldC)) : (float4)(0.0)); + float4 dot05 = (start_index != 0) ? vload4(0, dst_write0 + 5 * ldC) : ((beta != 0.0)? ((float)beta * vload4(0, dst_write0 + 5 * ldC)) : (float4)(0.0)); + float4 dot06 = (start_index != 0) ? vload4(0, dst_write0 + 6 * ldC) : ((beta != 0.0)? ((float)beta * vload4(0, dst_write0 + 6 * ldC)) : (float4)(0.0)); + float4 dot07 = (start_index != 0) ? vload4(0, dst_write0 + 7 * ldC) : ((beta != 0.0)? ((float)beta * vload4(0, dst_write0 + 7 * ldC)) : (float4)(0.0)); + + int end_index = min(start_index + stride, K); + while( start_index + TILE_K <= end_index ) { + brow0 = vload16(0, src1_read0); + brow1 = vload16(0, src1_read0 + ldB); + brow2 = vload16(0, src1_read0 + 2 * ldB); + brow3 = vload16(0, src1_read0 + 3 * ldB); + + float8 arow0 = (float)alpha * vload8(0, src0_read); + float8 arow1 = (float)alpha * vload8(0, src0_read + ldA); + +#define DOT_PRODUCT( _dot, _arow, index, _brow) \ + _dot.s0 = mad( intel_sub_group_shuffle( _arow.s0, index ), _brow, _dot.s0 ); \ + _dot.s1 = mad( intel_sub_group_shuffle( _arow.s1, index ), _brow, _dot.s1 ); \ + _dot.s2 = mad( intel_sub_group_shuffle( _arow.s2, index ), _brow, _dot.s2 ); \ + _dot.s3 = mad( intel_sub_group_shuffle( _arow.s3, index ), _brow, _dot.s3 ); \ + _dot.s4 = mad( intel_sub_group_shuffle( _arow.s4, index ), _brow, _dot.s4 ); \ + _dot.s5 = mad( intel_sub_group_shuffle( _arow.s5, index ), _brow, _dot.s5 ); \ + _dot.s6 = mad( intel_sub_group_shuffle( _arow.s6, index ), _brow, _dot.s6 ); \ + _dot.s7 = mad( intel_sub_group_shuffle( _arow.s7, index ), _brow, _dot.s7 ); + +#define MM_DOT_PRODUCT( _brow, _dot) \ + DOT_PRODUCT(_dot, arow0, 0, _brow.s0); \ + DOT_PRODUCT(_dot, arow1, 0, _brow.s1); \ + DOT_PRODUCT(_dot, arow0, 1, _brow.s2); \ + DOT_PRODUCT(_dot, arow1, 1, _brow.s3); \ + DOT_PRODUCT(_dot, arow0, 2, _brow.s4); \ + DOT_PRODUCT(_dot, arow1, 2, _brow.s5); \ + DOT_PRODUCT(_dot, arow0, 3, _brow.s6); \ + DOT_PRODUCT(_dot, arow1, 3, _brow.s7); \ + DOT_PRODUCT(_dot, arow0, 4, _brow.s8); \ + DOT_PRODUCT(_dot, arow1, 4, _brow.s9); \ + DOT_PRODUCT(_dot, arow0, 5, _brow.sa); \ + DOT_PRODUCT(_dot, arow1, 5, _brow.sb); \ + DOT_PRODUCT(_dot, arow0, 6, _brow.sc); \ + DOT_PRODUCT(_dot, arow1, 6, _brow.sd); \ + DOT_PRODUCT(_dot, arow0, 7, _brow.se); \ + DOT_PRODUCT(_dot, arow1, 7, _brow.sf); + + MM_DOT_PRODUCT( brow0, dot0 ); + MM_DOT_PRODUCT( brow1, dot1 ); + MM_DOT_PRODUCT( brow2, dot2 ); + MM_DOT_PRODUCT( brow3, dot3 ); +#undef MM_DOT_PRODUCT +#undef DOT_PRODUCT + + src1_read0 += TILE_K; + src0_read += TILE_K * ldA; + start_index += TILE_K; + } + + if(start_index < end_index) { + brow0 = vload16(0, src1_read0); src1_read0 += ldB; + brow1 = vload16(0, src1_read0); src1_read0 += ldB; + brow2 = vload16(0, src1_read0); src1_read0 += ldB; + brow3 = vload16(0, src1_read0); + + float8 arow0 = (float)alpha * vload8(0, src0_read); + float8 arow1 = (float)alpha * vload8(0, src0_read + ldA); + +#define DOT_PRODUCT( _dot, _arow, index, _brow) \ + _dot.s0 = (w < K) ? mad( intel_sub_group_shuffle( _arow.s0, index ), _brow, _dot.s0 ) : _dot.s0; \ + _dot.s1 = (w < K) ? mad( intel_sub_group_shuffle( _arow.s1, index ), _brow, _dot.s1 ) : _dot.s1; \ + _dot.s2 = (w < K) ? mad( intel_sub_group_shuffle( _arow.s2, index ), _brow, _dot.s2 ) : _dot.s2; \ + _dot.s3 = (w < K) ? mad( intel_sub_group_shuffle( _arow.s3, index ), _brow, _dot.s3 ) : _dot.s3; \ + _dot.s4 = (w < K) ? mad( intel_sub_group_shuffle( _arow.s4, index ), _brow, _dot.s4 ) : _dot.s4; \ + _dot.s5 = (w < K) ? mad( intel_sub_group_shuffle( _arow.s5, index ), _brow, _dot.s5 ) : _dot.s5; \ + _dot.s6 = (w < K) ? mad( intel_sub_group_shuffle( _arow.s6, index ), _brow, _dot.s6 ) : _dot.s6; \ + _dot.s7 = (w++ < K) ? mad( intel_sub_group_shuffle( _arow.s7, index ), _brow, _dot.s7 ) : _dot.s7; + +#define MM_DOT_PRODUCT( _brow, _dot) \ + DOT_PRODUCT(_dot, arow0, 0, _brow.s0); \ + DOT_PRODUCT(_dot, arow1, 0, _brow.s1); \ + DOT_PRODUCT(_dot, arow0, 1, _brow.s2); \ + DOT_PRODUCT(_dot, arow1, 1, _brow.s3); \ + DOT_PRODUCT(_dot, arow0, 2, _brow.s4); \ + DOT_PRODUCT(_dot, arow1, 2, _brow.s5); \ + DOT_PRODUCT(_dot, arow0, 3, _brow.s6); \ + DOT_PRODUCT(_dot, arow1, 3, _brow.s7); \ + DOT_PRODUCT(_dot, arow0, 4, _brow.s8); \ + DOT_PRODUCT(_dot, arow1, 4, _brow.s9); \ + DOT_PRODUCT(_dot, arow0, 5, _brow.sa); \ + DOT_PRODUCT(_dot, arow1, 5, _brow.sb); \ + DOT_PRODUCT(_dot, arow0, 6, _brow.sc); \ + DOT_PRODUCT(_dot, arow1, 6, _brow.sd); \ + DOT_PRODUCT(_dot, arow0, 7, _brow.se); \ + DOT_PRODUCT(_dot, arow1, 7, _brow.sf); + + int w = start_index; + MM_DOT_PRODUCT( brow0, dot0 ); + w = start_index; + MM_DOT_PRODUCT( brow1, dot1 ); + w = start_index; + MM_DOT_PRODUCT( brow2, dot2 ); + w = start_index; + MM_DOT_PRODUCT( brow3, dot3 ); +#undef MM_DOT_PRODUCT +#undef DOT_PRODUCT + } + + dot00 += (float4)(dot0.s0, dot1.s0, dot2.s0, dot3.s0); + dot01 += (float4)(dot0.s1, dot1.s1, dot2.s1, dot3.s1); + dot02 += (float4)(dot0.s2, dot1.s2, dot2.s2, dot3.s2); + dot03 += (float4)(dot0.s3, dot1.s3, dot2.s3, dot3.s3); + dot04 += (float4)(dot0.s4, dot1.s4, dot2.s4, dot3.s4); + dot05 += (float4)(dot0.s5, dot1.s5, dot2.s5, dot3.s5); + dot06 += (float4)(dot0.s6, dot1.s6, dot2.s6, dot3.s6); + dot07 += (float4)(dot0.s7, dot1.s7, dot2.s7, dot3.s7); + + if(global_x * 4 < N && global_y * 8 < M) { + if(mad24(global_x, 4, 3) < N) { + vstore4(dot00, 0, dst_write0); dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { vstore4(dot01, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { vstore4(dot02, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { vstore4(dot03, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { vstore4(dot04, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { vstore4(dot05, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { vstore4(dot06, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { vstore4(dot07, 0, dst_write0); } + } else if(mad24(global_x, 4, 2) < N) { + vstore2(dot00.xy, 0, dst_write0); + dst_write0[2] = dot00.z; + dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { + vstore2(dot01.xy, 0, dst_write0); + dst_write0[2] = dot01.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 2) < M) { + vstore2(dot02.xy, 0, dst_write0); + dst_write0[2] = dot02.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 3) < M) { + vstore2(dot03.xy, 0, dst_write0); + dst_write0[2] = dot03.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 4) < M) { + vstore2(dot04.xy, 0, dst_write0); + dst_write0[2] = dot04.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 5) < M) { + vstore2(dot05.xy, 0, dst_write0); + dst_write0[2] = dot05.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 6) < M) { + vstore2(dot06.xy, 0, dst_write0); + dst_write0[2] = dot06.z; + dst_write0 += ldC; + } else + return; + if(mad24(global_y, 8, 7) < M) { + vstore2(dot07.xy, 0, dst_write0); + dst_write0[2] = dot07.z; + } + } else if(mad24(global_x, 4, 1) < N) { + vstore2(dot00.xy, 0, dst_write0); dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { vstore2(dot01.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { vstore2(dot02.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { vstore2(dot03.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { vstore2(dot04.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { vstore2(dot05.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { vstore2(dot06.xy, 0, dst_write0); dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { vstore2(dot07.xy, 0, dst_write0); } + } else { + dst_write0[0] = dot00.x; dst_write0 += ldC; + if(mad24(global_y, 8, 1) < M) { dst_write0[0] = dot01.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 2) < M) { dst_write0[0] = dot02.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 3) < M) { dst_write0[0] = dot03.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 4) < M) { dst_write0[0] = dot04.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 5) < M) { dst_write0[0] = dot05.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 6) < M) { dst_write0[0] = dot06.x; dst_write0 += ldC; } + else return; + if(mad24(global_y, 8, 7) < M) { dst_write0[0] = dot07.x; } + } + } +} + +#undef VEC_SIZE +#undef LWG_HEIGHT +#undef TILE_M +#undef TILE_K +#undef TILE_N + +#endif From 636ab095b0dda4f63da71e681e47d5e69e6be6b7 Mon Sep 17 00:00:00 2001 From: Arnaud Brejeon Date: Wed, 19 Apr 2017 03:13:39 -0700 Subject: [PATCH 102/144] Merge pull request #8535 from arnaudbrejeon:std_array Add support for std::array (#8535) * Add support for std::array * Add std::array support * Remove UMat constructor with std::array parameter --- modules/core/include/opencv2/core/cvdef.h | 15 ++ modules/core/include/opencv2/core/mat.hpp | 45 +++- modules/core/include/opencv2/core/mat.inl.hpp | 101 +++++++- modules/core/src/convert.cpp | 4 + modules/core/src/lda.cpp | 4 +- modules/core/src/matmul.cpp | 2 +- modules/core/src/matrix.cpp | 223 ++++++++++++++++-- modules/core/test/test_mat.cpp | 92 ++++++++ 8 files changed, 466 insertions(+), 20 deletions(-) diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index 43f8a02a72..a0c3438116 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -364,6 +364,21 @@ Cv64suf; # endif #endif +/****************************************************************************************\ +* C++11 std::array * +\****************************************************************************************/ + +#ifndef CV_CXX_STD_ARRAY +# if __cplusplus >= 201103L +# define CV_CXX_STD_ARRAY 1 +# include +# endif +#else +# if CV_CXX_STD_ARRAY == 0 +# undef CV_CXX_STD_ARRAY +# endif +#endif + //! @} #endif // OPENCV_CORE_CVDEF_H diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index e3a24032d0..0a74e72817 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -165,7 +165,9 @@ public: UMAT =10 << KIND_SHIFT, STD_VECTOR_UMAT =11 << KIND_SHIFT, STD_BOOL_VECTOR =12 << KIND_SHIFT, - STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT + STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT, + STD_ARRAY =14 << KIND_SHIFT, + STD_ARRAY_MAT =15 << KIND_SHIFT }; _InputArray(); @@ -189,6 +191,11 @@ public: _InputArray(const UMat& um); _InputArray(const std::vector& umv); +#ifdef CV_CXX_STD_ARRAY + template _InputArray(const std::array<_Tp, _N>& arr); + template _InputArray(const std::array& arr); +#endif + Mat getMat(int idx=-1) const; Mat getMat_(int idx=-1) const; UMat getUMat(int idx=-1) const; @@ -316,6 +323,13 @@ public: _OutputArray(const UMat& m); _OutputArray(const std::vector& vec); +#ifdef CV_CXX_STD_ARRAY + template _OutputArray(std::array<_Tp, _N>& arr); + template _OutputArray(const std::array<_Tp, _N>& arr); + template _OutputArray(std::array& arr); + template _OutputArray(const std::array& arr); +#endif + bool fixedSize() const; bool fixedType() const; bool needed() const; @@ -374,6 +388,14 @@ public: template _InputOutputArray(const Matx<_Tp, m, n>& matx); _InputOutputArray(const UMat& m); _InputOutputArray(const std::vector& vec); + +#ifdef CV_CXX_STD_ARRAY + template _InputOutputArray(std::array<_Tp, _N>& arr); + template _InputOutputArray(const std::array<_Tp, _N>& arr); + template _InputOutputArray(std::array& arr); + template _InputOutputArray(const std::array& arr); +#endif + }; typedef const _InputArray& InputArray; @@ -955,6 +977,12 @@ public: */ template explicit Mat(const std::vector<_Tp>& vec, bool copyData=false); +#ifdef CV_CXX_STD_ARRAY + /** @overload + */ + template explicit Mat(const std::array<_Tp, _N>& arr, bool copyData=false); +#endif + /** @overload */ template explicit Mat(const Vec<_Tp, n>& vec, bool copyData=true); @@ -1575,6 +1603,10 @@ public: template operator Vec<_Tp, n>() const; template operator Matx<_Tp, m, n>() const; +#ifdef CV_CXX_STD_ARRAY + template operator std::array<_Tp, _N>() const; +#endif + /** @brief Reports whether the matrix is continuous or not. The method returns true if the matrix elements are stored continuously without gaps at the end of @@ -2114,6 +2146,10 @@ public: explicit Mat_(const Point3_::channel_type>& pt, bool copyData=true); explicit Mat_(const MatCommaInitializer_<_Tp>& commaInitializer); +#ifdef CV_CXX_STD_ARRAY + template explicit Mat_(const std::array<_Tp, _N>& arr, bool copyData=false); +#endif + Mat_& operator = (const Mat& m); Mat_& operator = (const Mat_& m); //! set all the elements to s. @@ -2207,6 +2243,12 @@ public: //! conversion to vector. operator std::vector<_Tp>() const; + +#ifdef CV_CXX_STD_ARRAY + //! conversion to array. + template operator std::array<_Tp, _N>() const; +#endif + //! conversion to Vec template operator Vec::channel_type, n>() const; //! conversion to Matx @@ -2281,6 +2323,7 @@ public: UMat(const UMat& m, const std::vector& ranges); //! builds matrix from std::vector with or without copying the data template explicit UMat(const std::vector<_Tp>& vec, bool copyData=false); + //! builds matrix from cv::Vec; the data is copied by default template explicit UMat(const Vec<_Tp, n>& vec, bool copyData=true); //! builds matrix from cv::Matx; the data is copied by default diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index aa746e8807..399c92220d 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -77,6 +77,16 @@ template inline _InputArray::_InputArray(const std::vector<_Tp>& vec) { init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); } +#ifdef CV_CXX_STD_ARRAY +template inline +_InputArray::_InputArray(const std::array<_Tp, _N>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_READ, arr.data(), Size(1, _N)); } + +template inline +_InputArray::_InputArray(const std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_READ, arr.data(), Size(1, _N)); } +#endif + inline _InputArray::_InputArray(const std::vector& vec) { init(FIXED_TYPE + STD_BOOL_VECTOR + DataType::type + ACCESS_READ, &vec); } @@ -133,7 +143,9 @@ inline bool _InputArray::isUMat() const { return kind() == _InputArray::UMAT; } inline bool _InputArray::isMatVector() const { return kind() == _InputArray::STD_VECTOR_MAT; } inline bool _InputArray::isUMatVector() const { return kind() == _InputArray::STD_VECTOR_UMAT; } inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; } -inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VECTOR || kind() == _InputArray::STD_BOOL_VECTOR; } +inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VECTOR || + kind() == _InputArray::STD_BOOL_VECTOR || + kind() == _InputArray::STD_ARRAY; } inline bool _InputArray::isGpuMatVector() const { return kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT; } //////////////////////////////////////////////////////////////////////////////////////// @@ -149,6 +161,16 @@ template inline _OutputArray::_OutputArray(std::vector<_Tp>& vec) { init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +#ifdef CV_CXX_STD_ARRAY +template inline +_OutputArray::_OutputArray(std::array<_Tp, _N>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_WRITE, arr.data(), Size(1, _N)); } + +template inline +_OutputArray::_OutputArray(std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _N)); } +#endif + inline _OutputArray::_OutputArray(std::vector&) { CV_Error(Error::StsUnsupportedFormat, "std::vector cannot be an output array\n"); } @@ -177,6 +199,16 @@ template inline _OutputArray::_OutputArray(const std::vector<_Tp>& vec) { init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } +#ifdef CV_CXX_STD_ARRAY +template inline +_OutputArray::_OutputArray(const std::array<_Tp, _N>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_WRITE, arr.data(), Size(1, _N)); } + +template inline +_OutputArray::_OutputArray(const std::array& arr) +{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _N)); } +#endif + template inline _OutputArray::_OutputArray(const std::vector >& vec) { init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } @@ -244,6 +276,16 @@ template inline _InputOutputArray::_InputOutputArray(std::vector<_Tp>& vec) { init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } +#ifdef CV_CXX_STD_ARRAY +template inline +_InputOutputArray::_InputOutputArray(std::array<_Tp, _N>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_RW, arr.data(), Size(1, _N)); } + +template inline +_InputOutputArray::_InputOutputArray(std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _N)); } +#endif + inline _InputOutputArray::_InputOutputArray(std::vector&) { CV_Error(Error::StsUnsupportedFormat, "std::vector cannot be an input/output array\n"); } @@ -271,6 +313,16 @@ template inline _InputOutputArray::_InputOutputArray(const std::vector<_Tp>& vec) { init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } +#ifdef CV_CXX_STD_ARRAY +template inline +_InputOutputArray::_InputOutputArray(const std::array<_Tp, _N>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_RW, arr.data(), Size(1, _N)); } + +template inline +_InputOutputArray::_InputOutputArray(const std::array& arr) +{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _N)); } +#endif + template inline _InputOutputArray::_InputOutputArray(const std::vector >& vec) { init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } @@ -505,6 +557,25 @@ Mat::Mat(const std::vector<_Tp>& vec, bool copyData) Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this); } +#ifdef CV_CXX_STD_ARRAY +template inline +Mat::Mat(const std::array<_Tp, _N>& arr, bool copyData) + : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows((int)arr.size()), + cols(1), data(0), datastart(0), dataend(0), allocator(0), u(0), size(&rows) +{ + if(arr.empty()) + return; + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + datastart = data = (uchar*)arr.data(); + datalimit = dataend = datastart + rows * step[0]; + } + else + Mat((int)arr.size(), 1, DataType<_Tp>::type, (uchar*)arr.data()).copyTo(*this); +} +#endif + template inline Mat::Mat(const Vec<_Tp, n>& vec, bool copyData) : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(n), cols(1), data(0), @@ -1114,6 +1185,16 @@ Mat::operator std::vector<_Tp>() const return v; } +#ifdef CV_CXX_STD_ARRAY +template inline +Mat::operator std::array<_Tp, _N>() const +{ + std::array<_Tp, _N> v; + copyTo(v); + return v; +} +#endif + template inline Mat::operator Vec<_Tp, n>() const { @@ -1468,6 +1549,13 @@ Mat_<_Tp>::Mat_(const std::vector<_Tp>& vec, bool copyData) : Mat(vec, copyData) {} +#ifdef CV_CXX_STD_ARRAY +template template inline +Mat_<_Tp>::Mat_(const std::array<_Tp, _N>& arr, bool copyData) + : Mat(arr, copyData) +{} +#endif + template inline Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat& m) { @@ -1745,6 +1833,16 @@ Mat_<_Tp>::operator std::vector<_Tp>() const return v; } +#ifdef CV_CXX_STD_ARRAY +template template inline +Mat_<_Tp>::operator std::array<_Tp, _N>() const +{ + std::array<_Tp, _N> a; + copyTo(a); + return a; +} +#endif + template template inline Mat_<_Tp>::operator Vec::channel_type, n>() const { @@ -3426,7 +3524,6 @@ cols(1), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows) Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this); } - inline UMat& UMat::operator = (const UMat& m) { diff --git a/modules/core/src/convert.cpp b/modules/core/src/convert.cpp index 6c060f9c9c..8d3c242659 100644 --- a/modules/core/src/convert.cpp +++ b/modules/core/src/convert.cpp @@ -637,9 +637,11 @@ void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst, ocl_mixChannels(src, dst, fromTo, npairs)) bool src_is_mat = src.kind() != _InputArray::STD_VECTOR_MAT && + src.kind() != _InputArray::STD_ARRAY_MAT && src.kind() != _InputArray::STD_VECTOR_VECTOR && src.kind() != _InputArray::STD_VECTOR_UMAT; bool dst_is_mat = dst.kind() != _InputArray::STD_VECTOR_MAT && + dst.kind() != _InputArray::STD_ARRAY_MAT && dst.kind() != _InputArray::STD_VECTOR_VECTOR && dst.kind() != _InputArray::STD_VECTOR_UMAT; int i; @@ -668,9 +670,11 @@ void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst, ocl_mixChannels(src, dst, &fromTo[0], fromTo.size()>>1)) bool src_is_mat = src.kind() != _InputArray::STD_VECTOR_MAT && + src.kind() != _InputArray::STD_ARRAY_MAT && src.kind() != _InputArray::STD_VECTOR_VECTOR && src.kind() != _InputArray::STD_VECTOR_UMAT; bool dst_is_mat = dst.kind() != _InputArray::STD_VECTOR_MAT && + dst.kind() != _InputArray::STD_ARRAY_MAT && dst.kind() != _InputArray::STD_VECTOR_VECTOR && dst.kind() != _InputArray::STD_VECTOR_UMAT; int i; diff --git a/modules/core/src/lda.cpp b/modules/core/src/lda.cpp index 4ccbf8a834..a706eeb3fe 100644 --- a/modules/core/src/lda.cpp +++ b/modules/core/src/lda.cpp @@ -53,7 +53,8 @@ static Mat argsort(InputArray _src, bool ascending=true) static Mat asRowMatrix(InputArrayOfArrays src, int rtype, double alpha=1, double beta=0) { // make sure the input data is a vector of matrices or vector of vector - if(src.kind() != _InputArray::STD_VECTOR_MAT && src.kind() != _InputArray::STD_VECTOR_VECTOR) { + if(src.kind() != _InputArray::STD_VECTOR_MAT && src.kind() != _InputArray::STD_ARRAY_MAT && + src.kind() != _InputArray::STD_VECTOR_VECTOR) { String error_message = "The data is expected as InputArray::STD_VECTOR_MAT (a std::vector) or _InputArray::STD_VECTOR_VECTOR (a std::vector< std::vector<...> >)."; CV_Error(Error::StsBadArg, error_message); } @@ -1096,6 +1097,7 @@ void LDA::lda(InputArrayOfArrays _src, InputArray _lbls) { void LDA::compute(InputArrayOfArrays _src, InputArray _lbls) { switch(_src.kind()) { case _InputArray::STD_VECTOR_MAT: + case _InputArray::STD_ARRAY_MAT: lda(asRowMatrix(_src, CV_64FC1), _lbls); break; case _InputArray::MAT: diff --git a/modules/core/src/matmul.cpp b/modules/core/src/matmul.cpp index 3b4b8bd1ad..8b06193cf6 100644 --- a/modules/core/src/matmul.cpp +++ b/modules/core/src/matmul.cpp @@ -2579,7 +2579,7 @@ void cv::calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray { CV_INSTRUMENT_REGION() - if(_src.kind() == _InputArray::STD_VECTOR_MAT) + if(_src.kind() == _InputArray::STD_VECTOR_MAT || _src.kind() == _InputArray::STD_ARRAY_MAT) { std::vector src; _src.getMatVector(src); diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 2e479f7c56..edc4462d20 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -1235,7 +1235,7 @@ Mat _InputArray::getMat_(int i) const return (Mat)*((const MatExpr*)obj); } - if( k == MATX ) + if( k == MATX || k == STD_ARRAY ) { CV_Assert( i < 0 ); return Mat(sz, flags, obj); @@ -1286,6 +1286,14 @@ Mat _InputArray::getMat_(int i) const return v[i]; } + if( k == STD_ARRAY_MAT ) + { + const Mat* v = (const Mat*)obj; + CV_Assert( 0 <= i && i < sz.height ); + + return v[i]; + } + if( k == STD_VECTOR_UMAT ) { const std::vector& v = *(const std::vector*)obj; @@ -1381,7 +1389,7 @@ void _InputArray::getMatVector(std::vector& mv) const return; } - if( k == MATX ) + if( k == MATX || k == STD_ARRAY ) { size_t n = sz.height, esz = CV_ELEM_SIZE(flags); mv.resize(n); @@ -1436,6 +1444,17 @@ void _InputArray::getMatVector(std::vector& mv) const return; } + if( k == STD_ARRAY_MAT ) + { + const Mat* v = (const Mat*)obj; + size_t n = sz.height; + mv.resize(n); + + for( size_t i = 0; i < n; i++ ) + mv[i] = v[i]; + return; + } + if( k == STD_VECTOR_UMAT ) { const std::vector& v = *(const std::vector*)obj; @@ -1472,6 +1491,17 @@ void _InputArray::getUMatVector(std::vector& umv) const return; } + if( k == STD_ARRAY_MAT ) + { + const Mat* v = (const Mat*)obj; + size_t n = sz.height; + umv.resize(n); + + for( size_t i = 0; i < n; i++ ) + umv[i] = v[i].getUMat(accessFlags); + return; + } + if( k == STD_VECTOR_UMAT ) { const std::vector& v = *(const std::vector*)obj; @@ -1584,7 +1614,7 @@ Size _InputArray::size(int i) const return ((const UMat*)obj)->size(); } - if( k == MATX ) + if( k == MATX || k == STD_ARRAY ) { CV_Assert( i < 0 ); return sz; @@ -1631,6 +1661,16 @@ Size _InputArray::size(int i) const return vv[i].size(); } + if( k == STD_ARRAY_MAT ) + { + const Mat* vv = (const Mat*)obj; + if( i < 0 ) + return sz.height==0 ? Size() : Size(sz.height, 1); + CV_Assert( i < sz.height ); + + return vv[i].size(); + } + if (k == STD_VECTOR_CUDA_GPU_MAT) { const std::vector& vv = *(const std::vector*)obj; @@ -1709,6 +1749,16 @@ int _InputArray::sizend(int* arrsz, int i) const for(j = 0; j < d; j++) arrsz[j] = m.size.p[j]; } + else if( k == STD_ARRAY_MAT && i >= 0 ) + { + const Mat* vv = (const Mat*)obj; + CV_Assert( i < sz.height ); + const Mat& m = vv[i]; + d = m.dims; + if(arrsz) + for(j = 0; j < d; j++) + arrsz[j] = m.size.p[j]; + } else if( k == STD_VECTOR_UMAT && i >= 0 ) { const std::vector& vv = *(const std::vector*)obj; @@ -1789,7 +1839,7 @@ int _InputArray::dims(int i) const return ((const UMat*)obj)->dims; } - if( k == MATX ) + if( k == MATX || k == STD_ARRAY ) { CV_Assert( i < 0 ); return 2; @@ -1823,6 +1873,16 @@ int _InputArray::dims(int i) const return vv[i].dims; } + if( k == STD_ARRAY_MAT ) + { + const Mat* vv = (const Mat*)obj; + if( i < 0 ) + return 1; + CV_Assert( i < sz.height ); + + return vv[i].dims; + } + if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; @@ -1881,6 +1941,15 @@ size_t _InputArray::total(int i) const return vv[i].total(); } + if( k == STD_ARRAY_MAT ) + { + const Mat* vv = (const Mat*)obj; + if( i < 0 ) + return sz.height; + + CV_Assert( i < sz.height ); + return vv[i].total(); + } if( k == STD_VECTOR_UMAT ) { @@ -1908,7 +1977,7 @@ int _InputArray::type(int i) const if( k == EXPR ) return ((const MatExpr*)obj)->type(); - if( k == MATX || k == STD_VECTOR || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR ) + if( k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR ) return CV_MAT_TYPE(flags); if( k == NONE ) @@ -1938,6 +2007,18 @@ int _InputArray::type(int i) const return vv[i >= 0 ? i : 0].type(); } + if( k == STD_ARRAY_MAT ) + { + const Mat* vv = (const Mat*)obj; + if( sz.height == 0 ) + { + CV_Assert((flags & FIXED_TYPE) != 0); + return CV_MAT_TYPE(flags); + } + CV_Assert( i < sz.height ); + return vv[i >= 0 ? i : 0].type(); + } + if (k == STD_VECTOR_CUDA_GPU_MAT) { const std::vector& vv = *(const std::vector*)obj; @@ -1986,7 +2067,7 @@ bool _InputArray::empty() const if( k == EXPR ) return false; - if( k == MATX ) + if( k == MATX || k == STD_ARRAY ) return false; if( k == STD_VECTOR ) @@ -2016,6 +2097,11 @@ bool _InputArray::empty() const return vv.empty(); } + if( k == STD_ARRAY_MAT ) + { + return sz.height == 0; + } + if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; @@ -2051,7 +2137,7 @@ bool _InputArray::isContinuous(int i) const if( k == UMAT ) return i < 0 ? ((const UMat*)obj)->isContinuous() : true; - if( k == EXPR || k == MATX || k == STD_VECTOR || + if( k == EXPR || k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == NONE || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR ) return true; @@ -2062,6 +2148,13 @@ bool _InputArray::isContinuous(int i) const return vv[i].isContinuous(); } + if( k == STD_ARRAY_MAT ) + { + const Mat* vv = (const Mat*)obj; + CV_Assert(i < sz.height); + return vv[i].isContinuous(); + } + if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; @@ -2086,7 +2179,7 @@ bool _InputArray::isSubmatrix(int i) const if( k == UMAT ) return i < 0 ? ((const UMat*)obj)->isSubmatrix() : false; - if( k == EXPR || k == MATX || k == STD_VECTOR || + if( k == EXPR || k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == NONE || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR ) return false; @@ -2097,6 +2190,13 @@ bool _InputArray::isSubmatrix(int i) const return vv[i].isSubmatrix(); } + if( k == STD_ARRAY_MAT ) + { + const Mat* vv = (const Mat*)obj; + CV_Assert(i < sz.height); + return vv[i].isSubmatrix(); + } + if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; @@ -2125,7 +2225,7 @@ size_t _InputArray::offset(int i) const return ((const UMat*)obj)->offset; } - if( k == EXPR || k == MATX || k == STD_VECTOR || + if( k == EXPR || k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == NONE || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR ) return 0; @@ -2139,6 +2239,15 @@ size_t _InputArray::offset(int i) const return (size_t)(vv[i].ptr() - vv[i].datastart); } + if( k == STD_ARRAY_MAT ) + { + const Mat* vv = (const Mat*)obj; + if( i < 0 ) + return 1; + CV_Assert( i < sz.height ); + return (size_t)(vv[i].ptr() - vv[i].datastart); + } + if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; @@ -2180,7 +2289,7 @@ size_t _InputArray::step(int i) const return ((const UMat*)obj)->step; } - if( k == EXPR || k == MATX || k == STD_VECTOR || + if( k == EXPR || k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == NONE || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR ) return 0; @@ -2193,6 +2302,15 @@ size_t _InputArray::step(int i) const return vv[i].step; } + if( k == STD_ARRAY_MAT ) + { + const Mat* vv = (const Mat*)obj; + if( i < 0 ) + return 1; + CV_Assert( i < sz.height ); + return vv[i].step; + } + if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; @@ -2222,7 +2340,7 @@ void _InputArray::copyTo(const _OutputArray& arr) const if( k == NONE ) arr.release(); - else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_BOOL_VECTOR ) + else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == STD_BOOL_VECTOR ) { Mat m = getMat(); m.copyTo(arr); @@ -2247,7 +2365,7 @@ void _InputArray::copyTo(const _OutputArray& arr, const _InputArray & mask) cons if( k == NONE ) arr.release(); - else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_BOOL_VECTOR ) + else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == STD_BOOL_VECTOR ) { Mat m = getMat(); m.copyTo(arr, mask); @@ -2436,6 +2554,14 @@ void _OutputArray::create(int d, const int* sizes, int mtype, int i, return; } + if( k == STD_ARRAY ) + { + int type0 = CV_MAT_TYPE(flags); + CV_Assert( mtype == type0 || (CV_MAT_CN(mtype) == 1 && ((1 << type0) & fixedDepthMask) != 0) ); + CV_Assert( d == 2 && sz.area() == sizes[0]*sizes[1]); + return; + } + if( k == STD_VECTOR || k == STD_VECTOR_VECTOR ) { CV_Assert( d == 2 && (sizes[0] == 1 || sizes[1] == 1 || sizes[0]*sizes[1] == 0) ); @@ -2583,6 +2709,65 @@ void _OutputArray::create(int d, const int* sizes, int mtype, int i, return; } + if( k == STD_ARRAY_MAT ) + { + Mat* v = (Mat*)obj; + + if( i < 0 ) + { + CV_Assert( d == 2 && (sizes[0] == 1 || sizes[1] == 1 || sizes[0]*sizes[1] == 0) ); + size_t len = sizes[0]*sizes[1] > 0 ? sizes[0] + sizes[1] - 1 : 0, len0 = sz.height; + + CV_Assert(len == len0); + if( fixedType() ) + { + int _type = CV_MAT_TYPE(flags); + for( size_t j = len0; j < len; j++ ) + { + if( v[j].type() == _type ) + continue; + CV_Assert( v[j].empty() ); + v[j].flags = (v[j].flags & ~CV_MAT_TYPE_MASK) | _type; + } + } + return; + } + + CV_Assert( i < sz.height ); + Mat& m = v[i]; + + if( allowTransposed ) + { + if( !m.isContinuous() ) + { + CV_Assert(!fixedType() && !fixedSize()); + m.release(); + } + + if( d == 2 && m.dims == 2 && m.data && + m.type() == mtype && m.rows == sizes[1] && m.cols == sizes[0] ) + return; + } + + if(fixedType()) + { + if(CV_MAT_CN(mtype) == m.channels() && ((1 << CV_MAT_TYPE(flags)) & fixedDepthMask) != 0 ) + mtype = m.type(); + else + CV_Assert(CV_MAT_TYPE(mtype) == m.type()); + } + + if(fixedSize()) + { + CV_Assert(m.dims == d); + for(int j = 0; j < d; ++j) + CV_Assert(m.size[j] == sizes[j]); + } + + m.create(d, sizes, mtype); + return; + } + if( k == STD_VECTOR_UMAT ) { std::vector& v = *(std::vector*)obj; @@ -2748,13 +2933,21 @@ Mat& _OutputArray::getMatRef(int i) const CV_Assert( k == MAT ); return *(Mat*)obj; } - else + + CV_Assert( k == STD_VECTOR_MAT || k == STD_ARRAY_MAT ); + + if( k == STD_VECTOR_MAT ) { - CV_Assert( k == STD_VECTOR_MAT ); std::vector& v = *(std::vector*)obj; CV_Assert( i < (int)v.size() ); return v[i]; } + else + { + Mat* v = (Mat*)obj; + CV_Assert( 0 <= i && i < sz.height ); + return v[i]; + } } UMat& _OutputArray::getUMatRef(int i) const @@ -2807,7 +3000,7 @@ void _OutputArray::setTo(const _InputArray& arr, const _InputArray & mask) const if( k == NONE ) ; - else if( k == MAT || k == MATX || k == STD_VECTOR ) + else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_ARRAY ) { Mat m = getMat(); m.setTo(arr, mask); diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 98ce812ee9..7f2451e842 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1634,3 +1634,95 @@ TEST(Mat, regression_7873_mat_vector_initialize) ASSERT_EQ(3, sub_mat.size[1]); ASSERT_EQ(2, sub_mat.size[2]); } + +#ifdef CV_CXX_STD_ARRAY +TEST(Core_Mat_array, outputArray_create_getMat) +{ + cv::Mat_ src_base(5, 1); + std::array dst8; + + src_base << 1, 2, 3, 4, 5; + + Mat src(src_base); + OutputArray _dst(dst8); + + { + _dst.create(src.rows, src.cols, src.type()); + Mat dst = _dst.getMat(); + EXPECT_EQ(src.dims, dst.dims); + EXPECT_EQ(src.cols, dst.cols); + EXPECT_EQ(src.rows, dst.rows); + } +} + +TEST(Core_Mat_array, copyTo_roi_column) +{ + cv::Mat_ src_base(5, 2); + + src_base << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; + + Mat src_full(src_base); + Mat src(src_full.col(0)); + + std::array dst1; + src.copyTo(dst1); + std::cout << "src = " << src << std::endl; + std::cout << "dst = " << Mat(dst1) << std::endl; + EXPECT_EQ((size_t)5, dst1.size()); + EXPECT_EQ(1, (int)dst1[0]); + EXPECT_EQ(3, (int)dst1[1]); + EXPECT_EQ(5, (int)dst1[2]); + EXPECT_EQ(7, (int)dst1[3]); + EXPECT_EQ(9, (int)dst1[4]); +} + +TEST(Core_Mat_array, copyTo_roi_row) +{ + cv::Mat_ src_base(2, 5); + std::array dst1; + + src_base << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; + + Mat src_full(src_base); + Mat src(src_full.row(0)); + OutputArray _dst(dst1); + { + _dst.create(5, 1, src.type()); + Mat dst = _dst.getMat(); + EXPECT_EQ(src.dims, dst.dims); + EXPECT_EQ(1, dst.cols); + EXPECT_EQ(5, dst.rows); + } + + std::array dst2; + src.copyTo(dst2); + std::cout << "src = " << src << std::endl; + std::cout << "dst = " << Mat(dst2) << std::endl; + EXPECT_EQ(1, (int)dst2[0]); + EXPECT_EQ(2, (int)dst2[1]); + EXPECT_EQ(3, (int)dst2[2]); + EXPECT_EQ(4, (int)dst2[3]); + EXPECT_EQ(5, (int)dst2[4]); +} + +TEST(Core_Mat_array, SplitMerge) +{ + std::array src; + for(size_t i=0; i dst; + split(merged, dst); + + Mat diff; + for(size_t i=0; i Date: Wed, 19 Apr 2017 23:20:17 +0300 Subject: [PATCH 103/144] got rid of Blob and BlobShape completely; use cv::Mat and std::vector instead --- .../core/include/opencv2/core/cvstd.inl.hpp | 11 +++++++ modules/core/include/opencv2/core/mat.hpp | 9 ++++++ modules/core/include/opencv2/core/mat.inl.hpp | 11 +++++++ modules/core/src/matrix.cpp | 30 +++++++++++++++---- 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/modules/core/include/opencv2/core/cvstd.inl.hpp b/modules/core/include/opencv2/core/cvstd.inl.hpp index 2a5b170f90..874364e3c1 100644 --- a/modules/core/include/opencv2/core/cvstd.inl.hpp +++ b/modules/core/include/opencv2/core/cvstd.inl.hpp @@ -270,6 +270,17 @@ std::ostream& operator << (std::ostream& out, const Rect_<_Tp>& rect) return out << "[" << rect.width << " x " << rect.height << " from (" << rect.x << ", " << rect.y << ")]"; } +static inline std::ostream& operator << (std::ostream& out, const MatSize& msize) +{ + int i, dims = msize.p[-1]; + for( i = 0; i < dims; i++ ) + { + out << msize.p[i]; + if( i < dims-1 ) + out << " x "; + } + return out; +} #endif // OPENCV_NOSTL } // cv diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index e3a24032d0..adebe81f98 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -1215,6 +1215,9 @@ public: /** @overload */ Mat reshape(int cn, int newndims, const int* newsz) const; + /** @overload */ + Mat reshape(int cn, const std::vector& newshape) const; + /** @brief Transposes a matrix. The method performs matrix transposition by means of matrix expressions. It does not perform the @@ -1717,6 +1720,12 @@ public: */ size_t total() const; + /** @brief Returns the total number of array elements. + + The method returns the number of elements within a certain sub-array slice with startDim <= dim < endDim + */ + size_t total(int startDim, int endDim=INT_MAX) const; + //! returns N if the matrix is 1-channel (N x ptdim) or ptdim-channel (1 x N) or (N x 1); negative number otherwise int checkVector(int elemChannels, int depth=-1, bool requireContinuous=true) const; diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index aa746e8807..5e214b7409 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -807,6 +807,17 @@ size_t Mat::total() const return p; } +inline +size_t Mat::total(int startDim, int endDim) const +{ + CV_Assert( 0 <= startDim && startDim <= endDim); + size_t p = 1; + int endDim_ = endDim <= dims ? endDim : dims; + for( int i = startDim; i < endDim_; i++ ) + p *= size[i]; + return p; +} + inline uchar* Mat::ptr(int y) { diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 2e479f7c56..13a4f9134e 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -1052,12 +1052,20 @@ Mat Mat::reshape(int new_cn, int new_rows) const int cn = channels(); Mat hdr = *this; - if( dims > 2 && new_rows == 0 && new_cn != 0 && size[dims-1]*cn % new_cn == 0 ) + if( dims > 2 ) { - hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT); - hdr.step[dims-1] = CV_ELEM_SIZE(hdr.flags); - hdr.size[dims-1] = hdr.size[dims-1]*cn / new_cn; - return hdr; + if( new_rows == 0 && new_cn != 0 && size[dims-1]*cn % new_cn == 0 ) + { + hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT); + hdr.step[dims-1] = CV_ELEM_SIZE(hdr.flags); + hdr.size[dims-1] = hdr.size[dims-1]*cn / new_cn; + return hdr; + } + if( new_rows > 0 ) + { + int sz[] = { new_rows, (int)(total()/new_rows) }; + return reshape(new_cn, 2, sz); + } } CV_Assert( dims <= 2 ); @@ -4482,6 +4490,18 @@ Mat Mat::reshape(int _cn, int _newndims, const int* _newsz) const return Mat(); } +Mat Mat::reshape(int _cn, const std::vector& _newshape) const +{ + if(_newshape.empty()) + { + CV_Assert(empty()); + return *this; + } + + return reshape(_cn, (int)_newshape.size(), &_newshape[0]); +} + + NAryMatIterator::NAryMatIterator() : arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0) { From 35c7216846ac1982e19e594e2144c11e16787c26 Mon Sep 17 00:00:00 2001 From: Pavel Vlasov Date: Thu, 13 Apr 2017 15:50:23 +0300 Subject: [PATCH 104/144] IPP for OpenCV 2017u2 initial enabling patch; --- 3rdparty/ippicv/CMakeLists.txt | 42 + 3rdparty/ippicv/ippicv.cmake | 31 +- CMakeLists.txt | 21 +- cmake/OpenCVFindIPP.cmake | 45 +- cmake/OpenCVFindIPPIW.cmake | 154 ++++ cmake/OpenCVFindLibsPerf.cmake | 5 + cmake/templates/cvconfig.h.in | 1 + modules/calib3d/src/stereosgbm.cpp | 48 +- modules/core/include/opencv2/core/base.hpp | 4 + modules/core/include/opencv2/core/private.hpp | 253 +++++- modules/core/perf/opencl/perf_matop.cpp | 2 +- modules/core/src/convert.cpp | 2 +- modules/core/src/copy.cpp | 8 +- modules/core/src/dxt.cpp | 36 +- modules/core/src/matrix.cpp | 367 ++++---- modules/core/src/system.cpp | 39 +- modules/imgproc/src/color.cpp | 796 ++++++++---------- modules/imgproc/src/deriv.cpp | 485 +++-------- modules/imgproc/src/distransform.cpp | 8 +- modules/imgproc/src/filter.cpp | 9 +- modules/imgproc/src/histogram.cpp | 275 +++--- modules/imgproc/src/imgwarp.cpp | 465 +++++----- modules/imgproc/src/morph.cpp | 406 +++++---- modules/imgproc/src/precomp.hpp | 13 + modules/imgproc/src/smooth.cpp | 221 ++--- modules/imgproc/src/templmatch.cpp | 197 +++-- modules/imgproc/test/test_filter.cpp | 2 +- 27 files changed, 2087 insertions(+), 1848 deletions(-) create mode 100644 3rdparty/ippicv/CMakeLists.txt create mode 100644 cmake/OpenCVFindIPPIW.cmake diff --git a/3rdparty/ippicv/CMakeLists.txt b/3rdparty/ippicv/CMakeLists.txt new file mode 100644 index 0000000000..b9fb79f10d --- /dev/null +++ b/3rdparty/ippicv/CMakeLists.txt @@ -0,0 +1,42 @@ +# ---------------------------------------------------------------------------- +# CMake file for IPP IW. See root CMakeLists.txt +# +# ---------------------------------------------------------------------------- +project(${IPP_IW_LIBRARY}) + +ocv_include_directories(${IPP_INCLUDE_DIRS} ${IPP_IW_PATH}/include) +add_definitions(-DIW_BUILD) +if(HAVE_IPP_ICV_ONLY) + add_definitions(-DICV_BASE) +endif() + +file(GLOB lib_srcs ${IPP_IW_PATH}/src/*.c) +file(GLOB lib_hdrs ${IPP_IW_PATH}/include/*.h ${IPP_IW_PATH}/include/iw/*.h ${IPP_IW_PATH}/include/iw++/*.hpp) + +# ---------------------------------------------------------------------------------- +# Define the library target: +# ---------------------------------------------------------------------------------- + +add_library(${IPP_IW_LIBRARY} STATIC ${lib_srcs} ${lib_hdrs}) + +if(UNIX) + if(CMAKE_COMPILER_IS_GNUCXX OR CV_ICC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wno-unused-function") + endif() +endif() + +set_target_properties(${IPP_IW_LIBRARY} + PROPERTIES OUTPUT_NAME ${IPP_IW_LIBRARY} + DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" + COMPILE_PDB_NAME ${IPP_IW_LIBRARY} + COMPILE_PDB_NAME_DEBUG "${IPP_IW_LIBRARY}${OPENCV_DEBUG_POSTFIX}" + ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH} + ) + +if(ENABLE_SOLUTION_FOLDERS) + set_target_properties(${IPP_IW_LIBRARY} PROPERTIES FOLDER "3rdparty") +endif() + +if(NOT BUILD_SHARED_LIBS) + ocv_install_target(${IPP_IW_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) +endif() diff --git a/3rdparty/ippicv/ippicv.cmake b/3rdparty/ippicv/ippicv.cmake index a477d60b8a..7cec77c4ee 100644 --- a/3rdparty/ippicv/ippicv.cmake +++ b/3rdparty/ippicv/ippicv.cmake @@ -2,23 +2,38 @@ function(download_ippicv root_var) set(${root_var} "" PARENT_SCOPE) # Commit SHA in the opencv_3rdparty repo - set(IPPICV_COMMIT "81a676001ca8075ada498583e4166079e5744668") + set(IPPICV_COMMIT "a62e20676a60ee0ad6581e217fe7e4bada3b95db") # Define actual ICV versions if(APPLE) - set(OPENCV_ICV_NAME "ippicv_macosx_20151201.tgz") - set(OPENCV_ICV_HASH "4ff1fde9a7cfdfe7250bfcd8334e0f2f") set(OPENCV_ICV_PLATFORM "macosx") - set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_osx") + set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_mac") + if(X86_64) + set(OPENCV_ICV_NAME "ippicv_2017u2_mac_intel64_20170418.tgz") + set(OPENCV_ICV_HASH "0c25953c99dbb499ff502485a9356d8d") + else() + set(OPENCV_ICV_NAME "ippicv_2017u2_mac_ia32_20170418.tgz") + set(OPENCV_ICV_HASH "5f225948f3f64067c681293c098d50d8") + endif() elseif((UNIX AND NOT ANDROID) OR (UNIX AND ANDROID_ABI MATCHES "x86")) - set(OPENCV_ICV_NAME "ippicv_linux_20151201.tgz") - set(OPENCV_ICV_HASH "808b791a6eac9ed78d32a7666804320e") set(OPENCV_ICV_PLATFORM "linux") set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_lnx") + if(X86_64) + set(OPENCV_ICV_NAME "ippicv_2017u2_lnx_intel64_20170418.tgz") + set(OPENCV_ICV_HASH "87cbdeb627415d8e4bc811156289fa3a") + else() + set(OPENCV_ICV_NAME "ippicv_2017u2_lnx_ia32_20170406.tgz") + set(OPENCV_ICV_HASH "f2cece00d802d4dea86df52ed095257e") + endif() elseif(WIN32 AND NOT ARM) - set(OPENCV_ICV_NAME "ippicv_windows_20151201.zip") - set(OPENCV_ICV_HASH "04e81ce5d0e329c3fbc606ae32cad44d") set(OPENCV_ICV_PLATFORM "windows") set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_win") + if(X86_64) + set(OPENCV_ICV_NAME "ippicv_2017u2_win_intel64_20170418.zip") + set(OPENCV_ICV_HASH "75060a0c662c0800f48995b7e9b085f6") + else() + set(OPENCV_ICV_NAME "ippicv_2017u2_win_ia32_20170418.zip") + set(OPENCV_ICV_HASH "60fcf3ccd9a2ebc9e432ffb5cb91638b") + endif() else() return() endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c913e0230..a340289a84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -270,6 +270,7 @@ OCV_OPTION(BUILD_JPEG "Build libjpeg from source" WIN32 O OCV_OPTION(BUILD_PNG "Build libpng from source" WIN32 OR ANDROID OR APPLE ) OCV_OPTION(BUILD_OPENEXR "Build openexr from source" (WIN32 OR ANDROID OR APPLE) AND NOT WINRT) OCV_OPTION(BUILD_TBB "Download and build TBB from source" ANDROID ) +OCV_OPTION(BUILD_IPP_IW "Build IPP IW from source" NOT MINGW IF (X86_64 OR X86) AND NOT WINRT ) # OpenCV installation options # =================================================== @@ -1238,17 +1239,27 @@ status("") status(" Other third-party libraries:") if(WITH_IPP AND HAVE_IPP) - status(" Use IPP:" "${IPP_VERSION_STR} [${IPP_VERSION_MAJOR}.${IPP_VERSION_MINOR}.${IPP_VERSION_BUILD}]") - status(" at:" "${IPP_ROOT_DIR}") + status(" Use Intel IPP:" "${IPP_VERSION_STR} [${IPP_VERSION_MAJOR}.${IPP_VERSION_MINOR}.${IPP_VERSION_BUILD}]") + status(" at:" "${IPP_ROOT_DIR}") if(NOT HAVE_IPP_ICV_ONLY) - status(" linked:" BUILD_WITH_DYNAMIC_IPP THEN "dynamic" ELSE "static") + status(" linked:" BUILD_WITH_DYNAMIC_IPP THEN "dynamic" ELSE "static") + endif() + if(HAVE_IPP_IW) + if(BUILD_IPP_IW) + status(" Use Intel IPP IW:" "build (${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE})") + else() + status(" Use Intel IPP IW:" "prebuilt binaries (${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE})") + endif() + else() + status(" Use Intel IPP IW:" NO) endif() else() - status(" Use IPP:" WITH_IPP AND NOT HAVE_IPP THEN "IPP not found or implicitly disabled" ELSE NO) + status(" Use Intel IPP:" WITH_IPP AND NOT HAVE_IPP THEN "IPP not found or implicitly disabled" ELSE NO) + status(" Use Intel IPP IW:" WITH_IPP AND NOT HAVE_IPP AND HAVE_IPP_IW THEN "IPP not found or implicitly disabled" ELSE NO) endif() if(DEFINED WITH_IPP_A) -status(" Use IPP Async:" HAVE_IPP_A THEN "YES" ELSE NO) +status(" Use Intel IPP Async:" HAVE_IPP_A THEN "YES" ELSE NO) endif(DEFINED WITH_IPP_A) if(DEFINED WITH_VA) diff --git a/cmake/OpenCVFindIPP.cmake b/cmake/OpenCVFindIPP.cmake index fd6b568baf..04b17f712e 100644 --- a/cmake/OpenCVFindIPP.cmake +++ b/cmake/OpenCVFindIPP.cmake @@ -35,7 +35,7 @@ unset(IPP_VERSION_MINOR) unset(IPP_VERSION_BUILD) if (X86 AND UNIX AND NOT APPLE AND NOT ANDROID AND BUILD_SHARED_LIBS) - message(STATUS "On 32-bit Linux IPP can not currently be used with dynamic libs because of linker errors. Set BUILD_SHARED_LIBS=OFF") + message(STATUS "On 32-bit Linux Intel IPP can not currently be used with dynamic libs because of linker errors. Set BUILD_SHARED_LIBS=OFF") return() endif() @@ -47,14 +47,14 @@ if(CMAKE_CL_64) set(IPP_X64 1) endif() -# This function detects IPP version by analyzing .h file +# This function detects Intel IPP version by analyzing .h file macro(ipp_get_version VERSION_FILE) unset(_VERSION_STR) unset(_MAJOR) unset(_MINOR) unset(_BUILD) - # read IPP version info from file + # read Intel IPP version info from file file(STRINGS ${VERSION_FILE} STR1 REGEX "IPP_VERSION_MAJOR") file(STRINGS ${VERSION_FILE} STR2 REGEX "IPP_VERSION_MINOR") file(STRINGS ${VERSION_FILE} STR3 REGEX "IPP_VERSION_BUILD") @@ -96,29 +96,29 @@ macro(ipp_detect_version) elseif(EXISTS ${IPP_ROOT_DIR}/include/ipp.h) # nothing else() - _ipp_not_supported("Can't resolve IPP directory: ${IPP_ROOT_DIR}") + _ipp_not_supported("Can't resolve Intel IPP directory: ${IPP_ROOT_DIR}") endif() ipp_get_version(${IPP_INCLUDE_DIRS}/ippversion.h) ocv_assert(IPP_VERSION_STR VERSION_GREATER "1.0") - message(STATUS "found IPP${__msg}: ${_MAJOR}.${_MINOR}.${_BUILD} [${IPP_VERSION_STR}]") + message(STATUS "found Intel IPP${__msg}: ${_MAJOR}.${_MINOR}.${_BUILD} [${IPP_VERSION_STR}]") message(STATUS "at: ${IPP_ROOT_DIR}") if(${IPP_VERSION_STR} VERSION_LESS "7.0") - _ipp_not_supported("IPP ${IPP_VERSION_STR} is not supported") + _ipp_not_supported("Intel IPP ${IPP_VERSION_STR} is not supported") endif() set(HAVE_IPP 1) macro(_ipp_set_library_dir DIR) if(NOT EXISTS ${DIR}) - _ipp_not_supported("IPP library directory not found") + _ipp_not_supported("Intel IPP library directory not found") endif() set(IPP_LIBRARY_DIR ${DIR}) endmacro() - if(APPLE) + if(APPLE AND NOT HAVE_IPP_ICV_ONLY) _ipp_set_library_dir(${IPP_ROOT_DIR}/lib) elseif(IPP_X64) _ipp_set_library_dir(${IPP_ROOT_DIR}/lib/intel64) @@ -127,7 +127,7 @@ macro(ipp_detect_version) endif() macro(_ipp_add_library name) - # dynamic linking is only supported for standalone version of IPP + # dynamic linking is only supported for standalone version of Intel IPP if (BUILD_WITH_DYNAMIC_IPP AND NOT HAVE_IPP_ICV_ONLY) if (WIN32) set(IPP_LIB_PREFIX ${CMAKE_IMPORT_LIBRARY_PREFIX}) @@ -142,7 +142,7 @@ macro(ipp_detect_version) endif () if (EXISTS ${IPP_LIBRARY_DIR}/${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX}) if (BUILD_WITH_DYNAMIC_IPP AND NOT HAVE_IPP_ICV_ONLY) - # When using dynamic libraries from standalone IPP it is your responsibility to install those on the target system + # When using dynamic libraries from standalone Intel IPP it is your responsibility to install those on the target system list(APPEND IPP_LIBRARIES ${IPP_LIBRARY_DIR}/${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX}) else () add_library(ipp${name} STATIC IMPORTED) @@ -161,33 +161,32 @@ macro(ipp_detect_version) endif() endif() else() - message(STATUS "Can't find IPP library: ${name} at ${IPP_LIBRARY_DIR}/${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX}") + message(STATUS "Can't find Intel IPP library: ${name} at ${IPP_LIBRARY_DIR}/${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX}") endif() endmacro() set(IPP_PREFIX "ipp") if(${IPP_VERSION_STR} VERSION_LESS "8.0") if (BUILD_WITH_DYNAMIC_IPP AND NOT HAVE_IPP_ICV_ONLY) - set(IPP_SUFFIX "") # dynamic not threaded libs suffix IPP 7.x + set(IPP_SUFFIX "") # dynamic not threaded libs suffix Intel IPP 7.x else () - set(IPP_SUFFIX "_l") # static not threaded libs suffix IPP 7.x + set(IPP_SUFFIX "_l") # static not threaded libs suffix Intel IPP 7.x endif () else () if(WIN32) if (BUILD_WITH_DYNAMIC_IPP AND NOT HAVE_IPP_ICV_ONLY) - set(IPP_SUFFIX "") # dynamic not threaded libs suffix IPP 8.x for Windows + set(IPP_SUFFIX "") # dynamic not threaded libs suffix Intel IPP 8.x for Windows else () - set(IPP_SUFFIX "mt") # static not threaded libs suffix IPP 8.x for Windows + set(IPP_SUFFIX "mt") # static not threaded libs suffix Intel IPP 8.x for Windows endif () else() - set(IPP_SUFFIX "") # static not threaded libs suffix IPP 8.x for Linux/OS X + set(IPP_SUFFIX "") # static not threaded libs suffix Intel IPP 8.x for Linux/OS X endif() endif() if(HAVE_IPP_ICV_ONLY) _ipp_add_library(icv) else() - _ipp_add_library(m) _ipp_add_library(cv) _ipp_add_library(i) _ipp_add_library(cc) @@ -201,7 +200,7 @@ macro(ipp_detect_version) get_filename_component(INTEL_COMPILER_LIBRARY_DIR ${IPP_ROOT_DIR}/../compiler/lib REALPATH) endif() if(NOT EXISTS ${INTEL_COMPILER_LIBRARY_DIR}) - _ipp_not_supported("IPP configuration error: can't find Intel compiler library dir ${INTEL_COMPILER_LIBRARY_DIR}") + _ipp_not_supported("Intel IPP configuration error: can't find Intel compiler library dir ${INTEL_COMPILER_LIBRARY_DIR}") endif() if(NOT APPLE) if(IPP_X64) @@ -231,7 +230,7 @@ macro(ipp_detect_version) endif() endif() - #message(STATUS "IPP libs: ${IPP_LIBRARIES}") + #message(STATUS "Intel IPP libs: ${IPP_LIBRARIES}") endmacro() # OPENCV_IPP_PATH is an environment variable for internal usage only, do not use it @@ -240,12 +239,6 @@ if(DEFINED ENV{OPENCV_IPP_PATH} AND NOT DEFINED IPPROOT) endif() if(NOT DEFINED IPPROOT) - if(IOS AND NOT x86_64) - # 2016/10: There is an issue with MacOS binary .a file. - # It is fat multiarch library, and can't be "merged" multiple times. - # So try to ignore i386 version - return() - endif() include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/ippicv.cmake") download_ippicv(IPPROOT) if(NOT IPPROOT) @@ -261,7 +254,7 @@ endif() if(WIN32 AND MINGW AND NOT IPP_VERSION_MAJOR LESS 7) - # Since IPP built with Microsoft compiler and /GS option + # Since Intel IPP built with Microsoft compiler and /GS option # ====================================================== # From Windows SDK 7.1 # (usually in "C:\Program Files\Microsoft Visual Studio 10.0\VC\lib"), diff --git a/cmake/OpenCVFindIPPIW.cmake b/cmake/OpenCVFindIPPIW.cmake new file mode 100644 index 0000000000..e74c2fb324 --- /dev/null +++ b/cmake/OpenCVFindIPPIW.cmake @@ -0,0 +1,154 @@ +# +# The script to detect Intel(R) Integrated Performance Primitives Integration Wrappers (IPP IW) +# installation/package +# +# +# On return this will define: +# +# HAVE_IPP_IW - True if Intel IPP found +# IPP_IW_PATH - Root of Intel IPP IW directory +# IPP_IW_LIBRARIES - Intel IPP IW libraries +# IPP_IW_INCLUDES - Intel IPP IW include folder +# + +unset(HAVE_IPP_IW CACHE) +unset(IPP_IW_PATH) +unset(IPP_IW_LIBRARIES) +unset(IPP_IW_INCLUDES) +unset(IW_CONFIG_DEBUG) +#set(IW_CONFIG_DEBUG 1) + +if(NOT HAVE_IPP) + return() +endif() + +macro(ippiw_debugmsg MESSAGE) + if(DEFINED IW_CONFIG_DEBUG) + message(STATUS "${MESSAGE}") + endif() +endmacro() + +# This function detects Intel IPP IW version by analyzing .h file +macro(ippiw_setup PATH BUILD) + set(FILE "${PATH}/include/iw/iw_version.h") + ippiw_debugmsg("Checking path: ${PATH}") + if(EXISTS "${FILE}") + ippiw_debugmsg("vfile\tok") + file(STRINGS "${FILE}" IW_VERSION_MAJOR REGEX "IW_VERSION_MAJOR") + file(STRINGS "${FILE}" IW_VERSION_MINOR REGEX "IW_VERSION_MINOR") + file(STRINGS "${FILE}" IW_VERSION_UPDATE REGEX "IW_VERSION_UPDATE") + + file(STRINGS "${FILE}" IW_MIN_COMPATIBLE_IPP_MAJOR REGEX "IW_MIN_COMPATIBLE_IPP_MAJOR") + file(STRINGS "${FILE}" IW_MIN_COMPATIBLE_IPP_MINOR REGEX "IW_MIN_COMPATIBLE_IPP_MINOR") + file(STRINGS "${FILE}" IW_MIN_COMPATIBLE_IPP_UPDATE REGEX "IW_MIN_COMPATIBLE_IPP_UPDATE") + + string(REGEX MATCH "[0-9]+" IW_MIN_COMPATIBLE_IPP_MAJOR ${IW_MIN_COMPATIBLE_IPP_MAJOR}) + string(REGEX MATCH "[0-9]+" IW_MIN_COMPATIBLE_IPP_MINOR ${IW_MIN_COMPATIBLE_IPP_MINOR}) + string(REGEX MATCH "[0-9]+" IW_MIN_COMPATIBLE_IPP_UPDATE ${IW_MIN_COMPATIBLE_IPP_UPDATE}) + + string(REGEX MATCH "[0-9]+" IW_VERSION_MAJOR ${IW_VERSION_MAJOR}) + string(REGEX MATCH "[0-9]+" IW_VERSION_MINOR ${IW_VERSION_MINOR}) + string(REGEX MATCH "[0-9]+" IW_VERSION_UPDATE ${IW_VERSION_UPDATE}) + + math(EXPR IPP_VERSION_EXP "${IPP_VERSION_MAJOR}*10000 + ${IPP_VERSION_MINOR}*100 + ${IPP_VERSION_BUILD}") + math(EXPR IW_MIN_COMPATIBLE_IPP_EXP "${IW_MIN_COMPATIBLE_IPP_MAJOR}*10000 + ${IW_MIN_COMPATIBLE_IPP_MINOR}*100 + ${IW_MIN_COMPATIBLE_IPP_UPDATE}") + + if((IPP_VERSION_EXP GREATER IW_MIN_COMPATIBLE_IPP_EXP) OR (IPP_VERSION_EXP EQUAL IW_MIN_COMPATIBLE_IPP_EXP)) + ippiw_debugmsg("version\tok") + if(${BUILD}) + # check sources + if(EXISTS "${PATH}/src/iw_core.c") + ippiw_debugmsg("sources\tok") + set(IPP_IW_PATH "${PATH}") + message(STATUS "found Intel IPP IW sources: ${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE}") + message(STATUS "at: ${IPP_IW_PATH}") + + set(IPP_IW_LIBRARY ippiw) + set(IPP_IW_INCLUDES "${IPP_IW_PATH}/include") + set(IPP_IW_LIBRARIES ${IPP_IW_LIBRARY}) + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OpenCV_SOURCE_DIR}/3rdparty/ippicv/CMakeLists.txt" "${IPP_IW_PATH}/") + add_subdirectory("${IPP_IW_PATH}/" ${OpenCV_BINARY_DIR}/3rdparty/ippiw) + set(HAVE_IPP_IW 1) + return() + endif() + else() + # check binaries + if(IPP_X64) + set(FILE "${PATH}/lib/intel64/${CMAKE_STATIC_LIBRARY_PREFIX}ipp_iw${CMAKE_STATIC_LIBRARY_SUFFIX}") + else() + set(FILE "${PATH}/lib/ia32/${CMAKE_STATIC_LIBRARY_PREFIX}ipp_iw${CMAKE_STATIC_LIBRARY_SUFFIX}") + endif() + if(EXISTS ${FILE}) + ippiw_debugmsg("binaries\tok (64=${IPP_X64})") + set(IPP_IW_PATH "${PATH}") + message(STATUS "found Intel IPP IW binaries: ${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE}") + message(STATUS "at: ${IPP_IW_PATH}") + + set(IPP_IW_INCLUDES "${IPP_IW_PATH}/include") + set(IPP_IW_LIBRARIES ${FILE}) + set(HAVE_IPP_IW 1) + set(BUILD_IPP_IW 0) + return() + endif() + endif() + endif() + endif() + set(HAVE_IPP_IW 0) +endmacro() + +# check os and architecture +if(APPLE) + set(IW_PACKAGE_SUBDIR "ippiw_mac") +elseif((UNIX AND NOT ANDROID) OR (UNIX AND ANDROID_ABI MATCHES "x86")) + set(IW_PACKAGE_SUBDIR "ippiw_lnx") +elseif(WIN32 AND NOT ARM) + set(IW_PACKAGE_SUBDIR "ippiw_win") +else() + message(SEND_ERROR "Improper system for Intel IPP Integrations Wrappers. This message shouldn't appera. Check Intel IPP configurations steps") + return() +endif() + +# check build options first +if(BUILD_IPP_IW) + # custom path + if(DEFINED IPPIWROOT) + ippiw_setup("${IPPIWROOT}/" 1) + message(STATUS "Can't find Intel IPP IW sources at: ${IPPIWROOT}") + endif() + + # local sources + ippiw_setup("${OpenCV_SOURCE_DIR}/3rdparty/ippiw" 1) + + # Package sources + ippiw_setup("${IPPROOT}/../${IW_PACKAGE_SUBDIR}/" 1) +endif() + + +# custom binaries +if(DEFINED IPPIWROOT) + ippiw_setup("${IPPIWROOT}/" 0) + message(STATUS "Can't find Intel IPP IW sources at: ${IPPIWROOT}") +endif() + +# check binaries in IPP folder +ippiw_setup("${IPPROOT}/" 0) + +# check binaries near IPP folder +ippiw_setup("${IPPROOT}/../${IW_PACKAGE_SUBDIR}/" 0) + + +# take Intel IPP IW from ICV package +if(NOT HAVE_IPP_ICV_ONLY AND BUILD_IPP_IW) + message(STATUS "Cannot find Intel IPP IW. Checking \"Intel IPP for OpenCV\" package") + set(TEMP_ROOT 0) + include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/ippicv.cmake") + download_ippicv(TEMP_ROOT) + + # Package sources. Only sources are compatible with regular Intel IPP + ippiw_setup("${TEMP_ROOT}/../${IW_PACKAGE_SUBDIR}/" 1) +endif() + + +set(HAVE_IPP_IW 0) +message(STATUS "Cannot find Intel IPP Integration Wrappers, optimizations will be limited. Use IPPIWROOT to set custom location") +return() diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake index 70b6cf543e..d19fc947e9 100644 --- a/cmake/OpenCVFindLibsPerf.cmake +++ b/cmake/OpenCVFindLibsPerf.cmake @@ -36,6 +36,11 @@ endif(WITH_TBB) if(WITH_IPP) include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindIPP.cmake") if(HAVE_IPP) + include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindIPPIW.cmake") + if(HAVE_IPP_IW) + ocv_include_directories(${IPP_IW_INCLUDES}) + list(APPEND OPENCV_LINKER_LIBS ${IPP_IW_LIBRARIES}) + endif() ocv_include_directories(${IPP_INCLUDE_DIRS}) list(APPEND OPENCV_LINKER_LIBS ${IPP_LIBRARIES}) endif() diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in index f20ff0c174..267aebf513 100644 --- a/cmake/templates/cvconfig.h.in +++ b/cmake/templates/cvconfig.h.in @@ -101,6 +101,7 @@ /* Intel Integrated Performance Primitives */ #cmakedefine HAVE_IPP #cmakedefine HAVE_IPP_ICV_ONLY +#cmakedefine HAVE_IPP_IW /* Intel IPP Async */ #cmakedefine HAVE_IPP_A diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp index d5c160b0fc..eca3c06303 100644 --- a/modules/calib3d/src/stereosgbm.cpp +++ b/modules/calib3d/src/stereosgbm.cpp @@ -1705,43 +1705,37 @@ void filterSpecklesImpl(cv::Mat& img, int newVal, int maxSpeckleSize, int maxDif } #ifdef HAVE_IPP -static bool ipp_filterSpeckles(Mat &img, int maxSpeckleSize, int newVal, int maxDiff) +static bool ipp_filterSpeckles(Mat &img, int maxSpeckleSize, int newVal, int maxDiff, Mat &buffer) { +#if IPP_VERSION_X100 >= 810 CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 810 - int type = img.type(); - Ipp32s bufsize = 0; - IppiSize roisize = { img.cols, img.rows }; - IppDataType datatype = type == CV_8UC1 ? ipp8u : ipp16s; - Ipp8u *pBuffer = NULL; - IppStatus status = ippStsNoErr; + IppDataType dataType = ippiGetDataType(img.depth()); + IppiSize size = ippiSize(img.size()); + int bufferSize; - if(ippiMarkSpecklesGetBufferSize(roisize, datatype, CV_MAT_CN(type), &bufsize) < 0) + if(img.channels() != 1) return false; - pBuffer = (Ipp8u*)ippMalloc(bufsize); - if(!pBuffer && bufsize) + if(dataType != ipp8u && dataType != ipp16s) return false; - if (type == CV_8UC1) - { - status = CV_INSTRUMENT_FUN_IPP(ippiMarkSpeckles_8u_C1IR, img.ptr(), (int)img.step, roisize, - (Ipp8u)newVal, maxSpeckleSize, (Ipp8u)maxDiff, ippiNormL1, pBuffer); - } - else - { - status = CV_INSTRUMENT_FUN_IPP(ippiMarkSpeckles_16s_C1IR, img.ptr(), (int)img.step, roisize, - (Ipp16s)newVal, maxSpeckleSize, (Ipp16s)maxDiff, ippiNormL1, pBuffer); - } - if(pBuffer) ippFree(pBuffer); + if(ippiMarkSpecklesGetBufferSize(size, dataType, 1, &bufferSize) < 0) + return false; - if (status >= 0) - return true; + if(bufferSize && (buffer.empty() || (int)(buffer.step*buffer.rows) < bufferSize)) + buffer.create(1, (int)bufferSize, CV_8U); + + switch(dataType) + { + case ipp8u: return CV_INSTRUMENT_FUN_IPP(ippiMarkSpeckles_8u_C1IR, img.ptr(), (int)img.step, size, (Ipp8u)newVal, maxSpeckleSize, (Ipp8u)maxDiff, ippiNormL1, buffer.ptr()) >= 0; + case ipp16s: return CV_INSTRUMENT_FUN_IPP(ippiMarkSpeckles_16s_C1IR, img.ptr(), (int)img.step, size, (Ipp16s)newVal, maxSpeckleSize, (Ipp16s)maxDiff, ippiNormL1, buffer.ptr()) >= 0; + default: return false; + } #else - CV_UNUSED(img); CV_UNUSED(maxSpeckleSize); CV_UNUSED(newVal); CV_UNUSED(maxDiff); -#endif + CV_UNUSED(img); CV_UNUSED(maxSpeckleSize); CV_UNUSED(newVal); CV_UNUSED(maxDiff); CV_UNUSED(buffer); return false; +#endif } #endif @@ -1759,7 +1753,7 @@ void cv::filterSpeckles( InputOutputArray _img, double _newval, int maxSpeckleSi int newVal = cvRound(_newval), maxDiff = cvRound(_maxDiff); - CV_IPP_RUN(IPP_VERSION_X100 >= 810 && !__buf.needed() && (type == CV_8UC1 || type == CV_16SC1), ipp_filterSpeckles(img, maxSpeckleSize, newVal, maxDiff)); + CV_IPP_RUN_FAST(ipp_filterSpeckles(img, maxSpeckleSize, newVal, maxDiff, _buf)); if (type == CV_8UC1) filterSpecklesImpl(img, newVal, maxSpeckleSize, maxDiff, _buf); diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index 07ca3a51a1..ec961f0575 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -671,7 +671,11 @@ namespace cudev namespace ipp { +#if OPENCV_ABI_COMPATIBILITY > 300 +CV_EXPORTS unsigned long long getIppFeatures(); +#else CV_EXPORTS int getIppFeatures(); +#endif CV_EXPORTS void setIppStatus(int status, const char * const funcname = NULL, const char * const filename = NULL, int line = 0); CV_EXPORTS int getIppStatus(); diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp index c43bd727e7..50b5de2ac8 100644 --- a/modules/core/include/opencv2/core/private.hpp +++ b/modules/core/include/opencv2/core/private.hpp @@ -185,28 +185,78 @@ CV_EXPORTS void scalarToRawData(const cv::Scalar& s, void* buf, int type, int un * Structures and macros for integration with IPP * \****************************************************************************************/ -#ifdef HAVE_IPP -#include "ipp.h" +// Temporary disabled named IPP region. Accuracy +#define IPP_DISABLE_PYRAMIDS_UP 1 // Different results +#define IPP_DISABLE_PYRAMIDS_DOWN 1 // Different results +#define IPP_DISABLE_PYRAMIDS_BUILD 1 // Different results +#define IPP_DISABLE_WARPAFFINE 1 // Different results +#define IPP_DISABLE_WARPPERSPECTIVE 1 // Different results +#define IPP_DISABLE_REMAP 1 // Different results +#define IPP_DISABLE_MORPH_ADV 1 // mask flipping in IPP +#define IPP_DISABLE_SORT_IDX 0 // different order in index tables +#define IPP_DISABLE_YUV_RGB 1 // accuracy difference +#define IPP_DISABLE_RGB_YUV 1 // breaks OCL accuracy tests +#define IPP_DISABLE_RGB_HSV 1 // breaks OCL accuracy tests +#define IPP_DISABLE_RGB_LAB 1 // breaks OCL accuracy tests +#define IPP_DISABLE_LAB_RGB 1 // breaks OCL accuracy tests +#define IPP_DISABLE_RGB_XYZ 1 // big accuracy difference +#define IPP_DISABLE_XYZ_RGB 1 // big accuracy difference +#define IPP_DISABLE_HAAR 1 // improper integration/results +#define IPP_DISABLE_HOUGH 1 // improper integration/results +#define IPP_DISABLE_RESIZE_8U 1 // Incompatible accuracy +#define IPP_DISABLE_RESIZE_NEAREST 1 // Accuracy mismatch (max diff 1) +#define IPP_DISABLE_RESIZE_AREA 1 // Accuracy mismatch (max diff 1) +// Temporary disabled named IPP region. Performance +#define IPP_DISABLE_PERF_COPYMAKE 1 // performance variations +#define IPP_DISABLE_PERF_LUT 1 // there are no performance benefits (PR #2653) +#define IPP_DISABLE_PERF_TRUE_DIST_MT 1 // cv::distanceTransform OpenCV MT performance is better +#define IPP_DISABLE_PERF_CANNY_MT 1 // cv::Canny OpenCV MT performance is better +#define IPP_DISABLE_PERF_HISTU32F_SSE42 1 // cv::calcHist optimizations problem +#define IPP_DISABLE_PERF_MORPH_SSE42 1 // cv::erode, cv::dilate optimizations problem +#define IPP_DISABLE_PERF_MAG_SSE42 1 // cv::magnitude optimizations problem +#define IPP_DISABLE_PERF_BOX16S_SSE42 1 // cv::boxFilter optimizations problem + +#define IPP_DISABLE_BLOCK 0 // legacy switch + +#ifdef HAVE_IPP +#include "ippversion.h" #ifndef IPP_VERSION_UPDATE // prior to 7.1 #define IPP_VERSION_UPDATE 0 #endif #define IPP_VERSION_X100 (IPP_VERSION_MAJOR * 100 + IPP_VERSION_MINOR*10 + IPP_VERSION_UPDATE) -// General define for ipp function disabling -#define IPP_DISABLE_BLOCK 0 +#ifdef HAVE_IPP_ICV_ONLY +#define ICV_BASE +#if IPP_VERSION_X100 >= 201700 +#include "ippicv.h" +#else +#include "ipp.h" +#endif +#else +#include "ipp.h" +#endif +#ifdef HAVE_IPP_IW +#include "iw++/iw.hpp" +#endif #ifdef CV_MALLOC_ALIGN #undef CV_MALLOC_ALIGN #endif #define CV_MALLOC_ALIGN 32 // required for AVX optimization +#if IPP_VERSION_X100 >= 201700 +#define CV_IPP_MALLOC(SIZE) ippMalloc_L(SIZE) +#else +#define CV_IPP_MALLOC(SIZE) ippMalloc((int)SIZE) +#endif + #define setIppErrorStatus() cv::ipp::setIppStatus(-1, CV_Func, __FILE__, __LINE__) -static inline IppiSize ippiSize(int width, int height) +static inline IppiSize ippiSize(size_t width, size_t height) { - IppiSize size = { width, height }; + IppiSize size = { (int)width, (int)height }; return size; } @@ -216,6 +266,20 @@ static inline IppiSize ippiSize(const cv::Size & _size) return size; } +#if IPP_VERSION_X100 >= 201700 +static inline IppiSizeL ippiSizeL(size_t width, size_t height) +{ + IppiSizeL size = { (IppSizeL)width, (IppSizeL)height }; + return size; +} + +static inline IppiSizeL ippiSizeL(const cv::Size & _size) +{ + IppiSizeL size = { _size.width, _size.height }; + return size; +} +#endif + static inline IppiPoint ippiPoint(const cv::Point & _point) { IppiPoint point = { _point.x, _point.y }; @@ -230,34 +294,177 @@ static inline IppiPoint ippiPoint(int x, int y) static inline IppiBorderType ippiGetBorderType(int borderTypeNI) { - return borderTypeNI == cv::BORDER_CONSTANT ? ippBorderConst : - borderTypeNI == cv::BORDER_WRAP ? ippBorderWrap : - borderTypeNI == cv::BORDER_REPLICATE ? ippBorderRepl : - borderTypeNI == cv::BORDER_REFLECT_101 ? ippBorderMirror : - borderTypeNI == cv::BORDER_REFLECT ? ippBorderMirrorR : (IppiBorderType)-1; + return borderTypeNI == cv::BORDER_CONSTANT ? ippBorderConst : + borderTypeNI == cv::BORDER_TRANSPARENT ? ippBorderTransp : + borderTypeNI == cv::BORDER_REPLICATE ? ippBorderRepl : + borderTypeNI == cv::BORDER_REFLECT_101 ? ippBorderMirror : + (IppiBorderType)-1; +} + +static inline IppiMaskSize ippiGetMaskSize(int kx, int ky) +{ + return (kx == 1 && ky == 3) ? ippMskSize1x3 : + (kx == 1 && ky == 5) ? ippMskSize1x5 : + (kx == 3 && ky == 1) ? ippMskSize3x1 : + (kx == 3 && ky == 3) ? ippMskSize3x3 : + (kx == 5 && ky == 1) ? ippMskSize5x1 : + (kx == 5 && ky == 5) ? ippMskSize5x5 : + (IppiMaskSize)-1; } static inline IppDataType ippiGetDataType(int depth) { + depth = CV_MAT_DEPTH(depth); return depth == CV_8U ? ipp8u : depth == CV_8S ? ipp8s : depth == CV_16U ? ipp16u : depth == CV_16S ? ipp16s : depth == CV_32S ? ipp32s : depth == CV_32F ? ipp32f : - depth == CV_64F ? ipp64f : (IppDataType)-1; + depth == CV_64F ? ipp64f : + (IppDataType)-1; } -// IPP temporary buffer hepler +#ifdef HAVE_IPP_IW +static inline IwiDerivativeType ippiGetDerivType(int dx, int dy, bool nvert) +{ + return (dx == 1 && dy == 0) ? ((nvert)?iwiDerivNVerFirst:iwiDerivVerFirst) : + (dx == 0 && dy == 1) ? iwiDerivHorFirst : + (dx == 2 && dy == 0) ? iwiDerivVerSecond : + (dx == 0 && dy == 2) ? iwiDerivHorSecond : + (IwiDerivativeType)-1; +} + +static inline void ippiGetImage(const cv::Mat &src, ::ipp::IwiImage &dst) +{ + ::ipp::IwiBorderSize inMemBorder; + if(src.isSubmatrix()) // already have physical border + { + cv::Size origSize; + cv::Point offset; + src.locateROI(origSize, offset); + + inMemBorder.borderLeft = (Ipp32u)offset.x; + inMemBorder.borderTop = (Ipp32u)offset.y; + inMemBorder.borderRight = (Ipp32u)(origSize.width - src.cols - offset.x); + inMemBorder.borderBottom = (Ipp32u)(origSize.height - src.rows - offset.y); + } + + dst.Init(ippiSize(src.size()), ippiGetDataType(src.depth()), src.channels(), inMemBorder, (void*)src.ptr(), src.step); +} + +static inline ::ipp::IwiImage ippiGetImage(const cv::Mat &src) +{ + ::ipp::IwiImage image; + ippiGetImage(src, image); + return image; +} + +static inline IppiBorderType ippiGetBorder(::ipp::IwiImage &image, int ocvBorderType, IppiBorderSize &borderSize) +{ + int inMemFlags = 0; + IppiBorderType border = ippiGetBorderType(ocvBorderType & ~cv::BORDER_ISOLATED); + if((int)border == -1) + return (IppiBorderType)0; + + if(!(ocvBorderType & cv::BORDER_ISOLATED)) + { + if(image.m_inMemSize.borderLeft) + { + if(image.m_inMemSize.borderLeft >= borderSize.borderLeft) + inMemFlags |= ippBorderInMemLeft; + else + return (IppiBorderType)0; + } + else + borderSize.borderLeft = 0; + if(image.m_inMemSize.borderTop) + { + if(image.m_inMemSize.borderTop >= borderSize.borderTop) + inMemFlags |= ippBorderInMemTop; + else + return (IppiBorderType)0; + } + else + borderSize.borderTop = 0; + if(image.m_inMemSize.borderRight) + { + if(image.m_inMemSize.borderRight >= borderSize.borderRight) + inMemFlags |= ippBorderInMemRight; + else + return (IppiBorderType)0; + } + else + borderSize.borderRight = 0; + if(image.m_inMemSize.borderBottom) + { + if(image.m_inMemSize.borderBottom >= borderSize.borderBottom) + inMemFlags |= ippBorderInMemBottom; + else + return (IppiBorderType)0; + } + else + borderSize.borderBottom = 0; + } + else + borderSize.borderLeft = borderSize.borderRight = borderSize.borderTop = borderSize.borderBottom = 0; + + return (IppiBorderType)(border|inMemFlags); +} + +static inline ::ipp::IwValue ippiGetValue(const cv::Scalar &scalar) +{ + return ::ipp::IwValue(scalar[0], scalar[1], scalar[2], scalar[3]); +} + +static inline int ippiSuggestThreadsNum(const ::ipp::IwiImage &image, double multiplier) +{ + int threads = cv::getNumThreads(); + if(image.m_size.height > threads) + { + size_t opMemory = (int)(image.m_step*image.m_size.height*multiplier); + int l2cache = 0; +#if IPP_VERSION_X100 >= 201700 + ippGetL2CacheSize(&l2cache); +#endif + if(!l2cache) + l2cache = 1 << 18; + + return IPP_MAX(1, (IPP_MIN((int)(opMemory/l2cache), threads))); + } + return 1; +} +#endif + +static inline int ippiSuggestThreadsNum(const cv::Mat &image, double multiplier) +{ + int threads = cv::getNumThreads(); + if(image.rows > threads) + { + size_t opMemory = (int)(image.total()*multiplier); + int l2cache = 0; +#if IPP_VERSION_X100 >= 201700 + ippGetL2CacheSize(&l2cache); +#endif + if(!l2cache) + l2cache = 1 << 18; + + return IPP_MAX(1, (IPP_MIN((int)(opMemory/l2cache), threads))); + } + return 1; +} + +// IPP temporary buffer helper template class IppAutoBuffer { public: - IppAutoBuffer() { m_pBuffer = NULL; } - IppAutoBuffer(int size) { Alloc(size); } - ~IppAutoBuffer() { Release(); } - T* Alloc(int size) { m_pBuffer = (T*)ippMalloc(size); return m_pBuffer; } - void Release() { if(m_pBuffer) ippFree(m_pBuffer); } + IppAutoBuffer() { m_size = 0; m_pBuffer = NULL; } + IppAutoBuffer(size_t size) { m_size = 0; m_pBuffer = NULL; allocate(size); } + ~IppAutoBuffer() { deallocate(); } + T* allocate(size_t size) { if(m_size < size) { deallocate(); m_pBuffer = (T*)CV_IPP_MALLOC(size); m_size = size; } return m_pBuffer; } + void deallocate() { if(m_pBuffer) { ippFree(m_pBuffer); m_pBuffer = NULL; } m_size = 0; } + inline T* get() { return (T*)m_pBuffer;} inline operator T* () { return (T*)m_pBuffer;} inline operator const T* () const { return (const T*)m_pBuffer;} private: @@ -265,9 +472,17 @@ private: IppAutoBuffer(IppAutoBuffer &) {} IppAutoBuffer& operator =(const IppAutoBuffer &) {return *this;} - T* m_pBuffer; + size_t m_size; + T* m_pBuffer; }; +// Extracts border interpolation type without flags +#if IPP_VERSION_MAJOR >= 2017 +#define IPP_BORDER_INTER(BORDER) (IppiBorderType)((BORDER)&0xF|((((BORDER)&ippBorderInMem) == ippBorderInMem)?ippBorderInMem:0)); +#else +#define IPP_BORDER_INTER(BORDER) (IppiBorderType)((BORDER)&0xF); +#endif + #else #define IPP_VERSION_X100 0 #endif diff --git a/modules/core/perf/opencl/perf_matop.cpp b/modules/core/perf/opencl/perf_matop.cpp index 0fd5d437c4..8c39a91f0f 100644 --- a/modules/core/perf/opencl/perf_matop.cpp +++ b/modules/core/perf/opencl/perf_matop.cpp @@ -139,7 +139,7 @@ OCL_PERF_TEST_P(CopyToFixture, CopyToWithMaskUninit, dst.release(); startTimer(); src.copyTo(dst, mask); - cv::ocl::finish(); + cvtest::ocl::perf::safeFinish(); stopTimer(); } diff --git a/modules/core/src/convert.cpp b/modules/core/src/convert.cpp index 6c060f9c9c..b1e9af36d9 100644 --- a/modules/core/src/convert.cpp +++ b/modules/core/src/convert.cpp @@ -5512,7 +5512,7 @@ public: size_t elemSize1 = dst.elemSize1(); CV_DbgAssert(elemSize1 == 1); - lutBuffer = (uchar*)ippMalloc(256 * (int)elemSize1 * 4); + lutBuffer = (uchar*)CV_IPP_MALLOC(256 * (int)elemSize1 * 4); lutTable[0] = lutBuffer + 0; lutTable[1] = lutBuffer + 1 * 256 * elemSize1; lutTable[2] = lutBuffer + 2 * 256 * elemSize1; diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index 1dd56f3cfe..fb8da3bfac 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -298,13 +298,7 @@ void Mat::copyTo( OutputArray _dst ) const const uchar* sptr = data; uchar* dptr = dst.data; - CV_IPP_RUN( - (size_t)cols*elemSize() <= (size_t)INT_MAX && - (size_t)step <= (size_t)INT_MAX && - (size_t)dst.step <= (size_t)INT_MAX - , - CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1R, sptr, (int)step, dptr, (int)dst.step, ippiSize((int)(cols*elemSize()), rows)) >= 0 - ) + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1R_L, sptr, (int)step, dptr, (int)dst.step, ippiSizeL((int)(cols*elemSize()), rows)) >= 0) Size sz = getContinuousSize(*this, dst); size_t len = sz.width*elemSize(); diff --git a/modules/core/src/dxt.cpp b/modules/core/src/dxt.cpp index e33b105ba6..e2a0222969 100644 --- a/modules/core/src/dxt.cpp +++ b/modules/core/src/dxt.cpp @@ -1580,13 +1580,13 @@ public: return; } - IppiDFTSpec_C_32fc* pDFTSpec = (IppiDFTSpec_C_32fc*)ippMalloc( sizeSpec ); + IppiDFTSpec_C_32fc* pDFTSpec = (IppiDFTSpec_C_32fc*)CV_IPP_MALLOC( sizeSpec ); if ( sizeInit > 0 ) - pMemInit = (Ipp8u*)ippMalloc( sizeInit ); + pMemInit = (Ipp8u*)CV_IPP_MALLOC( sizeInit ); if ( sizeBuffer > 0 ) - pBuffer = (Ipp8u*)ippMalloc( sizeBuffer ); + pBuffer = (Ipp8u*)CV_IPP_MALLOC( sizeBuffer ); status = ippiDFTInit_C_32fc( srcRoiSize, norm_flag, ippAlgHintNone, pDFTSpec, pMemInit ); @@ -1661,13 +1661,13 @@ public: return; } - IppiDFTSpec_R_32f* pDFTSpec = (IppiDFTSpec_R_32f*)ippMalloc( sizeSpec ); + IppiDFTSpec_R_32f* pDFTSpec = (IppiDFTSpec_R_32f*)CV_IPP_MALLOC( sizeSpec ); if ( sizeInit > 0 ) - pMemInit = (Ipp8u*)ippMalloc( sizeInit ); + pMemInit = (Ipp8u*)CV_IPP_MALLOC( sizeInit ); if ( sizeBuffer > 0 ) - pBuffer = (Ipp8u*)ippMalloc( sizeBuffer ); + pBuffer = (Ipp8u*)CV_IPP_MALLOC( sizeBuffer ); status = ippiDFTInit_R_32f( srcRoiSize, norm_flag, ippAlgHintNone, pDFTSpec, pMemInit ); @@ -1767,13 +1767,13 @@ static bool ippi_DFT_C_32F(const uchar * src, size_t src_step, uchar * dst, size if ( status < 0 ) return false; - IppiDFTSpec_C_32fc* pDFTSpec = (IppiDFTSpec_C_32fc*)ippMalloc( sizeSpec ); + IppiDFTSpec_C_32fc* pDFTSpec = (IppiDFTSpec_C_32fc*)CV_IPP_MALLOC( sizeSpec ); if ( sizeInit > 0 ) - pMemInit = (Ipp8u*)ippMalloc( sizeInit ); + pMemInit = (Ipp8u*)CV_IPP_MALLOC( sizeInit ); if ( sizeBuffer > 0 ) - pBuffer = (Ipp8u*)ippMalloc( sizeBuffer ); + pBuffer = (Ipp8u*)CV_IPP_MALLOC( sizeBuffer ); status = ippiDFTInit_C_32fc( srcRoiSize, norm_flag, ippAlgHintNone, pDFTSpec, pMemInit ); @@ -1823,13 +1823,13 @@ static bool ippi_DFT_R_32F(const uchar * src, size_t src_step, uchar * dst, size if ( status < 0 ) return false; - IppiDFTSpec_R_32f* pDFTSpec = (IppiDFTSpec_R_32f*)ippMalloc( sizeSpec ); + IppiDFTSpec_R_32f* pDFTSpec = (IppiDFTSpec_R_32f*)CV_IPP_MALLOC( sizeSpec ); if ( sizeInit > 0 ) - pMemInit = (Ipp8u*)ippMalloc( sizeInit ); + pMemInit = (Ipp8u*)CV_IPP_MALLOC( sizeInit ); if ( sizeBuffer > 0 ) - pBuffer = (Ipp8u*)ippMalloc( sizeBuffer ); + pBuffer = (Ipp8u*)CV_IPP_MALLOC( sizeBuffer ); status = ippiDFTInit_R_32f( srcRoiSize, norm_flag, ippAlgHintNone, pDFTSpec, pMemInit ); @@ -3852,20 +3852,20 @@ public: return; } - pDCTSpec = (Ipp8u*)ippMalloc(specSize); + pDCTSpec = (Ipp8u*)CV_IPP_MALLOC(specSize); if(!pDCTSpec && specSize) { *ok = false; return; } - pBuffer = (Ipp8u*)ippMalloc(bufferSize); + pBuffer = (Ipp8u*)CV_IPP_MALLOC(bufferSize); if(!pBuffer && bufferSize) { *ok = false; IPP_RETURN } - pInitBuf = (Ipp8u*)ippMalloc(initSize); + pInitBuf = (Ipp8u*)CV_IPP_MALLOC(initSize); if(!pInitBuf && initSize) { *ok = false; @@ -3981,17 +3981,17 @@ static bool ippi_DCT_32f(const uchar * src, size_t src_step, uchar * dst, size_t if(ippDctGetSize(srcRoiSize, &specSize, &initSize, &bufferSize) < 0) return false; - pDCTSpec = (Ipp8u*)ippMalloc(specSize); + pDCTSpec = (Ipp8u*)CV_IPP_MALLOC(specSize); if(!pDCTSpec && specSize) return false; - pBuffer = (Ipp8u*)ippMalloc(bufferSize); + pBuffer = (Ipp8u*)CV_IPP_MALLOC(bufferSize); if(!pBuffer && bufferSize) { IPP_RELEASE return false; } - pInitBuf = (Ipp8u*)ippMalloc(initSize); + pInitBuf = (Ipp8u*)CV_IPP_MALLOC(initSize); if(!pInitBuf && initSize) { IPP_RELEASE diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 2e479f7c56..142a0d21ae 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -3955,50 +3955,6 @@ void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype) namespace cv { -#ifdef HAVE_IPP -#define USE_IPP_SORT - -typedef IppStatus (CV_STDCALL * IppSortFunc)(void *, int); -typedef IppSortFunc IppFlipFunc; - -static IppSortFunc getSortFunc(int depth, bool sortDescending) -{ - if (!sortDescending) - return depth == CV_8U ? (IppSortFunc)ippsSortAscend_8u_I : -#if IPP_DISABLE_BLOCK - depth == CV_16U ? (IppSortFunc)ippsSortAscend_16u_I : - depth == CV_16S ? (IppSortFunc)ippsSortAscend_16s_I : - depth == CV_32S ? (IppSortFunc)ippsSortAscend_32s_I : - depth == CV_32F ? (IppSortFunc)ippsSortAscend_32f_I : - depth == CV_64F ? (IppSortFunc)ippsSortAscend_64f_I : -#endif - 0; - else - return depth == CV_8U ? (IppSortFunc)ippsSortDescend_8u_I : -#if IPP_DISABLE_BLOCK - depth == CV_16U ? (IppSortFunc)ippsSortDescend_16u_I : - depth == CV_16S ? (IppSortFunc)ippsSortDescend_16s_I : - depth == CV_32S ? (IppSortFunc)ippsSortDescend_32s_I : - depth == CV_32F ? (IppSortFunc)ippsSortDescend_32f_I : - depth == CV_64F ? (IppSortFunc)ippsSortDescend_64f_I : -#endif - 0; -} - -static IppFlipFunc getFlipFunc(int depth) -{ - CV_SUPPRESS_DEPRECATED_START - return - depth == CV_8U || depth == CV_8S ? (IppFlipFunc)ippsFlip_8u_I : - depth == CV_16U || depth == CV_16S ? (IppFlipFunc)ippsFlip_16u_I : - depth == CV_32S || depth == CV_32F ? (IppFlipFunc)ippsFlip_32f_I : - depth == CV_64F ? (IppFlipFunc)ippsFlip_64f_I : 0; - CV_SUPPRESS_DEPRECATED_END -} - - -#endif - template static void sort_( const Mat& src, Mat& dst, int flags ) { AutoBuffer buf; @@ -4017,17 +3973,6 @@ template static void sort_( const Mat& src, Mat& dst, int flags ) } bptr = (T*)buf; -#ifdef USE_IPP_SORT - int depth = src.depth(); - IppSortFunc ippSortFunc = 0; - IppFlipFunc ippFlipFunc = 0; - CV_IPP_CHECK() - { - ippSortFunc = getSortFunc(depth, sortDescending); - ippFlipFunc = getFlipFunc(depth); - } -#endif - for( int i = 0; i < n; i++ ) { T* ptr = bptr; @@ -4047,41 +3992,12 @@ template static void sort_( const Mat& src, Mat& dst, int flags ) ptr[j] = src.ptr(j)[i]; } -#ifdef USE_IPP_SORT - if (!ippSortFunc || CV_INSTRUMENT_FUN_IPP(ippSortFunc, ptr, len) < 0) -#endif + std::sort( ptr, ptr + len ); + if( sortDescending ) { -#ifdef USE_IPP_SORT - if (depth == CV_8U) - setIppErrorStatus(); -#endif - std::sort( ptr, ptr + len ); - if( sortDescending ) - { -#ifdef USE_IPP_SORT - if (!ippFlipFunc || CV_INSTRUMENT_FUN_IPP(ippFlipFunc, ptr, len) < 0) -#endif - { -#ifdef USE_IPP_SORT - setIppErrorStatus(); -#endif - for( int j = 0; j < len/2; j++ ) - std::swap(ptr[j], ptr[len-1-j]); - } -#ifdef USE_IPP_SORT - else - { - CV_IMPL_ADD(CV_IMPL_IPP); - } -#endif - } + for( int j = 0; j < len/2; j++ ) + std::swap(ptr[j], ptr[len-1-j]); } -#ifdef USE_IPP_SORT - else - { - CV_IMPL_ADD(CV_IMPL_IPP); - } -#endif if( !sortRows ) for( int j = 0; j < len; j++ ) @@ -4089,6 +4005,94 @@ template static void sort_( const Mat& src, Mat& dst, int flags ) } } +#ifdef HAVE_IPP +typedef IppStatus (CV_STDCALL *IppSortFunc)(void *pSrcDst, int len, Ipp8u *pBuffer); + +static IppSortFunc getSortFunc(int depth, bool sortDescending) +{ + if (!sortDescending) + return depth == CV_8U ? (IppSortFunc)ippsSortRadixAscend_8u_I : + depth == CV_16U ? (IppSortFunc)ippsSortRadixAscend_16u_I : + depth == CV_16S ? (IppSortFunc)ippsSortRadixAscend_16s_I : + depth == CV_32S ? (IppSortFunc)ippsSortRadixAscend_32s_I : + depth == CV_32F ? (IppSortFunc)ippsSortRadixAscend_32f_I : + depth == CV_64F ? (IppSortFunc)ippsSortRadixAscend_64f_I : + 0; + else + return depth == CV_8U ? (IppSortFunc)ippsSortRadixDescend_8u_I : + depth == CV_16U ? (IppSortFunc)ippsSortRadixDescend_16u_I : + depth == CV_16S ? (IppSortFunc)ippsSortRadixDescend_16s_I : + depth == CV_32S ? (IppSortFunc)ippsSortRadixDescend_32s_I : + depth == CV_32F ? (IppSortFunc)ippsSortRadixDescend_32f_I : + depth == CV_64F ? (IppSortFunc)ippsSortRadixDescend_64f_I : + 0; +} + +static bool ipp_sort(const Mat& src, Mat& dst, int flags) +{ + CV_INSTRUMENT_REGION_IPP() + + bool sortRows = (flags & 1) == CV_SORT_EVERY_ROW; + bool sortDescending = (flags & CV_SORT_DESCENDING) != 0; + bool inplace = (src.data == dst.data); + int depth = src.depth(); + IppDataType type = ippiGetDataType(depth); + + IppSortFunc ippsSortRadix_I = getSortFunc(depth, sortDescending); + if(!ippsSortRadix_I) + return false; + + if(sortRows) + { + AutoBuffer buffer; + int bufferSize; + if(ippsSortRadixGetBufferSize(src.cols, type, &bufferSize) < 0) + return false; + + buffer.allocate(bufferSize); + + if(!inplace) + src.copyTo(dst); + + for(int i = 0; i < dst.rows; i++) + { + if(CV_INSTRUMENT_FUN_IPP(ippsSortRadix_I, (void*)dst.ptr(i), dst.cols, buffer) < 0) + return false; + } + } + else + { + AutoBuffer buffer; + int bufferSize; + if(ippsSortRadixGetBufferSize(src.rows, type, &bufferSize) < 0) + return false; + + buffer.allocate(bufferSize); + + Mat row(1, src.rows, src.type()); + Mat srcSub; + Mat dstSub; + Rect subRect(0,0,1,src.rows); + + for(int i = 0; i < src.cols; i++) + { + subRect.x = i; + srcSub = Mat(src, subRect); + dstSub = Mat(dst, subRect); + srcSub.copyTo(row); + + if(CV_INSTRUMENT_FUN_IPP(ippsSortRadix_I, (void*)row.ptr(), dst.rows, buffer) < 0) + return false; + + row = row.reshape(1, dstSub.rows); + row.copyTo(dstSub); + } + } + + return true; +} +#endif + template class LessThanIdx { public: @@ -4097,30 +4101,6 @@ public: const _Tp* arr; }; -#if defined USE_IPP_SORT && IPP_DISABLE_BLOCK - -typedef IppStatus (CV_STDCALL *IppSortIndexFunc)(void *, int *, int); - -static IppSortIndexFunc getSortIndexFunc(int depth, bool sortDescending) -{ - if (!sortDescending) - return depth == CV_8U ? (IppSortIndexFunc)ippsSortIndexAscend_8u_I : - depth == CV_16U ? (IppSortIndexFunc)ippsSortIndexAscend_16u_I : - depth == CV_16S ? (IppSortIndexFunc)ippsSortIndexAscend_16s_I : - depth == CV_32S ? (IppSortIndexFunc)ippsSortIndexAscend_32s_I : - depth == CV_32F ? (IppSortIndexFunc)ippsSortIndexAscend_32f_I : - depth == CV_64F ? (IppSortIndexFunc)ippsSortIndexAscend_64f_I : 0; - else - return depth == CV_8U ? (IppSortIndexFunc)ippsSortIndexDescend_8u_I : - depth == CV_16U ? (IppSortIndexFunc)ippsSortIndexDescend_16u_I : - depth == CV_16S ? (IppSortIndexFunc)ippsSortIndexDescend_16s_I : - depth == CV_32S ? (IppSortIndexFunc)ippsSortIndexDescend_32s_I : - depth == CV_32F ? (IppSortIndexFunc)ippsSortIndexDescend_32f_I : - depth == CV_64F ? (IppSortIndexFunc)ippsSortIndexDescend_64f_I : 0; -} - -#endif - template static void sortIdx_( const Mat& src, Mat& dst, int flags ) { AutoBuffer buf; @@ -4142,17 +4122,6 @@ template static void sortIdx_( const Mat& src, Mat& dst, int flags ) T* bptr = (T*)buf; int* _iptr = (int*)ibuf; -#if defined USE_IPP_SORT && IPP_DISABLE_BLOCK - int depth = src.depth(); - IppSortIndexFunc ippFunc = 0; - IppFlipFunc ippFlipFunc = 0; - CV_IPP_CHECK() - { - ippFunc = getSortIndexFunc(depth, sortDescending); - ippFlipFunc = getFlipFunc(depth); - } -#endif - for( int i = 0; i < n; i++ ) { T* ptr = bptr; @@ -4171,40 +4140,12 @@ template static void sortIdx_( const Mat& src, Mat& dst, int flags ) for( int j = 0; j < len; j++ ) iptr[j] = j; -#if defined USE_IPP_SORT && IPP_DISABLE_BLOCK - if (sortRows || !ippFunc || ippFunc(ptr, iptr, len) < 0) -#endif + std::sort( iptr, iptr + len, LessThanIdx(ptr) ); + if( sortDescending ) { -#if defined USE_IPP_SORT && IPP_DISABLE_BLOCK - setIppErrorStatus(); -#endif - std::sort( iptr, iptr + len, LessThanIdx(ptr) ); - if( sortDescending ) - { -#if defined USE_IPP_SORT && IPP_DISABLE_BLOCK - if (!ippFlipFunc || ippFlipFunc(iptr, len) < 0) -#endif - { -#if defined USE_IPP_SORT && IPP_DISABLE_BLOCK - setIppErrorStatus(); -#endif - for( int j = 0; j < len/2; j++ ) - std::swap(iptr[j], iptr[len-1-j]); - } -#if defined USE_IPP_SORT && IPP_DISABLE_BLOCK - else - { - CV_IMPL_ADD(CV_IMPL_IPP); - } -#endif - } + for( int j = 0; j < len/2; j++ ) + std::swap(iptr[j], iptr[len-1-j]); } -#if defined USE_IPP_SORT && IPP_DISABLE_BLOCK - else - { - CV_IMPL_ADD(CV_IMPL_IPP); - } -#endif if( !sortRows ) for( int j = 0; j < len; j++ ) @@ -4212,24 +4153,110 @@ template static void sortIdx_( const Mat& src, Mat& dst, int flags ) } } -typedef void (*SortFunc)(const Mat& src, Mat& dst, int flags); +#ifdef HAVE_IPP +#if !IPP_DISABLE_SORT_IDX +typedef IppStatus (CV_STDCALL *IppSortIndexFunc)(const void* pSrc, Ipp32s srcStrideBytes, Ipp32s *pDstIndx, int len, Ipp8u *pBuffer); +static IppSortIndexFunc getSortIndexFunc(int depth, bool sortDescending) +{ + if (!sortDescending) + return depth == CV_8U ? (IppSortIndexFunc)ippsSortRadixIndexAscend_8u : + depth == CV_16U ? (IppSortIndexFunc)ippsSortRadixIndexAscend_16u : + depth == CV_16S ? (IppSortIndexFunc)ippsSortRadixIndexAscend_16s : + depth == CV_32S ? (IppSortIndexFunc)ippsSortRadixIndexAscend_32s : + depth == CV_32F ? (IppSortIndexFunc)ippsSortRadixIndexAscend_32f : + 0; + else + return depth == CV_8U ? (IppSortIndexFunc)ippsSortRadixIndexDescend_8u : + depth == CV_16U ? (IppSortIndexFunc)ippsSortRadixIndexDescend_16u : + depth == CV_16S ? (IppSortIndexFunc)ippsSortRadixIndexDescend_16s : + depth == CV_32S ? (IppSortIndexFunc)ippsSortRadixIndexDescend_32s : + depth == CV_32F ? (IppSortIndexFunc)ippsSortRadixIndexDescend_32f : + 0; +} + +static bool ipp_sortIdx( const Mat& src, Mat& dst, int flags ) +{ + CV_INSTRUMENT_REGION_IPP() + + bool sortRows = (flags & 1) == CV_SORT_EVERY_ROW; + bool sortDescending = (flags & CV_SORT_DESCENDING) != 0; + int depth = src.depth(); + IppDataType type = ippiGetDataType(depth); + Ipp32s elemSize = (Ipp32s)src.elemSize1(); + + IppSortIndexFunc ippsSortRadixIndex = getSortIndexFunc(depth, sortDescending); + if(!ippsSortRadixIndex) + return false; + + if(sortRows) + { + AutoBuffer buffer; + int bufferSize; + if(ippsSortRadixIndexGetBufferSize(src.cols, type, &bufferSize) < 0) + return false; + + buffer.allocate(bufferSize); + + for(int i = 0; i < src.rows; i++) + { + if(CV_INSTRUMENT_FUN_IPP(ippsSortRadixIndex, (void*)src.ptr(i), elemSize, (Ipp32s*)dst.ptr(i), src.cols, buffer) < 0) + return false; + } + } + else + { + Mat dstRow(1, dst.rows, dst.type()); + Mat dstSub; + Rect subRect(0,0,1,src.rows); + + AutoBuffer buffer; + int bufferSize; + if(ippsSortRadixIndexGetBufferSize(src.rows, type, &bufferSize) < 0) + return false; + + buffer.allocate(bufferSize); + + Ipp32s pixStride = elemSize*dst.cols; + for(int i = 0; i < src.cols; i++) + { + subRect.x = i; + dstSub = Mat(dst, subRect); + + if(CV_INSTRUMENT_FUN_IPP(ippsSortRadixIndex, (void*)src.ptr(0, i), pixStride, (Ipp32s*)dstRow.ptr(), src.rows, buffer) < 0) + return false; + + dstRow = dstRow.reshape(1, dstSub.rows); + dstRow.copyTo(dstSub); + } + } + + return true; +} +#endif +#endif + +typedef void (*SortFunc)(const Mat& src, Mat& dst, int flags); } void cv::sort( InputArray _src, OutputArray _dst, int flags ) { CV_INSTRUMENT_REGION() + Mat src = _src.getMat(); + CV_Assert( src.dims <= 2 && src.channels() == 1 ); + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + CV_IPP_RUN_FAST(ipp_sort(src, dst, flags)); + static SortFunc tab[] = { sort_, sort_, sort_, sort_, sort_, sort_, sort_, 0 }; - Mat src = _src.getMat(); SortFunc func = tab[src.depth()]; - CV_Assert( src.dims <= 2 && src.channels() == 1 && func != 0 ); - _dst.create( src.size(), src.type() ); - Mat dst = _dst.getMat(); + CV_Assert( func != 0 ); + func( src, dst, flags ); } @@ -4237,20 +4264,24 @@ void cv::sortIdx( InputArray _src, OutputArray _dst, int flags ) { CV_INSTRUMENT_REGION() - static SortFunc tab[] = - { - sortIdx_, sortIdx_, sortIdx_, sortIdx_, - sortIdx_, sortIdx_, sortIdx_, 0 - }; Mat src = _src.getMat(); - SortFunc func = tab[src.depth()]; - CV_Assert( src.dims <= 2 && src.channels() == 1 && func != 0 ); - + CV_Assert( src.dims <= 2 && src.channels() == 1 ); Mat dst = _dst.getMat(); if( dst.data == src.data ) _dst.release(); _dst.create( src.size(), CV_32S ); dst = _dst.getMat(); +#if !IPP_DISABLE_SORT_IDX + CV_IPP_RUN_FAST(ipp_sortIdx(src, dst, flags)); +#endif + + static SortFunc tab[] = + { + sortIdx_, sortIdx_, sortIdx_, sortIdx_, + sortIdx_, sortIdx_, sortIdx_, 0 + }; + SortFunc func = tab[src.depth()]; + CV_Assert( func != 0 ); func( src, dst, flags ); } diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index e5402614eb..526b474c0b 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -1738,19 +1738,19 @@ IntrumentationRegion::~IntrumentationRegion() namespace ipp { +#ifdef HAVE_IPP struct IPPInitSingleton { public: IPPInitSingleton() { - useIPP = true; - ippStatus = 0; - funcname = NULL; - filename = NULL; - linen = 0; - ippFeatures = 0; + useIPP = true; + ippStatus = 0; + funcname = NULL; + filename = NULL; + linen = 0; + ippFeatures = 0; -#ifdef HAVE_IPP const char* pIppEnv = getenv("OPENCV_IPP"); cv::String env = pIppEnv; if(env.size()) @@ -1783,7 +1783,7 @@ public: } IPP_INITIALIZER(ippFeatures) -#endif + ippFeatures = ippGetEnabledCpuFeatures(); } bool useIPP; @@ -1792,18 +1792,27 @@ public: const char *funcname; const char *filename; int linen; - int ippFeatures; + Ipp64u ippFeatures; }; static IPPInitSingleton& getIPPSingleton() { CV_SINGLETON_LAZY_INIT_REF(IPPInitSingleton, new IPPInitSingleton()) } +#endif +#if OPENCV_ABI_COMPATIBILITY > 300 +unsigned long long getIppFeatures() +#else int getIppFeatures() +#endif { #ifdef HAVE_IPP +#if OPENCV_ABI_COMPATIBILITY > 300 return getIPPSingleton().ippFeatures; +#else + return (int)getIPPSingleton().ippFeatures; +#endif #else return 0; #endif @@ -1811,20 +1820,32 @@ int getIppFeatures() void setIppStatus(int status, const char * const _funcname, const char * const _filename, int _line) { +#ifdef HAVE_IPP getIPPSingleton().ippStatus = status; getIPPSingleton().funcname = _funcname; getIPPSingleton().filename = _filename; getIPPSingleton().linen = _line; +#else + CV_UNUSED(status); CV_UNUSED(_funcname); CV_UNUSED(_filename); CV_UNUSED(_line); +#endif } int getIppStatus() { +#ifdef HAVE_IPP return getIPPSingleton().ippStatus; +#else + return 0; +#endif } String getIppErrorLocation() { +#ifdef HAVE_IPP return format("%s:%d %s", getIPPSingleton().filename ? getIPPSingleton().filename : "", getIPPSingleton().linen, getIPPSingleton().funcname ? getIPPSingleton().funcname : ""); +#else + return String(); +#endif } bool useIPP() diff --git a/modules/imgproc/src/color.cpp b/modules/imgproc/src/color.cpp index 8aefa4ce72..f07b1f65e0 100644 --- a/modules/imgproc/src/color.cpp +++ b/modules/imgproc/src/color.cpp @@ -446,19 +446,23 @@ static ippiGeneralFunc ippiCopyP3C3RTab[] = 0, (ippiGeneralFunc)ippiCopy_32f_P3C3R, 0, 0 }; +#if !IPP_DISABLE_RGB_XYZ static ippiGeneralFunc ippiRGB2XYZTab[] = { (ippiGeneralFunc)ippiRGBToXYZ_8u_C3R, 0, (ippiGeneralFunc)ippiRGBToXYZ_16u_C3R, 0, 0, (ippiGeneralFunc)ippiRGBToXYZ_32f_C3R, 0, 0 }; +#endif +#if !IPP_DISABLE_XYZ_RGB static ippiGeneralFunc ippiXYZ2RGBTab[] = { (ippiGeneralFunc)ippiXYZToRGB_8u_C3R, 0, (ippiGeneralFunc)ippiXYZToRGB_16u_C3R, 0, 0, (ippiGeneralFunc)ippiXYZToRGB_32f_C3R, 0, 0 }; +#endif -#if IPP_DISABLE_BLOCK +#if !IPP_DISABLE_RGB_HSV static ippiGeneralFunc ippiRGB2HSVTab[] = { (ippiGeneralFunc)ippiRGBToHSV_8u_C3R, 0, (ippiGeneralFunc)ippiRGBToHSV_16u_C3R, 0, @@ -484,13 +488,15 @@ static ippiGeneralFunc ippiHLS2RGBTab[] = 0, (ippiGeneralFunc)ippiHLSToRGB_32f_C3R, 0, 0 }; -#if IPP_DISABLE_BLOCK +#if !IPP_DISABLE_RGB_LAB static ippiGeneralFunc ippiRGBToLUVTab[] = { (ippiGeneralFunc)ippiRGBToLUV_8u_C3R, 0, (ippiGeneralFunc)ippiRGBToLUV_16u_C3R, 0, 0, (ippiGeneralFunc)ippiRGBToLUV_32f_C3R, 0, 0 }; +#endif +#if !IPP_DISABLE_LAB_RGB static ippiGeneralFunc ippiLUVToRGBTab[] = { (ippiGeneralFunc)ippiLUVToRGB_8u_C3R, 0, (ippiGeneralFunc)ippiLUVToRGB_16u_C3R, 0, @@ -8714,41 +8720,6 @@ void cvtBGRtoBGR5x5(const uchar * src_data, size_t src_step, CALL_HAL(cvtBGRtoBGR5x5, cv_hal_cvtBGRtoBGR5x5, src_data, src_step, dst_data, dst_step, width, height, scn, swapBlue, greenBits); -#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK // breaks OCL accuracy tests - CV_IPP_CHECK() - { - CV_SUPPRESS_DEPRECATED_START; - if (scn == 3 && greenBits == 6 && !swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralFunctor((ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R))) - return; - } - else if (scn == 4 && greenBits == 6 && !swapBlue) - { - if (CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(CV_8U, scn), dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[CV_8U], - (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 0, 1, 2, CV_8U))) - return; - } - else if (scn == 3 && greenBits == 6 && swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(CV_8U, scn), dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[CV_8U], - (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 2, 1, 0, CV_8U)) ) - return; - } - else if (scn == 4 && greenBits == 6 && swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(CV_8U, scn), dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[CV_8U], - (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 2, 1, 0, CV_8U)) ) - return; - } - CV_SUPPRESS_DEPRECATED_END; - } -#endif - CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2RGB5x5(scn, swapBlue ? 2 : 0, greenBits)); } @@ -8762,41 +8733,6 @@ void cvtBGR5x5toBGR(const uchar * src_data, size_t src_step, CALL_HAL(cvtBGR5x5toBGR, cv_hal_cvtBGR5x5toBGR, src_data, src_step, dst_data, dst_step, width, height, dcn, swapBlue, greenBits); -#if defined(HAVE_IPP) && IPP_VERSION_X100 < 900 - CV_IPP_CHECK() - { - CV_SUPPRESS_DEPRECATED_START; - if (dcn == 3 && greenBits == 6 && !swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R))) - return; - } - else if (dcn == 3 && greenBits == 6 && swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R, - ippiSwapChannelsC3RTab[CV_8U], 2, 1, 0, CV_8U))) - return; - } - else if (dcn == 4 && greenBits == 6 && !swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R, - ippiSwapChannelsC3C4RTab[CV_8U], 0, 1, 2, CV_8U))) - return; - } - else if (dcn == 4 && greenBits == 6 && swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R, - ippiSwapChannelsC3C4RTab[CV_8U], 2, 1, 0, CV_8U))) - return; - } - CV_SUPPRESS_DEPRECATED_END; - } -#endif - CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB5x52RGB(dcn, swapBlue ? 2 : 0, greenBits)); } @@ -8813,30 +8749,30 @@ void cvtBGRtoGray(const uchar * src_data, size_t src_step, #if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700 CV_IPP_CHECK() { - if(depth == CV_32F && scn == 3 && !swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPColor2GrayFunctor(ippiColor2GrayC3Tab[depth])) ) - return; - } - else if(depth == CV_32F && scn == 3 && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralFunctor(ippiRGB2GrayC3Tab[depth])) ) - return; - } - else if(depth == CV_32F && scn == 4 && !swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPColor2GrayFunctor(ippiColor2GrayC4Tab[depth])) ) - return; - } - else if(depth == CV_32F && scn == 4 && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralFunctor(ippiRGB2GrayC4Tab[depth])) ) - return; - } + if(depth == CV_32F && scn == 3 && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPColor2GrayFunctor(ippiColor2GrayC3Tab[depth])) ) + return; + } + else if(depth == CV_32F && scn == 3 && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralFunctor(ippiRGB2GrayC3Tab[depth])) ) + return; + } + else if(depth == CV_32F && scn == 4 && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPColor2GrayFunctor(ippiColor2GrayC4Tab[depth])) ) + return; + } + else if(depth == CV_32F && scn == 4 && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralFunctor(ippiRGB2GrayC4Tab[depth])) ) + return; + } } #endif @@ -8862,18 +8798,18 @@ void cvtGraytoBGR(const uchar * src_data, size_t src_step, #if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700 CV_IPP_CHECK() { - if(dcn == 3) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + if(dcn == 3) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, IPPGray2BGRFunctor(ippiCopyP3C3RTab[depth])) ) - return; - } - else if(dcn == 4) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + return; + } + else if(dcn == 4) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, IPPGray2BGRAFunctor(ippiCopyP3C3RTab[depth], ippiSwapChannelsC3C4RTab[depth], depth)) ) - return; - } + return; + } } #endif @@ -8919,37 +8855,39 @@ void cvtBGRtoYUV(const uchar * src_data, size_t src_step, CALL_HAL(cvtBGRtoYUV, cv_hal_cvtBGRtoYUV, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue, isCbCr); -#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK +#if defined(HAVE_IPP) +#if !IPP_DISABLE_RGB_YUV CV_IPP_CHECK() { - if (scn == 3 && depth == CV_8U && swapBlue && !isCbCr) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralFunctor((ippiGeneralFunc)ippiRGBToYUV_8u_C3R))) - return; - } - else if (scn == 3 && depth == CV_8U && !swapBlue && !isCbCr) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], - (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 2, 1, 0, depth))) - return; - } - else if (scn == 4 && depth == CV_8U && swapBlue && !isCbCr) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], - (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 0, 1, 2, depth))) - return; - } - else if (scn == 4 && depth == CV_8U && !swapBlue && !isCbCr) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], - (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 2, 1, 0, depth))) - return; - } + if (scn == 3 && depth == CV_8U && swapBlue && !isCbCr) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralFunctor((ippiGeneralFunc)ippiRGBToYUV_8u_C3R))) + return; + } + else if (scn == 3 && depth == CV_8U && !swapBlue && !isCbCr) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], + (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 2, 1, 0, depth))) + return; + } + else if (scn == 4 && depth == CV_8U && swapBlue && !isCbCr) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], + (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 0, 1, 2, depth))) + return; + } + else if (scn == 4 && depth == CV_8U && !swapBlue && !isCbCr) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], + (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 2, 1, 0, depth))) + return; + } } +#endif #endif int blueIdx = swapBlue ? 2 : 0; @@ -8971,37 +8909,39 @@ void cvtYUVtoBGR(const uchar * src_data, size_t src_step, CALL_HAL(cvtYUVtoBGR, cv_hal_cvtYUVtoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, dcn, swapBlue, isCbCr); -#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK +#if defined(HAVE_IPP) +#if !IPP_DISABLE_YUV_RGB CV_IPP_CHECK() { - if (dcn == 3 && depth == CV_8U && swapBlue && !isCbCr) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R))) - return; - } - else if (dcn == 3 && depth == CV_8U && !swapBlue && !isCbCr) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R, - ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth))) - return; - } - else if (dcn == 4 && depth == CV_8U && swapBlue && !isCbCr) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R, - ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth))) - return; - } - else if (dcn == 4 && depth == CV_8U && !swapBlue && !isCbCr) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R, - ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth))) - return; - } + if (dcn == 3 && depth == CV_8U && swapBlue && !isCbCr) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R))) + return; + } + else if (dcn == 3 && depth == CV_8U && !swapBlue && !isCbCr) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R, + ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth))) + return; + } + else if (dcn == 4 && depth == CV_8U && swapBlue && !isCbCr) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R, + ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth))) + return; + } + else if (dcn == 4 && depth == CV_8U && !swapBlue && !isCbCr) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R, + ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth))) + return; + } } +#endif #endif int blueIdx = swapBlue ? 2 : 0; @@ -9023,33 +8963,35 @@ void cvtBGRtoXYZ(const uchar * src_data, size_t src_step, CALL_HAL(cvtBGRtoXYZ, cv_hal_cvtBGRtoXYZ, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue); #if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700 +#if !IPP_DISABLE_RGB_XYZ CV_IPP_CHECK() { - if(scn == 3 && depth != CV_32F && !swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, scn), dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2XYZTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(scn == 4 && depth != CV_32F && !swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2XYZTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(scn == 3 && depth != CV_32F && swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, scn), dst_data, dst_step, width, height, - IPPGeneralFunctor(ippiRGB2XYZTab[depth])) ) - return; - } - else if(scn == 4 && depth != CV_32F && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2XYZTab[depth], 0, 1, 2, depth)) ) - return; - } + if(scn == 3 && depth != CV_32F && !swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, scn), dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2XYZTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(scn == 4 && depth != CV_32F && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2XYZTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(scn == 3 && depth != CV_32F && swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, scn), dst_data, dst_step, width, height, + IPPGeneralFunctor(ippiRGB2XYZTab[depth])) ) + return; + } + else if(scn == 4 && depth != CV_32F && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2XYZTab[depth], 0, 1, 2, depth)) ) + return; + } } +#endif #endif int blueIdx = swapBlue ? 2 : 0; @@ -9071,33 +9013,35 @@ void cvtXYZtoBGR(const uchar * src_data, size_t src_step, CALL_HAL(cvtXYZtoBGR, cv_hal_cvtXYZtoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, dcn, swapBlue); #if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700 +#if !IPP_DISABLE_XYZ_RGB CV_IPP_CHECK() { - if(dcn == 3 && depth != CV_32F && !swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(dcn == 4 && depth != CV_32F && !swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) - return; - } - if(dcn == 3 && depth != CV_32F && swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, - IPPGeneralFunctor(ippiXYZ2RGBTab[depth])) ) - return; - } - else if(dcn == 4 && depth != CV_32F && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) - return; - } + if(dcn == 3 && depth != CV_32F && !swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(dcn == 4 && depth != CV_32F && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) + return; + } + if(dcn == 3 && depth != CV_32F && swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, + IPPGeneralFunctor(ippiXYZ2RGBTab[depth])) ) + return; + } + else if(dcn == 4 && depth != CV_32F && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) + return; + } } +#endif #endif int blueIdx = swapBlue ? 2 : 0; @@ -9122,60 +9066,60 @@ void cvtBGRtoHSV(const uchar * src_data, size_t src_step, #if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700 CV_IPP_CHECK() { - if (depth == CV_8U && isFullRange) - { - if (isHSV) + if(depth == CV_8U && isFullRange) { -#if IPP_DISABLE_BLOCK // breaks OCL accuracy tests - if(scn == 3 && !swapBlue) + if (isHSV) { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(scn == 4 && !swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(scn == 4 && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 0, 1, 2, depth)) ) - return; - } +#if !IPP_DISABLE_RGB_HSV // breaks OCL accuracy tests + if(scn == 3 && !swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(scn == 4 && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(scn == 4 && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 0, 1, 2, depth)) ) + return; + } #endif - } - else - { - if(scn == 3 && !swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HLSTab[depth], 2, 1, 0, depth)) ) - return; } - else if(scn == 4 && !swapBlue) + else { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HLSTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(scn == 3 && swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height, - IPPGeneralFunctor(ippiRGB2HLSTab[depth])) ) - return; - } - else if(scn == 4 && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HLSTab[depth], 0, 1, 2, depth)) ) - return; + if(scn == 3 && !swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HLSTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(scn == 4 && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HLSTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(scn == 3 && swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height, + IPPGeneralFunctor(ippiRGB2HLSTab[depth])) ) + return; + } + else if(scn == 4 && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HLSTab[depth], 0, 1, 2, depth)) ) + return; + } } } } - } #endif int hrange = depth == CV_32F ? 360 : isFullRange ? 256 : 180; @@ -9209,63 +9153,63 @@ void cvtHSVtoBGR(const uchar * src_data, size_t src_step, #if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700 CV_IPP_CHECK() { - if (depth == CV_8U && isFullRange) - { - if (isHSV) + if (depth == CV_8U && isFullRange) { - if(dcn == 3 && !swapBlue) + if (isHSV) { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) - return; + if(dcn == 3 && !swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(dcn == 4 && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(dcn == 3 && swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, + IPPGeneralFunctor(ippiHSV2RGBTab[depth])) ) + return; + } + else if(dcn == 4 && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) + return; + } } - else if(dcn == 4 && !swapBlue) + else { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(dcn == 3 && swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, - IPPGeneralFunctor(ippiHSV2RGBTab[depth])) ) - return; - } - else if(dcn == 4 && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) - return; + if(dcn == 3 && !swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(dcn == 4 && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) + return; + } + else if(dcn == 3 && swapBlue) + { + if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, + IPPGeneralFunctor(ippiHLS2RGBTab[depth])) ) + return; + } + else if(dcn == 4 && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, + IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) + return; + } } } - else - { - if(dcn == 3 && !swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(dcn == 4 && !swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) - return; - } - else if(dcn == 3 && swapBlue) - { - if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height, - IPPGeneralFunctor(ippiHLS2RGBTab[depth])) ) - return; - } - else if(dcn == 4 && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height, - IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) - return; - } - } - } } #endif @@ -9297,72 +9241,72 @@ void cvtBGRtoLab(const uchar * src_data, size_t src_step, CALL_HAL(cvtBGRtoLab, cv_hal_cvtBGRtoLab, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue, isLab, srgb); -#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK +#if defined(HAVE_IPP) && !IPP_DISABLE_RGB_LAB CV_IPP_CHECK() { - if (!srgb) - { - if (isLab) + if (!srgb) { - if (scn == 3 && depth == CV_8U && !swapBlue) + if (isLab) { - if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralFunctor((ippiGeneralFunc)ippiBGRToLab_8u_C3R))) - return; + if (scn == 3 && depth == CV_8U && !swapBlue) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralFunctor((ippiGeneralFunc)ippiBGRToLab_8u_C3R))) + return; + } + else if (scn == 4 && depth == CV_8U && !swapBlue) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], + (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 0, 1, 2, depth))) + return; + } + else if (scn == 3 && depth == CV_8U && swapBlue) // slower than OpenCV + { + if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], + (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 2, 1, 0, depth))) + return; + } + else if (scn == 4 && depth == CV_8U && swapBlue) // slower than OpenCV + { + if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], + (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 2, 1, 0, depth))) + return; + } } - else if (scn == 4 && depth == CV_8U && !swapBlue) + else { - if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], - (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 0, 1, 2, depth))) - return; - } - else if (scn == 3 && depth == CV_8U && swapBlue) // slower than OpenCV - { - if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], - (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 2, 1, 0, depth))) - return; - } - else if (scn == 4 && depth == CV_8U && swapBlue) // slower than OpenCV - { - if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], - (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 2, 1, 0, depth))) - return; + if (scn == 3 && swapBlue) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralFunctor(ippiRGBToLUVTab[depth]))) + return; + } + else if (scn == 4 && swapBlue) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], + ippiRGBToLUVTab[depth], 0, 1, 2, depth))) + return; + } + else if (scn == 3 && !swapBlue) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], + ippiRGBToLUVTab[depth], 2, 1, 0, depth))) + return; + } + else if (scn == 4 && !swapBlue) + { + if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], + ippiRGBToLUVTab[depth], 2, 1, 0, depth))) + return; + } } } - else - { - if (scn == 3 && swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralFunctor(ippiRGBToLUVTab[depth]))) - return; - } - else if (scn == 4 && swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], - ippiRGBToLUVTab[depth], 0, 1, 2, depth))) - return; - } - else if (scn == 3 && !swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], - ippiRGBToLUVTab[depth], 2, 1, 0, depth))) - return; - } - else if (scn == 4 && !swapBlue) - { - if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], - ippiRGBToLUVTab[depth], 2, 1, 0, depth))) - return; - } - } - } } #endif @@ -9394,72 +9338,72 @@ void cvtLabtoBGR(const uchar * src_data, size_t src_step, CALL_HAL(cvtLabtoBGR, cv_hal_cvtLabtoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, dcn, swapBlue, isLab, srgb); -#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK +#if defined(HAVE_IPP) && !IPP_DISABLE_LAB_RGB CV_IPP_CHECK() { - if (!srgb) - { - if (isLab) + if (!srgb) { - if( dcn == 3 && depth == CV_8U && !swapBlue) + if (isLab) { - if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R)) ) - return; + if( dcn == 3 && depth == CV_8U && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R)) ) + return; + } + else if( dcn == 4 && depth == CV_8U && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R, + ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) + return; + } + if( dcn == 3 && depth == CV_8U && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R, + ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) + return; + } + else if( dcn == 4 && depth == CV_8U && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R, + ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) + return; + } } - else if( dcn == 4 && depth == CV_8U && !swapBlue) + else { - if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R, - ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) - return; - } - if( dcn == 3 && depth == CV_8U && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R, - ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) - return; - } - else if( dcn == 4 && depth == CV_8U && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R, - ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) - return; + if( dcn == 3 && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralFunctor(ippiLUVToRGBTab[depth])) ) + return; + } + else if( dcn == 4 && swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth], + ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) + return; + } + if( dcn == 3 && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth], + ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) + return; + } + else if( dcn == 4 && !swapBlue) + { + if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, + IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth], + ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) + return; + } } } - else - { - if( dcn == 3 && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralFunctor(ippiLUVToRGBTab[depth])) ) - return; - } - else if( dcn == 4 && swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth], - ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) ) - return; - } - if( dcn == 3 && !swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth], - ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) ) - return; - } - else if( dcn == 4 && !swapBlue) - { - if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height, - IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth], - ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) ) - return; - } - } - } } #endif @@ -9894,9 +9838,11 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn ) _dst.create(dstSz, CV_MAKETYPE(depth, dcn)); dst = _dst.getMat(); #ifdef HAVE_IPP - if (CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1R, src.data, (int)src.step, dst.data, (int)dst.step, - ippiSize(dstSz.width, dstSz.height)) >= 0) +#if IPP_VERSION_X100 >= 201700 + if (CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1R_L, src.data, (IppSizeL)src.step, dst.data, (IppSizeL)dst.step, + ippiSizeL(dstSz.width, dstSz.height)) >= 0) break; +#endif #endif src(Range(0, dstSz.height), Range::all()).copyTo(dst); } diff --git a/modules/imgproc/src/deriv.cpp b/modules/imgproc/src/deriv.cpp index 8486ec899b..327eaf6165 100644 --- a/modules/imgproc/src/deriv.cpp +++ b/modules/imgproc/src/deriv.cpp @@ -302,338 +302,91 @@ namespace cv #ifdef HAVE_IPP namespace cv { -static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, double scale, double delta, int borderType) + +static bool ipp_Deriv(InputArray _src, OutputArray _dst, int dx, int dy, int ksize, double scale, double delta, int borderType) { +#ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 810 - if ((0 > dx) || (0 > dy) || (1 != dx + dy)) - return false; - if (fabs(delta) > FLT_EPSILON) + ::ipp::IwiSize size(_src.size().width, _src.size().height); + IppDataType srcType = ippiGetDataType(_src.depth()); + IppDataType dstType = ippiGetDataType(_dst.depth()); + int channels = _src.channels(); + bool useScale = false; + bool useScharr = false; + + if(channels != _dst.channels() || channels > 1) return false; - IppiBorderType ippiBorderType = ippiGetBorderType(borderType & (~BORDER_ISOLATED)); - if ((int)ippiBorderType < 0) + if(fabs(delta) > FLT_EPSILON || fabs(scale-1) > FLT_EPSILON) + useScale = true; + + if(ksize <= 0) + { + ksize = 3; + useScharr = true; + } + + IppiMaskSize maskSize = ippiGetMaskSize(ksize, ksize); + if(maskSize < 0) return false; - int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype); - if (ddepth < 0) - ddepth = sdepth; - int dtype = CV_MAKETYPE(ddepth, cn); +#if IPP_VERSION_X100 <= 201703 + // Bug with mirror wrap + if(borderType == BORDER_REFLECT_101 && (ksize/2+1 > size.width || ksize/2+1 > size.height)) + return false; +#endif - Mat src = _src.getMat(); - if (0 == (BORDER_ISOLATED & borderType)) + IwiDerivativeType derivType = ippiGetDerivType(dx, dy, (useScharr)?false:true); + if(derivType < 0) + return false; + + // Acquire data and begin processing + try { - Size size; Point offset; - src.locateROI(size, offset); - if (0 < offset.x) - ippiBorderType = (IppiBorderType)(ippiBorderType | ippBorderInMemLeft); - if (0 < offset.y) - ippiBorderType = (IppiBorderType)(ippiBorderType | ippBorderInMemTop); - if (offset.x + src.cols < size.width) - ippiBorderType = (IppiBorderType)(ippiBorderType | ippBorderInMemRight); - if (offset.y + src.rows < size.height) - ippiBorderType = (IppiBorderType)(ippiBorderType | ippBorderInMemBottom); - } + Mat src = _src.getMat(); + Mat dst = _dst.getMat(); + ::ipp::IwiImage iwSrc = ippiGetImage(src); + ::ipp::IwiImage iwDst = ippiGetImage(dst); + ::ipp::IwiImage iwSrcProc = iwSrc; + ::ipp::IwiImage iwDstProc = iwDst; + ::ipp::IwiBorderSize borderSize(maskSize); + ::ipp::IwiBorderType ippBorder(ippiGetBorder(iwSrc, borderType, borderSize)); + if(!ippBorder.m_borderType) + return false; - bool horz = (0 == dx) && (1 == dy); - IppiSize roiSize = {src.cols, src.rows}; - - _dst.create( _src.size(), dtype); - Mat dst = _dst.getMat(); - IppStatus sts = ippStsErr; - if ((CV_8U == stype) && (CV_16S == dtype)) - { - int bufferSize = 0; Ipp8u *pBuffer; - if (horz) + if(srcType == ipp8u && dstType == ipp8u) { - if (0 > ippiFilterScharrHorizMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp8u, ipp16s, 1, &bufferSize)) - return false; - pBuffer = ippsMalloc_8u(bufferSize); - if (NULL == pBuffer) - return false; - sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrHorizMaskBorder_8u16s_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer); + iwDstProc.Alloc(iwDst.m_size, ipp16s, channels); + useScale = true; } + else if(srcType == ipp8u && dstType == ipp32f) + { + iwSrc -= borderSize; + iwSrcProc.Alloc(iwSrc.m_size, ipp32f, channels); + CV_INSTRUMENT_FUN_IPP(::ipp::iwiScale, &iwSrc, &iwSrcProc, 1, 0, ippAlgHintFast); + iwSrcProc += borderSize; + } + + if(useScharr) + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterScharr, &iwSrcProc, &iwDstProc, derivType, maskSize, ippBorder); else - { - if (0 > ippiFilterScharrVertMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp8u, ipp16s, 1, &bufferSize)) - return false; - pBuffer = ippsMalloc_8u(bufferSize); - if (NULL == pBuffer) - return false; - sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrVertMaskBorder_8u16s_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer); - } - ippsFree(pBuffer); - } - else if ((CV_16S == stype) && (CV_16S == dtype)) - { - int bufferSize = 0; Ipp8u *pBuffer; - if (horz) - { - if (0 > ippiFilterScharrHorizMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp16s, ipp16s, 1, &bufferSize)) - return false; - pBuffer = ippsMalloc_8u(bufferSize); - if (NULL == pBuffer) - return false; - sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrHorizMaskBorder_16s_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer); - } - else - { - if (0 > ippiFilterScharrVertMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp16s, ipp16s, 1, &bufferSize)) - return false; - pBuffer = ippsMalloc_8u(bufferSize); - if (NULL == pBuffer) - return false; - sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrVertMaskBorder_16s_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer); - } - ippsFree(pBuffer); - } - else if ((CV_32F == stype) && (CV_32F == dtype)) - { - int bufferSize = 0; Ipp8u *pBuffer; - if (horz) - { - if (0 > ippiFilterScharrHorizMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp32f, ipp32f, 1, &bufferSize)) - return false; - pBuffer = ippsMalloc_8u(bufferSize); - if (NULL == pBuffer) - return false; - sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrHorizMaskBorder_32f_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer); - } - else - { - if (0 > ippiFilterScharrVertMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp32f, ipp32f, 1, &bufferSize)) - return false; - pBuffer = ippsMalloc_8u(bufferSize); - if (NULL == pBuffer) - return false; - sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrVertMaskBorder_32f_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer); - } - ippsFree(pBuffer); - if (sts < 0) - return false;; + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterSobel, &iwSrcProc, &iwDstProc, derivType, maskSize, ippBorder); - if (FLT_EPSILON < fabs(scale - 1.0)) - sts = CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1R, dst.ptr(), (int)dst.step, (Ipp32f)scale, dst.ptr(), (int)dst.step, roiSize); + if(useScale) + CV_INSTRUMENT_FUN_IPP(::ipp::iwiScale, &iwDstProc, &iwDst, scale, delta, ippAlgHintFast); } - return (0 <= sts); + catch (::ipp::IwException) + { + return false; + } + + return true; #else - CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(ddepth); CV_UNUSED(dx); CV_UNUSED(dy); CV_UNUSED(scale); CV_UNUSED(delta); CV_UNUSED(borderType); + CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(dx); CV_UNUSED(dy); CV_UNUSED(ksize); CV_UNUSED(scale); CV_UNUSED(delta); CV_UNUSED(borderType); return false; #endif } - -static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType) -{ - CV_INSTRUMENT_REGION_IPP() - - if (((borderType & ~BORDER_ISOLATED) != BORDER_REPLICATE) || ((3 != ksize) && (5 != ksize))) - return false; - if (fabs(delta) > FLT_EPSILON) - return false; - if (1 != _src.channels()) - return false; - - int bufSize = 0; - cv::AutoBuffer buffer; - Mat src = _src.getMat(), dst = _dst.getMat(); - - if ((borderType & BORDER_ISOLATED) == 0 && src.isSubmatrix()) - return false; - - if ( ddepth < 0 ) - ddepth = src.depth(); - - IppiSize roi = {src.cols, src.rows}; - IppiMaskSize kernel = (IppiMaskSize)(ksize*10+ksize); - - if (src.type() == CV_8U && dst.type() == CV_16S && scale == 1) - { - if ((dx == 1) && (dy == 0)) - { -#if IPP_VERSION_X100 >= 900 - if (0 > ippiFilterSobelNegVertBorderGetBufferSize(roi, kernel, ipp8u, ipp16s, 1,&bufSize)) - return false; - buffer.allocate(bufSize); -#else - if (0 > ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(roi, kernel,&bufSize)) - return false; - buffer.allocate(bufSize); -#endif - - if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelNegVertBorder_8u16s_C1R, src.ptr(), (int)src.step, - dst.ptr(), (int)dst.step, roi, kernel, - ippBorderRepl, 0, (Ipp8u*)(char*)buffer)) - return false; - return true; - } - - if ((dx == 0) && (dy == 1)) - { -#if IPP_VERSION_X100 >= 900 - if (0 > ippiFilterSobelHorizBorderGetBufferSize(roi, kernel, ipp8u, ipp16s, 1,&bufSize)) - return false; - buffer.allocate(bufSize); -#else - if (0 > ippiFilterSobelHorizGetBufferSize_8u16s_C1R(roi, kernel,&bufSize)) - return false; - buffer.allocate(bufSize); -#endif - - if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelHorizBorder_8u16s_C1R, src.ptr(), (int)src.step, - dst.ptr(), (int)dst.step, roi, kernel, - ippBorderRepl, 0, (Ipp8u*)(char*)buffer)) - return false; - return true; - } - - if ((dx == 2) && (dy == 0)) - { -#if IPP_VERSION_X100 >= 900 - if (0 > ippiFilterSobelVertSecondBorderGetBufferSize(roi, kernel, ipp8u, ipp16s, 1,&bufSize)) - return false; - buffer.allocate(bufSize); -#else - if (0 > ippiFilterSobelVertSecondGetBufferSize_8u16s_C1R(roi, kernel,&bufSize)) - return false; - buffer.allocate(bufSize); -#endif - - if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelVertSecondBorder_8u16s_C1R, src.ptr(), (int)src.step, - dst.ptr(), (int)dst.step, roi, kernel, - ippBorderRepl, 0, (Ipp8u*)(char*)buffer)) - return false; - return true; - } - - if ((dx == 0) && (dy == 2)) - { -#if IPP_VERSION_X100 >= 900 - if (0 > ippiFilterSobelHorizSecondBorderGetBufferSize(roi, kernel, ipp8u, ipp16s, 1,&bufSize)) - return false; - buffer.allocate(bufSize); -#else - if (0 > ippiFilterSobelHorizSecondGetBufferSize_8u16s_C1R(roi, kernel,&bufSize)) - return false; - buffer.allocate(bufSize); -#endif - - if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelHorizSecondBorder_8u16s_C1R, src.ptr(), (int)src.step, - dst.ptr(), (int)dst.step, roi, kernel, - ippBorderRepl, 0, (Ipp8u*)(char*)buffer)) - return false; - return true; - } - } - - if (src.type() == CV_32F && dst.type() == CV_32F) - { -#if IPP_DISABLE_BLOCK - if ((dx == 1) && (dy == 0)) - { -#if IPP_VERSION_X100 >= 900 - if (0 > ippiFilterSobelNegVertBorderGetBufferSize(roi, kernel, ipp32f, ipp32f, 1,&bufSize)) - return false; - buffer.allocate(bufSize); -#else - if (0 > ippiFilterSobelNegVertGetBufferSize_32f_C1R(roi, kernel, &bufSize)) - return false; - buffer.allocate(bufSize); -#endif - - if (0 > ippiFilterSobelNegVertBorder_32f_C1R(src.ptr(), (int)src.step, - dst.ptr(), (int)dst.step, roi, kernel, - ippBorderRepl, 0, (Ipp8u*)(char*)buffer)) - return false; - if(scale != 1) - ippiMulC_32f_C1R(dst.ptr(), (int)dst.step, (Ipp32f)scale, dst.ptr(), (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows)); - return true; - } - - if ((dx == 0) && (dy == 1)) - { -#if IPP_VERSION_X100 >= 900 - if (0 > ippiFilterSobelHorizBorderGetBufferSize(roi, kernel, ipp32f, ipp32f, 1,&bufSize)) - return false; - buffer.allocate(bufSize); -#else - if (0 > ippiFilterSobelHorizGetBufferSize_32f_C1R(roi, kernel,&bufSize)) - return false; - buffer.allocate(bufSize); -#endif - - if (0 > ippiFilterSobelHorizBorder_32f_C1R(src.ptr(), (int)src.step, - dst.ptr(), (int)dst.step, roi, kernel, - ippBorderRepl, 0, (Ipp8u*)(char*)buffer)) - return false; - if(scale != 1) - ippiMulC_32f_C1R(dst.ptr(), (int)dst.step, (Ipp32f)scale, dst.ptr(), (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows)); - return true; - } -#endif - - if((dx == 2) && (dy == 0)) - { -#if IPP_VERSION_X100 >= 900 - if (0 > ippiFilterSobelVertSecondBorderGetBufferSize(roi, kernel, ipp32f, ipp32f, 1,&bufSize)) - return false; - buffer.allocate(bufSize); -#else - if (0 > ippiFilterSobelVertSecondGetBufferSize_32f_C1R(roi, kernel,&bufSize)) - return false; - buffer.allocate(bufSize); -#endif - - if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelVertSecondBorder_32f_C1R, src.ptr(), (int)src.step, - dst.ptr(), (int)dst.step, roi, kernel, - ippBorderRepl, 0, (Ipp8u*)(char*)buffer)) - return false; - if(scale != 1) - CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1R, dst.ptr(), (int)dst.step, (Ipp32f)scale, dst.ptr(), (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows)); - return true; - } - - if((dx == 0) && (dy == 2)) - { -#if IPP_VERSION_X100 >= 900 - if (0 > ippiFilterSobelHorizSecondBorderGetBufferSize(roi, kernel, ipp32f, ipp32f, 1,&bufSize)) - return false; - buffer.allocate(bufSize); -#else - if (0 > ippiFilterSobelHorizSecondGetBufferSize_32f_C1R(roi, kernel,&bufSize)) - return false; - buffer.allocate(bufSize); -#endif - - if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelHorizSecondBorder_32f_C1R, src.ptr(), (int)src.step, - dst.ptr(), (int)dst.step, roi, kernel, - ippBorderRepl, 0, (Ipp8u*)(char*)buffer)) - return false; - - if(scale != 1) - CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1R, dst.ptr(), (int)dst.step, (Ipp32f)scale, dst.ptr(), (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows)); - return true; - } - } - return false; -} - -static bool ipp_sobel(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType) -{ - CV_INSTRUMENT_REGION_IPP() - - if (ksize < 0) - { - if (IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType)) - return true; - } - else if (0 < ksize) - { - if (IPPDerivSobel(_src, _dst, ddepth, dx, dy, ksize, scale, delta, borderType)) - return true; - } - return false; -} } #endif @@ -722,7 +475,7 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, CV_OVX_RUN(true, openvx_sobel(_src, _dst, dx, dy, ksize, scale, delta, borderType)) - CV_IPP_RUN(!(ocl::useOpenCL() && _dst.isUMat()), ipp_sobel(_src, _dst, ddepth, dx, dy, ksize, scale, delta, borderType)); + CV_IPP_RUN(!(ocl::useOpenCL() && _dst.isUMat()), ipp_Deriv(_src, _dst, dx, dy, ksize, scale, delta, borderType)); int ktype = std::max(CV_32F, std::max(ddepth, sdepth)); @@ -766,7 +519,7 @@ void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, } #endif - CV_IPP_RUN(!(ocl::useOpenCL() && _dst.isUMat()), IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType)); + CV_IPP_RUN(!(ocl::useOpenCL() && _dst.isUMat()), ipp_Deriv(_src, _dst, dx, dy, 0, scale, delta, borderType)); int ktype = std::max(CV_32F, std::max(ddepth, sdepth)); @@ -986,69 +739,71 @@ static bool ocl_Laplacian3_8UC1(InputArray _src, OutputArray _dst, int ddepth, #if defined(HAVE_IPP) namespace cv { -static bool ipp_Laplacian(InputArray _src, OutputArray _dst, int ddepth, int ksize, - double scale, double delta, int borderType) + +static bool ipp_Laplacian(InputArray _src, OutputArray _dst, int ksize, double scale, double delta, int borderType) { +#ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() - int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype); - if (ddepth < 0) - ddepth = sdepth; - _dst.create( _src.size(), CV_MAKETYPE(ddepth, cn) ); + ::ipp::IwiSize size(_src.size().width, _src.size().height); + IppDataType srcType = ippiGetDataType(_src.depth()); + IppDataType dstType = ippiGetDataType(_dst.depth()); + int channels = _src.channels(); + bool useScale = false; - int iscale = saturate_cast(scale), idelta = saturate_cast(delta); - bool floatScale = std::fabs(scale - iscale) > DBL_EPSILON, needScale = iscale != 1; - bool floatDelta = std::fabs(delta - idelta) > DBL_EPSILON, needDelta = delta != 0; - int borderTypeNI = borderType & ~BORDER_ISOLATED; - Mat src = _src.getMat(), dst = _dst.getMat(); + if(channels != _dst.channels() || channels > 1) + return false; - if (src.data != dst.data) + if(fabs(delta) > FLT_EPSILON || fabs(scale-1) > FLT_EPSILON) + useScale = true; + + IppiMaskSize maskSize = ippiGetMaskSize(ksize, ksize); + if(maskSize < 0) + return false; + + // Acquire data and begin processing + try { - Ipp32s bufsize; - IppStatus status = (IppStatus)-1; - IppiSize roisize = { src.cols, src.rows }; - IppiMaskSize masksize = ksize == 3 ? ippMskSize3x3 : ippMskSize5x5; - IppiBorderType borderTypeIpp = ippiGetBorderType(borderTypeNI); + Mat src = _src.getMat(); + Mat dst = _dst.getMat(); + ::ipp::IwiImage iwSrc = ippiGetImage(src); + ::ipp::IwiImage iwDst = ippiGetImage(dst); + ::ipp::IwiImage iwSrcProc = iwSrc; + ::ipp::IwiImage iwDstProc = iwDst; + ::ipp::IwiBorderSize borderSize(maskSize); + ::ipp::IwiBorderType ippBorder(ippiGetBorder(iwSrc, borderType, borderSize)); + if(!ippBorder.m_borderType) + return false; -#define IPP_FILTER_LAPLACIAN(ippsrctype, ippdsttype, ippfavor) \ - do \ - { \ - if (borderTypeIpp >= 0 && ippiFilterLaplacianGetBufferSize_##ippfavor##_C1R(roisize, masksize, &bufsize) >= 0) \ - { \ - Ipp8u * buffer = ippsMalloc_8u(bufsize); \ - status = CV_INSTRUMENT_FUN_IPP(ippiFilterLaplacianBorder_##ippfavor##_C1R, src.ptr(), (int)src.step, dst.ptr(), \ - (int)dst.step, roisize, masksize, borderTypeIpp, 0, buffer); \ - ippsFree(buffer); \ - } \ - } while ((void)0, 0) - - CV_SUPPRESS_DEPRECATED_START - if (sdepth == CV_8U && ddepth == CV_16S && !floatScale && !floatDelta) + if(srcType == ipp8u && dstType == ipp8u) { - IPP_FILTER_LAPLACIAN(Ipp8u, Ipp16s, 8u16s); - - if (needScale && status >= 0) - status = CV_INSTRUMENT_FUN_IPP(ippiMulC_16s_C1IRSfs, (Ipp16s)iscale, dst.ptr(), (int)dst.step, roisize, 0); - if (needDelta && status >= 0) - status = CV_INSTRUMENT_FUN_IPP(ippiAddC_16s_C1IRSfs, (Ipp16s)idelta, dst.ptr(), (int)dst.step, roisize, 0); + iwDstProc.Alloc(iwDst.m_size, ipp16s, channels); + useScale = true; } - else if (sdepth == CV_32F && ddepth == CV_32F) + else if(srcType == ipp8u && dstType == ipp32f) { - IPP_FILTER_LAPLACIAN(Ipp32f, Ipp32f, 32f); - - if (needScale && status >= 0) - status = CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1IR, (Ipp32f)scale, dst.ptr(), (int)dst.step, roisize); - if (needDelta && status >= 0) - status = CV_INSTRUMENT_FUN_IPP(ippiAddC_32f_C1IR, (Ipp32f)delta, dst.ptr(), (int)dst.step, roisize); + iwSrc -= borderSize; + iwSrcProc.Alloc(iwSrc.m_size, ipp32f, channels); + CV_INSTRUMENT_FUN_IPP(::ipp::iwiScale, &iwSrc, &iwSrcProc, 1, 0); + iwSrcProc += borderSize; } - CV_SUPPRESS_DEPRECATED_END - if (status >= 0) - return true; + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterLaplacian, &iwSrcProc, &iwDstProc, maskSize, ippBorder); + + if(useScale) + CV_INSTRUMENT_FUN_IPP(::ipp::iwiScale, &iwDstProc, &iwDst, scale, delta); + + } + catch (::ipp::IwException ex) + { + return false; } -#undef IPP_FILTER_LAPLACIAN + return true; +#else + CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(ksize); CV_UNUSED(scale); CV_UNUSED(delta); CV_UNUSED(borderType); return false; +#endif } } #endif @@ -1080,9 +835,7 @@ void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize, ocl_Laplacian3_8UC1(_src, _dst, ddepth, kernel, delta, borderType)); } - CV_IPP_RUN((ksize == 3 || ksize == 5) && ((borderType & BORDER_ISOLATED) != 0 || !_src.isSubmatrix()) && - ((stype == CV_8UC1 && ddepth == CV_16S) || (ddepth == CV_32F && stype == CV_32FC1)) && (!cv::ocl::useOpenCL()), - ipp_Laplacian(_src, _dst, ddepth, ksize, scale, delta, borderType)); + CV_IPP_RUN(!(cv::ocl::useOpenCL() && _dst.isUMat()), ipp_Laplacian(_src, _dst, ksize, scale, delta, borderType)); #ifdef HAVE_TEGRA_OPTIMIZATION diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp index 36914d89d8..aba0a774c1 100644 --- a/modules/imgproc/src/distransform.cpp +++ b/modules/imgproc/src/distransform.cpp @@ -681,6 +681,8 @@ namespace cv { static void distanceTransform_L1_8U(InputArray _src, OutputArray _dst) { + CV_INSTRUMENT_REGION() + Mat src = _src.getMat(); CV_Assert( src.type() == CV_8UC1); @@ -745,7 +747,9 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe #ifdef HAVE_IPP CV_IPP_CHECK() { - if ((currentParallelFramework()==NULL) || (src.total()<(int)(1<<14))) +#if IPP_DISABLE_PERF_TRUE_DIST_MT + if(cv::getNumThreads()<=1 || (src.total()<(int)(1<<14))) +#endif { IppStatus status; IppiSize roi = { src.cols, src.rows }; @@ -755,7 +759,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe status = ippiTrueDistanceTransformGetBufferSize_8u32f_C1R(roi, &bufSize); if (status>=0) { - pBuffer = (Ipp8u *)ippMalloc( bufSize ); + pBuffer = (Ipp8u *)CV_IPP_MALLOC( bufSize ); status = CV_INSTRUMENT_FUN_IPP(ippiTrueDistanceTransform_8u32f_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roi, pBuffer); ippFree( pBuffer ); if (status>=0) diff --git a/modules/imgproc/src/filter.cpp b/modules/imgproc/src/filter.cpp index 641f960ab3..51d0bc4f51 100644 --- a/modules/imgproc/src/filter.cpp +++ b/modules/imgproc/src/filter.cpp @@ -4635,7 +4635,7 @@ static bool ippFilter2D(int stype, int dtype, int ddepth = CV_MAT_DEPTH(dtype); int sdepth = CV_MAT_DEPTH(stype); -#if IPP_VERSION_X100 >= 201700 && IPP_VERSION_X100 < 201702 // IPP bug with 1x1 kernel +#if IPP_VERSION_X100 >= 201700 && IPP_VERSION_X100 <= 201702 // IPP bug with 1x1 kernel if(kernel_width == 1 && kernel_height == 1) return false; #endif @@ -4662,6 +4662,7 @@ static bool ippFilter2D(int stype, int dtype, Ipp32s bufsize = 0; IppiSize dstRoiSize = { width, height }; IppStatus status; + status = ippiFilterBorderGetSize(kernelSize, dstRoiSize, dataType, kernelType, cn, &specSize, &bufsize); if (status < 0) return false; @@ -4670,7 +4671,7 @@ static bool ippFilter2D(int stype, int dtype, size_t good_kernel_step = sizeof(kernel_type) * static_cast(kernelSize.width); #if IPP_VERSION_X100 >= 900 if (kernel_step != good_kernel_step) { - kernelBuffer.Alloc((int)good_kernel_step * kernelSize.height); + kernelBuffer.allocate((int)good_kernel_step * kernelSize.height); status = trait::get_copy_fun()((kernel_type*)kernel_data, (int)kernel_step, kernelBuffer, (int)good_kernel_step, kernelSize); if (status < 0) return false; @@ -4683,8 +4684,8 @@ static bool ippFilter2D(int stype, int dtype, flip(kernel, kerFlip, -1); pKerBuffer = kernelBuffer; #endif - spec.Alloc(specSize); - buffer.Alloc(bufsize); + spec.allocate(specSize); + buffer.allocate(bufsize); status = trait::runInit(pKerBuffer, kernelSize, 0, dataType, cn, ippRndFinancial, spec); if (status < 0) { return false; diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp index a0a2909511..aa229a92bc 100644 --- a/modules/imgproc/src/histogram.cpp +++ b/modules/imgproc/src/histogram.cpp @@ -1178,86 +1178,150 @@ calcHist_8u( std::vector& _ptrs, const std::vector& _deltas, } #ifdef HAVE_IPP -class IPPCalcHistInvoker : - public ParallelLoopBody + +typedef IppStatus(CV_STDCALL * IppiHistogram_C1)(const void* pSrc, int srcStep, + IppiSize roiSize, Ipp32u* pHist, const IppiHistogramSpec* pSpec, Ipp8u* pBuffer); + +static IppiHistogram_C1 getIppiHistogramFunction_C1(int type) +{ + IppiHistogram_C1 ippFunction = + (type == CV_8UC1) ? (IppiHistogram_C1)ippiHistogram_8u_C1R : +#if IPP_VERSION_X100 >= 201700 || !(defined HAVE_IPP_ICV_ONLY) + (type == CV_16UC1) ? (IppiHistogram_C1)ippiHistogram_16u_C1R : + (type == CV_32FC1) ? (IppiHistogram_C1)ippiHistogram_32f_C1R : +#endif + NULL; + + return ippFunction; +} + +class ipp_calcHistParallelTLS { public: - IPPCalcHistInvoker(const Mat & _src, Mat & _hist, AutoBuffer & _levels, Ipp32s _histSize, Ipp32f _low, Ipp32f _high, bool * _ok) : - ParallelLoopBody(), src(&_src), hist(&_hist), levels(&_levels), histSize(_histSize), low(_low), high(_high), ok(_ok) + ipp_calcHistParallelTLS() {} + + IppAutoBuffer spec; + IppAutoBuffer buffer; + IppAutoBuffer thist; +}; + +class ipp_calcHistParallel: public ParallelLoopBody +{ +public: + ipp_calcHistParallel(const Mat &src, Mat &hist, Ipp32s histSize, const float *ranges, bool uniform, bool &ok): + ParallelLoopBody(), m_src(src), m_hist(hist), m_ok(ok) { - *ok = true; + ok = true; + + m_uniform = uniform; + m_ranges = ranges; + m_histSize = histSize; + m_type = ippiGetDataType(src.type()); + m_levelsNum = histSize+1; + ippiHistogram_C1 = getIppiHistogramFunction_C1(src.type()); + if(!ippiHistogram_C1) + { + ok = false; + return; + } + + m_fullRoi = ippiSize(src.size()); + m_bufferSize = 0; + m_specSize = 0; + + if(ippiHistogramGetBufferSize(m_type, m_fullRoi, &m_levelsNum, 1, 1, &m_specSize, &m_bufferSize) < 0) + { + ok = false; + return; + } + + hist.setTo(0); } virtual void operator() (const Range & range) const { - Ipp32s levelNum = histSize + 1; - Mat phist(hist->size(), hist->type(), Scalar::all(0)); -#if IPP_VERSION_X100 >= 900 - IppiSize roi = {src->cols, range.end - range.start}; - int bufferSize = 0; - int specSize = 0; - IppiHistogramSpec *pSpec = NULL; - Ipp8u *pBuffer = NULL; + CV_INSTRUMENT_REGION_IPP() - if(ippiHistogramGetBufferSize(ipp8u, roi, &levelNum, 1, 1, &specSize, &bufferSize) < 0) + if(!m_ok) + return; + + ipp_calcHistParallelTLS *pTls = m_tls.get(); + + IppiSize roi = {m_src.cols, range.end - range.start }; + bool mtLoop = false; + if(m_fullRoi.height != roi.height) + mtLoop = true; + + if(!pTls->spec) { - *ok = false; + pTls->spec.allocate(m_specSize); + if(!pTls->spec.get()) + { + m_ok = false; + return; + } + + pTls->buffer.allocate(m_bufferSize); + if(!pTls->buffer.get() && m_bufferSize) + { + m_ok = false; + return; + } + + if(m_uniform) + { + if(ippiHistogramUniformInit(m_type, (Ipp32f*)&m_ranges[0], (Ipp32f*)&m_ranges[1], (Ipp32s*)&m_levelsNum, 1, pTls->spec) < 0) + { + m_ok = false; + return; + } + } + else + { + if(ippiHistogramInit(m_type, (const Ipp32f**)&m_ranges, (Ipp32s*)&m_levelsNum, 1, pTls->spec) < 0) + { + m_ok = false; + return; + } + } + + pTls->thist.allocate(m_histSize*sizeof(Ipp32u)); + } + + if(CV_INSTRUMENT_FUN_IPP(ippiHistogram_C1, m_src.ptr(range.start), (int)m_src.step, roi, pTls->thist, pTls->spec, pTls->buffer) < 0) + { + m_ok = false; return; } - pBuffer = (Ipp8u*)ippMalloc(bufferSize); - if(!pBuffer && bufferSize) + if(mtLoop) { - *ok = false; - return; + for(int i = 0; i < m_histSize; i++) + CV_XADD((int*)(m_hist.ptr(i)), *(int*)((Ipp32u*)pTls->thist + i)); } - - pSpec = (IppiHistogramSpec*)ippMalloc(specSize); - if(!pSpec && specSize) - { - if(pBuffer) ippFree(pBuffer); - *ok = false; - return; - } - - if(ippiHistogramUniformInit(ipp8u, (Ipp32f*)&low, (Ipp32f*)&high, (Ipp32s*)&levelNum, 1, pSpec) < 0) - { - if(pSpec) ippFree(pSpec); - if(pBuffer) ippFree(pBuffer); - *ok = false; - return; - } - - IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiHistogram_8u_C1R, src->ptr(range.start), (int)src->step, ippiSize(src->cols, range.end - range.start), - phist.ptr(), pSpec, pBuffer); - - if(pSpec) ippFree(pSpec); - if(pBuffer) ippFree(pBuffer); -#else - CV_SUPPRESS_DEPRECATED_START - IppStatus status = ippiHistogramEven_8u_C1R(src->ptr(range.start), (int)src->step, ippiSize(src->cols, range.end - range.start), - phist.ptr(), (Ipp32s*)(Ipp32f*)*levels, levelNum, (Ipp32s)low, (Ipp32s)high); - CV_SUPPRESS_DEPRECATED_END -#endif - if(status < 0) - { - *ok = false; - return; - } - - for (int i = 0; i < histSize; ++i) - CV_XADD((int *)(hist->data + i * hist->step), *(int *)(phist.data + i * phist.step)); + else + ippiCopy_32s_C1R((Ipp32s*)pTls->thist.get(), sizeof(Ipp32u), (Ipp32s*)m_hist.ptr(), (int)m_hist.step, ippiSize(1, m_histSize)); } private: - const Mat * src; - Mat * hist; - AutoBuffer * levels; - Ipp32s histSize; - Ipp32f low, high; - bool * ok; + const Mat &m_src; + Mat &m_hist; + Ipp32s m_histSize; + const float *m_ranges; + bool m_uniform; - const IPPCalcHistInvoker & operator = (const IPPCalcHistInvoker & ); + IppiHistogram_C1 ippiHistogram_C1; + IppiSize m_fullRoi; + IppDataType m_type; + Ipp32s m_levelsNum; + int m_bufferSize; + int m_specSize; + + mutable Mutex m_syncMutex; + TLSData m_tls; + + volatile bool &m_ok; + const ipp_calcHistParallel & operator = (const ipp_calcHistParallel & ); }; #endif @@ -1319,49 +1383,49 @@ namespace cv } #endif -#if defined(HAVE_IPP) +#ifdef HAVE_IPP +#define IPP_HISTOGRAM_PARALLEL 1 namespace cv { -static bool ipp_calchist(const Mat* images, int nimages, const int* channels, - InputArray _mask, OutputArray _hist, int dims, const int* histSize, - const float** ranges, bool uniform, bool accumulate ) +static bool ipp_calchist(const Mat &image, Mat &hist, int histSize, const float** ranges, bool uniform, bool accumulate) { CV_INSTRUMENT_REGION_IPP() - Mat mask = _mask.getMat(); - - CV_Assert(dims > 0 && histSize); - - _hist.create(dims, histSize, CV_32F); - Mat hist = _hist.getMat(), ihist = hist; - ihist.flags = (ihist.flags & ~CV_MAT_TYPE_MASK)|CV_32S; - - { - if (nimages == 1 && images[0].type() == CV_8UC1 && dims == 1 && channels && - channels[0] == 0 && mask.empty() && images[0].dims <= 2 && - !accumulate && uniform) - { - ihist.setTo(Scalar::all(0)); - AutoBuffer levels(histSize[0]); - - bool ok = true; - const Mat & src = images[0]; - int nstripes = std::min(8, static_cast(src.total() / (1 << 16))); -#ifdef HAVE_CONCURRENCY - nstripes = 1; + // No SSE42 optimization for uniform 32f +#if IPP_DISABLE_PERF_HISTU32F_SSE42 + if(uniform && image.depth() == CV_32F && !(ipp::getIppFeatures()&ippCPUID_AVX)) + return false; #endif - IPPCalcHistInvoker invoker(src, ihist, levels, histSize[0], ranges[0][0], ranges[0][1], &ok); - Range range(0, src.rows); - parallel_for_(range, invoker, nstripes); - if (ok) - { - ihist.convertTo(hist, CV_32F); - return true; - } + Mat ihist = hist; + if(accumulate) + ihist.create(1, &histSize, CV_32S); + + bool ok = true; + int threads = ippiSuggestThreadsNum(image, (1+((double)ihist.total()/image.total()))*2); + Range range(0, image.rows); + ipp_calcHistParallel invoker(image, ihist, histSize, ranges[0], uniform, ok); + if(!ok) + return false; + + if(IPP_HISTOGRAM_PARALLEL && threads > 1) + parallel_for_(range, invoker, threads*2); + else + invoker(range); + + if(ok) + { + if(accumulate) + { + IppiSize histRoi = ippiSize(1, histSize); + IppAutoBuffer fhist(histSize*sizeof(Ipp32f)); + CV_INSTRUMENT_FUN_IPP(ippiConvert_32s32f_C1R, (Ipp32s*)ihist.ptr(), (int)ihist.step, (Ipp32f*)fhist, sizeof(Ipp32f), histRoi); + CV_INSTRUMENT_FUN_IPP(ippiAdd_32f_C1IR, (Ipp32f*)fhist, sizeof(Ipp32f), (Ipp32f*)hist.ptr(), (int)hist.step, histRoi); } + else + CV_INSTRUMENT_FUN_IPP(ippiConvert_32s32f_C1R, (Ipp32s*)ihist.ptr(), (int)ihist.step, (Ipp32f*)hist.ptr(), (int)hist.step, ippiSize(1, histSize)); } - return false; + return ok; } } #endif @@ -1379,23 +1443,24 @@ void cv::calcHist( const Mat* images, int nimages, const int* channels, ranges && ranges[0], openvx_calchist(images[0], _hist, histSize[0], ranges[0])) - CV_IPP_RUN(nimages == 1 && images[0].type() == CV_8UC1 && dims == 1 && channels && - channels[0] == 0 && _mask.getMat().empty() && images[0].dims <= 2 && - !accumulate && uniform, - ipp_calchist(images, nimages, channels, - _mask, _hist, dims, histSize, - ranges, uniform, accumulate)); - Mat mask = _mask.getMat(); CV_Assert(dims > 0 && histSize); const uchar* const histdata = _hist.getMat().ptr(); _hist.create(dims, histSize, CV_32F); - Mat hist = _hist.getMat(), ihist = hist; + Mat hist = _hist.getMat(); + + if(histdata != hist.data) + accumulate = false; + + CV_IPP_RUN(nimages == 1 && dims == 1 && channels && channels[0] == 0 && _mask.empty() && images[0].dims <= 2, + ipp_calchist(images[0], hist, histSize[0], ranges, uniform, accumulate)); + + Mat ihist = hist; ihist.flags = (ihist.flags & ~CV_MAT_TYPE_MASK)|CV_32S; - if( !accumulate || histdata != hist.data ) + if(!accumulate) hist = Scalar(0.); else hist.convertTo(ihist, CV_32S); diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index 84a7e5218a..21dddcbbdb 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -57,73 +57,66 @@ using namespace cv; namespace cv { -#if IPP_VERSION_X100 >= 710 - typedef IppStatus (CV_STDCALL* ippiResizeFunc)(const void*, int, const void*, int, IppiPoint, IppiSize, IppiBorderType, void*, void*, Ipp8u*); - typedef IppStatus (CV_STDCALL* ippiResizeGetBufferSize)(void*, IppiSize, Ipp32u, int*); - typedef IppStatus (CV_STDCALL* ippiResizeGetSrcOffset)(void*, IppiPoint, IppiPoint*); -#endif -#if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700) && IPP_DISABLE_BLOCK - typedef IppStatus (CV_STDCALL* ippiSetFunc)(const void*, void *, int, IppiSize); - typedef IppStatus (CV_STDCALL* ippiWarpPerspectiveFunc)(const void*, IppiSize, int, IppiRect, void *, int, IppiRect, double [3][3], int); - typedef IppStatus (CV_STDCALL* ippiWarpAffineBackFunc)(const void*, IppiSize, int, IppiRect, void *, int, IppiRect, double [2][3], int); +#if defined (HAVE_IPP) && (!IPP_DISABLE_WARPAFFINE || !IPP_DISABLE_WARPPERSPECTIVE || !IPP_DISABLE_REMAP) +typedef IppStatus (CV_STDCALL* ippiSetFunc)(const void*, void *, int, IppiSize); - template - bool IPPSetSimple(cv::Scalar value, void *dataPointer, int step, IppiSize &size, ippiSetFunc func) +template +bool IPPSetSimple(cv::Scalar value, void *dataPointer, int step, IppiSize &size, ippiSetFunc func) +{ + CV_INSTRUMENT_REGION_IPP() + + Type values[channels]; + for( int i = 0; i < channels; i++ ) + values[i] = saturate_cast(value[i]); + return func(values, dataPointer, step, size) >= 0; +} + +static bool IPPSet(const cv::Scalar &value, void *dataPointer, int step, IppiSize &size, int channels, int depth) +{ + CV_INSTRUMENT_REGION_IPP() + + if( channels == 1 ) { - CV_INSTRUMENT_REGION_IPP() - - Type values[channels]; - for( int i = 0; i < channels; i++ ) - values[i] = saturate_cast(value[i]); - return func(values, dataPointer, step, size) >= 0; + switch( depth ) + { + case CV_8U: + return CV_INSTRUMENT_FUN_IPP(ippiSet_8u_C1R, saturate_cast(value[0]), (Ipp8u *)dataPointer, step, size) >= 0; + case CV_16U: + return CV_INSTRUMENT_FUN_IPP(ippiSet_16u_C1R, saturate_cast(value[0]), (Ipp16u *)dataPointer, step, size) >= 0; + case CV_32F: + return CV_INSTRUMENT_FUN_IPP(ippiSet_32f_C1R, saturate_cast(value[0]), (Ipp32f *)dataPointer, step, size) >= 0; + } } - - static bool IPPSet(const cv::Scalar &value, void *dataPointer, int step, IppiSize &size, int channels, int depth) + else { - CV_INSTRUMENT_REGION_IPP() - - if( channels == 1 ) + if( channels == 3 ) { switch( depth ) { case CV_8U: - return CV_INSTRUMENT_FUN_IPP(ippiSet_8u_C1R,(saturate_cast(value[0]), (Ipp8u *)dataPointer, step, size)) >= 0; + return IPPSetSimple<3, Ipp8u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_8u_C3R); case CV_16U: - return CV_INSTRUMENT_FUN_IPP(ippiSet_16u_C1R,(saturate_cast(value[0]), (Ipp16u *)dataPointer, step, size)) >= 0; + return IPPSetSimple<3, Ipp16u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_16u_C3R); case CV_32F: - return CV_INSTRUMENT_FUN_IPP(ippiSet_32f_C1R,(saturate_cast(value[0]), (Ipp32f *)dataPointer, step, size)) >= 0; + return IPPSetSimple<3, Ipp32f>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_32f_C3R); } } - else + else if( channels == 4 ) { - if( channels == 3 ) + switch( depth ) { - switch( depth ) - { - case CV_8U: - return IPPSetSimple<3, Ipp8u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_8u_C3R); - case CV_16U: - return IPPSetSimple<3, Ipp16u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_16u_C3R); - case CV_32F: - return IPPSetSimple<3, Ipp32f>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_32f_C3R); - } - } - else if( channels == 4 ) - { - switch( depth ) - { - case CV_8U: - return IPPSetSimple<4, Ipp8u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_8u_C4R); - case CV_16U: - return IPPSetSimple<4, Ipp16u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_16u_C4R); - case CV_32F: - return IPPSetSimple<4, Ipp32f>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_32f_C4R); - } + case CV_8U: + return IPPSetSimple<4, Ipp8u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_8u_C4R); + case CV_16U: + return IPPSetSimple<4, Ipp16u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_16u_C4R); + case CV_32F: + return IPPSetSimple<4, Ipp32f>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_32f_C4R); } } - return false; } + return false; +} #endif /************** interpolation formulas and tables ***************/ @@ -2708,135 +2701,7 @@ static int computeResizeAreaTab( int ssize, int dsize, int cn, double scale, Dec return k; } -#define CHECK_IPP_STATUS(STATUS) if (STATUS < 0) { *ok = false; return; } - -#define SET_IPP_RESIZE_LINEAR_FUNC_PTR(TYPE, CN) \ - ippiResize = (ippiResizeFunc)ippiResizeLinear_##TYPE##_##CN##R; \ - CHECK_IPP_STATUS(ippiResizeGetSize_##TYPE(srcSize, dstSize, (IppiInterpolationType)mode, 0, &specSize, &initSize));\ - specBuf.allocate(specSize);\ - pSpec = (uchar*)specBuf;\ - CHECK_IPP_STATUS(ippiResizeLinearInit_##TYPE(srcSize, dstSize, (IppiResizeSpec_32f*)pSpec)); - -#define SET_IPP_RESIZE_LINEAR_FUNC_64_PTR(TYPE, CN) \ - if (mode == (int)ippCubic) { *ok = false; return; } \ - ippiResize = (ippiResizeFunc)ippiResizeLinear_##TYPE##_##CN##R; \ - CHECK_IPP_STATUS(ippiResizeGetSize_##TYPE(srcSize, dstSize, (IppiInterpolationType)mode, 0, &specSize, &initSize));\ - specBuf.allocate(specSize);\ - pSpec = (uchar*)specBuf;\ - CHECK_IPP_STATUS(ippiResizeLinearInit_##TYPE(srcSize, dstSize, (IppiResizeSpec_64f*)pSpec));\ - getBufferSizeFunc = (ippiResizeGetBufferSize)ippiResizeGetBufferSize_##TYPE;\ - getSrcOffsetFunc = (ippiResizeGetSrcOffset) ippiResizeGetSrcOffset_##TYPE; - -#define SET_IPP_RESIZE_CUBIC_FUNC_PTR(TYPE, CN) \ - ippiResize = (ippiResizeFunc)ippiResizeCubic_##TYPE##_##CN##R; \ - CHECK_IPP_STATUS(ippiResizeGetSize_##TYPE(srcSize, dstSize, (IppiInterpolationType)mode, 0, &specSize, &initSize));\ - specBuf.allocate(specSize);\ - pSpec = (uchar*)specBuf;\ - AutoBuffer buf(initSize);\ - uchar* pInit = (uchar*)buf;\ - CHECK_IPP_STATUS(ippiResizeCubicInit_##TYPE(srcSize, dstSize, 0.f, 0.75f, (IppiResizeSpec_32f*)pSpec, pInit)); - -#define SET_IPP_RESIZE_PTR(TYPE, CN) \ - if (mode == (int)ippLinear) { SET_IPP_RESIZE_LINEAR_FUNC_PTR(TYPE, CN);} \ - else if (mode == (int)ippCubic) { SET_IPP_RESIZE_CUBIC_FUNC_PTR(TYPE, CN);} \ - else { *ok = false; return; } \ - getBufferSizeFunc = (ippiResizeGetBufferSize)ippiResizeGetBufferSize_##TYPE; \ - getSrcOffsetFunc = (ippiResizeGetSrcOffset)ippiResizeGetSrcOffset_##TYPE; - -#if IPP_VERSION_X100 >= 710 -class IPPresizeInvoker : - public ParallelLoopBody -{ -public: - IPPresizeInvoker(const Mat & _src, Mat & _dst, double _inv_scale_x, double _inv_scale_y, int _mode, bool *_ok) : - ParallelLoopBody(), src(_src), dst(_dst), inv_scale_x(_inv_scale_x), - inv_scale_y(_inv_scale_y), pSpec(NULL), mode(_mode), - ippiResize(NULL), getBufferSizeFunc(NULL), getSrcOffsetFunc(NULL), ok(_ok) - { - *ok = true; - IppiSize srcSize, dstSize; - int type = src.type(), specSize = 0, initSize = 0; - srcSize.width = src.cols; - srcSize.height = src.rows; - dstSize.width = dst.cols; - dstSize.height = dst.rows; - - switch (type) - { -#if IPP_DISABLE_BLOCK // disabled since it breaks tests for CascadeClassifier - case CV_8UC1: SET_IPP_RESIZE_PTR(8u,C1); break; - case CV_8UC3: SET_IPP_RESIZE_PTR(8u,C3); break; - case CV_8UC4: SET_IPP_RESIZE_PTR(8u,C4); break; -#endif - case CV_16UC1: SET_IPP_RESIZE_PTR(16u,C1); break; - case CV_16UC3: SET_IPP_RESIZE_PTR(16u,C3); break; - case CV_16UC4: SET_IPP_RESIZE_PTR(16u,C4); break; - case CV_16SC1: SET_IPP_RESIZE_PTR(16s,C1); break; - case CV_16SC3: SET_IPP_RESIZE_PTR(16s,C3); break; - case CV_16SC4: SET_IPP_RESIZE_PTR(16s,C4); break; - case CV_32FC1: SET_IPP_RESIZE_PTR(32f,C1); break; - case CV_32FC3: SET_IPP_RESIZE_PTR(32f,C3); break; - case CV_32FC4: SET_IPP_RESIZE_PTR(32f,C4); break; - case CV_64FC1: SET_IPP_RESIZE_LINEAR_FUNC_64_PTR(64f,C1); break; - case CV_64FC3: SET_IPP_RESIZE_LINEAR_FUNC_64_PTR(64f,C3); break; - case CV_64FC4: SET_IPP_RESIZE_LINEAR_FUNC_64_PTR(64f,C4); break; - default: { *ok = false; return; } break; - } - } - - ~IPPresizeInvoker() - { - } - - virtual void operator() (const Range& range) const - { - if (*ok == false) - return; - - int cn = src.channels(); - int dsty = min(cvRound(range.start * inv_scale_y), dst.rows); - int dstwidth = min(cvRound(src.cols * inv_scale_x), dst.cols); - int dstheight = min(cvRound(range.end * inv_scale_y), dst.rows); - - IppiPoint dstOffset = { 0, dsty }, srcOffset = {0, 0}; - IppiSize dstSize = { dstwidth, dstheight - dsty }; - int bufsize = 0, itemSize = (int)src.elemSize1(); - - CHECK_IPP_STATUS(getBufferSizeFunc(pSpec, dstSize, cn, &bufsize)); - CHECK_IPP_STATUS(getSrcOffsetFunc(pSpec, dstOffset, &srcOffset)); - - const Ipp8u* pSrc = src.ptr(srcOffset.y) + srcOffset.x * cn * itemSize; - Ipp8u* pDst = dst.ptr(dstOffset.y) + dstOffset.x * cn * itemSize; - - AutoBuffer buf(bufsize + 64); - uchar* bufptr = alignPtr((uchar*)buf, 32); - - if( CV_INSTRUMENT_FUN_IPP(ippiResize, pSrc, (int)src.step[0], pDst, (int)dst.step[0], dstOffset, dstSize, ippBorderRepl, 0, pSpec, bufptr) < 0 ) - *ok = false; - else - { - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); - } - } -private: - const Mat & src; - Mat & dst; - double inv_scale_x; - double inv_scale_y; - void *pSpec; - AutoBuffer specBuf; - int mode; - ippiResizeFunc ippiResize; - ippiResizeGetBufferSize getBufferSizeFunc; - ippiResizeGetSrcOffset getSrcOffsetFunc; - bool *ok; - const IPPresizeInvoker& operator= (const IPPresizeInvoker&); -}; - -#endif - #ifdef HAVE_OPENCL - static void ocl_computeResizeAreaTabs(int ssize, int dsize, double scale, int * const map_tab, float * const alpha_tab, int * const ofs_tab) { @@ -3090,28 +2955,190 @@ static bool ocl_resize( InputArray _src, OutputArray _dst, Size dsize, #endif -#if IPP_VERSION_X100 >= 710 -static bool ipp_resize_mt(Mat & src, Mat & dst, - double inv_scale_x, double inv_scale_y, int interpolation) +#ifdef HAVE_IPP +#define IPP_RESIZE_PARALLEL 1 + +#ifdef HAVE_IPP_IW +class ipp_resizeParallel: public ParallelLoopBody { +public: + ipp_resizeParallel(::ipp::IwiImage &src, ::ipp::IwiImage &dst, bool &ok): + m_src(src), m_dst(dst), m_ok(ok) {} + ~ipp_resizeParallel() + { + } + + void Init(IppiInterpolationType inter) + { + iwiResize.InitAlloc(m_src.m_size, m_dst.m_size, m_src.m_dataType, m_src.m_channels, inter, ::ipp::IwiResizeParams(0, 0, 0.75, 4), ippBorderRepl); + + m_ok = true; + } + + virtual void operator() (const Range& range) const + { + CV_INSTRUMENT_REGION_IPP() + + if(!m_ok) + return; + + try + { + ::ipp::IwiRoi roi = ::ipp::IwiRect(0, range.start, m_dst.m_size.width, range.end - range.start); + CV_INSTRUMENT_FUN_IPP(iwiResize, &m_src, &m_dst, &roi); + } + catch(::ipp::IwException) + { + m_ok = false; + return; + } + } +private: + ::ipp::IwiImage &m_src; + ::ipp::IwiImage &m_dst; + + mutable ::ipp::IwiResize iwiResize; + + volatile bool &m_ok; + const ipp_resizeParallel& operator= (const ipp_resizeParallel&); +}; + +class ipp_resizeAffineParallel: public ParallelLoopBody +{ +public: + ipp_resizeAffineParallel(::ipp::IwiImage &src, ::ipp::IwiImage &dst, bool &ok): + m_src(src), m_dst(dst), m_ok(ok) {} + ~ipp_resizeAffineParallel() + { + } + + void Init(IppiInterpolationType inter, double scaleX, double scaleY) + { + double shift = (inter == ippNearest)?-1e-10:-0.5; + double coeffs[2][3] = { + {scaleX, 0, shift+0.5*scaleX}, + {0, scaleY, shift+0.5*scaleY} + }; + + iwiWarpAffine.InitAlloc(m_src.m_size, m_dst.m_size, m_src.m_dataType, m_src.m_channels, coeffs, ippWarpForward, inter, ::ipp::IwiWarpAffineParams(0, 0.75, 0), ippBorderRepl); + + m_ok = true; + } + + virtual void operator() (const Range& range) const + { + CV_INSTRUMENT_REGION_IPP() + + if(!m_ok) + return; + + try + { + ::ipp::IwiRoi roi = ::ipp::IwiRect(0, range.start, m_dst.m_size.width, range.end - range.start); + CV_INSTRUMENT_FUN_IPP(iwiWarpAffine, &m_src, &m_dst, &roi); + } + catch(::ipp::IwException) + { + m_ok = false; + return; + } + } +private: + ::ipp::IwiImage &m_src; + ::ipp::IwiImage &m_dst; + + mutable ::ipp::IwiWarpAffine iwiWarpAffine; + + volatile bool &m_ok; + const ipp_resizeAffineParallel& operator= (const ipp_resizeAffineParallel&); +}; +#endif + +static bool ipp_resize(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, double inv_scale_x, double inv_scale_y, + int depth, int channels, int interpolation) +{ +#ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() - int mode = -1; - if (interpolation == INTER_LINEAR && src.rows >= 2 && src.cols >= 2) - mode = ippLinear; - else if (interpolation == INTER_CUBIC && src.rows >= 4 && src.cols >= 4) - mode = ippCubic; - else + IppDataType ippDataType = ippiGetDataType(depth); + IppiInterpolationType ippInter = ippiGetInterpolation(interpolation); + if(ippInter < 0) return false; - bool ok = true; - Range range(0, src.rows); - IPPresizeInvoker invoker(src, dst, inv_scale_x, inv_scale_y, mode, &ok); - parallel_for_(range, invoker, dst.total()/(double)(1<<16)); - if( ok ) - return true; +#if IPP_DISABLE_RESIZE_NEAREST + if(ippInter == ippNearest) + return false; +#endif +#if IPP_DISABLE_RESIZE_AREA + if(ippInter == ippSuper) + return false; +#endif + + if(ippInter != ippLinear && ippDataType == ipp64f) + return false; + + // Accuracy mismatch is 1 but affects detectors greatly +#if IPP_DISABLE_RESIZE_8U + if(ippDataType == ipp8u && ippInter == ippLinear) + return false; +#endif + + bool affine = false; + const double IPP_RESIZE_EPS = (depth == CV_64F)?0:1e-10; + double ex = fabs((double)dst_width / src_width - inv_scale_x) / inv_scale_x; + double ey = fabs((double)dst_height / src_height - inv_scale_y) / inv_scale_y; + + // Use affine transform resize to allow sub-pixel accuracy + if(ex > IPP_RESIZE_EPS || ey > IPP_RESIZE_EPS) + affine = true; + + // Affine doesn't support Lanczos and Super interpolations + if(affine && (ippInter == ippLanczos || ippInter == ippSuper)) + return false; + + try + { + ::ipp::IwiImage iwSrc(::ipp::IwiSize(src_width, src_height), ippDataType, channels, 0, (void*)src_data, src_step); + ::ipp::IwiImage iwDst(::ipp::IwiSize(dst_width, dst_height), ippDataType, channels, 0, (void*)dst_data, dst_step); + + bool ok; + int threads = ippiSuggestThreadsNum(iwDst, 1+((double)(src_width*src_height)/(dst_width*dst_height))); + Range range(0, dst_height); + ipp_resizeParallel invokerGeneral(iwSrc, iwDst, ok); + ipp_resizeAffineParallel invokerAffine(iwSrc, iwDst, ok); + ParallelLoopBody *pInvoker = NULL; + if(affine) + { + pInvoker = &invokerAffine; + invokerAffine.Init(ippInter, inv_scale_x, inv_scale_y); + } + else + { + pInvoker = &invokerGeneral; + invokerGeneral.Init(ippInter); + } + + if(IPP_RESIZE_PARALLEL && threads > 1) + parallel_for_(range, *pInvoker, threads*4); + else + pInvoker->operator()(range); + + if(!ok) + return false; + } + catch(::ipp::IwException) + { + return false; + } + return true; +#else + CV_UNUSED(src_data); CV_UNUSED(src_step); CV_UNUSED(src_width); CV_UNUSED(src_height); CV_UNUSED(dst_data); CV_UNUSED(dst_step); + CV_UNUSED(dst_width); CV_UNUSED(dst_height); CV_UNUSED(inv_scale_x); CV_UNUSED(inv_scale_y); CV_UNUSED(depth); + CV_UNUSED(channels); CV_UNUSED(interpolation); return false; +#endif } #endif @@ -3135,6 +3162,13 @@ void resize(int src_type, CALL_HAL(resize, cv_hal_resize, src_type, src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, inv_scale_x, inv_scale_y, interpolation); + int depth = CV_MAT_DEPTH(src_type), cn = CV_MAT_CN(src_type); + Size dsize = Size(saturate_cast(src_width*inv_scale_x), + saturate_cast(src_height*inv_scale_y)); + CV_Assert( dsize.area() > 0 ); + + CV_IPP_RUN_FAST(ipp_resize(src_data, src_step, src_width, src_height, dst_data, dst_step, dsize.width, dsize.height, inv_scale_x, inv_scale_y, depth, cn, interpolation)) + static ResizeFunc linear_tab[] = { resizeGeneric_< @@ -3239,7 +3273,6 @@ void resize(int src_type, resizeArea_, 0 }; - int depth = CV_MAT_DEPTH(src_type), cn = CV_MAT_CN(src_type); double scale_x = 1./inv_scale_x, scale_y = 1./inv_scale_y; int iscale_x = saturate_cast(scale_x); @@ -3248,31 +3281,9 @@ void resize(int src_type, bool is_area_fast = std::abs(scale_x - iscale_x) < DBL_EPSILON && std::abs(scale_y - iscale_y) < DBL_EPSILON; - Size dsize = Size(saturate_cast(src_width*inv_scale_x), - saturate_cast(src_height*inv_scale_y)); - CV_Assert( dsize.area() > 0 ); - Mat src(Size(src_width, src_height), src_type, const_cast(src_data), src_step); Mat dst(dsize, src_type, dst_data, dst_step); -#ifdef HAVE_IPP - int mode = -1; - if (interpolation == INTER_LINEAR && src_height >= 2 && src_width >= 2) - mode = INTER_LINEAR; - else if (interpolation == INTER_CUBIC && src_height >= 4 && src_width >= 4) - mode = INTER_CUBIC; - - const double IPP_RESIZE_EPS = 1e-10; - double ex = fabs((double)dsize.width / src_width - inv_scale_x) / inv_scale_x; - double ey = fabs((double)dsize.height / src_height - inv_scale_y) / inv_scale_y; -#endif - CV_IPP_RUN(IPP_VERSION_X100 >= 710 && ((ex < IPP_RESIZE_EPS && ey < IPP_RESIZE_EPS && depth != CV_64F) || (ex == 0 && ey == 0 && depth == CV_64F)) && - (interpolation == INTER_LINEAR || interpolation == INTER_CUBIC) && - !(interpolation == INTER_LINEAR && is_area_fast && iscale_x == 2 && iscale_y == 2 && depth == CV_8U) && - mode >= 0 && (cn == 1 || cn == 3 || cn == 4) && (depth == CV_16U || depth == CV_16S || depth == CV_32F || - (depth == CV_64F && mode == INTER_LINEAR)), - ipp_resize_mt(src, dst, inv_scale_x, inv_scale_y, interpolation)) - if( interpolation == INTER_NEAREST ) { resizeNN( src, dst, inv_scale_x, inv_scale_y ); @@ -4829,7 +4840,7 @@ static bool openvx_remap(Mat src, Mat dst, Mat map1, Mat map2, int interpolation } #endif -#if defined HAVE_IPP && IPP_DISABLE_BLOCK +#if defined HAVE_IPP && !IPP_DISABLE_REMAP typedef IppStatus (CV_STDCALL * ippiRemap)(const void * pSrc, IppiSize srcSize, int srcStep, IppiRect srcRoi, const Ipp32f* pxMap, int xMapStep, const Ipp32f* pyMap, int yMapStep, @@ -4861,9 +4872,9 @@ public: return; } - if (CV_INSTRUMENT_FUN_PTR_CALL_IPP(ippFunc,(src.ptr(), ippiSize(src.size()), (int)src.step, srcRoiRect, + if (CV_INSTRUMENT_FUN_IPP(ippFunc, src.ptr(), ippiSize(src.size()), (int)src.step, srcRoiRect, map1.ptr(), (int)map1.step, map2.ptr(), (int)map2.step, - dstRoi.ptr(), (int)dstRoi.step, dstRoiSize, ippInterpolation)) < 0) + dstRoi.ptr(), (int)dstRoi.step, dstRoiSize, ippInterpolation) < 0) *ok = false; else { @@ -4952,7 +4963,7 @@ void cv::remap( InputArray _src, OutputArray _dst, int type = src.type(), depth = CV_MAT_DEPTH(type); -#if defined HAVE_IPP && IPP_DISABLE_BLOCK +#if defined HAVE_IPP && !IPP_DISABLE_REMAP CV_IPP_CHECK() { if ((interpolation == INTER_LINEAR || interpolation == INTER_CUBIC || interpolation == INTER_NEAREST) && @@ -5680,7 +5691,9 @@ private: }; -#if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_WARPAFFINE +typedef IppStatus (CV_STDCALL* ippiWarpAffineBackFunc)(const void*, IppiSize, int, IppiRect, void *, int, IppiRect, double [2][3], int); + class IPPWarpAffineInvoker : public ParallelLoopBody { @@ -5711,7 +5724,7 @@ public: } // Aug 2013: problem in IPP 7.1, 8.0 : sometimes function return ippStsCoeffErr - IppStatus status = CV_INSTRUMENT_FUN_PTR_CALL_IPP(func,( src.ptr(), srcsize, (int)src.step[0], srcroi, dst.ptr(), + IppStatus status = CV_INSTRUMENT_FUN_IPP(func,( src.ptr(), srcsize, (int)src.step[0], srcroi, dst.ptr(), (int)dst.step[0], dstroi, coeffs, mode )); if( status < 0) *ok = false; @@ -5988,7 +6001,7 @@ void cv::warpAffine( InputArray _src, OutputArray _dst, M[2] = b1; M[5] = b2; } -#if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_WARPAFFINE CV_IPP_CHECK() { int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); @@ -6403,7 +6416,9 @@ private: Scalar borderValue; }; -#if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_WARPPERSPECTIVE +typedef IppStatus (CV_STDCALL* ippiWarpPerspectiveFunc)(const void*, IppiSize, int, IppiRect, void *, int, IppiRect, double [3][3], int); + class IPPWarpPerspectiveInvoker : public ParallelLoopBody { @@ -6434,7 +6449,7 @@ public: } } - IppStatus status = CV_INSTRUMENT_FUN_PTR_CALL_IPP(func,(src.ptr(), srcsize, (int)src.step[0], srcroi, dst.ptr(), (int)dst.step[0], dstroi, coeffs, mode)); + IppStatus status = CV_INSTRUMENT_FUN_IPP(func,(src.ptr(), srcsize, (int)src.step[0], srcroi, dst.ptr(), (int)dst.step[0], dstroi, coeffs, mode)); if (status != ippStsNoErr) *ok = false; else @@ -6507,7 +6522,7 @@ void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0, CV_Assert( (M0.type() == CV_32F || M0.type() == CV_64F) && M0.rows == 3 && M0.cols == 3 ); M0.convertTo(matM, matM.type()); -#if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_WARPPERSPECTIVE CV_IPP_CHECK() { int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); diff --git a/modules/imgproc/src/morph.cpp b/modules/imgproc/src/morph.cpp index 4dd0508514..982b2946fe 100644 --- a/modules/imgproc/src/morph.cpp +++ b/modules/imgproc/src/morph.cpp @@ -1113,68 +1113,20 @@ static bool halMorph(int op, int src_type, int dst_type, } // ===== 2. IPP implementation - #ifdef HAVE_IPP - -#if IPP_VERSION_X100 >= 810 - -template struct IppMorphTrait {}; - -#if IPP_VERSION_X100 >= 900 - -#define DEFINE_TRAIT(cvtype, ipptype, flavor, channels, zerodef)\ -template <>\ -struct IppMorphTrait\ -{\ - typedef Ipp##ipptype ipp_data_type;\ - enum { cn = channels };\ - IppDataType getDataType() {return ipp##ipptype;}\ -\ - IppStatus getMorphSize(IppiSize roiSize, IppiSize maskSize, int* pSpecSize, int* pBufferSize) {return ippiMorphologyBorderGetSize_##flavor(roiSize, maskSize, pSpecSize, pBufferSize);}\ - IppStatus morphInit(IppiSize roiSize, const Ipp8u* pMask, IppiSize maskSize, IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiMorphologyBorderInit_##flavor(roiSize, pMask, maskSize, pMorphSpec, pBuffer);}\ - IppStatus filterGetMinSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType dataType, int numChannels, int* pBufferSize) {return ippiFilterMinBorderGetBufferSize(dstRoiSize, maskSize, dataType, numChannels, pBufferSize);}\ - IppStatus filterGetMaxSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType dataType, int numChannels, int* pBufferSize) {return ippiFilterMaxBorderGetBufferSize(dstRoiSize, maskSize, dataType, numChannels, pBufferSize);}\ - IppStatus filterMinBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint, Ipp8u* pBuffer) { ipp_data_type zerodef; return CV_INSTRUMENT_FUN_IPP(ippiFilterMinBorder_##flavor, pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, ippBorderRepl, zero, pBuffer); }\ - IppStatus filterMaxBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint, Ipp8u* pBuffer) { ipp_data_type zerodef; return CV_INSTRUMENT_FUN_IPP(ippiFilterMaxBorder_##flavor, pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, ippBorderRepl, zero, pBuffer); }\ - IppStatus morphDilate(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) { ipp_data_type zerodef; return CV_INSTRUMENT_FUN_IPP(ippiDilateBorder_##flavor, pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, zero, pMorphSpec, pBuffer); }\ - IppStatus morphErode(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) { ipp_data_type zerodef; return CV_INSTRUMENT_FUN_IPP(ippiErodeBorder_##flavor, pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, zero, pMorphSpec, pBuffer); }\ -}; - -#else - -#define DEFINE_TRAIT(cvtype, ipptype, flavor, channels, zerodef)\ -template <>\ -struct IppMorphTrait\ -{\ - typedef Ipp##ipptype ipp_data_type;\ - enum { cn = channels };\ - IppDataType getDataType() {return ipp##ipptype;}\ -\ - IppStatus getMorphSize(IppiSize roiSize, IppiSize maskSize, int* pSpecSize, int* pBufferSize) {return ippiMorphologyBorderGetSize_##flavor(roiSize.width, maskSize, pSpecSize, pBufferSize);}\ - IppStatus morphInit(IppiSize roiSize, const Ipp8u* pMask, IppiSize maskSize, IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiMorphologyBorderInit_##flavor(roiSize.width, pMask, maskSize, pMorphSpec, pBuffer);}\ - IppStatus filterGetMinSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType, int, int* pBufferSize) {return ippiFilterMinGetBufferSize_##flavor(dstRoiSize.width, maskSize, pBufferSize);}\ - IppStatus filterGetMaxSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType, int, int* pBufferSize) {return ippiFilterMinGetBufferSize_##flavor(dstRoiSize.width, maskSize, pBufferSize);}\ - IppStatus filterMinBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint anchor, Ipp8u* pBuffer) { return ippiFilterMinBorderReplicate_##flavor(pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, anchor, pBuffer); }\ - IppStatus filterMaxBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint anchor, Ipp8u* pBuffer) { return ippiFilterMaxBorderReplicate_##flavor(pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, anchor, pBuffer); }\ - IppStatus morphDilate(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiDilateBorder_##flavor(pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, 0, pMorphSpec, pBuffer);}\ - IppStatus morphErode(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiErodeBorder_##flavor(pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, 0, pMorphSpec, pBuffer);}\ -}; - +#ifdef HAVE_IPP_IW +static inline IwiMorphologyType ippiGetMorphologyType(int morphOp) +{ + return morphOp == MORPH_ERODE ? iwiMorphErode : + morphOp == MORPH_DILATE ? iwiMorphDilate : + morphOp == MORPH_OPEN ? iwiMorphOpen : + morphOp == MORPH_CLOSE ? iwiMorphClose : + morphOp == MORPH_GRADIENT ? iwiMorphGradient : + morphOp == MORPH_TOPHAT ? iwiMorphTophat : + morphOp == MORPH_BLACKHAT ? iwiMorphBlackhat : (IwiMorphologyType)-1; +} #endif -DEFINE_TRAIT(CV_8UC1, 8u, 8u_C1R, 1, zero = 0) -DEFINE_TRAIT(CV_8UC3, 8u, 8u_C3R, 3, zero[3] = {0}) -DEFINE_TRAIT(CV_8UC4, 8u, 8u_C4R, 4, zero[4] = {0}) -DEFINE_TRAIT(CV_32FC1, 32f, 32f_C1R, 1, zero = 0) -DEFINE_TRAIT(CV_32FC3, 32f, 32f_C3R, 3, zero[3] = {0}) -DEFINE_TRAIT(CV_32FC4, 32f, 32f_C4R, 4, zero[4] = {0}) - -#undef DEFINE_TRAIT - -//-------------------------------------- - - -template static bool ippMorph(int op, int src_type, int dst_type, const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, @@ -1185,146 +1137,131 @@ static bool ippMorph(int op, int src_type, int dst_type, int kernel_width, int kernel_height, int anchor_x, int anchor_y, int borderType, const double borderValue[4], int iterations, bool isSubmatrix) { - IppMorphTrait trait; - typedef typename IppMorphTrait::ipp_data_type ipp_data_type; - IppAutoBuffer specBuf; - IppAutoBuffer workBuf; - IppiSize kernelSize; - bool rectKernel; - IppiPoint anchor; - +#ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() - CV_UNUSED(roi_width); CV_UNUSED(roi_height); CV_UNUSED(roi_x); CV_UNUSED(roi_y); - CV_UNUSED(roi_width2); CV_UNUSED(roi_height2); CV_UNUSED(roi_x2); CV_UNUSED(roi_y2); - CV_UNUSED(dst_type); + // Problem with SSE42 optimizations +#if IPP_DISABLE_PERF_MORPH_SSE42 + if(!(ipp::getIppFeatures()&ippCPUID_AVX)) + return false; +#endif - anchor = ippiPoint(anchor_x, anchor_y); + ::ipp::IwAutoBuffer kernelTempBuffer; + ::ipp::IwiBorderSize iwBorderSize; + ::ipp::IwiBorderType iwBorderType; + ::ipp::IwiImage iwMask; + ::ipp::IwiImage iwInter; + ::ipp::IwiSize initSize(width, height); + ::ipp::IwiSize kernelSize(kernel_width, kernel_height); + ::ipp::IwiPoint anchor(anchor_x, anchor_y); + IppDataType type = ippiGetDataType(CV_MAT_DEPTH(src_type)); + int channels = CV_MAT_CN(src_type); + IwiMorphologyType morphType = ippiGetMorphologyType(op); - Mat kernel(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step); - int depth = CV_MAT_DEPTH(src_type), cn = CV_MAT_CN(src_type); + CV_UNUSED(isSubmatrix); - if( !( depth == CV_8U || depth == CV_32F ) - || !(cn == 1 || cn == 3 || cn == 4) - || !( borderType == cv::BORDER_REPLICATE - || (borderType == cv::BORDER_CONSTANT && Vec(borderValue) == morphologyDefaultBorderValue() && kernel.size() == Size(3,3))) - || !( op == MORPH_DILATE || op == MORPH_ERODE) - || isSubmatrix - || src_data == dst_data) + if(morphType < 0) return false; - // In case BORDER_CONSTANT, IPPMorphReplicate works correct with kernels of size 3*3 only - if( borderType == cv::BORDER_CONSTANT && kernel.data ) - { - int x, y; - for( y = 0; y < kernel.rows; y++ ) - { - if( kernel.at(y, anchor.x) != 0 ) - continue; - for( x = 0; x < kernel.cols; x++ ) - { - if( kernel.at(y,x) != 0 ) - return false; - } - } - for( x = 0; x < kernel.cols; x++ ) - { - if( kernel.at(anchor.y, x) != 0 ) - continue; - for( y = 0; y < kernel.rows; y++ ) - { - if( kernel.at(y,x) != 0 ) - return false; - } - } - - } - - Size ksize = !kernel.empty() ? kernel.size() : Size(3,3); - - rectKernel = false; - if( kernel.empty() ) - { - ksize = Size(1+iterations*2,1+iterations*2); - anchor = ippiPoint(iterations, iterations); - rectKernel = true; - iterations = 1; - } - else if( iterations >= 1 && countNonZero(kernel) == kernel.rows*kernel.cols ) - { - ksize = Size(ksize.width + (iterations-1)*(ksize.width-1), - ksize.height + (iterations-1)*(ksize.height-1)), - anchor = ippiPoint(anchor.x*iterations, anchor.y*iterations); - kernel = Mat(); - rectKernel = true; - iterations = 1; - } - - // TODO: implement the case of iterations > 1. - if( iterations > 1 ) + if(iterations > 1 && morphType != iwiMorphErode && morphType != iwiMorphDilate) return false; - IppiSize roiSize = {width, height}; - kernelSize = ippiSize(ksize); + if(src_type != dst_type) + return false; - IppStatus res; - if (!rectKernel) + try { - if (((kernel.cols - 1) / 2 != anchor.x) || ((kernel.rows - 1) / 2 != anchor.y)) + ::ipp::IwiImage iwSrc(initSize, type, channels, ::ipp::IwiBorderSize(roi_x, roi_y, roi_width-roi_x-width, roi_height-roi_y-height), (void*)src_data, src_step); + ::ipp::IwiImage iwDst(initSize, type, channels, ::ipp::IwiBorderSize(roi_x2, roi_y2, roi_width2-roi_x2-width, roi_height2-roi_y2-height), (void*)dst_data, dst_step); + + ::ipp::iwiFilterMorphology_GetBorderSize(morphType, kernelSize, iwBorderSize); + if(morphType != iwiMorphErode && morphType != iwiMorphDilate) + { + iwBorderSize.borderLeft /= 2; + iwBorderSize.borderTop /= 2; + iwBorderSize.borderRight /= 2; + iwBorderSize.borderBottom /= 2; + } + + iwBorderType = ippiGetBorder(iwSrc, borderType, iwBorderSize); + if(!iwBorderType.m_borderType || ((iwBorderType.m_borderFlags&ippBorderInMem) && (iwBorderType.m_borderFlags&ippBorderInMem) != ippBorderInMem)) return false; - int specSize = 0, bufferSize = 0; - res = trait.getMorphSize(roiSize, kernelSize, &specSize, &bufferSize); - if (res >= 0) + + if(iwBorderType.m_borderType == ippBorderConst) { - specBuf.Alloc(specSize); - workBuf.Alloc(bufferSize); - res = trait.morphInit(roiSize, kernel.ptr(), kernelSize, specBuf, workBuf); - if (res < 0) - return false; - } - } - else - { - if (((kernelSize.width - 1) / 2 != anchor.x) || ((kernelSize.height - 1) / 2 != anchor.y)) - return false; - if (op == MORPH_ERODE) - { - int bufSize = 0; - res = trait.filterGetMinSize(roiSize, kernelSize, trait.getDataType(), trait.cn, &bufSize); - if (res >= 0) - workBuf.Alloc(bufSize); + if(Vec(borderValue) == morphologyDefaultBorderValue()) + iwBorderType.m_borderType = ippBorderDefault; else - return false; + iwBorderType.SetValue(borderValue[0], borderValue[1], borderValue[2], borderValue[3]); + } + if(morphType != iwiMorphErode && morphType != iwiMorphDilate) + { + if((iwBorderType.m_borderFlags&ippBorderInMem) == ippBorderInMem) + iwBorderType.m_borderFlags = ippBorderFirstStageInMem; + } + + // Test input parameters on dummy structures + { + ::ipp::IwiImage testSrc(initSize, type, channels); + ::ipp::IwiImage testDst(initSize, type, channels); + ::ipp::IwiImage testMask(ippiSize(kernel_width, kernel_height), ipp8u, CV_MAT_CN(kernel_type)); + + ::ipp::iwiFilterMorphology(&testSrc, &testDst, morphType, &testMask, &anchor, iwBorderType); + } + + iwMask.Init(ippiSize(kernel_width, kernel_height), ippiGetDataType(CV_MAT_DEPTH(kernel_type)), CV_MAT_CN(kernel_type), 0, kernel_data, kernel_step); + if((int)kernel_step != kernel_width || CV_MAT_DEPTH(kernel_type) != CV_8U) + { + kernelTempBuffer.Alloc(kernel_width*kernel_height); + ::ipp::IwiImage iwMaskTmp(ippiSize(kernel_width, kernel_height), ipp8u, 1, 0, kernelTempBuffer, kernel_width); + ::ipp::iwiScale(&iwMask, &iwMaskTmp, 1, 0); + iwMask = iwMaskTmp; + } + + if(iterations > 1) + { + iwInter.Alloc(initSize, type, channels); + + ::ipp::IwiImage *pSwap[2] = {&iwInter, &iwDst}; + ::ipp::IwiBorderType iterBorder = iwBorderType; + iterBorder.m_borderFlags = 0; + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterMorphology, &iwSrc, &iwInter, morphType, &iwMask, NULL, iwBorderType); + + for(int i = 0; i < iterations-1; i++) + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterMorphology, pSwap[i&0x1], pSwap[(i+1)&0x1], morphType, &iwMask, NULL, iterBorder); + if(iterations&0x1) + CV_INSTRUMENT_FUN_IPP(::ipp::iwiCopyMask, &iwInter, &iwDst); } else { - int bufSize = 0; - res = trait.filterGetMaxSize(roiSize, kernelSize, trait.getDataType(), trait.cn, &bufSize); - if (res >= 0) - workBuf.Alloc(bufSize); + if(src_data == dst_data) + { + iwInter.Alloc(initSize, type, channels); + + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterMorphology, &iwSrc, &iwInter, morphType, &iwMask, NULL, iwBorderType); + CV_INSTRUMENT_FUN_IPP(::ipp::iwiCopyMask, &iwInter, &iwDst); + } else - return false; + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterMorphology, &iwSrc, &iwDst, morphType, &iwMask, NULL, iwBorderType); } } + catch(::ipp::IwException ex) + { + return false; + } - if (!rectKernel) - { - if (op == MORPH_ERODE) - res = (trait.morphErode((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, specBuf, workBuf)); - else - res = (trait.morphDilate((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, specBuf, workBuf)); - } - else - { - if (op == MORPH_ERODE) - res = (trait.filterMinBorder((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, kernelSize, anchor, workBuf)); - else - res = (trait.filterMaxBorder((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, kernelSize, anchor, workBuf)); - } - return res >= 0; -} + return true; +#else + CV_UNUSED(op); CV_UNUSED(src_type); CV_UNUSED(dst_type); CV_UNUSED(src_data); CV_UNUSED(src_step); CV_UNUSED(dst_data); + CV_UNUSED(dst_step); CV_UNUSED(width); CV_UNUSED(height); CV_UNUSED(roi_width); CV_UNUSED(roi_height); + CV_UNUSED(roi_x); CV_UNUSED(roi_y); CV_UNUSED(roi_width2); CV_UNUSED(roi_height2); CV_UNUSED(roi_x2); CV_UNUSED(roi_y2); + CV_UNUSED(kernel_type); CV_UNUSED(kernel_data); CV_UNUSED(kernel_step); CV_UNUSED(kernel_width); CV_UNUSED(kernel_height); + CV_UNUSED(anchor_x); CV_UNUSED(anchor_y); CV_UNUSED(borderType); CV_UNUSED(borderValue); CV_UNUSED(iterations); + CV_UNUSED(isSubmatrix); + return false; +#endif +}; -#endif // IPP_VERSION_X100 >= 810 #endif // HAVE_IPP // ===== 3. Fallback implementation @@ -1393,37 +1330,12 @@ void morph(int op, int src_type, int dst_type, return; } -#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 810 - -#define ONE_CASE(type) \ - case type: \ - res = ippMorph(op, src_type, dst_type, src_data, src_step, dst_data, dst_step, width, height, \ - roi_width, roi_height, roi_x, roi_y, \ - roi_width2, roi_height2, roi_x2, roi_y2, \ - kernel_type, kernel_data, kernel_step, \ - kernel_width, kernel_height, anchor_x, anchor_y, \ - borderType, borderValue, iterations, isSubmatrix); \ - break; - - CV_IPP_CHECK() - { - bool res = false; - switch (src_type) - { - ONE_CASE(CV_8UC1) - ONE_CASE(CV_8UC3) - ONE_CASE(CV_8UC4) - ONE_CASE(CV_32FC1) - ONE_CASE(CV_32FC3) - ONE_CASE(CV_32FC4) - } - if (res) - return; - } - -#undef ONE_CASE - -#endif + CV_IPP_RUN_FAST(ippMorph(op, src_type, dst_type, src_data, src_step, dst_data, dst_step, width, height, + roi_width, roi_height, roi_x, roi_y, + roi_width2, roi_height2, roi_x2, roi_y2, + kernel_type, kernel_data, kernel_step, + kernel_width, kernel_height, anchor_x, anchor_y, + borderType, borderValue, iterations, isSubmatrix)); ocvMorph(op, src_type, dst_type, src_data, src_step, dst_data, dst_step, width, height, roi_width, roi_height, roi_x, roi_y, @@ -1854,6 +1766,8 @@ static void morphOp( int op, InputArray _src, OutputArray _dst, Point anchor, int iterations, int borderType, const Scalar& borderValue ) { + CV_INSTRUMENT_REGION() + Mat kernel = _kernel.getMat(); Size ksize = !kernel.empty() ? kernel.size() : Size(3,3); anchor = normalizeAnchor(anchor, ksize); @@ -1996,7 +1910,77 @@ static bool ocl_morphologyEx(InputArray _src, OutputArray _dst, int op, } } +#endif +#ifdef HAVE_IPP +#if !IPP_DISABLE_MORPH_ADV +namespace cv { +static bool ipp_morphologyEx(int op, InputArray _src, OutputArray _dst, + InputArray _kernel, + Point anchor, int iterations, + int borderType, const Scalar& borderValue) +{ +#if defined HAVE_IPP_IW + Mat kernel = _kernel.getMat(); + Size ksize = !kernel.empty() ? kernel.size() : Size(3,3); + anchor = normalizeAnchor(anchor, ksize); + + if (iterations == 0 || kernel.rows*kernel.cols == 1) + { + _src.copyTo(_dst); + return true; + } + + if (kernel.empty()) + { + kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2)); + anchor = Point(iterations, iterations); + iterations = 1; + } + else if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols ) + { + anchor = Point(anchor.x*iterations, anchor.y*iterations); + kernel = getStructuringElement(MORPH_RECT, + Size(ksize.width + (iterations-1)*(ksize.width-1), + ksize.height + (iterations-1)*(ksize.height-1)), + anchor); + iterations = 1; + } + + Mat src = _src.getMat(); + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + + Point s_ofs; + Size s_wsz(src.cols, src.rows); + Point d_ofs; + Size d_wsz(dst.cols, dst.rows); + bool isolated = (borderType&BORDER_ISOLATED)?true:false; + borderType = (borderType&~BORDER_ISOLATED); + + if(!isolated) + { + src.locateROI(s_wsz, s_ofs); + dst.locateROI(d_wsz, d_ofs); + } + + return ippMorph(op, src.type(), dst.type(), + src.data, src.step, + dst.data, dst.step, + src.cols, src.rows, + s_wsz.width, s_wsz.height, s_ofs.x, s_ofs.y, + d_wsz.width, d_wsz.height, d_ofs.x, d_ofs.y, + kernel.type(), kernel.data, kernel.step, kernel.cols, kernel.rows, anchor.x, anchor.y, + borderType, borderValue.val, iterations, + (src.isSubmatrix() && !isolated)); +#else + CV_UNUSED(op); CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(_kernel); CV_UNUSED(anchor); + CV_UNUSED(iterations); CV_UNUSED(borderType); CV_UNUSED(borderValue); + return false; +#endif +} +} +#endif #endif void cv::morphologyEx( InputArray _src, OutputArray _dst, int op, @@ -2024,7 +2008,11 @@ void cv::morphologyEx( InputArray _src, OutputArray _dst, int op, _dst.create(src.size(), src.type()); Mat dst = _dst.getMat(); - Mat k1, k2, e1, e2; //only for hit and miss op +#if !IPP_DISABLE_MORPH_ADV + CV_IPP_RUN_FAST(ipp_morphologyEx(op, src, dst, kernel, anchor, iterations, borderType, borderValue)); +#endif + + Mat k1, k2, e1, e2; //only for hit and miss op switch( op ) { diff --git a/modules/imgproc/src/precomp.hpp b/modules/imgproc/src/precomp.hpp index 20a43a6736..40598a083e 100644 --- a/modules/imgproc/src/precomp.hpp +++ b/modules/imgproc/src/precomp.hpp @@ -93,6 +93,19 @@ extern const float icv8x32fSqrTab[]; #undef CV_CALC_MAX #define CV_CALC_MAX(a, b) if((a) < (b)) (a) = (b) +#ifdef HAVE_IPP +static inline IppiInterpolationType ippiGetInterpolation(int inter) +{ + inter &= cv::INTER_MAX; + return inter == cv::INTER_NEAREST ? ippNearest : + inter == cv::INTER_LINEAR ? ippLinear : + inter == cv::INTER_CUBIC ? ippCubic : + inter == cv::INTER_LANCZOS4 ? ippLanczos : + inter == cv::INTER_AREA ? ippSuper : + (IppiInterpolationType)-1; +} +#endif + #include "_geom.h" #include "filterengine.hpp" diff --git a/modules/imgproc/src/smooth.cpp b/modules/imgproc/src/smooth.cpp index d9c88d6dad..ae6629f57c 100644 --- a/modules/imgproc/src/smooth.cpp +++ b/modules/imgproc/src/smooth.cpp @@ -2295,101 +2295,54 @@ static bool openvx_gaussianBlur(InputArray _src, OutputArray _dst, Size ksize, #endif #ifdef HAVE_IPP - -static bool ipp_GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, - double sigma1, double sigma2, - int borderType ) +static bool ipp_GaussianBlur(InputArray _src, OutputArray _dst, Size ksize, + double sigma1, double sigma2, int borderType ) { +#ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 810 - if ((borderType & BORDER_ISOLATED) == 0 && _src.isSubmatrix()) +#if IPP_VERSION_X100 <= 201702 && ((defined _MSC_VER && defined _M_IX86) || (defined __GNUC__ && defined __i386__)) + CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(ksize); CV_UNUSED(sigma1); CV_UNUSED(sigma2); CV_UNUSED(borderType); + return false; // bug on ia32 +#else + if(sigma1 != sigma2) return false; - int type = _src.type(); - Size size = _src.size(); + if(sigma1 < FLT_EPSILON) + return false; - if( borderType != BORDER_CONSTANT && (borderType & BORDER_ISOLATED) != 0 ) + if(ksize.width != ksize.height) + return false; + + // Acquire data and begin processing + try { - if( size.height == 1 ) - ksize.height = 1; - if( size.width == 1 ) - ksize.width = 1; + Mat src = _src.getMat(); + Mat dst = _dst.getMat(); + ::ipp::IwiImage iwSrc = ippiGetImage(src); + ::ipp::IwiImage iwDst = ippiGetImage(dst); + ::ipp::IwiBorderSize borderSize(::ipp::IwiSize(ippiSize(ksize))); + ::ipp::IwiBorderType ippBorder(ippiGetBorder(iwSrc, borderType, borderSize)); + if(!ippBorder.m_borderType) + return false; + + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterGaussian, &iwSrc, &iwDst, ksize.width, (float)sigma1, ippBorder); + } + catch (::ipp::IwException ex) + { + return false; } - int depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); - - if ((depth == CV_8U || depth == CV_16U || depth == CV_16S || depth == CV_32F) && (cn == 1 || cn == 3) && - sigma1 == sigma2 && ksize.width == ksize.height && sigma1 != 0.0 ) - { - IppiBorderType ippBorder = ippiGetBorderType(borderType); - if (ippBorderConst == ippBorder || ippBorderRepl == ippBorder) - { - Mat src = _src.getMat(), dst = _dst.getMat(); - IppiSize roiSize = { src.cols, src.rows }; - IppDataType dataType = ippiGetDataType(depth); - Ipp32s specSize = 0, bufferSize = 0; - - if (ippiFilterGaussianGetBufferSize(roiSize, (Ipp32u)ksize.width, dataType, cn, &specSize, &bufferSize) >= 0) - { - IppAutoBuffer spec(specSize); - IppAutoBuffer buffer(bufferSize); - - if (ippiFilterGaussianInit(roiSize, (Ipp32u)ksize.width, (Ipp32f)sigma1, ippBorder, dataType, cn, spec, buffer) >= 0) - { -#define IPP_FILTER_GAUSS_C1(ippfavor) \ - { \ - Ipp##ippfavor borderValues = 0; \ - status = CV_INSTRUMENT_FUN_IPP(ippiFilterGaussianBorder_##ippfavor##_C1R, src.ptr(), (int)src.step, \ - dst.ptr(), (int)dst.step, roiSize, borderValues, spec, buffer); \ - } - -#define IPP_FILTER_GAUSS_CN(ippfavor, ippcn) \ - { \ - Ipp##ippfavor borderValues[] = { 0, 0, 0 }; \ - status = CV_INSTRUMENT_FUN_IPP(ippiFilterGaussianBorder_##ippfavor##_C##ippcn##R, src.ptr(), (int)src.step, \ - dst.ptr(), (int)dst.step, roiSize, borderValues, spec, buffer); \ - } - - IppStatus status = ippStsErr; -#if IPP_VERSION_X100 > 900 // Buffer overflow may happen in IPP 9.0.0 and less - if (type == CV_8UC1) - IPP_FILTER_GAUSS_C1(8u) - else + return true; #endif - if (type == CV_8UC3) - IPP_FILTER_GAUSS_CN(8u, 3) - else if (type == CV_16UC1) - IPP_FILTER_GAUSS_C1(16u) - else if (type == CV_16UC3) - IPP_FILTER_GAUSS_CN(16u, 3) - else if (type == CV_16SC1) - IPP_FILTER_GAUSS_C1(16s) - else if (type == CV_16SC3) - IPP_FILTER_GAUSS_CN(16s, 3) - else if (type == CV_32FC3) - IPP_FILTER_GAUSS_CN(32f, 3) - else if (type == CV_32FC1) - IPP_FILTER_GAUSS_C1(32f) - - if(status >= 0) - return true; - -#undef IPP_FILTER_GAUSS_C1 -#undef IPP_FILTER_GAUSS_CN - } - } - } - } #else CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(ksize); CV_UNUSED(sigma1); CV_UNUSED(sigma2); CV_UNUSED(borderType); -#endif return false; +#endif } #endif } - void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, double sigma1, double sigma2, int borderType ) @@ -2423,17 +2376,18 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, if(sigma1 == 0 && sigma2 == 0 && tegra::useTegra() && tegra::gaussian(src, dst, ksize, borderType)) return; #endif + bool useOpenCL = (_dst.isUMat() && _src.dims() <= 2 && + ((ksize.width == 3 && ksize.height == 3) || + (ksize.width == 5 && ksize.height == 5)) && + _src.rows() > ksize.height && _src.cols() > ksize.width); + (void)useOpenCL; - CV_IPP_RUN(!(ocl::useOpenCL() && _dst.isUMat()), ipp_GaussianBlur( _src, _dst, ksize, sigma1, sigma2, borderType)); + CV_IPP_RUN(!useOpenCL, ipp_GaussianBlur( _src, _dst, ksize, sigma1, sigma2, borderType)); Mat kx, ky; createGaussianKernels(kx, ky, type, ksize, sigma1, sigma2); - CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && - ((ksize.width == 3 && ksize.height == 3) || - (ksize.width == 5 && ksize.height == 5)) && - (size_t)_src.rows() > ky.total() && (size_t)_src.cols() > kx.total(), - ocl_GaussianBlur_8UC1(_src, _dst, ksize, CV_MAT_DEPTH(type), kx, ky, borderType)); + CV_OCL_RUN(useOpenCL, ocl_GaussianBlur_8UC1(_src, _dst, ksize, CV_MAT_DEPTH(type), kx, ky, borderType)); sepFilter2D(_src, _dst, CV_MAT_DEPTH(type), kx, ky, Point(-1,-1), 0, borderType ); } @@ -3430,60 +3384,69 @@ namespace cv #ifdef HAVE_IPP namespace cv { -static bool ipp_medianFilter( InputArray _src0, OutputArray _dst, int ksize ) +static bool ipp_medianFilter(Mat &src0, Mat &dst, int ksize) { CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 810 - Mat src0 = _src0.getMat(); - _dst.create( src0.size(), src0.type() ); - Mat dst = _dst.getMat(); - -#define IPP_FILTER_MEDIAN_BORDER(ippType, ippDataType, flavor) \ - do \ - { \ - if (ippiFilterMedianBorderGetBufferSize(dstRoiSize, maskSize, \ - ippDataType, CV_MAT_CN(type), &bufSize) >= 0) \ - { \ - Ipp8u * buffer = ippsMalloc_8u(bufSize); \ - IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_##flavor, src.ptr(), (int)src.step, \ - dst.ptr(), (int)dst.step, dstRoiSize, maskSize, \ - ippBorderRepl, (ippType)0, buffer); \ - ippsFree(buffer); \ - if (status >= 0) \ - { \ - CV_IMPL_ADD(CV_IMPL_IPP); \ - return true; \ - } \ - } \ - } \ - while ((void)0, 0) - - if( ksize <= 5 ) { - Ipp32s bufSize; - IppiSize dstRoiSize = ippiSize(dst.cols, dst.rows), maskSize = ippiSize(ksize, ksize); + int bufSize; + IppiSize dstRoiSize = ippiSize(dst.cols, dst.rows), maskSize = ippiSize(ksize, ksize); + IppDataType ippType = ippiGetDataType(src0.type()); + int channels = src0.channels(); + IppAutoBuffer buffer; + + if(src0.isSubmatrix()) + return false; + Mat src; - if( dst.data != src0.data ) + if(dst.data != src0.data) src = src0; else src0.copyTo(src); - int type = src0.type(); - if (type == CV_8UC1) - IPP_FILTER_MEDIAN_BORDER(Ipp8u, ipp8u, 8u_C1R); - else if (type == CV_16UC1) - IPP_FILTER_MEDIAN_BORDER(Ipp16u, ipp16u, 16u_C1R); - else if (type == CV_16SC1) - IPP_FILTER_MEDIAN_BORDER(Ipp16s, ipp16s, 16s_C1R); - else if (type == CV_32FC1) - IPP_FILTER_MEDIAN_BORDER(Ipp32f, ipp32f, 32f_C1R); + if(ippiFilterMedianBorderGetBufferSize(dstRoiSize, maskSize, ippType, channels, &bufSize) < 0) + return false; + + buffer.allocate(bufSize); + + switch(ippType) + { + case ipp8u: + if(channels == 1) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_8u_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else if(channels == 3) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_8u_C3R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else if(channels == 4) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_8u_C4R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else + return false; + case ipp16u: + if(channels == 1) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_16u_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else if(channels == 3) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_16u_C3R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else if(channels == 4) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_16u_C4R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else + return false; + case ipp16s: + if(channels == 1) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_16s_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else if(channels == 3) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_16s_C3R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else if(channels == 4) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_16s_C4R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else + return false; + case ipp32f: + if(channels == 1) + return CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_32f_C1R, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, dstRoiSize, maskSize, ippBorderRepl, 0, buffer) >= 0; + else + return false; + default: + return false; + } } -#undef IPP_FILTER_MEDIAN_BORDER -#else - CV_UNUSED(_src0); CV_UNUSED(_dst); CV_UNUSED(ksize); -#endif - return false; } } #endif @@ -3510,7 +3473,7 @@ void cv::medianBlur( InputArray _src0, OutputArray _dst, int ksize ) CV_OVX_RUN(true, openvx_medianFilter(_src0, _dst, ksize)) - CV_IPP_RUN(IPP_VERSION_X100 >= 810 && ksize <= 5, ipp_medianFilter(_src0,_dst, ksize)); + CV_IPP_RUN_FAST(ipp_medianFilter(src0, dst, ksize)); #ifdef HAVE_TEGRA_OPTIMIZATION if (tegra::useTegra() && tegra::medianBlur(src0, dst, ksize)) diff --git a/modules/imgproc/src/templmatch.cpp b/modules/imgproc/src/templmatch.cpp index 5bae692dc7..7ac52d717b 100644 --- a/modules/imgproc/src/templmatch.cpp +++ b/modules/imgproc/src/templmatch.cpp @@ -560,82 +560,6 @@ static bool ocl_matchTemplate( InputArray _img, InputArray _templ, OutputArray _ #endif -#if defined HAVE_IPP - -typedef IppStatus (CV_STDCALL * ippimatchTemplate)(const void*, int, IppiSize, const void*, int, IppiSize, Ipp32f* , int , IppEnum , Ipp8u*); - -static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst) -{ - CV_INSTRUMENT_REGION_IPP() - - IppStatus status; - - IppiSize srcRoiSize = {src.cols,src.rows}; - IppiSize tplRoiSize = {tpl.cols,tpl.rows}; - - Ipp8u *pBuffer; - int bufSize=0; - - int depth = src.depth(); - - ippimatchTemplate ippiCrossCorrNorm = - depth==CV_8U ? (ippimatchTemplate)ippiCrossCorrNorm_8u32f_C1R: - depth==CV_32F? (ippimatchTemplate)ippiCrossCorrNorm_32f_C1R: 0; - - if (ippiCrossCorrNorm==0) - return false; - - IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiNormNone | ippiROIValid); - - status = ippiCrossCorrNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize); - if ( status < 0 ) - return false; - - pBuffer = ippsMalloc_8u( bufSize ); - - status = CV_INSTRUMENT_FUN_IPP(ippiCrossCorrNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr(), (int)dst.step, funCfg, pBuffer); - - ippsFree( pBuffer ); - return status >= 0; -} - -static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst) -{ - CV_INSTRUMENT_REGION_IPP() - - IppStatus status; - - IppiSize srcRoiSize = {src.cols,src.rows}; - IppiSize tplRoiSize = {tpl.cols,tpl.rows}; - - Ipp8u *pBuffer; - int bufSize=0; - - int depth = src.depth(); - - ippimatchTemplate ippiSqrDistanceNorm = - depth==CV_8U ? (ippimatchTemplate)ippiSqrDistanceNorm_8u32f_C1R: - depth==CV_32F? (ippimatchTemplate)ippiSqrDistanceNorm_32f_C1R: 0; - - if (ippiSqrDistanceNorm==0) - return false; - - IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiNormNone | ippiROIValid); - - status = ippiSqrDistanceNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize); - if ( status < 0 ) - return false; - - pBuffer = ippsMalloc_8u( bufSize ); - - status = CV_INSTRUMENT_FUN_IPP(ippiSqrDistanceNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr(), (int)dst.step, funCfg, pBuffer); - - ippsFree( pBuffer ); - return status >= 0; -} - -#endif - #include "opencv2/core/hal/hal.hpp" void crossCorr( const Mat& img, const Mat& _templ, Mat& corr, @@ -915,11 +839,7 @@ static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _ else CV_Error(Error::StsNotImplemented, ""); } -} - -namespace cv -{ static void common_matchTemplate( Mat& img, Mat& templ, Mat& result, int method, int cn ) { if( method == CV_TM_CCORR ) @@ -1043,26 +963,117 @@ static void common_matchTemplate( Mat& img, Mat& templ, Mat& result, int method, #if defined HAVE_IPP namespace cv { -static bool ipp_matchTemplate( Mat& img, Mat& templ, Mat& result, int method, int cn ) +typedef IppStatus (CV_STDCALL * ippimatchTemplate)(const void*, int, IppiSize, const void*, int, IppiSize, Ipp32f* , int , IppEnum , Ipp8u*); + +static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst, bool normed) { CV_INSTRUMENT_REGION_IPP() - bool useIppMT = (templ.rows < img.rows/2 && templ.cols < img.cols/2); + IppStatus status; - if(cn == 1 && useIppMT) + IppiSize srcRoiSize = {src.cols,src.rows}; + IppiSize tplRoiSize = {tpl.cols,tpl.rows}; + + IppAutoBuffer buffer; + int bufSize=0; + + int depth = src.depth(); + + ippimatchTemplate ippiCrossCorrNorm = + depth==CV_8U ? (ippimatchTemplate)ippiCrossCorrNorm_8u32f_C1R: + depth==CV_32F? (ippimatchTemplate)ippiCrossCorrNorm_32f_C1R: 0; + + if (ippiCrossCorrNorm==0) + return false; + + IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiROIValid); + if(normed) + funCfg |= ippiNorm; + else + funCfg |= ippiNormNone; + + status = ippiCrossCorrNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize); + if ( status < 0 ) + return false; + + buffer.allocate( bufSize ); + + status = CV_INSTRUMENT_FUN_IPP(ippiCrossCorrNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr(), (int)dst.step, funCfg, buffer); + return status >= 0; +} + +static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst) +{ + CV_INSTRUMENT_REGION_IPP() + + IppStatus status; + + IppiSize srcRoiSize = {src.cols,src.rows}; + IppiSize tplRoiSize = {tpl.cols,tpl.rows}; + + IppAutoBuffer buffer; + int bufSize=0; + + int depth = src.depth(); + + ippimatchTemplate ippiSqrDistanceNorm = + depth==CV_8U ? (ippimatchTemplate)ippiSqrDistanceNorm_8u32f_C1R: + depth==CV_32F? (ippimatchTemplate)ippiSqrDistanceNorm_32f_C1R: 0; + + if (ippiSqrDistanceNorm==0) + return false; + + IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiROIValid | ippiNormNone); + status = ippiSqrDistanceNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize); + if ( status < 0 ) + return false; + + buffer.allocate( bufSize ); + + status = CV_INSTRUMENT_FUN_IPP(ippiSqrDistanceNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr(), (int)dst.step, funCfg, buffer); + return status >= 0; +} + +static bool ipp_matchTemplate( Mat& img, Mat& templ, Mat& result, int method) +{ + CV_INSTRUMENT_REGION_IPP() + + if(img.channels() != 1) + return false; + + // These functions are not efficient if template size is comparable with image size + if(templ.size().area()*4 > img.size().area()) + return false; + + if(method == CV_TM_SQDIFF) { - if(method == CV_TM_SQDIFF) + if(ipp_sqrDistance(img, templ, result)) + return true; + } + else if(method == CV_TM_SQDIFF_NORMED) + { + if(ipp_crossCorr(img, templ, result, false)) { - if (ipp_sqrDistance(img, templ, result)) - return true; + common_matchTemplate(img, templ, result, CV_TM_SQDIFF_NORMED, 1); + return true; } - else + } + else if(method == CV_TM_CCORR) + { + if(ipp_crossCorr(img, templ, result, false)) + return true; + } + else if(method == CV_TM_CCORR_NORMED) + { + if(ipp_crossCorr(img, templ, result, true)) + return true; + } + else if(method == CV_TM_CCOEFF || method == CV_TM_CCOEFF_NORMED) + { + if(ipp_crossCorr(img, templ, result, false)) { - if(ipp_crossCorr(img, templ, result)) - { - common_matchTemplate(img, templ, result, method, cn); - return true; - } + common_matchTemplate(img, templ, result, method, 1); + return true; } } @@ -1109,7 +1120,7 @@ void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result, return; #endif - CV_IPP_RUN(true, ipp_matchTemplate(img, templ, result, method, cn)) + CV_IPP_RUN_FAST(ipp_matchTemplate(img, templ, result, method)) crossCorr( img, templ, result, result.size(), result.type(), Point(0,0), 0, 0); diff --git a/modules/imgproc/test/test_filter.cpp b/modules/imgproc/test/test_filter.cpp index 886c5ab90a..6452aec232 100644 --- a/modules/imgproc/test/test_filter.cpp +++ b/modules/imgproc/test/test_filter.cpp @@ -715,7 +715,7 @@ void CV_SmoothBaseTest::get_test_array_types_and_sizes( int test_case_idx, double CV_SmoothBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int depth = test_mat[INPUT][0].depth(); - return depth <= CV_8S ? 1 : 1e-5; + return depth < CV_32F ? 1 : 1e-5; } From fc8f1890c06f765796d05387f00483b522a3762e Mon Sep 17 00:00:00 2001 From: Alessandro Gentilini Date: Fri, 21 Apr 2017 10:29:13 +0200 Subject: [PATCH 105/144] Fix markdown format. --- modules/imgproc/include/opencv2/imgproc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 4bab109107..88f41849c5 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -1285,7 +1285,7 @@ smoothing kernels (a symmetrical kernel with sum of weights equal to 1) and hand You may also use the higher-level GaussianBlur. @param ksize Aperture size. It should be odd ( \f$\texttt{ksize} \mod 2 = 1\f$ ) and positive. @param sigma Gaussian standard deviation. If it is non-positive, it is computed from ksize as -`sigma = 0.3\*((ksize-1)\*0.5 - 1) + 0.8`. +`sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8`. @param ktype Type of filter coefficients. It can be CV_32F or CV_64F . @sa sepFilter2D, getDerivKernels, getStructuringElement, GaussianBlur */ From ad7cf58450728d3a201baa4f30b9b79d2441e06d Mon Sep 17 00:00:00 2001 From: Vladislav Sovrasov Date: Wed, 19 Apr 2017 14:08:37 +0300 Subject: [PATCH 106/144] highgui: add ROI selector --- modules/highgui/CMakeLists.txt | 1 + modules/highgui/include/opencv2/highgui.hpp | 38 ++++ modules/highgui/src/roiSelector.cpp | 203 ++++++++++++++++++ .../AKAZE_tracking/planar_tracking.cpp | 2 +- .../features2D/AKAZE_tracking/utils.h | 55 ----- 5 files changed, 243 insertions(+), 56 deletions(-) create mode 100644 modules/highgui/src/roiSelector.cpp diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index 472d66799a..a0da13ef95 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -22,6 +22,7 @@ set(highgui_hdrs set(highgui_srcs ${CMAKE_CURRENT_LIST_DIR}/src/window.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/roiSelector.cpp ) file(GLOB highgui_ext_hdrs diff --git a/modules/highgui/include/opencv2/highgui.hpp b/modules/highgui/include/opencv2/highgui.hpp index 16ef8c4a9e..b1f203df03 100644 --- a/modules/highgui/include/opencv2/highgui.hpp +++ b/modules/highgui/include/opencv2/highgui.hpp @@ -468,6 +468,44 @@ Mouse-wheel events are currently supported only on Windows. */ CV_EXPORTS int getMouseWheelDelta(int flags); +/** @brief Selects ROI on the given image. +Function creates a window and allows user to select a ROI using mouse. +Controls: use `space` or `enter` to finish selection, use key `c` to cancel selection (function will return the zero cv::Rect). + +@param windowName name of the window where selection process will be shown. +@param img image to select a ROI. +@param showCrosshair if true crosshair of selection rectangle will be shown. +@param fromCenter if true center of selection will match initial mouse position. In opposite case a corner of +selection rectangle will correspont to the initial mouse position. +@return selected ROI or empty rect if selection canceled. + +@note The function sets it's own mouse callback for specified window using cv::setMouseCallback(windowName, ...). +After finish of work an empty callback will be set for the used window. + */ +CV_EXPORTS_W Rect selectROI(const String& windowName, InputArray img, bool showCrosshair = true, bool fromCenter = false); + +/** @overload + */ +CV_EXPORTS_W Rect selectROI(InputArray img, bool showCrosshair = true, bool fromCenter = false); + +/** @brief Selects ROIs on the given image. +Function creates a window and allows user to select a ROIs using mouse. +Controls: use `space` or `enter` to finish current selection and start a new one, +use `ecs` to terminate multiple ROI selection process. + +@param windowName name of the window where selection process will be shown. +@param img image to select a ROI. +@param boundingBoxes selected ROIs. +@param showCrosshair if true crosshair of selection rectangle will be shown. +@param fromCenter if true center of selection will match initial mouse position. In opposite case a corner of +selection rectangle will correspont to the initial mouse position. + +@note The function sets it's own mouse callback for specified window using cv::setMouseCallback(windowName, ...). +After finish of work an empty callback will be set for the used window. + */ +CV_EXPORTS_W void selectROIs(const String& windowName, InputArray img, + CV_OUT std::vector& boundingBoxes, bool showCrosshair = true, bool fromCenter = false); + /** @brief Creates a trackbar and attaches it to the specified window. The function createTrackbar creates a trackbar (a slider or range control) with the specified name diff --git a/modules/highgui/src/roiSelector.cpp b/modules/highgui/src/roiSelector.cpp new file mode 100644 index 0000000000..8bc6ba620f --- /dev/null +++ b/modules/highgui/src/roiSelector.cpp @@ -0,0 +1,203 @@ +// 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 +#include + +using namespace cv; + +namespace +{ +class ROISelector +{ + public: + Rect select(const String &windowName, Mat img, bool showCrossair = true, bool fromCenter = true) + { + // show notice to user + printf("Select a ROI and then press SPACE or ENTER button!\n"); + printf("Cancel the selection process by pressing c button!\n"); + + key = 0; + imageSize = img.size(); + + // set the drawing mode + selectorParams.drawFromCenter = fromCenter; + + // show the image and give feedback to user + imshow(windowName, img); + + // copy the data, rectangle should be drawn in the fresh image + selectorParams.image = img.clone(); + + // select the object + setMouseCallback(windowName, mouseHandler, (void*)this); + + // end selection process on SPACE (32) ESC (27) or ENTER (13) + while (!(key == 32 || key == 27 || key == 13)) + { + // draw the selected object + rectangle(selectorParams.image, selectorParams.box, Scalar(255, 0, 0), 2, 1); + + // draw cross air in the middle of bounding box + if (showCrossair) + { + // horizontal line + line(selectorParams.image, + Point((int)selectorParams.box.x, + (int)(selectorParams.box.y + selectorParams.box.height / 2)), + Point((int)(selectorParams.box.x + selectorParams.box.width), + (int)(selectorParams.box.y + selectorParams.box.height / 2)), + Scalar(255, 0, 0), 2, 1); + + // vertical line + line(selectorParams.image, + Point((int)(selectorParams.box.x + selectorParams.box.width / 2), + (int)selectorParams.box.y), + Point((int)(selectorParams.box.x + selectorParams.box.width / 2), + (int)(selectorParams.box.y + selectorParams.box.height)), + Scalar(255, 0, 0), 2, 1); + } + + // show the image bouding box + imshow(windowName, selectorParams.image); + + // reset the image + selectorParams.image = img.clone(); + + // get keyboard event + key = waitKey(30); + + if (key == 'c' || key == 'C')//cancel selection + { + selectorParams.box = Rect(); + break; + } + } + + //cleanup callback + setMouseCallback(windowName, emptyMouseHandler, NULL); + + return selectorParams.box; + } + + void select(const String &windowName, Mat img, std::vector &boundingBoxes, + bool showCrosshair = true, bool fromCenter = true) + { + printf("Finish the selection process by pressing ESC button!\n"); + boundingBoxes.clear(); + key = 0; + + // while key is not ESC (27) + for (;;) + { + Rect temp = select(windowName, img, showCrosshair, fromCenter); + if (key == 27) + break; + if (temp.width > 0 && temp.height > 0) + boundingBoxes.push_back(temp); + } + } + + struct handlerT + { + // basic parameters + bool isDrawing; + Rect2d box; + Mat image; + + // parameters for drawing from the center + bool drawFromCenter; + Point2f center; + + // initializer list + handlerT() : isDrawing(false), drawFromCenter(true){}; + } selectorParams; + + private: + static void emptyMouseHandler(int, int, int, int, void*) + { + } + + static void mouseHandler(int event, int x, int y, int flags, void *param) + { + ROISelector *self = static_cast(param); + self->opencv_mouse_callback(event, x, y, flags); + } + + void opencv_mouse_callback(int event, int x, int y, int) + { + switch (event) + { + // update the selected bounding box + case EVENT_MOUSEMOVE: + if (selectorParams.isDrawing) + { + if (selectorParams.drawFromCenter) + { + selectorParams.box.width = 2 * (x - selectorParams.center.x); + selectorParams.box.height = 2 * (y - selectorParams.center.y); + selectorParams.box.x = std::min( + std::max(selectorParams.center.x - selectorParams.box.width / 2.0, 0.), (double)imageSize.width); + selectorParams.box.y = std::min( + std::max(selectorParams.center.y - selectorParams.box.height / 2.0, 0.), (double)imageSize.height); + } + else + { + selectorParams.box.width = std::max( + std::min(x - selectorParams.box.x, (double)imageSize.width - selectorParams.box.x), - selectorParams.box.x); + selectorParams.box.height = std::max( + std::min(y - selectorParams.box.y, (double)imageSize.height - selectorParams.box.y), - selectorParams.box.y); + } + } + break; + + // start to select the bounding box + case EVENT_LBUTTONDOWN: + selectorParams.isDrawing = true; + selectorParams.box = Rect2d(x, y, 0, 0); + selectorParams.center = Point2f((float)x, (float)y); + break; + + // cleaning up the selected bounding box + case EVENT_LBUTTONUP: + selectorParams.isDrawing = false; + if (selectorParams.box.width < 0) + { + selectorParams.box.x += selectorParams.box.width; + selectorParams.box.width *= -1; + } + if (selectorParams.box.height < 0) + { + selectorParams.box.y += selectorParams.box.height; + selectorParams.box.height *= -1; + } + break; + } + } + + // save the keypressed characted + int key; + Size imageSize; +}; +} + +Rect cv::selectROI(InputArray img, bool showCrosshair, bool fromCenter) +{ + ROISelector selector; + return selector.select("ROI selector", img.getMat(), showCrosshair, fromCenter); +} + +Rect cv::selectROI(const String& windowName, InputArray img, bool showCrosshair, bool fromCenter) +{ + ROISelector selector; + return selector.select(windowName, img.getMat(), showCrosshair, fromCenter); +} + +void cv::selectROIs(const String& windowName, InputArray img, + std::vector& boundingBox, bool showCrosshair, bool fromCenter) +{ + ROISelector selector; + selector.select(windowName, img.getMat(), boundingBox, showCrosshair, fromCenter); +} diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp index 77bd9a6894..6ccb83119a 100755 --- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp +++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp @@ -159,7 +159,7 @@ int main(int argc, char **argv) cout << "Please select a bounding box, and press any key to continue." << endl; vector bb; - cv::Rect2d uBox = selectROI(video_name, frame); + cv::Rect uBox = cv::selectROI(video_name, frame); bb.push_back(cv::Point2f(static_cast(uBox.x), static_cast(uBox.y))); bb.push_back(cv::Point2f(static_cast(uBox.x+uBox.width), static_cast(uBox.y))); bb.push_back(cv::Point2f(static_cast(uBox.x+uBox.width), static_cast(uBox.y+uBox.height))); diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/utils.h b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/utils.h index 2142e988c0..a3e9d7dbde 100644 --- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/utils.h +++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/utils.h @@ -56,59 +56,4 @@ vector Points(vector keypoints) } return res; } - -Rect2d selectROI(const String &video_name, const Mat &frame) -{ - struct Data - { - Point center; - Rect2d box; - - static void mouseHandler(int event, int x, int y, int flags, void *param) - { - Data *data = (Data*)param; - switch( event ) - { - // start to select the bounding box - case EVENT_LBUTTONDOWN: - data->box = cvRect( x, y, 0, 0 ); - data->center = Point2f((float)x,(float)y); - break; - // update the selected bounding box - case EVENT_MOUSEMOVE: - if(flags == 1) - { - data->box.width = 2 * (x - data->center.x); - data->box.height = 2 * (y - data->center.y); - data->box.x = data->center.x - data->box.width / 2.0; - data->box.y = data->center.y - data->box.height / 2.0; - } - break; - // cleaning up the selected bounding box - case EVENT_LBUTTONUP: - if( data->box.width < 0 ) - { - data->box.x += data->box.width; - data->box.width *= -1; - } - if( data->box.height < 0 ) - { - data->box.y += data->box.height; - data->box.height *= -1; - } - break; - } - } - } data; - - setMouseCallback(video_name, Data::mouseHandler, &data); - while(waitKey(1) < 0) - { - Mat draw = frame.clone(); - rectangle(draw, data.box, Scalar(255,0,0), 2, 1); - imshow(video_name, draw); - } - return data.box; -} - #endif // UTILS_H From 0f5aaade6108671f0b283761ac2479fe6065b89f Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Fri, 21 Apr 2017 23:07:46 +0900 Subject: [PATCH 107/144] fix test error on VS2012 --- modules/core/test/test_io.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp index 33af4c8b76..2b35f91d43 100644 --- a/modules/core/test/test_io.cpp +++ b/modules/core/test/test_io.cpp @@ -1059,7 +1059,11 @@ TEST(Core_InputOutput, FileStorage_DMatch) EXPECT_NO_THROW(fs << "d" << d); cv::String fs_result = fs.releaseAndGetString(); +#if defined _MSC_VER && _MSC_VER <= 1700 /* MSVC 2012 and older */ + EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n---\nd: [ 1, 2, 3, -1.5000000000000000e+000 ]\n"); +#else EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n---\nd: [ 1, 2, 3, -1.5000000000000000e+00 ]\n"); +#endif cv::FileStorage fs_read(fs_result, cv::FileStorage::READ | cv::FileStorage::MEMORY); @@ -1086,12 +1090,21 @@ TEST(Core_InputOutput, FileStorage_DMatch_vector) EXPECT_NO_THROW(fs << "dv" << dv); cv::String fs_result = fs.releaseAndGetString(); +#if defined _MSC_VER && _MSC_VER <= 1700 /* MSVC 2012 and older */ + EXPECT_STREQ(fs_result.c_str(), +"%YAML:1.0\n" +"---\n" +"dv: [ 1, 2, 3, -1.5000000000000000e+000, 2, 3, 4,\n" +" 1.5000000000000000e+000, 3, 2, 1, 5.0000000000000000e-001 ]\n" +); +#else EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n" "---\n" "dv: [ 1, 2, 3, -1.5000000000000000e+00, 2, 3, 4, 1.5000000000000000e+00,\n" " 3, 2, 1, 5.0000000000000000e-01 ]\n" ); +#endif cv::FileStorage fs_read(fs_result, cv::FileStorage::READ | cv::FileStorage::MEMORY); @@ -1130,6 +1143,17 @@ TEST(Core_InputOutput, FileStorage_DMatch_vector_vector) EXPECT_NO_THROW(fs << "dvv" << dvv); cv::String fs_result = fs.releaseAndGetString(); +#if defined _MSC_VER && _MSC_VER <= 1700 /* MSVC 2012 and older */ + EXPECT_STREQ(fs_result.c_str(), +"%YAML:1.0\n" +"---\n" +"dvv:\n" +" - [ 1, 2, 3, -1.5000000000000000e+000, 2, 3, 4,\n" +" 1.5000000000000000e+000, 3, 2, 1, 5.0000000000000000e-001 ]\n" +" - [ 3, 2, 1, 5.0000000000000000e-001, 1, 2, 3,\n" +" -1.5000000000000000e+000 ]\n" +); +#else EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n" "---\n" @@ -1138,6 +1162,7 @@ TEST(Core_InputOutput, FileStorage_DMatch_vector_vector) " 3, 2, 1, 5.0000000000000000e-01 ]\n" " - [ 3, 2, 1, 5.0000000000000000e-01, 1, 2, 3, -1.5000000000000000e+00 ]\n" ); +#endif cv::FileStorage fs_read(fs_result, cv::FileStorage::READ | cv::FileStorage::MEMORY); From 7ffa49e02ce2dbfea242a905251cb64bfc97aa6d Mon Sep 17 00:00:00 2001 From: Pyotr Chekmaryov <4ekmah@gmail.com> Date: Sat, 22 Apr 2017 00:00:08 +0000 Subject: [PATCH 108/144] Vertical passes added and we have working parralel version. --- modules/calib3d/include/opencv2/calib3d.hpp | 3 +- modules/calib3d/src/stereosgbm.cpp | 1490 +++++------------- modules/calib3d/test/test_stereomatching.cpp | 32 +- 3 files changed, 418 insertions(+), 1107 deletions(-) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index f2915850f9..46a470bc0f 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -1810,8 +1810,7 @@ public: MODE_SGBM = 0, MODE_HH = 1, MODE_SGBM_3WAY = 2, - MODE_HH4 = 3, - MODE_HH4_OLD = 4 + MODE_HH4 = 3 }; CV_WRAP virtual int getPreFilterCap() const = 0; diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp index 8a6bfebc67..5f841775ec 100644 --- a/modules/calib3d/src/stereosgbm.cpp +++ b/modules/calib3d/src/stereosgbm.cpp @@ -1170,6 +1170,402 @@ struct CalcVerticalSums: public ParallelLoopBody int ftzero; }; +struct CalcHorizontalSums: public ParallelLoopBody +{ + CalcHorizontalSums(const Mat& _img1, const Mat& _img2, Mat& _disp1, const StereoSGBMParams& params, + CostType* alignedBuf): img1(_img1), img2(_img2), disp1(_disp1) + { + minD = params.minDisparity; + maxD = minD + params.numDisparities; + P1 = params.P1 > 0 ? params.P1 : 2; + P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion + uniquenessRatio = params.uniquenessRatio >= 0 ? params.uniquenessRatio : 10; + disp12MaxDiff = params.disp12MaxDiff > 0 ? params.disp12MaxDiff : 1; + height = img1.rows; + width = img1.cols; + minX1 = std::max(maxD, 0); + maxX1 = width + std::min(minD, 0); + INVALID_DISP = minD - 1; + INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; + D = maxD - minD; + width1 = maxX1 - minX1; + costBufSize = width1*D; + CSBufSize = costBufSize*height; + D2 = D + 16; + LrSize = 2 * D2; //TODO: Check: do we need this value or not? + Cbuf = alignedBuf; + Sbuf = Cbuf + CSBufSize; + } + + void operator()( const Range& range ) const + { + int y1 = range.start, y2 = range.end; + static const CostType MAX_COST = SHRT_MAX; + static const int ALIGN = 16; + size_t auxBufsSize = LrSize + width*(sizeof(CostType) + sizeof(DispType)) + 32; + + Mat auxBuff; + auxBuff.create(1, (int)auxBufsSize, CV_8U); + CostType *Lr = (CostType*)alignPtr(auxBuff.ptr(), ALIGN) + 8; + CostType* disp2cost = Lr + LrSize; + DispType* disp2ptr = (DispType*)(disp2cost + width); + + CostType minLr; + + for( int y = y1; y != y2; y++) + { + int x, d; + DispType* disp1ptr = disp1.ptr(y); + CostType* C = Cbuf + y*costBufSize; + CostType* S = Sbuf + y*costBufSize; + + for( x = 0; x < width; x++ ) + { + disp1ptr[x] = disp2ptr[x] = (DispType)INVALID_DISP_SCALED; + disp2cost[x] = MAX_COST; + } + + // clear buffers + memset( Lr - 8, 0, LrSize*sizeof(CostType) ); + minLr = 0; + /* + [formula 13 in the paper] + compute L_r(p, d) = C(p, d) + + min(L_r(p-r, d), + L_r(p-r, d-1) + P1, + L_r(p-r, d+1) + P1, + min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) + where p = (x,y), r is one of the directions. + we process all the directions at once: + 0: r=(-dx, 0) + 1: r=(-1, -dy) + 2: r=(0, -dy) + 3: r=(1, -dy) + 4: r=(-2, -dy) + 5: r=(-1, -dy*2) + 6: r=(1, -dy*2) + 7: r=(2, -dy) + */ + for( x = 0; x != width1; x++) + { + int delta = minLr + P2; + + CostType* Lr_ppr = Lr + ((x&1)? 0 : D2); + + Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; //TODO: Well, probably, it's better do this once before. + + CostType* Lr_p = Lr + ((x&1)? D2 :0); + const CostType* Cp = C + x*D; + CostType* Sp = S + x*D; + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _P1 = v_setall_s16((short)P1); +// +// v_int16x8 _delta0 = v_setall_s16((short)delta0); +// v_int16x8 _delta1 = v_setall_s16((short)delta1); +// v_int16x8 _delta2 = v_setall_s16((short)delta2); +// v_int16x8 _delta3 = v_setall_s16((short)delta3); +// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); +// +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 Cpd = v_load(Cp + d); +// v_int16x8 L0, L1, L2, L3; +// +// L0 = v_load(Lr_ppr + d); +// L1 = v_load(Lr_p1 + d); +// L2 = v_load(Lr_p2 + d); +// L3 = v_load(Lr_p3 + d); +// +// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); +// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); +// +// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); +// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); +// +// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); +// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); +// +// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); +// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); +// +// L0 = v_min(L0, _delta0); +// L0 = ((L0 - _delta0) + Cpd); +// +// L1 = v_min(L1, _delta1); +// L1 = ((L1 - _delta1) + Cpd); +// +// L2 = v_min(L2, _delta2); +// L2 = ((L2 - _delta2) + Cpd); +// +// L3 = v_min(L3, _delta3); +// L3 = ((L3 - _delta3) + Cpd); +// +// v_store(Lr_p + d, L0); +// v_store(Lr_p + d + D2, L1); +// v_store(Lr_p + d + D2*2, L2); +// v_store(Lr_p + d + D2*3, L3); +// +// // Get minimum from in L0-L3 +// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; +// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... +// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... +// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... +// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... +// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... +// v_int16x8 t0 = v_min(t0123L, t0123H); +// _minL0 = v_min(_minL0, t0); +// +// v_int16x8 Sval = v_load(Sp + d); +// +// L0 = L0 + L1; +// L2 = L2 + L3; +// Sval = Sval + L0; +// Sval = Sval + L2; +// +// v_store(Sp + d, Sval); +// } +// +// v_int32x4 minL, minH; +// v_expand(_minL0, minL, minH); +// v_pack_store(&minLr[x], v_min(minL, minH)); +// } +// else +// #endif + { + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) + { + int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L); + } + minLr = (CostType)minL; + } + } + + memset( Lr - 8, 0, LrSize*sizeof(CostType) ); + minLr = 0; + + for( x = width1-1; x != -1; x--) + { + int delta = minLr + P2; + + CostType* Lr_ppr = Lr + ((x&1)? 0 :D2); + + Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; + + CostType* Lr_p = Lr + ((x&1)? D2 :0); + const CostType* Cp = C + x*D; + CostType* Sp = S + x*D; + int minS = MAX_COST, bestDisp = -1; + +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _P1 = v_setall_s16((short)P1); +// +// v_int16x8 _delta0 = v_setall_s16((short)delta0); +// v_int16x8 _delta1 = v_setall_s16((short)delta1); +// v_int16x8 _delta2 = v_setall_s16((short)delta2); +// v_int16x8 _delta3 = v_setall_s16((short)delta3); +// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); +// +// for( d = 0; d < D; d += 8 ) +// { +// v_int16x8 Cpd = v_load(Cp + d); +// v_int16x8 L0, L1, L2, L3; +// +// L0 = v_load(Lr_ppr + d); +// L1 = v_load(Lr_p1 + d); +// L2 = v_load(Lr_p2 + d); +// L3 = v_load(Lr_p3 + d); +// +// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); +// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); +// +// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); +// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); +// +// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); +// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); +// +// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); +// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); +// +// L0 = v_min(L0, _delta0); +// L0 = ((L0 - _delta0) + Cpd); +// +// L1 = v_min(L1, _delta1); +// L1 = ((L1 - _delta1) + Cpd); +// +// L2 = v_min(L2, _delta2); +// L2 = ((L2 - _delta2) + Cpd); +// +// L3 = v_min(L3, _delta3); +// L3 = ((L3 - _delta3) + Cpd); +// +// v_store(Lr_p + d, L0); +// v_store(Lr_p + d + D2, L1); +// v_store(Lr_p + d + D2*2, L2); +// v_store(Lr_p + d + D2*3, L3); +// +// // Get minimum from in L0-L3 +// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; +// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... +// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... +// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... +// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... +// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... +// v_int16x8 t0 = v_min(t0123L, t0123H); +// _minL0 = v_min(_minL0, t0); +// +// v_int16x8 Sval = v_load(Sp + d); +// +// L0 = L0 + L1; +// L2 = L2 + L3; +// Sval = Sval + L0; +// Sval = Sval + L2; +// +// v_store(Sp + d, Sval); +// } +// +// v_int32x4 minL, minH; +// v_expand(_minL0, minL, minH); +// v_pack_store(&minLr[x], v_min(minL, minH)); +// } +// else +// #endif +//TODO:Next piece of code is came from postprocessing. Be very careful with joining them!!! +// #if CV_SIMD128 +// if( useSIMD ) +// { +// v_int16x8 _minS = v_setall_s16(MAX_COST), _bestDisp = v_setall_s16(-1); +// v_int16x8 _d8 = v_int16x8(0, 1, 2, 3, 4, 5, 6, 7), _8 = v_setall_s16(8); +// +// for( d = 0; d < D; d+= 8 ) +// { +// v_int16x8 L0 = v_load(Sp + d); +// v_int16x8 mask = L0 < _minS; +// _minS = v_min( L0, _minS ); +// _bestDisp = _bestDisp ^ ((_bestDisp ^ _d8) & mask); +// _d8 = _d8 + _8; +// } +// v_int32x4 _d0, _d1; +// v_expand(_minS, _d0, _d1); +// minS = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); +// v_int16x8 v_mask = v_setall_s16((short)minS) == _minS; +// +// _bestDisp = (_bestDisp & v_mask) | (v_setall_s16(SHRT_MAX) & ~v_mask); +// v_expand(_bestDisp, _d0, _d1); +// bestDisp = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); +// } +// else +// #endif + { + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) + { + int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L); + if( Sp[d] < minS ) + { + minS = Sp[d]; + bestDisp = d; + } + } + minLr = (CostType)minL; + } + //Some postprocessing procedures and saving + for( d = 0; d < D; d++ ) + { + if( Sp[d]*(100 - uniquenessRatio) < minS*100 && std::abs(bestDisp - d) > 1 ) + break; + } + if( d < D ) + continue; + d = bestDisp; + int _x2 = x + minX1 - d - minD; + if( disp2cost[_x2] > minS ) + { + disp2cost[_x2] = (CostType)minS; + disp2ptr[_x2] = (DispType)(d + minD); + } + + if( 0 < d && d < D-1 ) + { + // do subpixel quadratic interpolation: + // fit parabola into (x1=d-1, y1=Sp[d-1]), (x2=d, y2=Sp[d]), (x3=d+1, y3=Sp[d+1]) + // then find minimum of the parabola. + int denom2 = std::max(Sp[d-1] + Sp[d+1] - 2*Sp[d], 1); + d = d*DISP_SCALE + ((Sp[d-1] - Sp[d+1])*DISP_SCALE + denom2)/(denom2*2); + } + else + d *= DISP_SCALE; + disp1ptr[x + minX1] = (DispType)(d + minD*DISP_SCALE); + } + //Left-right check sanity procedure + for( x = minX1; x < maxX1; x++ ) + { + // we round the computed disparity both towards -inf and +inf and check + // if either of the corresponding disparities in disp2 is consistent. + // This is to give the computed disparity a chance to look valid if it is. + int d1 = disp1ptr[x]; + if( d1 == INVALID_DISP_SCALED ) + continue; + int _d = d1 >> DISP_SHIFT; + int d_ = (d1 + DISP_SCALE-1) >> DISP_SHIFT; + int _x = x - _d, x_ = x - d_; + if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && //4e: To dismiss disparity, we should assure, that there is no any + 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) //4e: chance to understand this as correct. + disp1ptr[x] = (DispType)INVALID_DISP_SCALED; + } + } + } + + static const int NLR = 2; + static const int LrBorder = NLR - 1; + static const int DISP_SHIFT = StereoMatcher::DISP_SHIFT; + static const int DISP_SCALE = (1 << DISP_SHIFT); + const Mat& img1; + const Mat& img2; + Mat& disp1; + CostType* Cbuf; + CostType* Sbuf; + int minD; + int maxD; + int D; + int D2; + int width; + int width1; + int height; + int P1; + int P2; + int minX1; + int maxX1; + size_t costBufSize; + size_t CSBufSize; + size_t LrSize; + int INVALID_DISP; + int INVALID_DISP_SCALED; + int uniquenessRatio; + int disp12MaxDiff; +}; /* This is new experimential version of disparity calculation, which should be parralled after TODO: Don't forget to rewrire this commentaries after @@ -1218,20 +1614,17 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, const int ALIGN = 16; const int DISP_SHIFT = StereoMatcher::DISP_SHIFT; const int DISP_SCALE = (1 << DISP_SHIFT); - const CostType MAX_COST = SHRT_MAX; - int minD = params.minDisparity, maxD = minD + params.numDisparities; Size SADWindowSize; //4e: SAD means Sum of Absolute Differences SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; //4e: and this is always square int ftzero = std::max(params.preFilterCap, 15) | 1; //4e:ftzero clips x-derivatives. I think, this story with arrays is about non-realized SIMD method - int uniquenessRatio = params.uniquenessRatio >= 0 ? params.uniquenessRatio : 10; - int disp12MaxDiff = params.disp12MaxDiff > 0 ? params.disp12MaxDiff : 1; int P1 = params.P1 > 0 ? params.P1 : 2, P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion int k, width = disp1.cols, height = disp1.rows; int minX1 = std::max(maxD, 0), maxX1 = width + std::min(minD, 0); int D = maxD - minD, width1 = maxX1 - minX1; - int INVALID_DISP = minD - 1, INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; int SH2 = SADWindowSize.height/2; + int INVALID_DISP = minD - 1; + int INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; //4e: array is such big due to derivative could be +-8*256 in worst cases PixType clipTab[TAB_SIZE]; @@ -1265,8 +1658,7 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, int hsumBufNRows = SH2*2 + 2; size_t totalBufSize = (LrSize + minLrSize)*NLR*sizeof(CostType) + // minLr[] and Lr[] costBufSize*hsumBufNRows*sizeof(CostType) + // hsumBuf //4e: TODO: Why we should increase sum window height one more time? - CSBufSize*2*sizeof(CostType) + // C, S //4e: C is Block sum of costs, S is multidirectional dynamic sum with same size - width*(sizeof(CostType) + sizeof(DispType)) + 1024; // disp2cost + disp2 + CSBufSize*2*sizeof(CostType) + 1024; // C, S //4e: C is Block sum of costs, S is multidirectional dynamic sum with same size if( buffer.empty() || !buffer.isContinuous() || buffer.cols*buffer.rows*buffer.elemSize() < totalBufSize ) @@ -1274,1098 +1666,18 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, // summary cost over different (nDirs) directions CostType* Cbuf = (CostType*)alignPtr(buffer.ptr(), ALIGN); - CostType* Sbuf = Cbuf + CSBufSize; - CostType* hsumBuf = Sbuf + CSBufSize; - - CostType* disp2cost = hsumBuf + costBufSize*hsumBufNRows + (LrSize + minLrSize)*NLR; //4e: It is containers for backwards disparity, made by S[d] too, but with other method - DispType* disp2ptr = (DispType*)(disp2cost + width); // add P2 to every C(x,y). it saves a few operations in the inner loops for(k = 0; k < (int)CSBufSize; k++ ) Cbuf[k] = (CostType)P2; parallel_for_(Range(0,width1),CalcVerticalSums(img1, img2, params, Cbuf, clipTab)); + parallel_for_(Range(0,height),CalcHorizontalSums(img1, img2, disp1, params, Cbuf)); -// for( int pass = 1; pass <= 2; pass++ ) //pass=1 or left-to-right pass - { - - CostType *Lr, *minLr; - - { //4e: Yes, and this is done at the end of next cycle, not here. - // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, - // and will occasionally use negative indices with the arrays - // we need to shift Lr[k] pointers by 1, to give the space for d=-1. - // however, then the alignment will be imperfect, i.e. bad for SSE, - // thus we shift the pointers by 8 (8*sizeof(short) == 16 - ideal alignment) - Lr = hsumBuf + costBufSize*hsumBufNRows + D2*LrBorder + 8; - memset( Lr - LrBorder*D2 - 8, 0, LrSize*sizeof(CostType) ); - minLr = hsumBuf + costBufSize*hsumBufNRows + LrSize*NLR + LrBorder; - memset( minLr - LrBorder, 0, minLrSize*sizeof(CostType) ); - } - - for( int y = 0; y != height; y++) - { - int x, d; - DispType* disp1ptr = disp1.ptr(y); - CostType* C = Cbuf + y*costBufSize; - CostType* S = Sbuf + y*costBufSize; - - for( x = 0; x < width; x++ ) - { - disp1ptr[x] = disp2ptr[x] = (DispType)INVALID_DISP_SCALED; - disp2cost[x] = MAX_COST; - } - - // clear the left and the right borders - memset( Lr - D2*LrBorder - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory - memset( Lr + width1*D2 - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: ...00000000|D2-16 of real costs value(and some of them are zeroes too)|00000000... - memset( minLr - LrBorder, 0, LrBorder*sizeof(CostType) ); - memset( minLr + width1, 0, LrBorder*sizeof(CostType) ); - - /* - [formula 13 in the paper] - compute L_r(p, d) = C(p, d) + - min(L_r(p-r, d), - L_r(p-r, d-1) + P1, - L_r(p-r, d+1) + P1, - min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) - where p = (x,y), r is one of the directions. - we process all the directions at once: - 0: r=(-dx, 0) - 1: r=(-1, -dy) - 2: r=(0, -dy) - 3: r=(1, -dy) - 4: r=(-2, -dy) - 5: r=(-1, -dy*2) - 6: r=(1, -dy*2) - 7: r=(2, -dy) - */ - for( x = 0; x != width1; x++) - { - int xd = x*D2; - - int delta = minLr[x - 1] + P2; - - CostType* Lr_ppr = Lr + xd - D2; - - Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; - - CostType* Lr_p = Lr + xd; - const CostType* Cp = C + x*D; - CostType* Sp = S + x*D; - -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _P1 = v_setall_s16((short)P1); -// -// v_int16x8 _delta0 = v_setall_s16((short)delta0); -// v_int16x8 _delta1 = v_setall_s16((short)delta1); -// v_int16x8 _delta2 = v_setall_s16((short)delta2); -// v_int16x8 _delta3 = v_setall_s16((short)delta3); -// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); -// -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 Cpd = v_load(Cp + d); -// v_int16x8 L0, L1, L2, L3; -// -// L0 = v_load(Lr_ppr + d); -// L1 = v_load(Lr_p1 + d); -// L2 = v_load(Lr_p2 + d); -// L3 = v_load(Lr_p3 + d); -// -// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); -// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); -// -// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); -// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); -// -// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); -// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); -// -// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); -// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); -// -// L0 = v_min(L0, _delta0); -// L0 = ((L0 - _delta0) + Cpd); -// -// L1 = v_min(L1, _delta1); -// L1 = ((L1 - _delta1) + Cpd); -// -// L2 = v_min(L2, _delta2); -// L2 = ((L2 - _delta2) + Cpd); -// -// L3 = v_min(L3, _delta3); -// L3 = ((L3 - _delta3) + Cpd); -// -// v_store(Lr_p + d, L0); -// v_store(Lr_p + d + D2, L1); -// v_store(Lr_p + d + D2*2, L2); -// v_store(Lr_p + d + D2*3, L3); -// -// // Get minimum from in L0-L3 -// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; -// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... -// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... -// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... -// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... -// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... -// v_int16x8 t0 = v_min(t0123L, t0123H); -// _minL0 = v_min(_minL0, t0); -// -// v_int16x8 Sval = v_load(Sp + d); -// -// L0 = L0 + L1; -// L2 = L2 + L3; -// Sval = Sval + L0; -// Sval = Sval + L2; -// -// v_store(Sp + d, Sval); -// } -// -// v_int32x4 minL, minH; -// v_expand(_minL0, minL, minH); -// v_pack_store(&minLr[x], v_min(minL, minH)); -// } -// else -// #endif - { - int minL = MAX_COST; - - for( d = 0; d < D; d++ ) - { - int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually - - L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; - - Lr_p[d] = (CostType)L; - minL = std::min(minL, L); - - Sp[d] = saturate_cast(Sp[d] + L); - } - minLr[x] = (CostType)minL; - } - } - - for( x = width1-1; x != -1; x--) - { - int xd = x*D2; - - int delta = minLr[x + 1] + P2; - - CostType* Lr_ppr = Lr + xd + D2; - - Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; - - CostType* Lr_p = Lr + xd; - const CostType* Cp = C + x*D; - CostType* Sp = S + x*D; - int minS = MAX_COST, bestDisp = -1; - -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _P1 = v_setall_s16((short)P1); -// -// v_int16x8 _delta0 = v_setall_s16((short)delta0); -// v_int16x8 _delta1 = v_setall_s16((short)delta1); -// v_int16x8 _delta2 = v_setall_s16((short)delta2); -// v_int16x8 _delta3 = v_setall_s16((short)delta3); -// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); -// -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 Cpd = v_load(Cp + d); -// v_int16x8 L0, L1, L2, L3; -// -// L0 = v_load(Lr_ppr + d); -// L1 = v_load(Lr_p1 + d); -// L2 = v_load(Lr_p2 + d); -// L3 = v_load(Lr_p3 + d); -// -// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); -// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); -// -// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); -// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); -// -// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); -// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); -// -// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); -// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); -// -// L0 = v_min(L0, _delta0); -// L0 = ((L0 - _delta0) + Cpd); -// -// L1 = v_min(L1, _delta1); -// L1 = ((L1 - _delta1) + Cpd); -// -// L2 = v_min(L2, _delta2); -// L2 = ((L2 - _delta2) + Cpd); -// -// L3 = v_min(L3, _delta3); -// L3 = ((L3 - _delta3) + Cpd); -// -// v_store(Lr_p + d, L0); -// v_store(Lr_p + d + D2, L1); -// v_store(Lr_p + d + D2*2, L2); -// v_store(Lr_p + d + D2*3, L3); -// -// // Get minimum from in L0-L3 -// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; -// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... -// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... -// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... -// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... -// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... -// v_int16x8 t0 = v_min(t0123L, t0123H); -// _minL0 = v_min(_minL0, t0); -// -// v_int16x8 Sval = v_load(Sp + d); -// -// L0 = L0 + L1; -// L2 = L2 + L3; -// Sval = Sval + L0; -// Sval = Sval + L2; -// -// v_store(Sp + d, Sval); -// } -// -// v_int32x4 minL, minH; -// v_expand(_minL0, minL, minH); -// v_pack_store(&minLr[x], v_min(minL, minH)); -// } -// else -// #endif -//TODO:Next piece of code is came from postprocessing. Be very careful with joining them!!! -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _minS = v_setall_s16(MAX_COST), _bestDisp = v_setall_s16(-1); -// v_int16x8 _d8 = v_int16x8(0, 1, 2, 3, 4, 5, 6, 7), _8 = v_setall_s16(8); -// -// for( d = 0; d < D; d+= 8 ) -// { -// v_int16x8 L0 = v_load(Sp + d); -// v_int16x8 mask = L0 < _minS; -// _minS = v_min( L0, _minS ); -// _bestDisp = _bestDisp ^ ((_bestDisp ^ _d8) & mask); -// _d8 = _d8 + _8; -// } -// v_int32x4 _d0, _d1; -// v_expand(_minS, _d0, _d1); -// minS = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); -// v_int16x8 v_mask = v_setall_s16((short)minS) == _minS; -// -// _bestDisp = (_bestDisp & v_mask) | (v_setall_s16(SHRT_MAX) & ~v_mask); -// v_expand(_bestDisp, _d0, _d1); -// bestDisp = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); -// } -// else -// #endif - { - int minL = MAX_COST; - - for( d = 0; d < D; d++ ) - { - int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually - - L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; - - Lr_p[d] = (CostType)L; - minL = std::min(minL, L); - - Sp[d] = saturate_cast(Sp[d] + L); - if( Sp[d] < minS ) - { - minS = Sp[d]; - bestDisp = d; - } - } - minLr[x] = (CostType)minL; - } - //Some postprocessing procedures and saving - for( d = 0; d < D; d++ ) - { - if( Sp[d]*(100 - uniquenessRatio) < minS*100 && std::abs(bestDisp - d) > 1 ) - break; - } - if( d < D ) - continue; - d = bestDisp; - int _x2 = x + minX1 - d - minD; - if( disp2cost[_x2] > minS ) - { - disp2cost[_x2] = (CostType)minS; - disp2ptr[_x2] = (DispType)(d + minD); - } - - if( 0 < d && d < D-1 ) - { - // do subpixel quadratic interpolation: - // fit parabola into (x1=d-1, y1=Sp[d-1]), (x2=d, y2=Sp[d]), (x3=d+1, y3=Sp[d+1]) - // then find minimum of the parabola. - int denom2 = std::max(Sp[d-1] + Sp[d+1] - 2*Sp[d], 1); - d = d*DISP_SCALE + ((Sp[d-1] - Sp[d+1])*DISP_SCALE + denom2)/(denom2*2); - } - else - d *= DISP_SCALE; - disp1ptr[x + minX1] = (DispType)(d + minD*DISP_SCALE); - } - //Left-right check sanity procedure - for( x = minX1; x < maxX1; x++ ) - { - // we round the computed disparity both towards -inf and +inf and check - // if either of the corresponding disparities in disp2 is consistent. - // This is to give the computed disparity a chance to look valid if it is. - int d1 = disp1ptr[x]; - if( d1 == INVALID_DISP_SCALED ) - continue; - int _d = d1 >> DISP_SHIFT; - int d_ = (d1 + DISP_SCALE-1) >> DISP_SHIFT; - int _x = x - _d, x_ = x - d_; - if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && //4e: To dismiss disparity, we should assure, that there is no any - 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) //4e: chance to understand this as correct. - disp1ptr[x] = (DispType)INVALID_DISP_SCALED; - } - } - } } ////////////////////////////////////////////////////////////////////////////////////////////////////// -/* - This is new experimential version of disparity calculation, which should be parralled after -TODO: Don't forget to rewrire this commentaries after - - computes disparity for "roi" in img1 w.r.t. img2 and write it to disp1buf. - that is, disp1buf(x, y)=d means that img1(x+roi.x, y+roi.y) ~ img2(x+roi.x-d, y+roi.y). - minD <= d < maxD. - disp2full is the reverse disparity map, that is: - disp2full(x+roi.x,y+roi.y)=d means that img2(x+roi.x, y+roi.y) ~ img1(x+roi.x+d, y+roi.y) - - note that disp1buf will have the same size as the roi and - disp2full will have the same size as img1 (or img2). - On exit disp2buf is not the final disparity, it is an intermediate result that becomes - final after all the tiles are processed. - - the disparity in disp1buf is written with sub-pixel accuracy - (4 fractional bits, see StereoSGBM::DISP_SCALE), - using quadratic interpolation, while the disparity in disp2buf - is written as is, without interpolation. - - disp2cost also has the same size as img1 (or img2). - It contains the minimum current cost, used to find the best disparity, corresponding to the minimal cost. - */ -static void computeDisparitySGBMParallelOld( const Mat& img1, const Mat& img2, - Mat& disp1, const StereoSGBMParams& params, - Mat& buffer ) -{ -//#if CV_SIMD128 -// // maxDisparity is supposed to multiple of 16, so we can forget doing else -// static const uchar LSBTab[] = -// { -// 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 -// }; -// static const v_uint16x8 v_LSB = v_uint16x8(0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); -// -// bool useSIMD = hasSIMD128(); -//#endif - - const int ALIGN = 16; - const int DISP_SHIFT = StereoMatcher::DISP_SHIFT; - const int DISP_SCALE = (1 << DISP_SHIFT); - const CostType MAX_COST = SHRT_MAX; - - int minD = params.minDisparity, maxD = minD + params.numDisparities; - Size SADWindowSize; //4e: SAD means Sum of Absolute Differences - SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; //4e: and this is always square - int ftzero = std::max(params.preFilterCap, 15) | 1; //4e:ftzero clips x-derivatives. I think, this story with arrays is about non-realized SIMD method - int uniquenessRatio = params.uniquenessRatio >= 0 ? params.uniquenessRatio : 10; - int disp12MaxDiff = params.disp12MaxDiff > 0 ? params.disp12MaxDiff : 1; - int P1 = params.P1 > 0 ? params.P1 : 2, P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion - int k, width = disp1.cols, height = disp1.rows; - int minX1 = std::max(maxD, 0), maxX1 = width + std::min(minD, 0); - int D = maxD - minD, width1 = maxX1 - minX1; - int INVALID_DISP = minD - 1, INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; - int SW2 = SADWindowSize.width/2, SH2 = SADWindowSize.height/2; - const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; //4e: array is such big due to derivative could be +-8*256 in worst cases - PixType clipTab[TAB_SIZE]; - - for( k = 0; k < TAB_SIZE; k++ ) //4e: If ftzero would = 4, array containment will be = -4 -4 -4 ... -4 -3 -2 -1 0 1 2 3 4 ... 4 4 4 - clipTab[k] = (PixType)(std::min(std::max(k - TAB_OFS, -ftzero), ftzero) + ftzero); - - if( minX1 >= maxX1 ) - { - disp1 = Scalar::all(INVALID_DISP_SCALED); - return; - } - - CV_Assert( D % 16 == 0 ); //TODO: Are you sure? By the way, why not 8? - - // NR - the number of directions. the loop on x below that computes Lr assumes that NR == 8. - // if you change NR, please, modify the loop as well. - int D2 = D+16; //4e: Somewhere in code we need d+1, so D+1. One of simplest solutuons is increasing D-dimension on 1. But 1 is 16, when storage should be aligned. - - // the number of L_r(.,.) and min_k L_r(.,.) lines in the buffer: - // for 8-way dynamic programming we need the current row and - // the previous row, i.e. 2 rows in total - const int NLR = 2; //4e: We assume, that we need one or more previous steps in our linear dynamic(one right here). - const int LrBorder = NLR - 1; //4e: for simplification of calculations we need border for taking previous dynamic solutions. - - // for each possible stereo match (img1(x,y) <=> img2(x-d,y)) - // we keep pixel difference cost (C) and the summary cost over NR directions (S). - // we also keep all the partial costs for the previous line L_r(x,d) and also min_k L_r(x, k) - size_t costBufSize = width1*D; - size_t CSBufSize = costBufSize*height; //4e: For HH mode it's better to keep whole array of costs. - size_t minLrSize = (width1 + LrBorder*2), LrSize = minLrSize*D2; //4e: TODO: Understand why NR2 per pass instead od NR2/2 (Probably, without any reason. That doesn't make code wrong) - int hsumBufNRows = SH2*2 + 2; - size_t totalBufSize = (LrSize + minLrSize)*NLR*sizeof(CostType) + // minLr[] and Lr[] - costBufSize*(hsumBufNRows + 1)*sizeof(CostType) + // hsumBuf, pixdiff //4e: TODO: Why we should increase sum window height one more time? - CSBufSize*2*sizeof(CostType) + // C, S //4e: C is Block sum of costs, S is multidirectional dynamic sum with same size - width*16*img1.channels()*sizeof(PixType) + // temp buffer for computing per-pixel cost //4e: It is needed for calcPixelCostBT function, as "buffer" value - width*(sizeof(CostType) + sizeof(DispType)) + 1024; // disp2cost + disp2 - - if( buffer.empty() || !buffer.isContinuous() || - buffer.cols*buffer.rows*buffer.elemSize() < totalBufSize ) - buffer.create(1, (int)totalBufSize, CV_8U); - - // summary cost over different (nDirs) directions - CostType* Cbuf = (CostType*)alignPtr(buffer.ptr(), ALIGN); - CostType* Sbuf = Cbuf + CSBufSize; - CostType* hsumBuf = Sbuf + CSBufSize; - CostType* pixDiff = hsumBuf + costBufSize*hsumBufNRows; - - CostType* disp2cost = pixDiff + costBufSize + (LrSize + minLrSize)*NLR; //4e: It is containers for backwards disparity, made by S[d] too, but with other method - DispType* disp2ptr = (DispType*)(disp2cost + width); - PixType* tempBuf = (PixType*)(disp2ptr + width); - - // add P2 to every C(x,y). it saves a few operations in the inner loops - for(k = 0; k < (int)CSBufSize; k++ ) - Cbuf[k] = (CostType)P2; - - // Two vertical passes - up to down and down to up - for( int pass = 1; pass <= 2; pass++ ) //TODO: rename this magic 2. - { - int y1, y2, dy; - - if( pass == 1 ) - { - y1 = 0; y2 = height; dy = 1; - } - else - { - y1 = height-1; y2 = -1; dy = -1; - } - - CostType *Lr[NLR]={0}, *minLr[NLR]={0}; //4e: arrays for L(x,y,r,d) of previous and current rows and minimums of them - - for( k = 0; k < NLR; k++ ) //4e: One of them is needed, and one of them is stored. So, we need to swap pointer - { //4e: Yes, and this is done at the end of next cycle, not here. - // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, - // and will occasionally use negative indices with the arrays - // we need to shift Lr[k] pointers by 1, to give the space for d=-1. - // however, then the alignment will be imperfect, i.e. bad for SSE, - // thus we shift the pointers by 8 (8*sizeof(short) == 16 - ideal alignment) - Lr[k] = pixDiff + costBufSize + LrSize*k + D2*LrBorder + 8; - memset( Lr[k] - LrBorder*D2 - 8, 0, LrSize*sizeof(CostType) ); - minLr[k] = pixDiff + costBufSize + LrSize*NLR + minLrSize*k + LrBorder; - memset( minLr[k] - LrBorder, 0, minLrSize*sizeof(CostType) ); - } - - for( int y = y1; y != y2; y += dy ) - { - int x, d; - CostType* C = Cbuf + y*costBufSize; - CostType* S = Sbuf + y*costBufSize; - - if( pass == 1 ) // compute C on the first pass, and reuse it on the second pass, if any. - { - int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; //4e: for first line's block sum we need calculate half-window of costs and only one for other - - for( k = dy1; k <= dy2; k++ ) - { - CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; //4e: Ring buffer for horizontally summed lines - - if( k < height ) - { - calcPixelCostBT( img1, img2, k, minD, maxD, pixDiff, tempBuf, clipTab, TAB_OFS, ftzero ); - - memset(hsumAdd, 0, D*sizeof(CostType)); - for( x = 0; x <= SW2*D; x += D ) //4e: Calculation summed costs for all disparities in first pixel of line - { - int scale = x == 0 ? SW2 + 1 : 1; - for( d = 0; d < D; d++ ) - hsumAdd[d] = (CostType)(hsumAdd[d] + pixDiff[x + d]*scale); - } - - if( y > 0 ) //4e: We calculate horizontal sums and forming full block sums for y coord by adding this horsums to previous line's sums and subtracting stored lowest - { //4e: horsum in hsumBuf. Exception is case y=0, where we need many iterations per lines to create full blocking sum. - const CostType* hsumSub = hsumBuf + (std::max(y - SH2 - 1, 0) % hsumBufNRows)*costBufSize; - const CostType* Cprev = C - costBufSize; //4e: Well, actually y>0, so we don't need this check: y==0 - - for( x = D; x < width1*D; x += D ) - { - const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); - const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); - -// #if CV_SIMD128 -// if( useSIMD ) -// { -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 hv = v_load(hsumAdd + x - D + d); -// v_int16x8 Cx = v_load(Cprev + x + d); -// v_int16x8 psub = v_load(pixSub + d); -// v_int16x8 padd = v_load(pixAdd + d); -// hv = (hv - psub + padd); -// psub = v_load(hsumSub + x + d); -// Cx = Cx - psub + hv; -// v_store(hsumAdd + x + d, hv); -// v_store(C + x + d, Cx); -// } -// } -// else -// #endif - { - for( d = 0; d < D; d++ ) - { - int hv = hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]); - C[x + d] = (CostType)(Cprev[x + d] + hv - hsumSub[x + d]); - } - } - } - } - else - { - for( x = D; x < width1*D; x += D ) //4e: Calcluates horizontal sums if (y==0). This piece of code is calling SH2+1 times and then result is used in different way - { //4e: to create full blocks sum. That's why this code is isolated from upper case. - const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); - const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); - - for( d = 0; d < D; d++ ) - hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]); - } - } - } - - if( y == 0 ) //4e: Calculating first full block sum. - { - int scale = k == 0 ? SH2 + 1 : 1; - for( x = 0; x < width1*D; x++ ) - C[x] = (CostType)(C[x] + hsumAdd[x]*scale); - } - } - - // also, clear the S buffer - for( k = 0; k < width1*D; k++ ) //4e: only on first pass, so it keep old information, don't be confused - S[k] = 0; - } - - // clear the left and the right borders - memset( Lr[0] - D2*LrBorder - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory - memset( Lr[0] + width1*D2 - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: ...00000000|D2-16 of real costs value(and some of them are zeroes too)|00000000... - memset( minLr[0] - LrBorder, 0, LrBorder*sizeof(CostType) ); - memset( minLr[0] + width1, 0, LrBorder*sizeof(CostType) ); - - /* - [formula 13 in the paper] - compute L_r(p, d) = C(p, d) + - min(L_r(p-r, d), - L_r(p-r, d-1) + P1, - L_r(p-r, d+1) + P1, - min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) - where p = (x,y), r is one of the directions. - we process all the directions at once: - 0: r=(-dx, 0) - 1: r=(-1, -dy) - 2: r=(0, -dy) - 3: r=(1, -dy) - 4: r=(-2, -dy) - 5: r=(-1, -dy*2) - 6: r=(1, -dy*2) - 7: r=(2, -dy) - */ - for( x = 0; x != width1; x++ ) - { - int xd = x*D2; - - int delta = minLr[1][x] + P2; - - CostType* Lr_ppr = Lr[1] + xd; - - Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; - - CostType* Lr_p = Lr[0] + xd; - const CostType* Cp = C + x*D; - CostType* Sp = S + x*D; - -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _P1 = v_setall_s16((short)P1); -// -// v_int16x8 _delta0 = v_setall_s16((short)delta0); -// v_int16x8 _delta1 = v_setall_s16((short)delta1); -// v_int16x8 _delta2 = v_setall_s16((short)delta2); -// v_int16x8 _delta3 = v_setall_s16((short)delta3); -// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); -// -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 Cpd = v_load(Cp + d); -// v_int16x8 L0, L1, L2, L3; -// -// L0 = v_load(Lr_p0 + d); -// L1 = v_load(Lr_p1 + d); -// L2 = v_load(Lr_ppr + d); -// L3 = v_load(Lr_p3 + d); -// -// L0 = v_min(L0, (v_load(Lr_p0 + d - 1) + _P1)); -// L0 = v_min(L0, (v_load(Lr_p0 + d + 1) + _P1)); -// -// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); -// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); -// -// L2 = v_min(L2, (v_load(Lr_ppr + d - 1) + _P1)); -// L2 = v_min(L2, (v_load(Lr_ppr + d + 1) + _P1)); -// -// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); -// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); -// -// L0 = v_min(L0, _delta0); -// L0 = ((L0 - _delta0) + Cpd); -// -// L1 = v_min(L1, _delta1); -// L1 = ((L1 - _delta1) + Cpd); -// -// L2 = v_min(L2, _delta2); -// L2 = ((L2 - _delta2) + Cpd); -// -// L3 = v_min(L3, _delta3); -// L3 = ((L3 - _delta3) + Cpd); -// -// v_store(Lr_p + d, L0); -// v_store(Lr_p + d + D2, L1); -// v_store(Lr_p + d + D2*2, L2); -// v_store(Lr_p + d + D2*3, L3); -// -// // Get minimum from in L0-L3 -// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; -// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... -// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... -// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... -// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... -// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... -// v_int16x8 t0 = v_min(t0123L, t0123H); -// _minL0 = v_min(_minL0, t0); -// -// v_int16x8 Sval = v_load(Sp + d); -// -// L0 = L0 + L1; -// L2 = L2 + L3; -// Sval = Sval + L0; -// Sval = Sval + L2; -// -// v_store(Sp + d, Sval); -// } -// -// v_int32x4 minL, minH; -// v_expand(_minL0, minL, minH); -// v_pack_store(&minLr[0][x], v_min(minL, minH)); -// } -// else -// #endif - { - int minL = MAX_COST; - - for( d = 0; d < D; d++ ) - { - int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually - - L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; - - Lr_p[d] = (CostType)L; - minL = std::min(minL, L); - - Sp[d] = saturate_cast(Sp[d] + L); - } - minLr[0][x] = (CostType)minL; - } - } - - // now shift the cyclic buffers - std::swap( Lr[0], Lr[1] ); - std::swap( minLr[0], minLr[1] ); - } - } -// for(int y = 0; y(y); - CostType* C = Cbuf + y*costBufSize; - CostType* S = Sbuf + y*costBufSize; - - for( x = 0; x < width; x++ ) - { - disp1ptr[x] = disp2ptr[x] = (DispType)INVALID_DISP_SCALED; - disp2cost[x] = MAX_COST; - } - - // clear the left and the right borders - memset( Lr - D2*LrBorder - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory - memset( Lr + width1*D2 - 8, 0, D2*LrBorder*sizeof(CostType) ); //4e: ...00000000|D2-16 of real costs value(and some of them are zeroes too)|00000000... - memset( minLr - LrBorder, 0, LrBorder*sizeof(CostType) ); - memset( minLr + width1, 0, LrBorder*sizeof(CostType) ); - - /* - [formula 13 in the paper] - compute L_r(p, d) = C(p, d) + - min(L_r(p-r, d), - L_r(p-r, d-1) + P1, - L_r(p-r, d+1) + P1, - min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) - where p = (x,y), r is one of the directions. - we process all the directions at once: - 0: r=(-dx, 0) - 1: r=(-1, -dy) - 2: r=(0, -dy) - 3: r=(1, -dy) - 4: r=(-2, -dy) - 5: r=(-1, -dy*2) - 6: r=(1, -dy*2) - 7: r=(2, -dy) - */ - for( x = 0; x != width1; x++) - { - int xd = x*D2; - - int delta = minLr[x - 1] + P2; - - CostType* Lr_ppr = Lr + xd - D2; - - Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; - - CostType* Lr_p = Lr + xd; - const CostType* Cp = C + x*D; - CostType* Sp = S + x*D; - -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _P1 = v_setall_s16((short)P1); -// -// v_int16x8 _delta0 = v_setall_s16((short)delta0); -// v_int16x8 _delta1 = v_setall_s16((short)delta1); -// v_int16x8 _delta2 = v_setall_s16((short)delta2); -// v_int16x8 _delta3 = v_setall_s16((short)delta3); -// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); -// -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 Cpd = v_load(Cp + d); -// v_int16x8 L0, L1, L2, L3; -// -// L0 = v_load(Lr_ppr + d); -// L1 = v_load(Lr_p1 + d); -// L2 = v_load(Lr_p2 + d); -// L3 = v_load(Lr_p3 + d); -// -// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); -// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); -// -// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); -// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); -// -// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); -// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); -// -// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); -// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); -// -// L0 = v_min(L0, _delta0); -// L0 = ((L0 - _delta0) + Cpd); -// -// L1 = v_min(L1, _delta1); -// L1 = ((L1 - _delta1) + Cpd); -// -// L2 = v_min(L2, _delta2); -// L2 = ((L2 - _delta2) + Cpd); -// -// L3 = v_min(L3, _delta3); -// L3 = ((L3 - _delta3) + Cpd); -// -// v_store(Lr_p + d, L0); -// v_store(Lr_p + d + D2, L1); -// v_store(Lr_p + d + D2*2, L2); -// v_store(Lr_p + d + D2*3, L3); -// -// // Get minimum from in L0-L3 -// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; -// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... -// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... -// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... -// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... -// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... -// v_int16x8 t0 = v_min(t0123L, t0123H); -// _minL0 = v_min(_minL0, t0); -// -// v_int16x8 Sval = v_load(Sp + d); -// -// L0 = L0 + L1; -// L2 = L2 + L3; -// Sval = Sval + L0; -// Sval = Sval + L2; -// -// v_store(Sp + d, Sval); -// } -// -// v_int32x4 minL, minH; -// v_expand(_minL0, minL, minH); -// v_pack_store(&minLr[x], v_min(minL, minH)); -// } -// else -// #endif - { - int minL = MAX_COST; - - for( d = 0; d < D; d++ ) - { - int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually - - L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; - - Lr_p[d] = (CostType)L; - minL = std::min(minL, L); - - Sp[d] = saturate_cast(Sp[d] + L); - } - minLr[x] = (CostType)minL; - } - } - - for( x = width1-1; x != -1; x--) - { - int xd = x*D2; - - int delta = minLr[x + 1] + P2; - - CostType* Lr_ppr = Lr + xd + D2; - - Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; - - CostType* Lr_p = Lr + xd; - const CostType* Cp = C + x*D; - CostType* Sp = S + x*D; - int minS = MAX_COST, bestDisp = -1; - -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _P1 = v_setall_s16((short)P1); -// -// v_int16x8 _delta0 = v_setall_s16((short)delta0); -// v_int16x8 _delta1 = v_setall_s16((short)delta1); -// v_int16x8 _delta2 = v_setall_s16((short)delta2); -// v_int16x8 _delta3 = v_setall_s16((short)delta3); -// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); -// -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 Cpd = v_load(Cp + d); -// v_int16x8 L0, L1, L2, L3; -// -// L0 = v_load(Lr_ppr + d); -// L1 = v_load(Lr_p1 + d); -// L2 = v_load(Lr_p2 + d); -// L3 = v_load(Lr_p3 + d); -// -// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); -// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); -// -// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); -// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); -// -// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); -// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); -// -// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); -// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); -// -// L0 = v_min(L0, _delta0); -// L0 = ((L0 - _delta0) + Cpd); -// -// L1 = v_min(L1, _delta1); -// L1 = ((L1 - _delta1) + Cpd); -// -// L2 = v_min(L2, _delta2); -// L2 = ((L2 - _delta2) + Cpd); -// -// L3 = v_min(L3, _delta3); -// L3 = ((L3 - _delta3) + Cpd); -// -// v_store(Lr_p + d, L0); -// v_store(Lr_p + d + D2, L1); -// v_store(Lr_p + d + D2*2, L2); -// v_store(Lr_p + d + D2*3, L3); -// -// // Get minimum from in L0-L3 -// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; -// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... -// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... -// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... -// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... -// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... -// v_int16x8 t0 = v_min(t0123L, t0123H); -// _minL0 = v_min(_minL0, t0); -// -// v_int16x8 Sval = v_load(Sp + d); -// -// L0 = L0 + L1; -// L2 = L2 + L3; -// Sval = Sval + L0; -// Sval = Sval + L2; -// -// v_store(Sp + d, Sval); -// } -// -// v_int32x4 minL, minH; -// v_expand(_minL0, minL, minH); -// v_pack_store(&minLr[x], v_min(minL, minH)); -// } -// else -// #endif -//TODO:Next piece of code is came from postprocessing. Be very careful with joining them!!! -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _minS = v_setall_s16(MAX_COST), _bestDisp = v_setall_s16(-1); -// v_int16x8 _d8 = v_int16x8(0, 1, 2, 3, 4, 5, 6, 7), _8 = v_setall_s16(8); -// -// for( d = 0; d < D; d+= 8 ) -// { -// v_int16x8 L0 = v_load(Sp + d); -// v_int16x8 mask = L0 < _minS; -// _minS = v_min( L0, _minS ); -// _bestDisp = _bestDisp ^ ((_bestDisp ^ _d8) & mask); -// _d8 = _d8 + _8; -// } -// v_int32x4 _d0, _d1; -// v_expand(_minS, _d0, _d1); -// minS = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); -// v_int16x8 v_mask = v_setall_s16((short)minS) == _minS; -// -// _bestDisp = (_bestDisp & v_mask) | (v_setall_s16(SHRT_MAX) & ~v_mask); -// v_expand(_bestDisp, _d0, _d1); -// bestDisp = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); -// } -// else -// #endif - { - int minL = MAX_COST; - - for( d = 0; d < D; d++ ) - { - int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually - - L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; - - Lr_p[d] = (CostType)L; - minL = std::min(minL, L); - - Sp[d] = saturate_cast(Sp[d] + L); - if( Sp[d] < minS ) - { - minS = Sp[d]; - bestDisp = d; - } - } - minLr[x] = (CostType)minL; - } - //Some postprocessing procedures and saving - for( d = 0; d < D; d++ ) - { - if( Sp[d]*(100 - uniquenessRatio) < minS*100 && std::abs(bestDisp - d) > 1 ) - break; - } - if( d < D ) - continue; - d = bestDisp; - int _x2 = x + minX1 - d - minD; - if( disp2cost[_x2] > minS ) - { - disp2cost[_x2] = (CostType)minS; - disp2ptr[_x2] = (DispType)(d + minD); - } - - if( 0 < d && d < D-1 ) - { - // do subpixel quadratic interpolation: - // fit parabola into (x1=d-1, y1=Sp[d-1]), (x2=d, y2=Sp[d]), (x3=d+1, y3=Sp[d+1]) - // then find minimum of the parabola. - int denom2 = std::max(Sp[d-1] + Sp[d+1] - 2*Sp[d], 1); - d = d*DISP_SCALE + ((Sp[d-1] - Sp[d+1])*DISP_SCALE + denom2)/(denom2*2); - } - else - d *= DISP_SCALE; - disp1ptr[x + minX1] = (DispType)(d + minD*DISP_SCALE); - } - //Left-right check sanity procedure - for( x = minX1; x < maxX1; x++ ) - { - // we round the computed disparity both towards -inf and +inf and check - // if either of the corresponding disparities in disp2 is consistent. - // This is to give the computed disparity a chance to look valid if it is. - int d1 = disp1ptr[x]; - if( d1 == INVALID_DISP_SCALED ) - continue; - int _d = d1 >> DISP_SHIFT; - int d_ = (d1 + DISP_SCALE-1) >> DISP_SHIFT; - int _x = x - _d, x_ = x - d_; - if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && //4e: To dismiss disparity, we should assure, that there is no any - 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) //4e: chance to understand this as correct. - disp1ptr[x] = (DispType)INVALID_DISP_SCALED; - } - } - } -} -////////////////////////////////////////////////////////////////////////////////////////////////////// - void getBufferPointers(Mat& buffer, int width, int width1, int D, int num_ch, int SH2, int P2, CostType*& curCostVolumeLine, CostType*& hsumBuf, CostType*& pixDiff, PixType*& tmpBuf, CostType*& horPassCostVolume, @@ -3018,8 +2330,6 @@ public: if(params.mode==MODE_SGBM_3WAY) computeDisparity3WaySGBM( left, right, disp, params, buffers, num_stripes ); - else if(params.mode==MODE_HH4_OLD) - computeDisparitySGBMParallelOld( left, right, disp, params, buffer ); else if(params.mode==MODE_HH4) computeDisparitySGBMParallel( left, right, disp, params, buffer ); else diff --git a/modules/calib3d/test/test_stereomatching.cpp b/modules/calib3d/test/test_stereomatching.cpp index e1b5c5200e..9a338bb11f 100644 --- a/modules/calib3d/test/test_stereomatching.cpp +++ b/modules/calib3d/test/test_stereomatching.cpp @@ -797,23 +797,25 @@ TEST(Calib3d_StereoSGBMPar, idontknowhowtotesthere) // int mode) Mat leftImg = imread("/home/q/Work/GitVault/opencv_extra/testdata/cv/stereomatching/datasets/teddy/im2.png"); Mat rightImg = imread("/home/q/Work/GitVault/opencv_extra/testdata/cv/stereomatching/datasets/teddy/im6.png"); - Mat leftDisp_old, leftDisp_new; +// Mat leftDisp_old, leftDisp_new; + { + Mat leftDisp; + Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH); + sgbm->compute( leftImg, rightImg, leftDisp); + CV_Assert( leftDisp.type() == CV_16SC1 ); + leftDisp/=8; + imwrite( "/home/q/Work/GitVault/modehh4_new.jpg", leftDisp); + } { Mat leftDisp; Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH4); - sgbm->compute( leftImg, rightImg, leftDisp_new ); - CV_Assert( leftDisp_new.type() == CV_16SC1 ); -// leftDisp/=8; -// imwrite( "/home/q/Work/GitVault/modehh4_new.jpg", leftDisp); + sgbm->compute( leftImg, rightImg, leftDisp); + CV_Assert( leftDisp.type() == CV_16SC1 ); + leftDisp/=8; + imwrite( "/home/q/Work/GitVault/modehh4_old.jpg", leftDisp); } - { - Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH4_OLD); - sgbm->compute( leftImg, rightImg, leftDisp_old ); - CV_Assert( leftDisp_old.type() == CV_16SC1 ); -// leftDisp/=8; -// imwrite( "/home/q/Work/GitVault/modehh4_old.jpg", leftDisp); - } - Mat diff; - absdiff(leftDisp_old,leftDisp_new,diff); - CV_Assert( countNonZero(diff)==0); +// Mat diff; +// absdiff(leftDisp_old,leftDisp_new,diff); +// CV_Assert( countNonZero(diff)==0); +// } From a4c70aebd0c7a41a54e583e42df2435f63f3ec4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20W=C3=BCrtz?= Date: Wed, 19 Apr 2017 20:41:48 +0200 Subject: [PATCH 109/144] Expose UMat OpenCL handles and buffer information to python --- modules/python/src2/cv2.cpp | 60 ++++++++++++++++++++++++++++++++++++- modules/python/test/test.py | 19 ++++++++---- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index bfd23b7e78..1eb4533812 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -508,13 +508,71 @@ static PyObject * UMatWrapper_get(cv2_UMatWrapperObject* self) return pyopencv_from(m); } +// UMatWrapper.handle() - returns the OpenCL handle of the UMat object +static PyObject * UMatWrapper_handle(cv2_UMatWrapperObject* self, PyObject *args, PyObject *kwds) +{ + const char *kwlist[] = {"accessFlags", NULL}; + int accessFlags; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", (char**) kwlist, &accessFlags)) + return 0; + return PyLong_FromVoidPtr(self->um->handle(accessFlags)); +} + +// UMatWrapper.isContinuous() - returns true if the matrix data is continuous +static PyObject * UMatWrapper_isContinuous(cv2_UMatWrapperObject* self) +{ + return PyBool_FromLong(self->um->isContinuous()); +} + +// UMatWrapper.isContinuous() - returns true if the matrix is a submatrix of another matrix +static PyObject * UMatWrapper_isSubmatrix(cv2_UMatWrapperObject* self) +{ + return PyBool_FromLong(self->um->isSubmatrix()); +} + +// UMatWrapper.context() - returns the OpenCL context used by OpenCV UMat +static PyObject * UMatWrapper_context(cv2_UMatWrapperObject*) +{ + return PyLong_FromVoidPtr(cv::ocl::Context::getDefault().ptr()); +} + +// UMatWrapper.context() - returns the OpenCL queue used by OpenCV UMat +static PyObject * UMatWrapper_queue(cv2_UMatWrapperObject*) +{ + return PyLong_FromVoidPtr(cv::ocl::Queue::getDefault().ptr()); +} + +static PyObject * UMatWrapper_offset_getter(cv2_UMatWrapperObject* self, void*) +{ + return PyLong_FromSsize_t(self->um->offset); +} + static PyMethodDef UMatWrapper_methods[] = { {"get", (PyCFunction)UMatWrapper_get, METH_NOARGS, "Returns numpy array" }, + {"handle", (PyCFunction)UMatWrapper_handle, METH_VARARGS | METH_KEYWORDS, + "Returns UMat native handle" + }, + {"isContinuous", (PyCFunction)UMatWrapper_isContinuous, METH_NOARGS, + "Returns true if the matrix data is continuous" + }, + {"isSubmatrix", (PyCFunction)UMatWrapper_isSubmatrix, METH_NOARGS, + "Returns true if the matrix is a submatrix of another matrix" + }, + {"context", (PyCFunction)UMatWrapper_context, METH_NOARGS | METH_STATIC, + "Returns OpenCL context handle" + }, + {"queue", (PyCFunction)UMatWrapper_queue, METH_NOARGS | METH_STATIC, + "Returns OpenCL queue handle" + }, {NULL, NULL, 0, NULL} /* Sentinel */ }; +static PyGetSetDef UMatWrapper_getset[] = { + {(char*) "offset", (getter) UMatWrapper_offset_getter, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; static PyTypeObject cv2_UMatWrapperType = { #if PY_MAJOR_VERSION >= 3 @@ -551,7 +609,7 @@ static PyTypeObject cv2_UMatWrapperType = { 0, /* tp_iternext */ UMatWrapper_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + UMatWrapper_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ diff --git a/modules/python/test/test.py b/modules/python/test/test.py index f4585471e8..be3f821aa9 100755 --- a/modules/python/test/test.py +++ b/modules/python/test/test.py @@ -127,12 +127,21 @@ class Hackathon244Tests(NewOpenCVTests): data = np.random.random([512, 512]) # UMat constructors data_um = cv2.UMat(data) # from ndarray - data_sub_um = cv2.UMat(data_um, [0, 256], [0, 256]) # from UMat - data_dst_um = cv2.UMat(256, 256, cv2.CV_64F) # from size/type - - # simple test + data_sub_um = cv2.UMat(data_um, [128, 256], [128, 256]) # from UMat + data_dst_um = cv2.UMat(128, 128, cv2.CV_64F) # from size/type + # test continuous and submatrix flags + assert data_um.isContinuous() and not data_um.isSubmatrix() + assert not data_sub_um.isContinuous() and data_sub_um.isSubmatrix() + # test operation on submatrix cv2.multiply(data_sub_um, 2., dst=data_dst_um) - assert np.allclose(2. * data[:256, :256], data_dst_um.get()) + assert np.allclose(2. * data[128:256, 128:256], data_dst_um.get()) + + def test_umat_handle(self): + a_um = cv2.UMat(256, 256, cv2.CV_32F) + ctx_handle = cv2.UMat.context() # obtain context handle + queue_handle = cv2.UMat.queue() # obtain queue handle + a_handle = a_um.handle(cv2.ACCESS_READ) # obtain buffer handle + offset = a_um.offset # obtain buffer offset def test_umat_matching(self): img1 = self.get_sample("samples/data/right01.jpg") From 4c095a76c03a5a233c5bd54fccea98a80316c8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20W=C3=BCrtz?= Date: Fri, 21 Apr 2017 12:21:54 +0200 Subject: [PATCH 110/144] Add docstring for UMat::handle --- modules/core/include/opencv2/core/mat.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 0a74e72817..d8adaeed04 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -2464,6 +2464,10 @@ public: UMat& operator = (UMat&& m); #endif + /*! Returns the OpenCL buffer handle on which UMat operates on. + The UMat instance should be kept alive during the use of the handle to prevent the buffer to be + returned to the OpenCV buffer pool. + */ void* handle(int accessFlags) const; void ndoffset(size_t* ofs) const; From 566630595dd8155bd7f80ac4e2862db1177dd6ca Mon Sep 17 00:00:00 2001 From: daB0bby Date: Sat, 22 Apr 2017 12:32:18 +0200 Subject: [PATCH 111/144] Fixes typo --- modules/highgui/include/opencv2/highgui.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/highgui/include/opencv2/highgui.hpp b/modules/highgui/include/opencv2/highgui.hpp index b1f203df03..a29c0cfdcb 100644 --- a/modules/highgui/include/opencv2/highgui.hpp +++ b/modules/highgui/include/opencv2/highgui.hpp @@ -491,7 +491,7 @@ CV_EXPORTS_W Rect selectROI(InputArray img, bool showCrosshair = true, bool from /** @brief Selects ROIs on the given image. Function creates a window and allows user to select a ROIs using mouse. Controls: use `space` or `enter` to finish current selection and start a new one, -use `ecs` to terminate multiple ROI selection process. +use `esc` to terminate multiple ROI selection process. @param windowName name of the window where selection process will be shown. @param img image to select a ROI. From cbda9b332bb29b2761b28623ca8a2cdb4e778518 Mon Sep 17 00:00:00 2001 From: berak Date: Mon, 24 Apr 2017 11:53:50 +0200 Subject: [PATCH 112/144] imgcodecs: fix webp IMREAD_GRAYSCALE loading --- modules/imgcodecs/src/grfmt_webp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/imgcodecs/src/grfmt_webp.cpp b/modules/imgcodecs/src/grfmt_webp.cpp index 981ce7bcc0..1281d832e1 100644 --- a/modules/imgcodecs/src/grfmt_webp.cpp +++ b/modules/imgcodecs/src/grfmt_webp.cpp @@ -162,6 +162,8 @@ bool WebPDecoder::readData(Mat &img) { if( m_width > 0 && m_height > 0 ) { + bool convert_grayscale = (img.type() == CV_8UC1); // IMREAD_GRAYSCALE requested + if (img.cols != m_width || img.rows != m_height || img.type() != m_type) { img.create(m_height, m_width, m_type); @@ -184,6 +186,10 @@ bool WebPDecoder::readData(Mat &img) if(res_ptr == out_data) { + if (convert_grayscale) + { + cvtColor(img, img, COLOR_BGR2GRAY); + } return true; } } From 8952863b9c1b76113767bffc1535392462cb99fa Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 24 Apr 2017 16:56:33 +0300 Subject: [PATCH 113/144] doc: change MathJax URL https://www.mathjax.org/cdn-shutting-down/#alternative-cdn-providers --- doc/Doxyfile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 9414b66f09..dd8d325c4d 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -174,7 +174,7 @@ FORMULA_FONTSIZE = 14 FORMULA_TRANSPARENT = YES USE_MATHJAX = YES MATHJAX_FORMAT = HTML-CSS -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = http://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0 MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols MATHJAX_CODEFILE = @CMAKE_CURRENT_SOURCE_DIR@/mymath.js SEARCHENGINE = YES From 40dc0bcd6395193d5b859bf28b3f4bd459311ad7 Mon Sep 17 00:00:00 2001 From: Brian Armstrong Date: Mon, 24 Apr 2017 18:03:59 -0700 Subject: [PATCH 114/144] fix ByteStreamBuffer --- modules/imgcodecs/src/loadsave.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index 4ceccd196e..6b15dbe3d6 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -70,21 +70,21 @@ protected: std::ios_base::seekdir dir, std::ios_base::openmode ) { - // get absolute offset - off_type off = offset; + char* whence = eback(); if (dir == std::ios_base::cur) { - off += gptr() - eback(); + whence = gptr(); } else if (dir == std::ios_base::end) { - off += egptr() - eback(); + whence = egptr(); } + char* to = whence + offset; // check limits - if (off >= (off_type)0 && off <= egptr() - eback()) + if (to >= eback() && to <= egptr()) { - setg(eback(), gptr() + off, egptr()); + setg(eback(), to, egptr()); return gptr() - eback(); } From d363e2789fd3d4e6b92de3e7e002ad9a61b901bc Mon Sep 17 00:00:00 2001 From: saskatchewancatch Date: Mon, 24 Apr 2017 21:01:38 -0600 Subject: [PATCH 115/144] 8632: Corrected cv::seamlessClone doc to reflect actual name of flag used in code --- modules/photo/include/opencv2/photo.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/photo/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp index a445dd3b03..1f5eeedbe1 100644 --- a/modules/photo/include/opencv2/photo.hpp +++ b/modules/photo/include/opencv2/photo.hpp @@ -748,7 +748,7 @@ complex outlines into a new background consuming and often leaves an undesirable halo. Seamless cloning, even averaged with the original image, is not effective. Mixed seamless cloning based on a loose selection proves effective. -- **FEATURE_EXCHANGE** Feature exchange allows the user to easily replace certain features of +- **MONOCHROME_TRANSFER** Monochrome transfer allows the user to easily replace certain features of one object by alternative features. */ CV_EXPORTS_W void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, From 3fe18392eff71f9f0a2d973d2378c4f7960dda80 Mon Sep 17 00:00:00 2001 From: saskatchewancatch Date: Thu, 20 Apr 2017 00:14:18 -0600 Subject: [PATCH 116/144] Updated comments for cv::ellipse and cv::ellipse2Poly to clarify some behaviour that has confused some users. Amend: Delete trailing whitespace to make doc tests happy --- modules/imgproc/include/opencv2/imgproc.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 4bab109107..bd03e3ce6d 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -4220,13 +4220,14 @@ CV_EXPORTS_W void circle(InputOutputArray img, Point center, int radius, /** @brief Draws a simple or thick elliptic arc or fills an ellipse sector. -The function cv::ellipse with less parameters draws an ellipse outline, a filled ellipse, an elliptic +The function cv::ellipse with more parameters draws an ellipse outline, a filled ellipse, an elliptic arc, or a filled ellipse sector. The drawing code uses general parametric form. A piecewise-linear curve is used to approximate the elliptic arc boundary. If you need more control of the ellipse rendering, you can retrieve the curve using cv::ellipse2Poly and then render it with polylines or fill it with cv::fillPoly. If you use the first variant of the function and want to draw the whole ellipse, not an arc, pass `startAngle=0` and -`endAngle=360`. The figure below explains the meaning of the parameters to draw the blue arc. +`endAngle=360`. If `startAngle` is greater than `endAngle`, they are swapped. The figure below explains +the meaning of the parameters to draw the blue arc. ![Parameters of Elliptic Arc](pics/ellipse.svg) @@ -4468,7 +4469,7 @@ CV_EXPORTS_W bool clipLine(Rect imgRect, CV_OUT CV_IN_OUT Point& pt1, CV_OUT CV_ /** @brief Approximates an elliptic arc with a polyline. The function ellipse2Poly computes the vertices of a polyline that approximates the specified -elliptic arc. It is used by cv::ellipse. +elliptic arc. It is used by cv::ellipse. If `arcStart` is greater than `arcEnd`, they are swapped. @param center Center of the arc. @param axes Half of the size of the ellipse main axes. See the ellipse for details. From 11c2ffaf1c4eef3508dafc2bf94c1473d26acb1a Mon Sep 17 00:00:00 2001 From: Pavel Vlasov Date: Fri, 21 Apr 2017 14:52:45 +0300 Subject: [PATCH 117/144] Update for IPP for OpenCV 2017u2 integration; Updated integrations for: cv::split cv::merge cv::insertChannel cv::extractChannel cv::Mat::convertTo - now with scaled conversions support cv::LUT - disabled due to performance issues Mat::copyTo Mat::setTo cv::flip cv::copyMakeBorder - currently disabled cv::polarToCart cv::pow - ipp pow function was removed due to performance issues cv::hal::magnitude32f/64f - disabled for <= SSE42, poor performance cv::countNonZero cv::minMaxIdx cv::norm cv::canny - new integration. Disabled for threaded; cv::cornerHarris cv::boxFilter cv::bilateralFilter cv::integral --- 3rdparty/ippicv/ippicv.cmake | 2 +- modules/core/include/opencv2/core/private.hpp | 2 - modules/core/src/convert.cpp | 333 +++++++-- modules/core/src/copy.cpp | 426 ++++------- modules/core/src/mathfuncs.cpp | 109 +-- modules/core/src/mathfuncs_core.dispatch.cpp | 4 +- modules/core/src/matmul.cpp | 87 +-- modules/core/src/stat.cpp | 704 ++++++++++-------- modules/imgproc/src/canny.cpp | 156 ++-- modules/imgproc/src/corner.cpp | 34 +- modules/imgproc/src/filter.cpp | 14 +- modules/imgproc/src/hough.cpp | 16 +- modules/imgproc/src/moments.cpp | 303 ++++---- modules/imgproc/src/pyramids.cpp | 12 +- modules/imgproc/src/smooth.cpp | 318 ++++---- modules/imgproc/src/sumpixels.cpp | 82 +- .../imgproc/test/test_bilateral_filter.cpp | 9 +- modules/imgproc/test/test_houghLines.cpp | 2 +- modules/objdetect/src/cascadedetect.cpp | 10 + modules/objdetect/src/cascadedetect.hpp | 8 + modules/objdetect/src/haar.cpp | 6 +- 21 files changed, 1392 insertions(+), 1245 deletions(-) diff --git a/3rdparty/ippicv/ippicv.cmake b/3rdparty/ippicv/ippicv.cmake index 7cec77c4ee..d601da4bb8 100644 --- a/3rdparty/ippicv/ippicv.cmake +++ b/3rdparty/ippicv/ippicv.cmake @@ -21,7 +21,7 @@ function(download_ippicv root_var) set(OPENCV_ICV_NAME "ippicv_2017u2_lnx_intel64_20170418.tgz") set(OPENCV_ICV_HASH "87cbdeb627415d8e4bc811156289fa3a") else() - set(OPENCV_ICV_NAME "ippicv_2017u2_lnx_ia32_20170406.tgz") + set(OPENCV_ICV_NAME "ippicv_2017u2_lnx_ia32_20170418.tgz") set(OPENCV_ICV_HASH "f2cece00d802d4dea86df52ed095257e") endif() elseif(WIN32 AND NOT ARM) diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp index 50b5de2ac8..dbe8bb631f 100644 --- a/modules/core/include/opencv2/core/private.hpp +++ b/modules/core/include/opencv2/core/private.hpp @@ -217,8 +217,6 @@ CV_EXPORTS void scalarToRawData(const cv::Scalar& s, void* buf, int type, int un #define IPP_DISABLE_PERF_MAG_SSE42 1 // cv::magnitude optimizations problem #define IPP_DISABLE_PERF_BOX16S_SSE42 1 // cv::boxFilter optimizations problem -#define IPP_DISABLE_BLOCK 0 // legacy switch - #ifdef HAVE_IPP #include "ippversion.h" #ifndef IPP_VERSION_UPDATE // prior to 7.1 diff --git a/modules/core/src/convert.cpp b/modules/core/src/convert.cpp index dd3fa641b1..f431033c09 100644 --- a/modules/core/src/convert.cpp +++ b/modules/core/src/convert.cpp @@ -85,6 +85,66 @@ static MergeFunc getMergeFunc(int depth) return mergeTab[depth]; } +#ifdef HAVE_IPP +#ifdef HAVE_IPP_IW +extern "C" { +IW_DECL(IppStatus) llwiCopySplit(const void *pSrc, int srcStep, void* const pDstOrig[], int dstStep, + IppiSize size, int typeSize, int channels); +} +#endif + +namespace cv { +static bool ipp_split(const Mat& src, Mat* mv, int channels) +{ +#ifdef HAVE_IPP_IW + CV_INSTRUMENT_REGION_IPP() + + if(channels != 3 && channels != 4) + return false; + + if(src.dims <= 2) + { + IppiSize size = ippiSize(src.size()); + void *dstPtrs[4] = {NULL}; + size_t dstStep = mv[0].step; + for(int i = 0; i < channels; i++) + { + dstPtrs[i] = mv[i].ptr(); + if(dstStep != mv[i].step) + return false; + } + + return CV_INSTRUMENT_FUN_IPP(llwiCopySplit, src.ptr(), (int)src.step, dstPtrs, (int)dstStep, size, (int)src.elemSize1(), channels) >= 0; + } + else + { + const Mat *arrays[5] = {NULL}; + uchar *ptrs[5] = {NULL}; + arrays[0] = &src; + + for(int i = 1; i < channels; i++) + { + arrays[i] = &mv[i-1]; + } + + NAryMatIterator it(arrays, ptrs); + IppiSize size = { (int)it.size, 1 }; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + if(CV_INSTRUMENT_FUN_IPP(llwiCopySplit, ptrs[0], 0, (void**)&ptrs[1], 0, size, (int)src.elemSize1(), channels) < 0) + return false; + } + return true; + } +#else + CV_UNUSED(src); CV_UNUSED(mv); CV_UNUSED(channels); + return false; +#endif +} +} +#endif + void cv::split(const Mat& src, Mat* mv) { CV_INSTRUMENT_REGION() @@ -96,6 +156,13 @@ void cv::split(const Mat& src, Mat* mv) return; } + for( k = 0; k < cn; k++ ) + { + mv[k].create(src.dims, src.size, depth); + } + + CV_IPP_RUN_FAST(ipp_split(src, mv, cn)); + SplitFunc func = getSplitFunc(depth); CV_Assert( func != 0 ); @@ -108,7 +175,6 @@ void cv::split(const Mat& src, Mat* mv) arrays[0] = &src; for( k = 0; k < cn; k++ ) { - mv[k].create(src.dims, src.size, depth); arrays[k+1] = &mv[k]; } @@ -206,6 +272,66 @@ void cv::split(InputArray _m, OutputArrayOfArrays _mv) split(m, &dst[0]); } +#ifdef HAVE_IPP +#ifdef HAVE_IPP_IW +extern "C" { +IW_DECL(IppStatus) llwiCopyMerge(const void* const pSrc[], int srcStep, void *pDst, int dstStep, + IppiSize size, int typeSize, int channels); +} +#endif + +namespace cv { +static bool ipp_merge(const Mat* mv, Mat& dst, int channels) +{ +#ifdef HAVE_IPP_IW + CV_INSTRUMENT_REGION_IPP() + + if(channels != 3 && channels != 4) + return false; + + if(mv[0].dims <= 2) + { + IppiSize size = ippiSize(mv[0].size()); + const void *srcPtrs[4] = {NULL}; + size_t srcStep = mv[0].step; + for(int i = 0; i < channels; i++) + { + srcPtrs[i] = mv[i].ptr(); + if(srcStep != mv[i].step) + return false; + } + + return CV_INSTRUMENT_FUN_IPP(llwiCopyMerge, srcPtrs, (int)srcStep, dst.ptr(), (int)dst.step, size, (int)mv[0].elemSize1(), channels) >= 0; + } + else + { + const Mat *arrays[5] = {NULL}; + uchar *ptrs[5] = {NULL}; + arrays[0] = &dst; + + for(int i = 1; i < channels; i++) + { + arrays[i] = &mv[i-1]; + } + + NAryMatIterator it(arrays, ptrs); + IppiSize size = { (int)it.size, 1 }; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + if(CV_INSTRUMENT_FUN_IPP(llwiCopyMerge, (const void**)&ptrs[1], 0, ptrs[0], 0, size, (int)mv[0].elemSize1(), channels) < 0) + return false; + } + return true; + } +#else + CV_UNUSED(dst); CV_UNUSED(mv); CV_UNUSED(channels); + return false; +#endif +} +} +#endif + void cv::merge(const Mat* mv, size_t n, OutputArray _dst) { CV_INSTRUMENT_REGION() @@ -234,6 +360,8 @@ void cv::merge(const Mat* mv, size_t n, OutputArray _dst) return; } + CV_IPP_RUN_FAST(ipp_merge(mv, dst, (int)n)); + if( !allch1 ) { AutoBuffer pairs(cn*2); @@ -691,6 +819,59 @@ void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst, mixChannels(&buf[0], nsrc, &buf[nsrc], ndst, &fromTo[0], fromTo.size()/2); } +#ifdef HAVE_IPP +#ifdef HAVE_IPP_IW +extern "C" { +IW_DECL(IppStatus) llwiCopyMixed(const void *pSrc, int srcStep, int srcChannels, void *pDst, int dstStep, int dstChannels, + IppiSize size, int typeSize, int channelsShift); +} +#endif + +namespace cv +{ +static bool ipp_extractInsertChannel(const Mat &src, Mat &dst, int channel) +{ +#ifdef HAVE_IPP_IW + CV_INSTRUMENT_REGION_IPP() + + int srcChannels = src.channels(); + int dstChannels = dst.channels(); + + if(src.dims != dst.dims) + return false; + + if(srcChannels == dstChannels || (srcChannels != 1 && dstChannels != 1)) + return false; + + if(src.dims <= 2) + { + IppiSize size = ippiSize(src.size()); + + return CV_INSTRUMENT_FUN_IPP(llwiCopyMixed, src.ptr(), (int)src.step, srcChannels, dst.ptr(), (int)dst.step, dstChannels, size, (int)src.elemSize1(), channel) >= 0; + } + else + { + const Mat *arrays[] = {&dst, NULL}; + uchar *ptrs[2] = {NULL}; + NAryMatIterator it(arrays, ptrs); + + IppiSize size = {(int)it.size, 1}; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + if(CV_INSTRUMENT_FUN_IPP(llwiCopyMixed, ptrs[0], 0, srcChannels, ptrs[1], 0, dstChannels, size, (int)src.elemSize1(), channel) < 0) + return false; + } + return true; + } +#else + CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(channel); + return false; +#endif +} +} +#endif + void cv::extractChannel(InputArray _src, OutputArray _dst, int coi) { CV_INSTRUMENT_REGION() @@ -711,6 +892,9 @@ void cv::extractChannel(InputArray _src, OutputArray _dst, int coi) Mat src = _src.getMat(); _dst.create(src.dims, &src.size[0], depth); Mat dst = _dst.getMat(); + + CV_IPP_RUN_FAST(ipp_extractInsertChannel(src, dst, coi)) + mixChannels(&src, 1, &dst, 1, ch, 1); } @@ -732,6 +916,9 @@ void cv::insertChannel(InputArray _src, InputOutputArray _dst, int coi) } Mat src = _src.getMat(), dst = _dst.getMat(); + + CV_IPP_RUN_FAST(ipp_extractInsertChannel(src, dst, coi)) + mixChannels(&src, 1, &dst, 1, ch, 1); } @@ -5264,6 +5451,72 @@ void cv::convertFp16( InputArray _src, OutputArray _dst) } } +#ifdef HAVE_IPP +namespace cv +{ +static bool ipp_convertTo(Mat &src, Mat &dst, double alpha, double beta) +{ +#ifdef HAVE_IPP_IW + CV_INSTRUMENT_REGION_IPP() + + IppDataType srcDepth = ippiGetDataType(src.depth()); + IppDataType dstDepth = ippiGetDataType(dst.depth()); + int channels = src.channels(); + + if(src.dims == 0) + return false; + + ::ipp::IwiImage iwSrc; + ::ipp::IwiImage iwDst; + + try + { + IppHintAlgorithm mode = ippAlgHintFast; + if(dstDepth == ipp64f || + (dstDepth == ipp32f && (srcDepth == ipp32s || srcDepth == ipp64f)) || + (dstDepth == ipp32s && (srcDepth == ipp32s || srcDepth == ipp64f))) + mode = ippAlgHintAccurate; + + if(src.dims <= 2) + { + Size sz = getContinuousSize(src, dst, channels); + + iwSrc.Init(ippiSize(sz), srcDepth, 1, NULL, (void*)src.ptr(), src.step); + iwDst.Init(ippiSize(sz), dstDepth, 1, NULL, (void*)dst.ptr(), dst.step); + + CV_INSTRUMENT_FUN_IPP(::ipp::iwiScale, &iwSrc, &iwDst, alpha, beta, mode); + } + else + { + const Mat *arrays[] = {&src, &dst, NULL}; + uchar *ptrs[2] = {NULL}; + NAryMatIterator it(arrays, ptrs); + + iwSrc.Init(ippiSize(it.size, 1), srcDepth, channels); + iwDst.Init(ippiSize(it.size, 1), dstDepth, channels); + + for(size_t i = 0; i < it.nplanes; i++, ++it) + { + iwSrc.m_ptr = ptrs[0]; + iwDst.m_ptr = ptrs[1]; + + CV_INSTRUMENT_FUN_IPP(::ipp::iwiScale, &iwSrc, &iwDst, alpha, beta, mode); + } + } + } + catch (::ipp::IwException) + { + return false; + } + return true; +#else + CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(alpha); CV_UNUSED(beta); + return false; +#endif +} +} +#endif + void cv::Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta) const { CV_INSTRUMENT_REGION() @@ -5283,6 +5536,13 @@ void cv::Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta) } Mat src = *this; + if( dims <= 2 ) + _dst.create( size(), _type ); + else + _dst.create( dims, size, _type ); + Mat dst = _dst.getMat(); + + CV_IPP_RUN_FAST(ipp_convertTo(src, dst, alpha, beta )); BinaryFunc func = noScale ? getConvertFunc(sdepth, ddepth) : getConvertScaleFunc(sdepth, ddepth); double scale[] = {alpha, beta}; @@ -5291,15 +5551,12 @@ void cv::Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta) if( dims <= 2 ) { - _dst.create( size(), _type ); - Mat dst = _dst.getMat(); Size sz = getContinuousSize(src, dst, cn); + func( src.data, src.step, 0, 0, dst.data, dst.step, sz, scale ); } else { - _dst.create( dims, size, _type ); - Mat dst = _dst.getMat(); const Mat* arrays[] = {&src, &dst, 0}; uchar* ptrs[2]; NAryMatIterator it(arrays, ptrs); @@ -5436,9 +5693,9 @@ static bool openvx_LUT(Mat src, Mat dst, Mat _lut) #endif #if defined(HAVE_IPP) +#if !IPP_DISABLE_PERF_LUT // there are no performance benefits (PR #2653) namespace ipp { -#if IPP_DISABLE_BLOCK // there are no performance benefits (PR #2653) class IppLUTParallelBody_LUTC1 : public ParallelLoopBody { public: @@ -5447,25 +5704,17 @@ public: const Mat& lut_; Mat& dst_; - typedef IppStatus (*IppFn)(const Ipp8u* pSrc, int srcStep, void* pDst, int dstStep, - IppiSize roiSize, const void* pTable, int nBitSize); - IppFn fn; - int width; + size_t elemSize1; IppLUTParallelBody_LUTC1(const Mat& src, const Mat& lut, Mat& dst, bool* _ok) : ok(_ok), src_(src), lut_(lut), dst_(dst) { width = dst.cols * dst.channels(); + elemSize1 = CV_ELEM_SIZE1(dst.depth()); - size_t elemSize1 = CV_ELEM_SIZE1(dst.depth()); - - fn = - elemSize1 == 1 ? (IppFn)ippiLUTPalette_8u_C1R : - elemSize1 == 4 ? (IppFn)ippiLUTPalette_8u32u_C1R : - NULL; - - *ok = (fn != NULL); + CV_DbgAssert(elemSize1 == 1 || elemSize1 == 4); + *ok = true; } void operator()( const cv::Range& range ) const @@ -5481,19 +5730,22 @@ public: IppiSize sz = { width, dst.rows }; - CV_DbgAssert(fn != NULL); - if (fn(src.data, (int)src.step[0], dst.data, (int)dst.step[0], sz, lut_.data, 8) < 0) + if (elemSize1 == 1) { - setIppErrorStatus(); - *ok = false; + if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C1R, (const Ipp8u*)src.data, (int)src.step[0], dst.data, (int)dst.step[0], sz, lut_.data, 8) >= 0) + return; } - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); + else if (elemSize1 == 4) + { + if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u32u_C1R, (const Ipp8u*)src.data, (int)src.step[0], (Ipp32u*)dst.data, (int)dst.step[0], sz, (Ipp32u*)lut_.data, 8) >= 0) + return; + } + *ok = false; } private: IppLUTParallelBody_LUTC1(const IppLUTParallelBody_LUTC1&); IppLUTParallelBody_LUTC1& operator=(const IppLUTParallelBody_LUTC1&); }; -#endif class IppLUTParallelBody_LUTCN : public ParallelLoopBody { @@ -5527,21 +5779,13 @@ public: { IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C3P3R, lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256); if (status < 0) - { - setIppErrorStatus(); return; - } - CV_IMPL_ADD(CV_IMPL_IPP); } else if (lutcn == 4) { IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C4P4R, lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256); if (status < 0) - { - setIppErrorStatus(); return; - } - CV_IMPL_ADD(CV_IMPL_IPP); } *ok = true; @@ -5568,25 +5812,14 @@ public: if (lutcn == 3) { - if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C3R, - src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0], - ippiSize(dst.size()), lutTable, 8) >= 0) - { - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); + if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C3R, src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0], ippiSize(dst.size()), lutTable, 8) >= 0) return; - } } else if (lutcn == 4) { - if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C4R, - src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0], - ippiSize(dst.size()), lutTable, 8) >= 0) - { - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); + if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C4R, src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0], ippiSize(dst.size()), lutTable, 8) >= 0) return; - } } - setIppErrorStatus(); *ok = false; } private: @@ -5608,15 +5841,13 @@ static bool ipp_lut(Mat &src, Mat &lut, Mat &dst) Ptr body; size_t elemSize1 = CV_ELEM_SIZE1(dst.depth()); -#if IPP_DISABLE_BLOCK // there are no performance benefits (PR #2653) + if (lutcn == 1) { ParallelLoopBody* p = new ipp::IppLUTParallelBody_LUTC1(src, lut, dst, &ok); body.reset(p); } - else -#endif - if ((lutcn == 3 || lutcn == 4) && elemSize1 == 1) + else if ((lutcn == 3 || lutcn == 4) && elemSize1 == 1) { ParallelLoopBody* p = new ipp::IppLUTParallelBody_LUTCN(src, lut, dst, &ok); body.reset(p); @@ -5635,6 +5866,8 @@ static bool ipp_lut(Mat &src, Mat &lut, Mat &dst) return false; } + +#endif #endif // IPP class LUTParallelBody : public ParallelLoopBody @@ -5703,7 +5936,9 @@ void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst ) CV_OVX_RUN(true, openvx_LUT(src, dst, lut)) +#if !IPP_DISABLE_PERF_LUT CV_IPP_RUN(_src.dims() <= 2, ipp_lut(src, lut, dst)); +#endif if (_src.dims() <= 2) { diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index fb8da3bfac..b13687463d 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -49,6 +49,19 @@ #include "precomp.hpp" #include "opencl_kernels_core.hpp" +#ifdef HAVE_IPP_IW +extern "C" { +IW_DECL(IppStatus) llwiCopyMask(const void *pSrc, int srcStep, void *pDst, int dstStep, + IppiSize size, int typeSize, int channels, const Ipp8u *pMask, int maskStep); +IW_DECL(IppStatus) llwiSet(const double *pValue, void *pDst, int dstStep, + IppiSize size, IppDataType dataType, int channels); +IW_DECL(IppStatus) llwiSetMask(const double *pValue, void *pDst, int dstStep, + IppiSize size, IppDataType dataType, int channels, const Ipp8u *pMask, int maskStep); +IW_DECL(IppStatus) llwiCopyMakeBorder(const void *pSrc, IppSizeL srcStep, void *pDst, IppSizeL dstStep, + IppiSizeL size, IppDataType dataType, int channels, IppiBorderSize *pBorderSize, IppiBorderType border, const Ipp64f *pBorderVal); +} +#endif + namespace cv { @@ -326,6 +339,42 @@ void Mat::copyTo( OutputArray _dst ) const } } +#ifdef HAVE_IPP +static bool ipp_copyTo(const Mat &src, Mat &dst, const Mat &mask) +{ +#ifdef HAVE_IPP_IW + CV_INSTRUMENT_REGION_IPP() + + if(mask.channels() > 1 && mask.depth() != CV_8U) + return false; + + if (src.dims <= 2) + { + IppiSize size = ippiSize(src.size()); + return CV_INSTRUMENT_FUN_IPP(llwiCopyMask, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, size, (int)src.elemSize1(), src.channels(), mask.ptr(), (int)mask.step) >= 0; + } + else + { + const Mat *arrays[] = {&src, &dst, &mask, NULL}; + uchar *ptrs[3] = {NULL}; + NAryMatIterator it(arrays, ptrs); + + IppiSize size = ippiSize(it.size, 1); + + for (size_t i = 0; i < it.nplanes; i++, ++it) + { + if(CV_INSTRUMENT_FUN_IPP(llwiCopyMask, ptrs[0], 0, ptrs[1], 0, size, (int)src.elemSize1(), src.channels(), ptrs[2], 0) < 0) + return false; + } + return true; + } +#else + CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(mask); + return false; +#endif +} +#endif + void Mat::copyTo( OutputArray _dst, InputArray _mask ) const { CV_INSTRUMENT_REGION() @@ -340,9 +389,10 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const int cn = channels(), mcn = mask.channels(); CV_Assert( mask.depth() == CV_8U && (mcn == 1 || mcn == cn) ); bool colorMask = mcn > 1; - - size_t esz = colorMask ? elemSize1() : elemSize(); - BinaryFunc copymask = getCopyMaskFunc(esz); + if( dims <= 2 ) + { + CV_Assert( size() == mask.size() ); + } uchar* data0 = _dst.getMat().data; _dst.create( dims, size, type() ); @@ -351,9 +401,13 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const if( dst.data != data0 ) // do not leave dst uninitialized dst = Scalar(0); + CV_IPP_RUN_FAST(ipp_copyTo(*this, dst, mask)) + + size_t esz = colorMask ? elemSize1() : elemSize(); + BinaryFunc copymask = getCopyMaskFunc(esz); + if( dims <= 2 ) { - CV_Assert( size() == mask.size() ); Size sz = getContinuousSize(*this, dst, mask, mcn); copymask(data, step, mask.data, mask.step, dst.data, dst.step, sz, &esz); return; @@ -380,36 +434,6 @@ Mat& Mat::operator = (const Scalar& s) if( is[0] == 0 && is[1] == 0 && is[2] == 0 && is[3] == 0 ) { -#if defined HAVE_IPP && IPP_DISABLE_BLOCK - CV_IPP_CHECK() - { - if (dims <= 2 || isContinuous()) - { - IppiSize roisize = { cols, rows }; - if (isContinuous()) - { - roisize.width = (int)total(); - roisize.height = 1; - - if (ippsZero_8u(data, static_cast(roisize.width * elemSize())) >= 0) - { - CV_IMPL_ADD(CV_IMPL_IPP) - return *this; - } - setIppErrorStatus(); - } - roisize.width *= (int)elemSize(); - - if (ippiSet_8u_C1R(0, data, (int)step, roisize) >= 0) - { - CV_IMPL_ADD(CV_IMPL_IPP) - return *this; - } - setIppErrorStatus(); - } - } -#endif - for( size_t i = 0; i < it.nplanes; i++, ++it ) memset( dptr, 0, elsize ); } @@ -437,89 +461,55 @@ Mat& Mat::operator = (const Scalar& s) return *this; } -#if defined HAVE_IPP -static bool ipp_Mat_setTo(Mat *src, Mat &value, Mat &mask) +#ifdef HAVE_IPP +static bool ipp_Mat_setTo_Mat(Mat &dst, Mat &_val, Mat &mask) { +#ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() - int cn = src->channels(), depth0 = src->depth(); + if(mask.empty()) + return false; - if (!mask.empty() && (src->dims <= 2 || (src->isContinuous() && mask.isContinuous())) && - (/*depth0 == CV_8U ||*/ depth0 == CV_16U || depth0 == CV_16S || depth0 == CV_32S || depth0 == CV_32F) && - (cn == 1 || cn == 3 || cn == 4)) + if(mask.depth() != CV_8U || mask.channels() > 1) + return false; + + if(dst.channels() > 4) + return false; + + if(dst.dims <= 2) { - uchar _buf[32]; - void * buf = _buf; - convertAndUnrollScalar( value, src->type(), _buf, 1 ); + IppiSize size = ippiSize(dst.size()); + IppDataType dataType = ippiGetDataType(dst.depth()); + ::ipp::IwValue s; + convertAndUnrollScalar(_val, CV_MAKETYPE(CV_64F, dst.channels()), (uchar*)((Ipp64f*)s), 1); - IppStatus status = (IppStatus)-1; - IppiSize roisize = { src->cols, src->rows }; - int mstep = (int)mask.step[0], dstep = (int)src->step[0]; - - if (src->isContinuous() && mask.isContinuous()) - { - roisize.width = (int)src->total(); - roisize.height = 1; - } - - if (cn == 1) - { - /*if (depth0 == CV_8U) - status = ippiSet_8u_C1MR(*(Ipp8u *)buf, (Ipp8u *)data, dstep, roisize, mask.data, mstep); - else*/ if (depth0 == CV_16U) - status = CV_INSTRUMENT_FUN_IPP(ippiSet_16u_C1MR, *(Ipp16u *)buf, (Ipp16u *)src->data, dstep, roisize, mask.data, mstep); - else if (depth0 == CV_16S) - status = CV_INSTRUMENT_FUN_IPP(ippiSet_16s_C1MR, *(Ipp16s *)buf, (Ipp16s *)src->data, dstep, roisize, mask.data, mstep); - else if (depth0 == CV_32S) - status = CV_INSTRUMENT_FUN_IPP(ippiSet_32s_C1MR, *(Ipp32s *)buf, (Ipp32s *)src->data, dstep, roisize, mask.data, mstep); - else if (depth0 == CV_32F) - status = CV_INSTRUMENT_FUN_IPP(ippiSet_32f_C1MR, *(Ipp32f *)buf, (Ipp32f *)src->data, dstep, roisize, mask.data, mstep); - } - else if (cn == 3 || cn == 4) - { - -#define IPP_SET(ippfavor, ippcn) \ - do \ - { \ - typedef Ipp##ippfavor ipptype; \ - ipptype ippvalue[4] = { ((ipptype *)buf)[0], ((ipptype *)buf)[1], ((ipptype *)buf)[2], ((ipptype *)buf)[3] }; \ - status = CV_INSTRUMENT_FUN_IPP(ippiSet_##ippfavor##_C##ippcn##MR, ippvalue, (ipptype *)src->data, dstep, roisize, mask.data, mstep); \ - } while ((void)0, 0) - -#define IPP_SET_CN(ippcn) \ - do \ - { \ - if (cn == ippcn) \ - { \ - /*if (depth0 == CV_8U) \ - IPP_SET(8u, ippcn); \ - else*/ if (depth0 == CV_16U) \ - IPP_SET(16u, ippcn); \ - else if (depth0 == CV_16S) \ - IPP_SET(16s, ippcn); \ - else if (depth0 == CV_32S) \ - IPP_SET(32s, ippcn); \ - else if (depth0 == CV_32F) \ - IPP_SET(32f, ippcn); \ - } \ - } while ((void)0, 0) - - IPP_SET_CN(3); - IPP_SET_CN(4); - -#undef IPP_SET_CN -#undef IPP_SET - } - - if (status >= 0) - return true; + return CV_INSTRUMENT_FUN_IPP(llwiSetMask, s, dst.ptr(), (int)dst.step, size, dataType, dst.channels(), mask.ptr(), (int)mask.step) >= 0; } + else + { + const Mat *arrays[] = {&dst, mask.empty()?NULL:&mask, NULL}; + uchar *ptrs[2] = {NULL}; + NAryMatIterator it(arrays, ptrs); + IppiSize size = {(int)it.size, 1}; + IppDataType dataType = ippiGetDataType(dst.depth()); + ::ipp::IwValue s; + convertAndUnrollScalar(_val, CV_MAKETYPE(CV_64F, dst.channels()), (uchar*)((Ipp64f*)s), 1); + + for( size_t i = 0; i < it.nplanes; i++, ++it) + { + if(CV_INSTRUMENT_FUN_IPP(llwiSetMask, s, ptrs[0], 0, size, dataType, dst.channels(), ptrs[1], 0) < 0) + return false; + } + return true; + } +#else + CV_UNUSED(dst); CV_UNUSED(_val); CV_UNUSED(mask); return false; +#endif } #endif - Mat& Mat::setTo(InputArray _value, InputArray _mask) { CV_INSTRUMENT_REGION() @@ -532,7 +522,7 @@ Mat& Mat::setTo(InputArray _value, InputArray _mask) CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT )); CV_Assert( mask.empty() || (mask.type() == CV_8U && size == mask.size) ); - CV_IPP_RUN_FAST(ipp_Mat_setTo((cv::Mat*)this, value, mask), *this) + CV_IPP_RUN_FAST(ipp_Mat_setTo_Mat(*this, value, mask), *this) size_t esz = elemSize(); BinaryFunc copymask = getCopyMaskFunc(esz); @@ -707,73 +697,36 @@ static bool ocl_flip(InputArray _src, OutputArray _dst, int flipCode ) #endif #if defined HAVE_IPP -static bool ipp_flip( Mat &src, Mat &dst, int flip_mode ) +static bool ipp_flip(Mat &src, Mat &dst, int flip_mode) { +#ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() - int type = src.type(); - - typedef IppStatus (CV_STDCALL * IppiMirror)(const void * pSrc, int srcStep, void * pDst, int dstStep, IppiSize roiSize, IppiAxis flip); - typedef IppStatus (CV_STDCALL * IppiMirrorI)(const void * pSrcDst, int srcDstStep, IppiSize roiSize, IppiAxis flip); - IppiMirror ippiMirror = 0; - IppiMirrorI ippiMirror_I = 0; - - if (src.data == dst.data) - { - CV_SUPPRESS_DEPRECATED_START - ippiMirror_I = - type == CV_8UC1 ? (IppiMirrorI)ippiMirror_8u_C1IR : - type == CV_8UC3 ? (IppiMirrorI)ippiMirror_8u_C3IR : - type == CV_8UC4 ? (IppiMirrorI)ippiMirror_8u_C4IR : - type == CV_16UC1 ? (IppiMirrorI)ippiMirror_16u_C1IR : - type == CV_16UC3 ? (IppiMirrorI)ippiMirror_16u_C3IR : - type == CV_16UC4 ? (IppiMirrorI)ippiMirror_16u_C4IR : - type == CV_16SC1 ? (IppiMirrorI)ippiMirror_16s_C1IR : - type == CV_16SC3 ? (IppiMirrorI)ippiMirror_16s_C3IR : - type == CV_16SC4 ? (IppiMirrorI)ippiMirror_16s_C4IR : - type == CV_32SC1 ? (IppiMirrorI)ippiMirror_32s_C1IR : - type == CV_32SC3 ? (IppiMirrorI)ippiMirror_32s_C3IR : - type == CV_32SC4 ? (IppiMirrorI)ippiMirror_32s_C4IR : - type == CV_32FC1 ? (IppiMirrorI)ippiMirror_32f_C1IR : - type == CV_32FC3 ? (IppiMirrorI)ippiMirror_32f_C3IR : - type == CV_32FC4 ? (IppiMirrorI)ippiMirror_32f_C4IR : 0; - CV_SUPPRESS_DEPRECATED_END - } + IppiAxis ippMode; + if(flip_mode < 0) + ippMode = ippAxsBoth; + else if(flip_mode == 0) + ippMode = ippAxsHorizontal; else - { - ippiMirror = - type == CV_8UC1 ? (IppiMirror)ippiMirror_8u_C1R : - type == CV_8UC3 ? (IppiMirror)ippiMirror_8u_C3R : - type == CV_8UC4 ? (IppiMirror)ippiMirror_8u_C4R : - type == CV_16UC1 ? (IppiMirror)ippiMirror_16u_C1R : - type == CV_16UC3 ? (IppiMirror)ippiMirror_16u_C3R : - type == CV_16UC4 ? (IppiMirror)ippiMirror_16u_C4R : - type == CV_16SC1 ? (IppiMirror)ippiMirror_16s_C1R : - type == CV_16SC3 ? (IppiMirror)ippiMirror_16s_C3R : - type == CV_16SC4 ? (IppiMirror)ippiMirror_16s_C4R : - type == CV_32SC1 ? (IppiMirror)ippiMirror_32s_C1R : - type == CV_32SC3 ? (IppiMirror)ippiMirror_32s_C3R : - type == CV_32SC4 ? (IppiMirror)ippiMirror_32s_C4R : - type == CV_32FC1 ? (IppiMirror)ippiMirror_32f_C1R : - type == CV_32FC3 ? (IppiMirror)ippiMirror_32f_C3R : - type == CV_32FC4 ? (IppiMirror)ippiMirror_32f_C4R : 0; - } - IppiAxis axis = flip_mode == 0 ? ippAxsHorizontal : - flip_mode > 0 ? ippAxsVertical : ippAxsBoth; - IppiSize roisize = { dst.cols, dst.rows }; + ippMode = ippAxsVertical; - if (ippiMirror != 0) + try { - if (CV_INSTRUMENT_FUN_IPP(ippiMirror, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, ippiSize(src.cols, src.rows), axis) >= 0) - return true; + ::ipp::IwiImage iwSrc = ippiGetImage(src); + ::ipp::IwiImage iwDst = ippiGetImage(dst); + + CV_INSTRUMENT_FUN_IPP(::ipp::iwiMirror, &iwSrc, &iwDst, ippMode); } - else if (ippiMirror_I != 0) + catch(::ipp::IwException) { - if (CV_INSTRUMENT_FUN_IPP(ippiMirror_I, dst.ptr(), (int)dst.step, roisize, axis) >= 0) - return true; + return false; } + return true; +#else + CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(flip_mode); return false; +#endif } #endif @@ -1178,7 +1131,41 @@ static bool ocl_copyMakeBorder( InputArray _src, OutputArray _dst, int top, int } } +#endif +#ifdef HAVE_IPP +namespace cv { + +static bool ipp_copyMakeBorder( Mat &_src, Mat &_dst, int top, int bottom, + int left, int right, int _borderType, const Scalar& value ) +{ +#if defined HAVE_IPP_IW && !IPP_DISABLE_PERF_COPYMAKE + CV_INSTRUMENT_REGION_IPP() + + ::ipp::IwiBorderSize borderSize(left, top, right, bottom); + ::ipp::IwiSize size(_src.cols, _src.rows); + IppDataType dataType = ippiGetDataType(_src.depth()); + IppiBorderType borderType = ippiGetBorderType(_borderType); + if((int)borderType == -1) + return false; + + if(_src.dims > 2) + return false; + + Rect dstRect(borderSize.borderLeft, borderSize.borderTop, + _dst.cols - borderSize.borderRight - borderSize.borderLeft, + _dst.rows - borderSize.borderBottom - borderSize.borderTop); + Mat subDst = Mat(_dst, dstRect); + Mat *pSrc = &_src; + + return CV_INSTRUMENT_FUN_IPP(llwiCopyMakeBorder, pSrc->ptr(), pSrc->step, subDst.ptr(), subDst.step, size, dataType, _src.channels(), &borderSize, borderType, &value[0]) >= 0; +#else + CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(top); CV_UNUSED(bottom); CV_UNUSED(left); CV_UNUSED(right); + CV_UNUSED(_borderType); CV_UNUSED(value); + return false; +#endif +} +} #endif void cv::copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom, @@ -1222,120 +1209,7 @@ void cv::copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom, borderType &= ~BORDER_ISOLATED; -#if defined HAVE_IPP && IPP_DISABLE_BLOCK - CV_IPP_CHECK() - { - typedef IppStatus (CV_STDCALL * ippiCopyMakeBorder)(const void * pSrc, int srcStep, IppiSize srcRoiSize, void * pDst, - int dstStep, IppiSize dstRoiSize, int topBorderHeight, int leftBorderWidth); - typedef IppStatus (CV_STDCALL * ippiCopyMakeBorderI)(const void * pSrc, int srcDstStep, IppiSize srcRoiSize, IppiSize dstRoiSize, - int topBorderHeight, int leftborderwidth); - typedef IppStatus (CV_STDCALL * ippiCopyConstBorder)(const void * pSrc, int srcStep, IppiSize srcRoiSize, void * pDst, int dstStep, - IppiSize dstRoiSize, int topBorderHeight, int leftBorderWidth, void * value); - - IppiSize srcRoiSize = { src.cols, src.rows }, dstRoiSize = { dst.cols, dst.rows }; - ippiCopyMakeBorder ippFunc = 0; - ippiCopyMakeBorderI ippFuncI = 0; - ippiCopyConstBorder ippFuncConst = 0; - bool inplace = dst.datastart == src.datastart; - - if (borderType == BORDER_CONSTANT) - { - ippFuncConst = - // type == CV_8UC1 ? (ippiCopyConstBorder)ippiCopyConstBorder_8u_C1R : bug in IPP 8.1 - type == CV_16UC1 ? (ippiCopyConstBorder)ippiCopyConstBorder_16u_C1R : - // type == CV_16SC1 ? (ippiCopyConstBorder)ippiCopyConstBorder_16s_C1R : bug in IPP 8.1 - // type == CV_32SC1 ? (ippiCopyConstBorder)ippiCopyConstBorder_32s_C1R : bug in IPP 8.1 - // type == CV_32FC1 ? (ippiCopyConstBorder)ippiCopyConstBorder_32f_C1R : bug in IPP 8.1 - type == CV_8UC3 ? (ippiCopyConstBorder)ippiCopyConstBorder_8u_C3R : - type == CV_16UC3 ? (ippiCopyConstBorder)ippiCopyConstBorder_16u_C3R : - type == CV_16SC3 ? (ippiCopyConstBorder)ippiCopyConstBorder_16s_C3R : - type == CV_32SC3 ? (ippiCopyConstBorder)ippiCopyConstBorder_32s_C3R : - type == CV_32FC3 ? (ippiCopyConstBorder)ippiCopyConstBorder_32f_C3R : - type == CV_8UC4 ? (ippiCopyConstBorder)ippiCopyConstBorder_8u_C4R : - type == CV_16UC4 ? (ippiCopyConstBorder)ippiCopyConstBorder_16u_C4R : - type == CV_16SC4 ? (ippiCopyConstBorder)ippiCopyConstBorder_16s_C4R : - type == CV_32SC4 ? (ippiCopyConstBorder)ippiCopyConstBorder_32s_C4R : - type == CV_32FC4 ? (ippiCopyConstBorder)ippiCopyConstBorder_32f_C4R : 0; - } - else if (borderType == BORDER_WRAP) - { - if (inplace) - { - CV_SUPPRESS_DEPRECATED_START - ippFuncI = - type == CV_32SC1 ? (ippiCopyMakeBorderI)ippiCopyWrapBorder_32s_C1IR : - type == CV_32FC1 ? (ippiCopyMakeBorderI)ippiCopyWrapBorder_32s_C1IR : 0; - CV_SUPPRESS_DEPRECATED_END - } - else - { - ippFunc = - type == CV_32SC1 ? (ippiCopyMakeBorder)ippiCopyWrapBorder_32s_C1R : - type == CV_32FC1 ? (ippiCopyMakeBorder)ippiCopyWrapBorder_32s_C1R : 0; - } - } - else if (borderType == BORDER_REPLICATE) - { - if (inplace) - { - CV_SUPPRESS_DEPRECATED_START - ippFuncI = - type == CV_8UC1 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_8u_C1IR : - type == CV_16UC1 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_16u_C1IR : - type == CV_16SC1 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_16s_C1IR : - type == CV_32SC1 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_32s_C1IR : - type == CV_32FC1 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_32f_C1IR : - type == CV_8UC3 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_8u_C3IR : - type == CV_16UC3 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_16u_C3IR : - type == CV_16SC3 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_16s_C3IR : - type == CV_32SC3 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_32s_C3IR : - type == CV_32FC3 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_32f_C3IR : - type == CV_8UC4 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_8u_C4IR : - type == CV_16UC4 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_16u_C4IR : - type == CV_16SC4 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_16s_C4IR : - type == CV_32SC4 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_32s_C4IR : - type == CV_32FC4 ? (ippiCopyMakeBorderI)ippiCopyReplicateBorder_32f_C4IR : 0; - CV_SUPPRESS_DEPRECATED_END - } - else - { - ippFunc = - type == CV_8UC1 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_8u_C1R : - type == CV_16UC1 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_16u_C1R : - type == CV_16SC1 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_16s_C1R : - type == CV_32SC1 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_32s_C1R : - type == CV_32FC1 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_32f_C1R : - type == CV_8UC3 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_8u_C3R : - type == CV_16UC3 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_16u_C3R : - type == CV_16SC3 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_16s_C3R : - type == CV_32SC3 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_32s_C3R : - type == CV_32FC3 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_32f_C3R : - type == CV_8UC4 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_8u_C4R : - type == CV_16UC4 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_16u_C4R : - type == CV_16SC4 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_16s_C4R : - type == CV_32SC4 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_32s_C4R : - type == CV_32FC4 ? (ippiCopyMakeBorder)ippiCopyReplicateBorder_32f_C4R : 0; - } - } - - if (ippFunc || ippFuncI || ippFuncConst) - { - uchar scbuf[32]; - scalarToRawData(value, scbuf, type); - - if ( (ippFunc && ippFunc(src.data, (int)src.step, srcRoiSize, dst.data, (int)dst.step, dstRoiSize, top, left) >= 0) || - (ippFuncI && ippFuncI(src.data, (int)src.step, srcRoiSize, dstRoiSize, top, left) >= 0) || - (ippFuncConst && ippFuncConst(src.data, (int)src.step, srcRoiSize, dst.data, (int)dst.step, - dstRoiSize, top, left, scbuf) >= 0)) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return; - } - - setIppErrorStatus(); - } - } -#endif + CV_IPP_RUN_FAST(ipp_copyMakeBorder(src, dst, top, bottom, left, right, borderType, value)) if( borderType != BORDER_CONSTANT ) copyMakeBorder_8u( src.ptr(), src.step, src.size(), diff --git a/modules/core/src/mathfuncs.cpp b/modules/core/src/mathfuncs.cpp index b9bdf49eb3..a3dfbd18e8 100644 --- a/modules/core/src/mathfuncs.cpp +++ b/modules/core/src/mathfuncs.cpp @@ -497,6 +497,65 @@ static bool ocl_polarToCart( InputArray _mag, InputArray _angle, #endif +#ifdef HAVE_IPP +static bool ipp_polarToCart(Mat &mag, Mat &angle, Mat &x, Mat &y) +{ + CV_INSTRUMENT_REGION_IPP() + + int depth = angle.depth(); + if(depth != CV_32F && depth != CV_64F) + return false; + + if(angle.dims <= 2) + { + int len = (int)(angle.cols*angle.channels()); + + if(depth == CV_32F) + { + for (int h = 0; h < angle.rows; h++) + { + if(CV_INSTRUMENT_FUN_IPP(ippsPolarToCart_32f, (const float*)mag.ptr(h), (const float*)angle.ptr(h), (float*)x.ptr(h), (float*)y.ptr(h), len) < 0) + return false; + } + } + else + { + for (int h = 0; h < angle.rows; h++) + { + if(CV_INSTRUMENT_FUN_IPP(ippsPolarToCart_64f, (const double*)mag.ptr(h), (const double*)angle.ptr(h), (double*)x.ptr(h), (double*)y.ptr(h), len) < 0) + return false; + } + } + return true; + } + else + { + const Mat *arrays[] = {&mag, &angle, &x, &y, NULL}; + uchar *ptrs[4] = {NULL}; + NAryMatIterator it(arrays, ptrs); + int len = (int)(it.size*angle.channels()); + + if(depth == CV_32F) + { + for (size_t i = 0; i < it.nplanes; i++, ++it) + { + if(CV_INSTRUMENT_FUN_IPP(ippsPolarToCart_32f, (const float*)ptrs[0], (const float*)ptrs[1], (float*)ptrs[2], (float*)ptrs[3], len) < 0) + return false; + } + } + else + { + for (size_t i = 0; i < it.nplanes; i++, ++it) + { + if(CV_INSTRUMENT_FUN_IPP(ippsPolarToCart_64f, (const double*)ptrs[0], (const double*)ptrs[1], (double*)ptrs[2], (double*)ptrs[3], len) < 0) + return false; + } + } + return true; + } +} +#endif + void polarToCart( InputArray src1, InputArray src2, OutputArray dst1, OutputArray dst2, bool angleInDegrees ) { @@ -514,28 +573,7 @@ void polarToCart( InputArray src1, InputArray src2, dst2.create( Angle.dims, Angle.size, type ); Mat X = dst1.getMat(), Y = dst2.getMat(); -#if defined(HAVE_IPP) - CV_IPP_CHECK() - { - if (Mag.isContinuous() && Angle.isContinuous() && X.isContinuous() && Y.isContinuous() && !angleInDegrees) - { - typedef IppStatus (CV_STDCALL * IppsPolarToCart)(const void * pSrcMagn, const void * pSrcPhase, - void * pDstRe, void * pDstIm, int len); - IppsPolarToCart ippsPolarToCart = - depth == CV_32F ? (IppsPolarToCart)ippsPolarToCart_32f : - depth == CV_64F ? (IppsPolarToCart)ippsPolarToCart_64f : 0; - CV_Assert(ippsPolarToCart != 0); - - IppStatus status = CV_INSTRUMENT_FUN_IPP(ippsPolarToCart, Mag.ptr(), Angle.ptr(), X.ptr(), Y.ptr(), static_cast(cn * X.total())); - if (status >= 0) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return; - } - setIppErrorStatus(); - } - } -#endif + CV_IPP_RUN(!angleInDegrees, ipp_polarToCart(Mag, Angle, X, Y)); const Mat* arrays[] = {&Mag, &Angle, &X, &Y, 0}; uchar* ptrs[4]; @@ -1167,11 +1205,6 @@ static bool ocl_pow(InputArray _src, double power, OutputArray _dst, #endif -static void InvSqrt_32f(const float* src, float* dst, int n) { hal::invSqrt32f(src, dst, n); } -static void InvSqrt_64f(const double* src, double* dst, int n) { hal::invSqrt64f(src, dst, n); } -static void Sqrt_32f(const float* src, float* dst, int n) { hal::sqrt32f(src, dst, n); } -static void Sqrt_64f(const double* src, double* dst, int n) { hal::sqrt64f(src, dst, n); } - void pow( InputArray _src, double power, OutputArray _dst ) { CV_INSTRUMENT_REGION() @@ -1228,8 +1261,8 @@ void pow( InputArray _src, double power, OutputArray _dst ) else if( fabs(fabs(power) - 0.5) < DBL_EPSILON ) { MathFunc func = power < 0 ? - (depth == CV_32F ? (MathFunc)InvSqrt_32f : (MathFunc)InvSqrt_64f) : - (depth == CV_32F ? (MathFunc)Sqrt_32f : (MathFunc)Sqrt_64f); + (depth == CV_32F ? (MathFunc)hal::invSqrt32f : (MathFunc)hal::invSqrt64f) : + (depth == CV_32F ? (MathFunc)hal::sqrt32f : (MathFunc)hal::sqrt64f); for( size_t i = 0; i < it.nplanes; i++, ++it ) func( ptrs[0], ptrs[1], len ); @@ -1261,24 +1294,6 @@ void pow( InputArray _src, double power, OutputArray _dst ) { int bsz = std::min(len - j, blockSize); -#if defined(HAVE_IPP) - CV_IPP_CHECK() - { - IppStatus status = depth == CV_32F ? - CV_INSTRUMENT_FUN_IPP(ippsPowx_32f_A21, (const float*)ptrs[0], (float)power, (float*)ptrs[1], bsz) : - CV_INSTRUMENT_FUN_IPP(ippsPowx_64f_A50, (const double*)ptrs[0], (double)power, (double*)ptrs[1], bsz); - - if (status >= 0) - { - CV_IMPL_ADD(CV_IMPL_IPP); - ptrs[0] += bsz*esz1; - ptrs[1] += bsz*esz1; - continue; - } - setIppErrorStatus(); - } -#endif - if( depth == CV_32F ) { float* x0 = (float*)ptrs[0]; diff --git a/modules/core/src/mathfuncs_core.dispatch.cpp b/modules/core/src/mathfuncs_core.dispatch.cpp index 1a462a0635..b64ec4af42 100644 --- a/modules/core/src/mathfuncs_core.dispatch.cpp +++ b/modules/core/src/mathfuncs_core.dispatch.cpp @@ -44,7 +44,7 @@ void magnitude32f(const float* x, const float* y, float* mag, int len) CV_INSTRUMENT_REGION() CALL_HAL(magnitude32f, cv_hal_magnitude32f, x, y, mag, len); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsMagnitude_32f, x, y, mag, len) >= 0); + CV_IPP_RUN(!IPP_DISABLE_PERF_MAG_SSE42 || (ipp::getIppFeatures()&ippCPUID_AVX), CV_INSTRUMENT_FUN_IPP(ippsMagnitude_32f, x, y, mag, len) >= 0); CV_CPU_DISPATCH(magnitude32f, (x, y, mag, len), CV_CPU_DISPATCH_MODES_ALL); @@ -55,7 +55,7 @@ void magnitude64f(const double* x, const double* y, double* mag, int len) CV_INSTRUMENT_REGION() CALL_HAL(magnitude64f, cv_hal_magnitude64f, x, y, mag, len); - CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsMagnitude_64f, x, y, mag, len) >= 0); + CV_IPP_RUN(!IPP_DISABLE_PERF_MAG_SSE42 || (ipp::getIppFeatures()&ippCPUID_AVX), CV_INSTRUMENT_FUN_IPP(ippsMagnitude_64f, x, y, mag, len) >= 0); CV_CPU_DISPATCH(magnitude64f, (x, y, mag, len), CV_CPU_DISPATCH_MODES_ALL); diff --git a/modules/core/src/matmul.cpp b/modules/core/src/matmul.cpp index 8b06193cf6..219089d157 100644 --- a/modules/core/src/matmul.cpp +++ b/modules/core/src/matmul.cpp @@ -3100,18 +3100,8 @@ dotProd_(const T* src1, const T* src2, int len) static double dotProd_8u(const uchar* src1, const uchar* src2, int len) { double r = 0; -#if ARITHM_USE_IPP && IPP_DISABLE_BLOCK - CV_IPP_CHECK() - { - if (0 <= CV_INSTRUMENT_FUN_IPP(ippiDotProd_8u64f_C1R, (src1, (int)(len*sizeof(src1[0])), - src2, (int)(len*sizeof(src2[0])), - ippiSize(len, 1), &r))) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return r; - } - setIppErrorStatus(); - } +#if ARITHM_USE_IPP + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiDotProd_8u64f_C1R, src1, len*sizeof(uchar), src2, len*sizeof(uchar), ippiSize(len, 1), &r) >= 0, r); #endif int i = 0; @@ -3298,51 +3288,27 @@ static double dotProd_8s(const schar* src1, const schar* src2, int len) static double dotProd_16u(const ushort* src1, const ushort* src2, int len) { -#if (ARITHM_USE_IPP == 1) - CV_IPP_CHECK() - { - double r = 0; - if (0 <= CV_INSTRUMENT_FUN_IPP(ippiDotProd_16u64f_C1R, src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r)) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return r; - } - setIppErrorStatus(); - } +#if ARITHM_USE_IPP + double r = 0; + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiDotProd_16u64f_C1R, src1, len*sizeof(ushort), src2, len*sizeof(ushort), ippiSize(len, 1), &r) >= 0, r); #endif return dotProd_(src1, src2, len); } static double dotProd_16s(const short* src1, const short* src2, int len) { -#if (ARITHM_USE_IPP == 1) && (IPP_VERSION_X100 != 900) // bug in IPP 9.0.0 - CV_IPP_CHECK() - { - double r = 0; - if (0 <= CV_INSTRUMENT_FUN_IPP(ippiDotProd_16s64f_C1R, src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r)) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return r; - } - setIppErrorStatus(); - } +#if ARITHM_USE_IPP && (IPP_VERSION_X100 != 900) // bug in IPP 9.0.0 + double r = 0; + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiDotProd_16s64f_C1R, src1, len*sizeof(short), src2, len*sizeof(short), ippiSize(len, 1), &r) >= 0, r); #endif return dotProd_(src1, src2, len); } static double dotProd_32s(const int* src1, const int* src2, int len) { -#if (ARITHM_USE_IPP == 1) - CV_IPP_CHECK() - { - double r = 0; - if (0 <= CV_INSTRUMENT_FUN_IPP(ippiDotProd_32s64f_C1R, src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r)) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return r; - } - setIppErrorStatus(); - } +#if ARITHM_USE_IPP + double r = 0; + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiDotProd_32s64f_C1R, src1, len*sizeof(int), src2, len*sizeof(int), ippiSize(len, 1), &r) >= 0, r); #endif return dotProd_(src1, src2, len); } @@ -3350,19 +3316,13 @@ static double dotProd_32s(const int* src1, const int* src2, int len) static double dotProd_32f(const float* src1, const float* src2, int len) { double r = 0.0; + +#if ARITHM_USE_IPP + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiDotProd_32f64f_C1R, src1, len*sizeof(float), src2, len*sizeof(float), ippiSize(len, 1), &r, ippAlgHintFast) >= 0, r); +#endif int i = 0; -#if (ARITHM_USE_IPP == 1) - CV_IPP_CHECK() - { - if (0 <= CV_INSTRUMENT_FUN_IPP(ippsDotProd_32f64f, src1, src2, len, &r)) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return r; - } - setIppErrorStatus(); - } -#elif CV_NEON +#if CV_NEON int len0 = len & -4, blockSize0 = (1 << 13), blockSize; float32x4_t v_zero = vdupq_n_f32(0.0f); CV_DECL_ALIGNED(16) float buf[4]; @@ -3389,18 +3349,11 @@ static double dotProd_32f(const float* src1, const float* src2, int len) static double dotProd_64f(const double* src1, const double* src2, int len) { -#if (ARITHM_USE_IPP == 1) - CV_IPP_CHECK() - { - double r = 0; - if (0 <= CV_INSTRUMENT_FUN_IPP(ippsDotProd_64f, src1, src2, len, &r)) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return r; - } - setIppErrorStatus(); - } +#if ARITHM_USE_IPP + double r = 0; + CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsDotProd_64f, src1, src2, len, &r) >= 0, r); #endif + return dotProd_(src1, src2, len); } diff --git a/modules/core/src/stat.cpp b/modules/core/src/stat.cpp index 3c5fb73de4..587d06d03c 100644 --- a/modules/core/src/stat.cpp +++ b/modules/core/src/stat.cpp @@ -1309,30 +1309,51 @@ static bool ipp_countNonZero( Mat &src, int &res ) { CV_INSTRUMENT_REGION_IPP() - Ipp32s count = 0; - IppStatus status = ippStsNoErr; + Ipp32s count = 0; + int depth = src.depth(); - int type = src.type(), depth = CV_MAT_DEPTH(type); - IppiSize roiSize = { src.cols, src.rows }; - Ipp32s srcstep = (Ipp32s)src.step; - if (src.isContinuous()) + if(src.dims <= 2) { - roiSize.width = (Ipp32s)src.total(); - roiSize.height = 1; - srcstep = (Ipp32s)src.total() * CV_ELEM_SIZE(type); + IppStatus status; + IppiSize size = {src.cols*src.channels(), src.rows}; + + if(depth == CV_8U) + status = CV_INSTRUMENT_FUN_IPP(ippiCountInRange_8u_C1R, (const Ipp8u *)src.ptr(), (int)src.step, size, &count, 0, 0); + else if(depth == CV_32F) + status = CV_INSTRUMENT_FUN_IPP(ippiCountInRange_32f_C1R, (const Ipp32f *)src.ptr(), (int)src.step, size, &count, 0, 0); + else + return false; + + if(status < 0) + return false; + + res = size.width*size.height - count; + } + else + { + IppStatus status; + const Mat *arrays[] = {&src, NULL}; + uchar *ptrs[1] = {NULL}; + NAryMatIterator it(arrays, ptrs); + IppiSize size = {(int)it.size*src.channels(), 1}; + + for (size_t i = 0; i < it.nplanes; i++, ++it) + { + if(depth == CV_8U) + status = CV_INSTRUMENT_FUN_IPP(ippiCountInRange_8u_C1R, (const Ipp8u *)src.ptr(), (int)src.step, size, &count, 0, 0); + else if(depth == CV_32F) + status = CV_INSTRUMENT_FUN_IPP(ippiCountInRange_32f_C1R, (const Ipp32f *)src.ptr(), (int)src.step, size, &count, 0, 0); + else + return false; + + if(status < 0) + return false; + + res += (size.width*size.height - count); + } } - if (depth == CV_8U) - status = CV_INSTRUMENT_FUN_IPP(ippiCountInRange_8u_C1R, (const Ipp8u *)src.data, srcstep, roiSize, &count, 0, 0); - else if (depth == CV_32F) - status = CV_INSTRUMENT_FUN_IPP(ippiCountInRange_32f_C1R, (const Ipp32f *)src.data, srcstep, roiSize, &count, 0, 0); - - if (status >= 0) - { - res = ((Ipp32s)src.total() - count); - return true; - } - return false; + return true; } } #endif @@ -1356,7 +1377,7 @@ int cv::countNonZero( InputArray _src ) #endif Mat src = _src.getMat(); - CV_IPP_RUN(0 && (_src.dims() <= 2 || _src.isContinuous()), ipp_countNonZero(src, res), res); + CV_IPP_RUN_FAST(ipp_countNonZero(src, res), res); CountNonZeroFunc func = getCountNonZeroTab(src.depth()); CV_Assert( func != 0 ); @@ -2373,109 +2394,273 @@ static bool openvx_minMaxIdx(Mat &src, double* minVal, double* maxVal, int* minI #endif #ifdef HAVE_IPP -static bool ipp_minMaxIdx( Mat &src, double* minVal, double* maxVal, int* minIdx, int* maxIdx, Mat &mask) +static IppStatus ipp_minMaxIndex_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u*, int) { + switch(dataType) + { + case ipp8u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + case ipp16u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + default: return ippStsDataTypeErr; + } +} + +static IppStatus ipp_minMaxIndexMask_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u* pMask, int maskStep) +{ + switch(dataType) + { + case ipp8u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_8u_C1MR, (const Ipp8u*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + case ipp16u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_16u_C1MR, (const Ipp16u*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_32f_C1MR, (const Ipp32f*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + default: return ippStsDataTypeErr; + } +} + +static IppStatus ipp_minMax_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float* pMaxVal, IppiPoint*, IppiPoint*, const Ipp8u*, int) +{ + IppStatus status; + + switch(dataType) + { +#if IPP_VERSION_X100 > 201701 // wrong min values + case ipp8u: + { + Ipp8u val[2]; + status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val[0], &val[1]); + *pMinVal = val[0]; + *pMaxVal = val[1]; + return status; + } +#endif + case ipp16u: + { + Ipp16u val[2]; + status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val[0], &val[1]); + *pMinVal = val[0]; + *pMaxVal = val[1]; + return status; + } + case ipp16s: + { + Ipp16s val[2]; + status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val[0], &val[1]); + *pMinVal = val[0]; + *pMaxVal = val[1]; + return status; + } + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMax_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, pMaxVal); + default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, pMinVal, pMaxVal, NULL, NULL, NULL, 0); + } +} + +static IppStatus ipp_minIdx_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float*, IppiPoint* pMinIndex, IppiPoint*, const Ipp8u*, int) +{ + IppStatus status; + + switch(dataType) + { + case ipp8u: + { + Ipp8u val; + status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); + *pMinVal = val; + return status; + } + case ipp16u: + { + Ipp16u val; + status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); + *pMinVal = val; + return status; + } + case ipp16s: + { + Ipp16s val; + status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); + *pMinVal = val; + return status; + } + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, &pMinIndex->x, &pMinIndex->y); + default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, pMinVal, NULL, pMinIndex, NULL, NULL, 0); + } +} + +static IppStatus ipp_maxIdx_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float*, float* pMaxVal, IppiPoint*, IppiPoint* pMaxIndex, const Ipp8u*, int) +{ + IppStatus status; + + switch(dataType) + { + case ipp8u: + { + Ipp8u val; + status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); + *pMaxVal = val; + return status; + } + case ipp16u: + { + Ipp16u val; + status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); + *pMaxVal = val; + return status; + } + case ipp16s: + { + Ipp16s val; + status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); + *pMaxVal = val; + return status; + } + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMaxVal, &pMaxIndex->x, &pMaxIndex->y); + default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, NULL, pMaxVal, NULL, pMaxIndex, NULL, 0); + } +} + +typedef IppStatus (*IppMinMaxSelector)(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u* pMask, int maskStep); + +static bool ipp_minMaxIdx(Mat &src, double* _minVal, double* _maxVal, int* _minIdx, int* _maxIdx, Mat &mask) +{ +#if IPP_VERSION_X100 >= 700 CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 700 - int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); - size_t total_size = src.total(); - int rows = src.size[0], cols = rows ? (int)(total_size/rows) : 0; - if( src.dims == 2 || (src.isContinuous() && mask.isContinuous() && cols > 0 && (size_t)rows*cols == total_size) ) + IppStatus status; + IppDataType dataType = ippiGetDataType(src.depth()); + float minVal = 0; + float maxVal = 0; + IppiPoint minIdx = {-1, -1}; + IppiPoint maxIdx = {-1, -1}; + + float *pMinVal = (_minVal)?&minVal:NULL; + float *pMaxVal = (_maxVal)?&maxVal:NULL; + IppiPoint *pMinIdx = (_minIdx)?&minIdx:NULL; + IppiPoint *pMaxIdx = (_maxIdx)?&maxIdx:NULL; + + IppMinMaxSelector ippMinMaxFun = ipp_minMaxIndexMask_wrap; + if(mask.empty()) { - IppiSize sz = { cols * cn, rows }; + if(_maxVal && _maxIdx && !_minVal && !_minIdx) + ippMinMaxFun = ipp_maxIdx_wrap; + else if(!_maxVal && !_maxIdx && _minVal && _minIdx) + ippMinMaxFun = ipp_minIdx_wrap; + else if(_maxVal && !_maxIdx && _minVal && !_minIdx) + ippMinMaxFun = ipp_minMax_wrap; + else + ippMinMaxFun = ipp_minMaxIndex_wrap; + } - if( !mask.empty() ) + if(src.dims <= 2) + { + IppiSize size = ippiSize(src.size()); + size.width *= src.channels(); + + status = ippMinMaxFun(src.ptr(), (int)src.step, size, dataType, pMinVal, pMaxVal, pMinIdx, pMaxIdx, (Ipp8u*)mask.ptr(), (int)mask.step); + if(status < 0 || status == ippStsNoOperation) + return false; + if(_minVal) + *_minVal = minVal; + if(_maxVal) + *_maxVal = maxVal; + if(_minIdx) { - typedef IppStatus (CV_STDCALL* ippiMaskMinMaxIndxFuncC1)(const void *, int, const void *, int, - IppiSize, Ipp32f *, Ipp32f *, IppiPoint *, IppiPoint *); - - CV_SUPPRESS_DEPRECATED_START - ippiMaskMinMaxIndxFuncC1 ippiMinMaxIndx_C1MR = - type == CV_8UC1 ? (ippiMaskMinMaxIndxFuncC1)ippiMinMaxIndx_8u_C1MR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC1 ? (ippiMaskMinMaxIndxFuncC1)ippiMinMaxIndx_8s_C1MR : -#endif - type == CV_16UC1 ? (ippiMaskMinMaxIndxFuncC1)ippiMinMaxIndx_16u_C1MR : - type == CV_32FC1 ? (ippiMaskMinMaxIndxFuncC1)ippiMinMaxIndx_32f_C1MR : 0; - CV_SUPPRESS_DEPRECATED_END - - if( ippiMinMaxIndx_C1MR ) + if(!mask.empty() && !minIdx.y && !minIdx.x) { - Ipp32f min, max; - IppiPoint minp, maxp; - if( CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_C1MR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, &min, &max, &minp, &maxp) >= 0 ) - { - if( minVal ) - *minVal = (double)min; - if( maxVal ) - *maxVal = (double)max; - if( !minp.x && !minp.y && !maxp.x && !maxp.y && !mask.ptr()[0] ) - minp.x = maxp.x = -1; - if( minIdx ) - { - size_t minidx = minp.y * cols + minp.x + 1; - ofs2idx(src, minidx, minIdx); - } - if( maxIdx ) - { - size_t maxidx = maxp.y * cols + maxp.x + 1; - ofs2idx(src, maxidx, maxIdx); - } - return true; - } + _minIdx[0] = -1; + _minIdx[1] = -1; + } + else + { + _minIdx[0] = minIdx.y; + _minIdx[1] = minIdx.x; } } - else + if(_maxIdx) { - typedef IppStatus (CV_STDCALL* ippiMinMaxIndxFuncC1)(const void *, int, IppiSize, Ipp32f *, Ipp32f *, IppiPoint *, IppiPoint *); - - CV_SUPPRESS_DEPRECATED_START - ippiMinMaxIndxFuncC1 ippiMinMaxIndx_C1R = -#if IPP_VERSION_X100 != 900 // bug in 9.0.0 avx2 optimization - depth == CV_8U ? (ippiMinMaxIndxFuncC1)ippiMinMaxIndx_8u_C1R : -#endif -#if IPP_VERSION_X100 < 900 - depth == CV_8S ? (ippiMinMaxIndxFuncC1)ippiMinMaxIndx_8s_C1R : -#endif - depth == CV_16U ? (ippiMinMaxIndxFuncC1)ippiMinMaxIndx_16u_C1R : -#if IPP_DISABLE_BLOCK && !((defined _MSC_VER && defined _M_IX86) || defined __i386__) - // See bug #4955: the function fails with SEGFAULT when the source matrix contains NANs - // IPPICV version is 9.0.1. - depth == CV_32F ? (ippiMinMaxIndxFuncC1)ippiMinMaxIndx_32f_C1R : -#endif - 0; - CV_SUPPRESS_DEPRECATED_END - - if( ippiMinMaxIndx_C1R ) + if(!mask.empty() && !maxIdx.y && !maxIdx.x) { - Ipp32f min, max; - IppiPoint minp, maxp; - if( CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_C1R, src.ptr(), (int)src.step[0], sz, &min, &max, &minp, &maxp) >= 0 ) - { - if( minVal ) - *minVal = (double)min; - if( maxVal ) - *maxVal = (double)max; - if( minIdx ) - { - size_t minidx = minp.y * cols + minp.x + 1; - ofs2idx(src, minidx, minIdx); - } - if( maxIdx ) - { - size_t maxidx = maxp.y * cols + maxp.x + 1; - ofs2idx(src, maxidx, maxIdx); - } - return true; - } + _maxIdx[0] = -1; + _maxIdx[1] = -1; + } + else + { + _maxIdx[0] = maxIdx.y; + _maxIdx[1] = maxIdx.x; } } } + else + { + const Mat *arrays[] = {&src, mask.empty()?NULL:&mask, NULL}; + uchar *ptrs[3] = {NULL}; + NAryMatIterator it(arrays, ptrs); + IppiSize size = ippiSize(it.size*src.channels(), 1); + int srcStep = (int)(size.width*src.elemSize1()); + int maskStep = size.width; + size_t idxPos = 1; + size_t minIdxAll = 0; + size_t maxIdxAll = 0; + float minValAll = IPP_MAXABS_32F; + float maxValAll = -IPP_MAXABS_32F; + + for(size_t i = 0; i < it.nplanes; i++, ++it, idxPos += size.width) + { + status = ippMinMaxFun(ptrs[0], srcStep, size, dataType, pMinVal, pMaxVal, pMinIdx, pMaxIdx, ptrs[1], maskStep); + if(status < 0) + return false; +#if IPP_VERSION_X100 > 201701 + // Zero-mask check, function should return ippStsNoOperation warning + if(status == ippStsNoOperation) + continue; #else + // Crude zero-mask check, waiting for fix in IPP function + if(ptrs[1]) + { + Mat localMask(Size(size.width, 1), CV_8U, ptrs[1], maskStep); + if(!cv::countNonZero(localMask)) + continue; + } #endif + + if(_minVal && minVal < minValAll) + { + minValAll = minVal; + minIdxAll = idxPos+minIdx.x; + } + if(_maxVal && maxVal > maxValAll) + { + maxValAll = maxVal; + maxIdxAll = idxPos+maxIdx.x; + } + } + if(!src.empty() && mask.empty()) + { + if(minIdxAll == 0) + minIdxAll = 1; + if(maxValAll == 0) + maxValAll = 1; + } + + if(_minVal) + *_minVal = minValAll; + if(_maxVal) + *_maxVal = maxValAll; + if(_minIdx) + ofs2idx(src, minIdxAll, _minIdx); + if(_maxIdx) + ofs2idx(src, maxIdxAll, _maxIdx); + } + + return true; +#else CV_UNUSED(src); CV_UNUSED(minVal); CV_UNUSED(maxVal); CV_UNUSED(minIdx); CV_UNUSED(maxIdx); CV_UNUSED(mask); return false; +#endif } #endif @@ -2499,7 +2684,7 @@ void cv::minMaxIdx(InputArray _src, double* minVal, CV_OVX_RUN(true, openvx_minMaxIdx(src, minVal, maxVal, minIdx, maxIdx, mask)) - CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_minMaxIdx(src, minVal, maxVal, minIdx, maxIdx, mask)) + CV_IPP_RUN_FAST(ipp_minMaxIdx(src, minVal, maxVal, minIdx, maxIdx, mask)) MinMaxIdxFunc func = getMinmaxTab(depth); CV_Assert( func != 0 ); @@ -2837,42 +3022,31 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result) CV_INSTRUMENT_REGION_IPP() #if IPP_VERSION_X100 >= 700 - int cn = src.channels(); size_t total_size = src.total(); int rows = src.size[0], cols = rows ? (int)(total_size/rows) : 0; if( (src.dims == 2 || (src.isContinuous() && mask.isContinuous())) - && cols > 0 && (size_t)rows*cols == total_size - && (normType == NORM_INF || normType == NORM_L1 || - normType == NORM_L2 || normType == NORM_L2SQR) ) + && cols > 0 && (size_t)rows*cols == total_size ) { - IppiSize sz = { cols, rows }; - int type = src.type(); if( !mask.empty() ) { + IppiSize sz = { cols, rows }; + int type = src.type(); + typedef IppStatus (CV_STDCALL* ippiMaskNormFuncC1)(const void *, int, const void *, int, IppiSize, Ipp64f *); ippiMaskNormFuncC1 ippiNorm_C1MR = normType == NORM_INF ? (type == CV_8UC1 ? (ippiMaskNormFuncC1)ippiNorm_Inf_8u_C1MR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC1 ? (ippiMaskNormFuncC1)ippiNorm_Inf_8s_C1MR : -#endif -// type == CV_16UC1 ? (ippiMaskNormFuncC1)ippiNorm_Inf_16u_C1MR : + type == CV_16UC1 ? (ippiMaskNormFuncC1)ippiNorm_Inf_16u_C1MR : type == CV_32FC1 ? (ippiMaskNormFuncC1)ippiNorm_Inf_32f_C1MR : 0) : normType == NORM_L1 ? (type == CV_8UC1 ? (ippiMaskNormFuncC1)ippiNorm_L1_8u_C1MR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC1 ? (ippiMaskNormFuncC1)ippiNorm_L1_8s_C1MR : -#endif type == CV_16UC1 ? (ippiMaskNormFuncC1)ippiNorm_L1_16u_C1MR : type == CV_32FC1 ? (ippiMaskNormFuncC1)ippiNorm_L1_32f_C1MR : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? (type == CV_8UC1 ? (ippiMaskNormFuncC1)ippiNorm_L2_8u_C1MR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC1 ? (ippiMaskNormFuncC1)ippiNorm_L2_8s_C1MR : -#endif type == CV_16UC1 ? (ippiMaskNormFuncC1)ippiNorm_L2_16u_C1MR : type == CV_32FC1 ? (ippiMaskNormFuncC1)ippiNorm_L2_32f_C1MR : 0) : 0; @@ -2885,39 +3059,29 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result) return true; } } -#if IPP_DISABLE_BLOCK typedef IppStatus (CV_STDCALL* ippiMaskNormFuncC3)(const void *, int, const void *, int, IppiSize, int, Ipp64f *); ippiMaskNormFuncC3 ippiNorm_C3CMR = normType == NORM_INF ? (type == CV_8UC3 ? (ippiMaskNormFuncC3)ippiNorm_Inf_8u_C3CMR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC3 ? (ippiMaskNormFuncC3)ippiNorm_Inf_8s_C3CMR : -#endif type == CV_16UC3 ? (ippiMaskNormFuncC3)ippiNorm_Inf_16u_C3CMR : type == CV_32FC3 ? (ippiMaskNormFuncC3)ippiNorm_Inf_32f_C3CMR : 0) : normType == NORM_L1 ? (type == CV_8UC3 ? (ippiMaskNormFuncC3)ippiNorm_L1_8u_C3CMR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC3 ? (ippiMaskNormFuncC3)ippiNorm_L1_8s_C3CMR : -#endif type == CV_16UC3 ? (ippiMaskNormFuncC3)ippiNorm_L1_16u_C3CMR : type == CV_32FC3 ? (ippiMaskNormFuncC3)ippiNorm_L1_32f_C3CMR : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? (type == CV_8UC3 ? (ippiMaskNormFuncC3)ippiNorm_L2_8u_C3CMR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC3 ? (ippiMaskNormFuncC3)ippiNorm_L2_8s_C3CMR : -#endif type == CV_16UC3 ? (ippiMaskNormFuncC3)ippiNorm_L2_16u_C3CMR : type == CV_32FC3 ? (ippiMaskNormFuncC3)ippiNorm_L2_32f_C3CMR : 0) : 0; if( ippiNorm_C3CMR ) { Ipp64f norm1, norm2, norm3; - if( CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, (src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 1, &norm1)) >= 0 && - CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, (src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 2, &norm2)) >= 0 && - CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, (src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 3, &norm3)) >= 0) + if( CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 1, &norm1) >= 0 && + CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 2, &norm2) >= 0 && + CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 3, &norm3) >= 0) { Ipp64f norm = normType == NORM_INF ? std::max(std::max(norm1, norm2), norm3) : @@ -2928,81 +3092,46 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result) return true; } } -#endif } else { + IppiSize sz = { cols*src.channels(), rows }; + int type = src.depth(); + typedef IppStatus (CV_STDCALL* ippiNormFuncHint)(const void *, int, IppiSize, Ipp64f *, IppHintAlgorithm hint); typedef IppStatus (CV_STDCALL* ippiNormFuncNoHint)(const void *, int, IppiSize, Ipp64f *); ippiNormFuncHint ippiNormHint = normType == NORM_L1 ? (type == CV_32FC1 ? (ippiNormFuncHint)ippiNorm_L1_32f_C1R : - type == CV_32FC3 ? (ippiNormFuncHint)ippiNorm_L1_32f_C3R : - type == CV_32FC4 ? (ippiNormFuncHint)ippiNorm_L1_32f_C4R : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? (type == CV_32FC1 ? (ippiNormFuncHint)ippiNorm_L2_32f_C1R : - type == CV_32FC3 ? (ippiNormFuncHint)ippiNorm_L2_32f_C3R : - type == CV_32FC4 ? (ippiNormFuncHint)ippiNorm_L2_32f_C4R : 0) : 0; ippiNormFuncNoHint ippiNorm = normType == NORM_INF ? (type == CV_8UC1 ? (ippiNormFuncNoHint)ippiNorm_Inf_8u_C1R : - type == CV_8UC3 ? (ippiNormFuncNoHint)ippiNorm_Inf_8u_C3R : - type == CV_8UC4 ? (ippiNormFuncNoHint)ippiNorm_Inf_8u_C4R : type == CV_16UC1 ? (ippiNormFuncNoHint)ippiNorm_Inf_16u_C1R : - type == CV_16UC3 ? (ippiNormFuncNoHint)ippiNorm_Inf_16u_C3R : - type == CV_16UC4 ? (ippiNormFuncNoHint)ippiNorm_Inf_16u_C4R : type == CV_16SC1 ? (ippiNormFuncNoHint)ippiNorm_Inf_16s_C1R : -#if (IPP_VERSION_X100 >= 810) - type == CV_16SC3 ? (ippiNormFuncNoHint)ippiNorm_Inf_16s_C3R : //Aug 2013: problem in IPP 7.1, 8.0 : -32768 - type == CV_16SC4 ? (ippiNormFuncNoHint)ippiNorm_Inf_16s_C4R : //Aug 2013: problem in IPP 7.1, 8.0 : -32768 -#endif type == CV_32FC1 ? (ippiNormFuncNoHint)ippiNorm_Inf_32f_C1R : - type == CV_32FC3 ? (ippiNormFuncNoHint)ippiNorm_Inf_32f_C3R : - type == CV_32FC4 ? (ippiNormFuncNoHint)ippiNorm_Inf_32f_C4R : 0) : normType == NORM_L1 ? (type == CV_8UC1 ? (ippiNormFuncNoHint)ippiNorm_L1_8u_C1R : - type == CV_8UC3 ? (ippiNormFuncNoHint)ippiNorm_L1_8u_C3R : - type == CV_8UC4 ? (ippiNormFuncNoHint)ippiNorm_L1_8u_C4R : type == CV_16UC1 ? (ippiNormFuncNoHint)ippiNorm_L1_16u_C1R : - type == CV_16UC3 ? (ippiNormFuncNoHint)ippiNorm_L1_16u_C3R : - type == CV_16UC4 ? (ippiNormFuncNoHint)ippiNorm_L1_16u_C4R : type == CV_16SC1 ? (ippiNormFuncNoHint)ippiNorm_L1_16s_C1R : - type == CV_16SC3 ? (ippiNormFuncNoHint)ippiNorm_L1_16s_C3R : - type == CV_16SC4 ? (ippiNormFuncNoHint)ippiNorm_L1_16s_C4R : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? (type == CV_8UC1 ? (ippiNormFuncNoHint)ippiNorm_L2_8u_C1R : - type == CV_8UC3 ? (ippiNormFuncNoHint)ippiNorm_L2_8u_C3R : - type == CV_8UC4 ? (ippiNormFuncNoHint)ippiNorm_L2_8u_C4R : type == CV_16UC1 ? (ippiNormFuncNoHint)ippiNorm_L2_16u_C1R : - type == CV_16UC3 ? (ippiNormFuncNoHint)ippiNorm_L2_16u_C3R : - type == CV_16UC4 ? (ippiNormFuncNoHint)ippiNorm_L2_16u_C4R : type == CV_16SC1 ? (ippiNormFuncNoHint)ippiNorm_L2_16s_C1R : - type == CV_16SC3 ? (ippiNormFuncNoHint)ippiNorm_L2_16s_C3R : - type == CV_16SC4 ? (ippiNormFuncNoHint)ippiNorm_L2_16s_C4R : 0) : 0; - // Make sure only zero or one version of the function pointer is valid - CV_Assert(!ippiNormHint || !ippiNorm); if( ippiNormHint || ippiNorm ) { - Ipp64f norm_array[4]; - IppStatus ret = ippiNormHint ? CV_INSTRUMENT_FUN_IPP(ippiNormHint, src.ptr(), (int)src.step[0], sz, norm_array, ippAlgHintAccurate) : - CV_INSTRUMENT_FUN_IPP(ippiNorm, src.ptr(), (int)src.step[0], sz, norm_array); + Ipp64f norm; + IppStatus ret = ippiNormHint ? CV_INSTRUMENT_FUN_IPP(ippiNormHint, src.ptr(), (int)src.step[0], sz, &norm, ippAlgHintAccurate) : + CV_INSTRUMENT_FUN_IPP(ippiNorm, src.ptr(), (int)src.step[0], sz, &norm); if( ret >= 0 ) { - Ipp64f norm = (normType == NORM_L2 || normType == NORM_L2SQR) ? norm_array[0] * norm_array[0] : norm_array[0]; - for( int i = 1; i < cn; i++ ) - { - norm = - normType == NORM_INF ? std::max(norm, norm_array[i]) : - normType == NORM_L1 ? norm + norm_array[i] : - normType == NORM_L2 || normType == NORM_L2SQR ? norm + norm_array[i] * norm_array[i] : - 0; - } - result = (normType == NORM_L2 ? (double)std::sqrt(norm) : (double)norm); + result = (normType == NORM_L2SQR) ? norm * norm : norm; return true; } } @@ -3248,53 +3377,38 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra if( normType & CV_RELATIVE ) { normType &= NORM_TYPE_MASK; - CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 || normType == NORM_L2SQR || - ((normType == NORM_HAMMING || normType == NORM_HAMMING2) && src1.type() == CV_8U) ); + size_t total_size = src1.total(); int rows = src1.size[0], cols = rows ? (int)(total_size/rows) : 0; if( (src1.dims == 2 || (src1.isContinuous() && src2.isContinuous() && mask.isContinuous())) - && cols > 0 && (size_t)rows*cols == total_size - && (normType == NORM_INF || normType == NORM_L1 || - normType == NORM_L2 || normType == NORM_L2SQR) ) + && cols > 0 && (size_t)rows*cols == total_size ) { - IppiSize sz = { cols, rows }; - int type = src1.type(); if( !mask.empty() ) { - typedef IppStatus (CV_STDCALL* ippiMaskNormRelFuncC1)(const void *, int, const void *, int, const void *, int, IppiSize, Ipp64f *); - ippiMaskNormRelFuncC1 ippiNormDiff_C1MR = + IppiSize sz = { cols, rows }; + int type = src1.type(); + + typedef IppStatus (CV_STDCALL* ippiMaskNormDiffFuncC1)(const void *, int, const void *, int, const void *, int, IppiSize, Ipp64f *); + ippiMaskNormDiffFuncC1 ippiNormRel_C1MR = normType == NORM_INF ? - (type == CV_8UC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_Inf_8u_C1MR : -#if IPP_VERSION_X100 < 900 -#ifndef __APPLE__ - type == CV_8SC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_Inf_8s_C1MR : -#endif -#endif - type == CV_16UC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_Inf_16u_C1MR : - type == CV_32FC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_Inf_32f_C1MR : + (type == CV_8UC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_Inf_8u_C1MR : + type == CV_16UC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_Inf_16u_C1MR : + type == CV_32FC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_Inf_32f_C1MR : 0) : normType == NORM_L1 ? - (type == CV_8UC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L1_8u_C1MR : -#if IPP_VERSION_X100 < 900 -#ifndef __APPLE__ - type == CV_8SC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L1_8s_C1MR : -#endif -#endif - type == CV_16UC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L1_16u_C1MR : - type == CV_32FC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L1_32f_C1MR : + (type == CV_8UC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_L1_8u_C1MR : + type == CV_16UC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_L1_16u_C1MR : + type == CV_32FC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_L1_32f_C1MR : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? - (type == CV_8UC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L2_8u_C1MR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L2_8s_C1MR : -#endif - type == CV_16UC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L2_16u_C1MR : - type == CV_32FC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L2_32f_C1MR : + (type == CV_8UC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_L2_8u_C1MR : + type == CV_16UC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_L2_16u_C1MR : + type == CV_32FC1 ? (ippiMaskNormDiffFuncC1)ippiNormRel_L2_32f_C1MR : 0) : 0; - if( ippiNormDiff_C1MR ) + if( ippiNormRel_C1MR ) { Ipp64f norm; - if( CV_INSTRUMENT_FUN_IPP(ippiNormDiff_C1MR, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], mask.ptr(), (int)mask.step[0], sz, &norm) >= 0 ) + if( CV_INSTRUMENT_FUN_IPP(ippiNormRel_C1MR, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], mask.ptr(), (int)mask.step[0], sz, &norm) >= 0 ) { result = (normType == NORM_L2SQR ? (double)(norm * norm) : (double)norm); return true; @@ -3303,47 +3417,43 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra } else { - typedef IppStatus (CV_STDCALL* ippiNormRelFuncNoHint)(const void *, int, const void *, int, IppiSize, Ipp64f *); + IppiSize sz = { cols*src1.channels(), rows }; + int type = src1.depth(); + typedef IppStatus (CV_STDCALL* ippiNormRelFuncHint)(const void *, int, const void *, int, IppiSize, Ipp64f *, IppHintAlgorithm hint); - ippiNormRelFuncNoHint ippiNormDiff = + typedef IppStatus (CV_STDCALL* ippiNormRelFuncNoHint)(const void *, int, const void *, int, IppiSize, Ipp64f *); + ippiNormRelFuncHint ippiNormRelHint = + normType == NORM_L1 ? + (type == CV_32F ? (ippiNormRelFuncHint)ippiNormRel_L1_32f_C1R : + 0) : + normType == NORM_L2 || normType == NORM_L2SQR ? + (type == CV_32F ? (ippiNormRelFuncHint)ippiNormRel_L2_32f_C1R : + 0) : 0; + ippiNormRelFuncNoHint ippiNormRel = normType == NORM_INF ? - (type == CV_8UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_8u_C1R : - type == CV_16UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_16u_C1R : - type == CV_16SC1 ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_16s_C1R : - type == CV_32FC1 ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_32f_C1R : + (type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_8u_C1R : + type == CV_16U ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_16u_C1R : + type == CV_16S ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_16s_C1R : + type == CV_32F ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_32f_C1R : 0) : normType == NORM_L1 ? - (type == CV_8UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_L1_8u_C1R : - type == CV_16UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_L1_16u_C1R : - type == CV_16SC1 ? (ippiNormRelFuncNoHint)ippiNormRel_L1_16s_C1R : + (type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_L1_8u_C1R : + type == CV_16U ? (ippiNormRelFuncNoHint)ippiNormRel_L1_16u_C1R : + type == CV_16S ? (ippiNormRelFuncNoHint)ippiNormRel_L1_16s_C1R : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? - (type == CV_8UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_L2_8u_C1R : - type == CV_16UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_L2_16u_C1R : - type == CV_16SC1 ? (ippiNormRelFuncNoHint)ippiNormRel_L2_16s_C1R : + (type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_L2_8u_C1R : + type == CV_16U ? (ippiNormRelFuncNoHint)ippiNormRel_L2_16u_C1R : + type == CV_16S ? (ippiNormRelFuncNoHint)ippiNormRel_L2_16s_C1R : 0) : 0; - ippiNormRelFuncHint ippiNormDiffHint = - normType == NORM_L1 ? - (type == CV_32FC1 ? (ippiNormRelFuncHint)ippiNormRel_L1_32f_C1R : - 0) : - normType == NORM_L2 || normType == NORM_L2SQR ? - (type == CV_32FC1 ? (ippiNormRelFuncHint)ippiNormRel_L2_32f_C1R : - 0) : 0; - if (ippiNormDiff) + if( ippiNormRelHint || ippiNormRel ) { Ipp64f norm; - if( CV_INSTRUMENT_FUN_IPP(ippiNormDiff, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm) >= 0 ) + IppStatus ret = ippiNormRelHint ? CV_INSTRUMENT_FUN_IPP(ippiNormRelHint, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm, ippAlgHintAccurate) : + CV_INSTRUMENT_FUN_IPP(ippiNormRel, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm); + if( ret >= 0 ) { - result = (double)norm; - return true; - } - } - if (ippiNormDiffHint) - { - Ipp64f norm; - if( CV_INSTRUMENT_FUN_IPP(ippiNormDiffHint, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm, ippAlgHintAccurate) >= 0 ) - { - result = (double)norm; + result = (normType == NORM_L2SQR) ? norm * norm : norm; return true; } } @@ -3352,47 +3462,32 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra return false; } - normType &= 7; - CV_Assert( normType == NORM_INF || normType == NORM_L1 || - normType == NORM_L2 || normType == NORM_L2SQR || - ((normType == NORM_HAMMING || normType == NORM_HAMMING2) && src1.type() == CV_8U) ); + normType &= NORM_TYPE_MASK; size_t total_size = src1.total(); int rows = src1.size[0], cols = rows ? (int)(total_size/rows) : 0; if( (src1.dims == 2 || (src1.isContinuous() && src2.isContinuous() && mask.isContinuous())) - && cols > 0 && (size_t)rows*cols == total_size - && (normType == NORM_INF || normType == NORM_L1 || - normType == NORM_L2 || normType == NORM_L2SQR) ) + && cols > 0 && (size_t)rows*cols == total_size ) { - IppiSize sz = { cols, rows }; - int type = src1.type(); if( !mask.empty() ) { + IppiSize sz = { cols, rows }; + int type = src1.type(); + typedef IppStatus (CV_STDCALL* ippiMaskNormDiffFuncC1)(const void *, int, const void *, int, const void *, int, IppiSize, Ipp64f *); ippiMaskNormDiffFuncC1 ippiNormDiff_C1MR = normType == NORM_INF ? (type == CV_8UC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_Inf_8u_C1MR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_Inf_8s_C1MR : -#endif type == CV_16UC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_Inf_16u_C1MR : type == CV_32FC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_Inf_32f_C1MR : 0) : normType == NORM_L1 ? (type == CV_8UC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L1_8u_C1MR : -#if IPP_VERSION_X100 < 900 -#ifndef __APPLE__ - type == CV_8SC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L1_8s_C1MR : -#endif -#endif type == CV_16UC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L1_16u_C1MR : type == CV_32FC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L1_32f_C1MR : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? (type == CV_8UC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L2_8u_C1MR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L2_8s_C1MR : -#endif type == CV_16UC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L2_16u_C1MR : type == CV_32FC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L2_32f_C1MR : 0) : 0; @@ -3405,30 +3500,20 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra return true; } } -#ifndef __APPLE__ typedef IppStatus (CV_STDCALL* ippiMaskNormDiffFuncC3)(const void *, int, const void *, int, const void *, int, IppiSize, int, Ipp64f *); ippiMaskNormDiffFuncC3 ippiNormDiff_C3CMR = normType == NORM_INF ? (type == CV_8UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_Inf_8u_C3CMR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_Inf_8s_C3CMR : -#endif type == CV_16UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_Inf_16u_C3CMR : type == CV_32FC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_Inf_32f_C3CMR : 0) : normType == NORM_L1 ? (type == CV_8UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L1_8u_C3CMR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L1_8s_C3CMR : -#endif type == CV_16UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L1_16u_C3CMR : type == CV_32FC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L1_32f_C3CMR : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? (type == CV_8UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_8u_C3CMR : -#if IPP_VERSION_X100 < 900 - type == CV_8SC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_8s_C3CMR : -#endif type == CV_16UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_16u_C3CMR : type == CV_32FC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_32f_C3CMR : 0) : 0; @@ -3448,83 +3533,46 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra return true; } } -#endif } else { + IppiSize sz = { cols*src1.channels(), rows }; + int type = src1.depth(); + typedef IppStatus (CV_STDCALL* ippiNormDiffFuncHint)(const void *, int, const void *, int, IppiSize, Ipp64f *, IppHintAlgorithm hint); typedef IppStatus (CV_STDCALL* ippiNormDiffFuncNoHint)(const void *, int, const void *, int, IppiSize, Ipp64f *); ippiNormDiffFuncHint ippiNormDiffHint = normType == NORM_L1 ? - (type == CV_32FC1 ? (ippiNormDiffFuncHint)ippiNormDiff_L1_32f_C1R : - type == CV_32FC3 ? (ippiNormDiffFuncHint)ippiNormDiff_L1_32f_C3R : - type == CV_32FC4 ? (ippiNormDiffFuncHint)ippiNormDiff_L1_32f_C4R : + (type == CV_32F ? (ippiNormDiffFuncHint)ippiNormDiff_L1_32f_C1R : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? - (type == CV_32FC1 ? (ippiNormDiffFuncHint)ippiNormDiff_L2_32f_C1R : - type == CV_32FC3 ? (ippiNormDiffFuncHint)ippiNormDiff_L2_32f_C3R : - type == CV_32FC4 ? (ippiNormDiffFuncHint)ippiNormDiff_L2_32f_C4R : + (type == CV_32F ? (ippiNormDiffFuncHint)ippiNormDiff_L2_32f_C1R : 0) : 0; ippiNormDiffFuncNoHint ippiNormDiff = normType == NORM_INF ? - (type == CV_8UC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_8u_C1R : - type == CV_8UC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_8u_C3R : - type == CV_8UC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_8u_C4R : - type == CV_16UC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16u_C1R : - type == CV_16UC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16u_C3R : - type == CV_16UC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16u_C4R : - type == CV_16SC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16s_C1R : -#if (IPP_VERSION_X100 >= 810) - type == CV_16SC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16s_C3R : //Aug 2013: problem in IPP 7.1, 8.0 : -32768 - type == CV_16SC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16s_C4R : //Aug 2013: problem in IPP 7.1, 8.0 : -32768 -#endif - type == CV_32FC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_32f_C1R : - type == CV_32FC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_32f_C3R : - type == CV_32FC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_32f_C4R : + (type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_8u_C1R : + type == CV_16U ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16u_C1R : + type == CV_16S ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16s_C1R : + type == CV_32F ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_32f_C1R : 0) : normType == NORM_L1 ? - (type == CV_8UC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_8u_C1R : - type == CV_8UC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_8u_C3R : - type == CV_8UC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_8u_C4R : - type == CV_16UC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16u_C1R : - type == CV_16UC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16u_C3R : - type == CV_16UC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16u_C4R : -#if !(IPP_VERSION_X100 == 820 || IPP_VERSION_X100 == 821) // Oct 2014: Accuracy issue with IPP 8.2 / 8.2.1 - type == CV_16SC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16s_C1R : -#endif - type == CV_16SC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16s_C3R : - type == CV_16SC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16s_C4R : + (type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_8u_C1R : + type == CV_16U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16u_C1R : + type == CV_16S ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16s_C1R : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? - (type == CV_8UC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_8u_C1R : - type == CV_8UC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_8u_C3R : - type == CV_8UC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_8u_C4R : - type == CV_16UC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16u_C1R : - type == CV_16UC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16u_C3R : - type == CV_16UC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16u_C4R : - type == CV_16SC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16s_C1R : - type == CV_16SC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16s_C3R : - type == CV_16SC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16s_C4R : + (type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_8u_C1R : + type == CV_16U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16u_C1R : + type == CV_16S ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16s_C1R : 0) : 0; - // Make sure only zero or one version of the function pointer is valid - CV_Assert(!ippiNormDiffHint || !ippiNormDiff); if( ippiNormDiffHint || ippiNormDiff ) { - Ipp64f norm_array[4]; - IppStatus ret = ippiNormDiffHint ? CV_INSTRUMENT_FUN_IPP(ippiNormDiffHint, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, norm_array, ippAlgHintAccurate) : - CV_INSTRUMENT_FUN_IPP(ippiNormDiff, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, norm_array); + Ipp64f norm; + IppStatus ret = ippiNormDiffHint ? CV_INSTRUMENT_FUN_IPP(ippiNormDiffHint, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm, ippAlgHintAccurate) : + CV_INSTRUMENT_FUN_IPP(ippiNormDiff, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm); if( ret >= 0 ) { - Ipp64f norm = (normType == NORM_L2 || normType == NORM_L2SQR) ? norm_array[0] * norm_array[0] : norm_array[0]; - for( int i = 1; i < src1.channels(); i++ ) - { - norm = - normType == NORM_INF ? std::max(norm, norm_array[i]) : - normType == NORM_L1 ? norm + norm_array[i] : - normType == NORM_L2 || normType == NORM_L2SQR ? norm + norm_array[i] * norm_array[i] : - 0; - } - result = (normType == NORM_L2 ? (double)std::sqrt(norm) : (double)norm); + result = (normType == NORM_L2SQR) ? norm * norm : norm; return true; } } diff --git a/modules/imgproc/src/canny.cpp b/modules/imgproc/src/canny.cpp index d10b5f7dfa..fbbb804dbf 100644 --- a/modules/imgproc/src/canny.cpp +++ b/modules/imgproc/src/canny.cpp @@ -51,14 +51,6 @@ #pragma warning( disable: 4127 ) // conditional expression is constant #endif - -#if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700) -#define USE_IPP_CANNY 1 -#else -#define USE_IPP_CANNY 0 -#endif - - namespace cv { @@ -66,73 +58,79 @@ static void CannyImpl(Mat& dx_, Mat& dy_, Mat& _dst, double low_thresh, double h #ifdef HAVE_IPP -template -static bool ippCanny(const Mat& _src, const Mat& dx_, const Mat& dy_, Mat& _dst, float low, float high) +static bool ipp_Canny(const Mat& src , const Mat& dx_, const Mat& dy_, Mat& dst, float low, float high, bool L2gradient, int aperture_size) { +#ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() -#if USE_IPP_CANNY - if (!useCustomDeriv && _src.isSubmatrix()) - return false; // IPP Sobel doesn't support transparent ROI border +#if IPP_DISABLE_PERF_CANNY_MT + if(cv::getNumThreads()>1) + return false; +#endif - int size = 0, size1 = 0; - IppiSize roi = { _src.cols, _src.rows }; + ::ipp::IwiSize size(dst.cols, dst.rows); + IppDataType type = ippiGetDataType(dst.depth()); + int channels = dst.channels(); + IppNormType norm = (L2gradient)?ippNormL2:ippNormL1; - if (ippiCannyGetSize(roi, &size) < 0) + if(size.width <= 3 || size.height <= 3) return false; - if (!useCustomDeriv) + if(channels != 1) + return false; + + if(type != ipp8u) + return false; + + if(src.empty()) { -#if IPP_VERSION_X100 < 900 - if (ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size1) < 0) - return false; - size = std::max(size, size1); - if (ippiFilterSobelHorizGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size1) < 0) - return false; -#else - if (ippiFilterSobelNegVertBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size1) < 0) - return false; - size = std::max(size, size1); - if (ippiFilterSobelHorizBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size1) < 0) - return false; -#endif - size = std::max(size, size1); - } + try + { + ::ipp::IwiImage iwSrcDx; + ::ipp::IwiImage iwSrcDy; + ::ipp::IwiImage iwDst; - AutoBuffer buf(size + 64); - uchar* buffer = alignPtr((uchar*)buf, 32); + ippiGetImage(dx_, iwSrcDx); + ippiGetImage(dy_, iwSrcDy); + ippiGetImage(dst, iwDst); - Mat dx, dy; - if (!useCustomDeriv) - { - Mat _dx(_src.rows, _src.cols, CV_16S); - if( CV_INSTRUMENT_FUN_IPP(ippiFilterSobelNegVertBorder_8u16s_C1R, _src.ptr(), (int)_src.step, - _dx.ptr(), (int)_dx.step, roi, - ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 ) + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterCannyDeriv, &iwSrcDx, &iwSrcDy, &iwDst, norm, low, high); + } + catch (::ipp::IwException ex) + { return false; - - Mat _dy(_src.rows, _src.cols, CV_16S); - if( CV_INSTRUMENT_FUN_IPP(ippiFilterSobelHorizBorder_8u16s_C1R, _src.ptr(), (int)_src.step, - _dy.ptr(), (int)_dy.step, roi, - ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 ) - return false; - - swap(dx, _dx); - swap(dy, _dy); + } } else { - dx = dx_; - dy = dy_; + IppiMaskSize kernel; + + if(aperture_size == 3) + kernel = ippMskSize3x3; + else if(aperture_size == 5) + kernel = ippMskSize5x5; + else + return false; + + try + { + ::ipp::IwiImage iwSrc; + ::ipp::IwiImage iwDst; + + ippiGetImage(src, iwSrc); + ippiGetImage(dst, iwDst); + + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterCanny, &iwSrc, &iwDst, ippFilterSobel, kernel, norm, low, high, ippBorderRepl); + } + catch (::ipp::IwException) + { + return false; + } } - if( CV_INSTRUMENT_FUN_IPP(ippiCanny_16s8u_C1R, dx.ptr(), (int)dx.step, - dy.ptr(), (int)dy.step, - _dst.ptr(), (int)_dst.step, roi, low, high, buffer) < 0 ) - return false; return true; #else - CV_UNUSED(_src); CV_UNUSED(dx_); CV_UNUSED(dy_); CV_UNUSED(_dst); CV_UNUSED(low); CV_UNUSED(high); + CV_UNUSED(src); CV_UNUSED(dx_); CV_UNUSED(dy_); CV_UNUSED(dst); CV_UNUSED(low); CV_UNUSED(high); CV_UNUSED(L2gradient); CV_UNUSED(aperture_size); return false; #endif } @@ -318,6 +316,8 @@ public: // In sobel transform we calculate ksize2 extra lines for the first and last rows of each slice // because IPPDerivSobel expects only isolated ROIs, in contrast with the opencv version which // uses the pixels outside of the ROI to form a border. + // + // TODO: statement above is not true anymore, so adjustments may be required int ksize2 = aperture_size / 2; // If Scharr filter: aperture_size is 3 and ksize2 is 1 if(aperture_size == -1) @@ -882,18 +882,18 @@ void Canny( InputArray _src, OutputArray _dst, return; #endif - CV_IPP_RUN(USE_IPP_CANNY && (aperture_size == 3 && !L2gradient && 1 == cn), ippCanny(src, Mat(), Mat(), dst, (float)low_thresh, (float)high_thresh)) + CV_IPP_RUN_FAST(ipp_Canny(src, Mat(), Mat(), dst, (float)low_thresh, (float)high_thresh, L2gradient, aperture_size)) -if (L2gradient) -{ - low_thresh = std::min(32767.0, low_thresh); - high_thresh = std::min(32767.0, high_thresh); + if (L2gradient) + { + low_thresh = std::min(32767.0, low_thresh); + high_thresh = std::min(32767.0, high_thresh); - if (low_thresh > 0) low_thresh *= low_thresh; - if (high_thresh > 0) high_thresh *= high_thresh; -} -int low = cvFloor(low_thresh); -int high = cvFloor(high_thresh); + if (low_thresh > 0) low_thresh *= low_thresh; + if (high_thresh > 0) high_thresh *= high_thresh; + } + int low = cvFloor(low_thresh); + int high = cvFloor(high_thresh); ptrdiff_t mapstep = src.cols + 2; AutoBuffer buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int)); @@ -938,15 +938,15 @@ int high = cvFloor(high_thresh); { m = borderPeaksParallel.front(); borderPeaksParallel.pop(); - if (!m[-1]) CANNY_PUSH_SERIAL(m - 1); - if (!m[1]) CANNY_PUSH_SERIAL(m + 1); - if (!m[-mapstep-1]) CANNY_PUSH_SERIAL(m - mapstep - 1); - if (!m[-mapstep]) CANNY_PUSH_SERIAL(m - mapstep); - if (!m[-mapstep+1]) CANNY_PUSH_SERIAL(m - mapstep + 1); - if (!m[mapstep-1]) CANNY_PUSH_SERIAL(m + mapstep - 1); - if (!m[mapstep]) CANNY_PUSH_SERIAL(m + mapstep); - if (!m[mapstep+1]) CANNY_PUSH_SERIAL(m + mapstep + 1); -} + if (!m[-1]) CANNY_PUSH_SERIAL(m - 1); + if (!m[1]) CANNY_PUSH_SERIAL(m + 1); + if (!m[-mapstep-1]) CANNY_PUSH_SERIAL(m - mapstep - 1); + if (!m[-mapstep]) CANNY_PUSH_SERIAL(m - mapstep); + if (!m[-mapstep+1]) CANNY_PUSH_SERIAL(m - mapstep + 1); + if (!m[mapstep-1]) CANNY_PUSH_SERIAL(m + mapstep - 1); + if (!m[mapstep]) CANNY_PUSH_SERIAL(m + mapstep); + if (!m[mapstep+1]) CANNY_PUSH_SERIAL(m + mapstep + 1); + } parallel_for_(Range(0, dst.rows), finalPass(map, dst, mapstep), dst.total()/(double)(1<<16)); } @@ -955,6 +955,8 @@ void Canny( InputArray _dx, InputArray _dy, OutputArray _dst, double low_thresh, double high_thresh, bool L2gradient ) { + CV_INSTRUMENT_REGION() + CV_Assert(_dx.dims() == 2); CV_Assert(_dx.type() == CV_16SC1 || _dx.type() == CV_16SC3); CV_Assert(_dy.type() == _dx.type()); @@ -975,7 +977,7 @@ void Canny( InputArray _dx, InputArray _dy, OutputArray _dst, Mat dx = _dx.getMat(); Mat dy = _dy.getMat(); - CV_IPP_RUN(USE_IPP_CANNY && (!L2gradient && 1 == cn), ippCanny(Mat(), dx, dy, dst, (float)low_thresh, (float)high_thresh)) + CV_IPP_RUN_FAST(ipp_Canny(Mat(), dx, dy, dst, (float)low_thresh, (float)high_thresh, L2gradient, 0)) if (cn > 1) { diff --git a/modules/imgproc/src/corner.cpp b/modules/imgproc/src/corner.cpp index da2e08ddb6..2f37ff6c90 100644 --- a/modules/imgproc/src/corner.cpp +++ b/modules/imgproc/src/corner.cpp @@ -604,9 +604,9 @@ namespace cv { static bool ipp_cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType ) { +#if IPP_VERSION_X100 >= 800 CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 800 Mat src = _src.getMat(); _dst.create( src.size(), CV_32FC1 ); Mat dst = _dst.getMat(); @@ -703,15 +703,11 @@ void cv::cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, in #if defined(HAVE_IPP) namespace cv { -static bool ipp_cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksize, double k, int borderType ) +static bool ipp_cornerHarris( Mat &src, Mat &dst, int blockSize, int ksize, double k, int borderType ) { +#if IPP_VERSION_X100 >= 810 CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK - Mat src = _src.getMat(); - _dst.create( src.size(), CV_32FC1 ); - Mat dst = _dst.getMat(); - { int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); int borderTypeNI = borderType & ~BORDER_ISOLATED; @@ -734,17 +730,17 @@ static bool ipp_cornerHarris( InputArray _src, OutputArray _dst, int blockSize, if (ippiHarrisCornerGetBufferSize(roisize, masksize, blockSize, datatype, cn, &bufsize) >= 0) { - Ipp8u * buffer = ippsMalloc_8u(bufsize); + Ipp8u * buffer = (Ipp8u*)CV_IPP_MALLOC(bufsize); IppiDifferentialKernel filterType = ksize > 0 ? ippFilterSobel : ippFilterScharr; IppiBorderType borderTypeIpp = borderTypeNI == BORDER_CONSTANT ? ippBorderConst : ippBorderRepl; IppStatus status = (IppStatus)-1; if (depth == CV_8U) - status = CV_INSTRUMENT_FUN_IPP(ippiHarrisCorner_8u32f_C1R,((const Ipp8u *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize, - filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer)); + status = CV_INSTRUMENT_FUN_IPP(ippiHarrisCorner_8u32f_C1R, (const Ipp8u *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize, + filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer); else if (depth == CV_32F) - status = CV_INSTRUMENT_FUN_IPP(ippiHarrisCorner_32f_C1R,((const Ipp32f *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize, - filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer)); + status = CV_INSTRUMENT_FUN_IPP(ippiHarrisCorner_32f_C1R, (const Ipp32f *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize, + filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer); ippsFree(buffer); if (status >= 0) @@ -756,7 +752,7 @@ static bool ipp_cornerHarris( InputArray _src, OutputArray _dst, int blockSize, } } #else - CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(blockSize); CV_UNUSED(ksize); CV_UNUSED(k); CV_UNUSED(borderType); + CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(blockSize); CV_UNUSED(ksize); CV_UNUSED(k); CV_UNUSED(borderType); #endif return false; } @@ -770,19 +766,17 @@ void cv::cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksi CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(), ocl_cornerMinEigenValVecs(_src, _dst, blockSize, ksize, k, borderType, HARRIS)) + Mat src = _src.getMat(); + _dst.create( src.size(), CV_32FC1 ); + Mat dst = _dst.getMat(); + #ifdef HAVE_IPP int borderTypeNI = borderType & ~BORDER_ISOLATED; bool isolated = (borderType & BORDER_ISOLATED) != 0; #endif CV_IPP_RUN(((ksize == 3 || ksize == 5) && (_src.type() == CV_8UC1 || _src.type() == CV_32FC1) && (borderTypeNI == BORDER_CONSTANT || borderTypeNI == BORDER_REPLICATE) && CV_MAT_CN(_src.type()) == 1 && - (!_src.isSubmatrix() || isolated)) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK, ipp_cornerHarris( _src, _dst, blockSize, ksize, k, borderType )); - - - Mat src = _src.getMat(); - _dst.create( src.size(), CV_32FC1 ); - Mat dst = _dst.getMat(); - + (!_src.isSubmatrix() || isolated)) && IPP_VERSION_X100 >= 810, ipp_cornerHarris( src, dst, blockSize, ksize, k, borderType )); cornerEigenValsVecs( src, dst, blockSize, ksize, HARRIS, k, borderType ); } diff --git a/modules/imgproc/src/filter.cpp b/modules/imgproc/src/filter.cpp index 51d0bc4f51..10d8315772 100644 --- a/modules/imgproc/src/filter.cpp +++ b/modules/imgproc/src/filter.cpp @@ -1360,14 +1360,14 @@ struct RowVec_32f { kernel = _kernel; haveSSE = checkHardwareSupport(CV_CPU_SSE); -#if defined USE_IPP_SEP_FILTERS && IPP_DISABLE_BLOCK +#if defined USE_IPP_SEP_FILTERS bufsz = -1; #endif } int operator()(const uchar* _src, uchar* _dst, int width, int cn) const { -#if defined USE_IPP_SEP_FILTERS && IPP_DISABLE_BLOCK +#if defined USE_IPP_SEP_FILTERS CV_IPP_CHECK() { int ret = ippiOperator(_src, _dst, width, cn); @@ -1408,7 +1408,7 @@ struct RowVec_32f Mat kernel; bool haveSSE; -#if defined USE_IPP_SEP_FILTERS && IPP_DISABLE_BLOCK +#if defined USE_IPP_SEP_FILTERS private: mutable int bufsz; int ippiOperator(const uchar* _src, uchar* _dst, int width, int cn) const @@ -1436,10 +1436,10 @@ private: float borderValue[] = {0.f, 0.f, 0.f}; // here is the trick. IPP needs border type and extrapolates the row. We did it already. // So we pass anchor=0 and ignore the right tail of results since they are incorrect there. - if( (cn == 1 && CV_INSTRUMENT_FUN_IPP(ippiFilterRowBorderPipeline_32f_C1R,(src, step, &dst, roisz, _kx, _ksize, 0, - ippBorderRepl, borderValue[0], bufptr)) < 0) || - (cn == 3 && CV_INSTRUMENT_FUN_IPP(ippiFilterRowBorderPipeline_32f_C3R,(src, step, &dst, roisz, _kx, _ksize, 0, - ippBorderRepl, borderValue, bufptr)) < 0)) + if( (cn == 1 && CV_INSTRUMENT_FUN_IPP(ippiFilterRowBorderPipeline_32f_C1R, src, step, &dst, roisz, _kx, _ksize, 0, + ippBorderRepl, borderValue[0], bufptr) < 0) || + (cn == 3 && CV_INSTRUMENT_FUN_IPP(ippiFilterRowBorderPipeline_32f_C3R, src, step, &dst, roisz, _kx, _ksize, 0, + ippBorderRepl, borderValue, bufptr) < 0)) { setIppErrorStatus(); return 0; diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index 13c11dbee3..6850499e65 100644 --- a/modules/imgproc/src/hough.cpp +++ b/modules/imgproc/src/hough.cpp @@ -96,7 +96,7 @@ HoughLinesStandard( const Mat& img, float rho, float theta, int numangle = cvRound((max_theta - min_theta) / theta); int numrho = cvRound(((width + height) * 2 + 1) / rho); -#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_HOUGH CV_IPP_CHECK() { IppiSize srcSize = { width, height }; @@ -108,8 +108,8 @@ HoughLinesStandard( const Mat& img, float rho, float theta, int linesCount = 0; lines.resize(ipp_linesMax); IppStatus ok = ippiHoughLineGetSize_8u_C1R(srcSize, delta, ipp_linesMax, &bufferSize); - Ipp8u* buffer = ippsMalloc_8u(bufferSize); - if (ok >= 0) {ok = CV_INSTRUMENT_FUN_IPP(ippiHoughLine_Region_8u32f_C1R,(image, step, srcSize, (IppPointPolar*) &lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer))}; + Ipp8u* buffer = ippsMalloc_8u_L(bufferSize); + if (ok >= 0) {ok = CV_INSTRUMENT_FUN_IPP(ippiHoughLine_Region_8u32f_C1R, image, step, srcSize, (IppPointPolar*) &lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer);}; ippsFree(buffer); if (ok >= 0) { @@ -429,7 +429,7 @@ HoughLinesProbabilistic( Mat& image, int numangle = cvRound(CV_PI / theta); int numrho = cvRound(((width + height) * 2 + 1) / rho); -#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_HOUGH CV_IPP_CHECK() { IppiSize srcSize = { width, height }; @@ -440,12 +440,12 @@ HoughLinesProbabilistic( Mat& image, int linesCount = 0; lines.resize(ipp_linesMax); IppStatus ok = ippiHoughProbLineGetSize_8u_C1R(srcSize, delta, &specSize, &bufferSize); - Ipp8u* buffer = ippsMalloc_8u(bufferSize); - pSpec = (IppiHoughProbSpec*) malloc(specSize); + Ipp8u* buffer = ippsMalloc_8u_L(bufferSize); + pSpec = (IppiHoughProbSpec*) ippsMalloc_8u_L(specSize); if (ok >= 0) ok = ippiHoughProbLineInit_8u32f_C1R(srcSize, delta, ippAlgHintNone, pSpec); - if (ok >= 0) {ok = CV_INSTRUMENT_FUN_IPP(ippiHoughProbLine_8u32f_C1R,(image.data, image.step, srcSize, threshold, lineLength, lineGap, (IppiPoint*) &lines[0], ipp_linesMax, &linesCount, buffer, pSpec))}; + if (ok >= 0) {ok = CV_INSTRUMENT_FUN_IPP(ippiHoughProbLine_8u32f_C1R, image.data, (int)image.step, srcSize, threshold, lineLength, lineGap, (IppiPoint*) &lines[0], ipp_linesMax, &linesCount, buffer, pSpec);}; - free(pSpec); + ippsFree(pSpec); ippsFree(buffer); if (ok >= 0) { diff --git a/modules/imgproc/src/moments.cpp b/modules/imgproc/src/moments.cpp index d445ed270d..d9ae2e2f25 100644 --- a/modules/imgproc/src/moments.cpp +++ b/modules/imgproc/src/moments.cpp @@ -556,13 +556,94 @@ static bool ocl_moments( InputArray _src, Moments& m, bool binary) m.m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym)); } + completeMomentState( &m ); + return true; } #endif -} +#ifdef HAVE_IPP +typedef IppStatus (CV_STDCALL * ippiMoments)(const void* pSrc, int srcStep, IppiSize roiSize, IppiMomentState_64f* pCtx); +static bool ipp_moments(Mat &src, Moments &m ) +{ +#if IPP_VERSION_X100 >= 900 + CV_INSTRUMENT_REGION_IPP() + + IppiSize roi = { src.cols, src.rows }; + IppiPoint point = { 0, 0 }; + int type = src.type(); + IppStatus ippStatus; + + IppAutoBuffer state; + int stateSize = 0; + + ippiMoments ippiMoments64f = + (type == CV_8UC1)?(ippiMoments)ippiMoments64f_8u_C1R: + (type == CV_16UC1)?(ippiMoments)ippiMoments64f_16u_C1R: + (type == CV_32FC1)?(ippiMoments)ippiMoments64f_32f_C1R: + NULL; + if(!ippiMoments64f) + return false; + + ippStatus = ippiMomentGetStateSize_64f(ippAlgHintAccurate, &stateSize); + if(ippStatus < 0) + return false; + + if(!state.allocate(stateSize) && stateSize) + return false; + + ippStatus = ippiMomentInit_64f(state, ippAlgHintAccurate); + if(ippStatus < 0) + return false; + + ippStatus = CV_INSTRUMENT_FUN_IPP(ippiMoments64f, src.ptr(), (int)src.step, roi, state); + if(ippStatus < 0) + return false; + + ippStatus = ippiGetSpatialMoment_64f(state, 0, 0, 0, point, &m.m00); + if(ippStatus < 0) + return false; + ippiGetSpatialMoment_64f(state, 1, 0, 0, point, &m.m10); + ippiGetSpatialMoment_64f(state, 0, 1, 0, point, &m.m01); + ippiGetSpatialMoment_64f(state, 2, 0, 0, point, &m.m20); + ippiGetSpatialMoment_64f(state, 1, 1, 0, point, &m.m11); + ippiGetSpatialMoment_64f(state, 0, 2, 0, point, &m.m02); + ippiGetSpatialMoment_64f(state, 3, 0, 0, point, &m.m30); + ippiGetSpatialMoment_64f(state, 2, 1, 0, point, &m.m21); + ippiGetSpatialMoment_64f(state, 1, 2, 0, point, &m.m12); + ippiGetSpatialMoment_64f(state, 0, 3, 0, point, &m.m03); + + ippStatus = ippiGetCentralMoment_64f(state, 2, 0, 0, &m.mu20); + if(ippStatus < 0) + return false; + ippiGetCentralMoment_64f(state, 1, 1, 0, &m.mu11); + ippiGetCentralMoment_64f(state, 0, 2, 0, &m.mu02); + ippiGetCentralMoment_64f(state, 3, 0, 0, &m.mu30); + ippiGetCentralMoment_64f(state, 2, 1, 0, &m.mu21); + ippiGetCentralMoment_64f(state, 1, 2, 0, &m.mu12); + ippiGetCentralMoment_64f(state, 0, 3, 0, &m.mu03); + + ippStatus = ippiGetNormalizedCentralMoment_64f(state, 2, 0, 0, &m.nu20); + if(ippStatus < 0) + return false; + ippiGetNormalizedCentralMoment_64f(state, 1, 1, 0, &m.nu11); + ippiGetNormalizedCentralMoment_64f(state, 0, 2, 0, &m.nu02); + ippiGetNormalizedCentralMoment_64f(state, 3, 0, 0, &m.nu30); + ippiGetNormalizedCentralMoment_64f(state, 2, 1, 0, &m.nu21); + ippiGetNormalizedCentralMoment_64f(state, 1, 2, 0, &m.nu12); + ippiGetNormalizedCentralMoment_64f(state, 0, 3, 0, &m.nu03); + + return true; +#else + CV_UNUSED(src); CV_UNUSED(m); + return false; +#endif +} +#endif + +} cv::Moments cv::moments( InputArray _src, bool binary ) { @@ -579,159 +660,93 @@ cv::Moments cv::moments( InputArray _src, bool binary ) return m; #ifdef HAVE_OPENCL - if( !(ocl::useOpenCL() && type == CV_8UC1 && - _src.isUMat() && ocl_moments(_src, m, binary)) ) + CV_OCL_RUN_(type == CV_8UC1 && _src.isUMat(), ocl_moments(_src, m, binary), m); #endif + + Mat mat = _src.getMat(); + if( mat.checkVector(2) >= 0 && (depth == CV_32F || depth == CV_32S)) + return contourMoments(mat); + + if( cn > 1 ) + CV_Error( CV_StsBadArg, "Invalid image type (must be single-channel)" ); + + CV_IPP_RUN(!binary, ipp_moments(mat, m), m); + + if( binary || depth == CV_8U ) + func = momentsInTile; + else if( depth == CV_16U ) + func = momentsInTile; + else if( depth == CV_16S ) + func = momentsInTile; + else if( depth == CV_32F ) + func = momentsInTile; + else if( depth == CV_64F ) + func = momentsInTile; + else + CV_Error( CV_StsUnsupportedFormat, "" ); + + Mat src0(mat); + + for( int y = 0; y < size.height; y += TILE_SIZE ) { - Mat mat = _src.getMat(); - if( mat.checkVector(2) >= 0 && (depth == CV_32F || depth == CV_32S)) - return contourMoments(mat); + Size tileSize; + tileSize.height = std::min(TILE_SIZE, size.height - y); - if( cn > 1 ) - CV_Error( CV_StsBadArg, "Invalid image type (must be single-channel)" ); - -#if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK - CV_IPP_CHECK() + for( int x = 0; x < size.width; x += TILE_SIZE ) { - if (!binary) + tileSize.width = std::min(TILE_SIZE, size.width - x); + Mat src(src0, cv::Rect(x, y, tileSize.width, tileSize.height)); + + if( binary ) { - IppiSize roi = { mat.cols, mat.rows }; - IppiMomentState_64f * moment = NULL; - // ippiMomentInitAlloc_64f, ippiMomentFree_64f are deprecated in 8.1, but there are not another way - // to initialize IppiMomentState_64f. When GetStateSize and Init functions will appear we have to - // change our code. - CV_SUPPRESS_DEPRECATED_START - if (ippiMomentInitAlloc_64f(&moment, ippAlgHintAccurate) >= 0) - { - typedef IppStatus (CV_STDCALL * ippiMoments)(const void * pSrc, int srcStep, IppiSize roiSize, IppiMomentState_64f* pCtx); - ippiMoments ippFunc = - type == CV_8UC1 ? (ippiMoments)ippiMoments64f_8u_C1R : - type == CV_16UC1 ? (ippiMoments)ippiMoments64f_16u_C1R : - type == CV_32FC1? (ippiMoments)ippiMoments64f_32f_C1R : 0; - - if (ippFunc) - { - if (CV_INSTRUMENT_FUN_IPP(ippFunc,(mat.data, (int)mat.step, roi, moment)) >= 0) - { - IppiPoint point = { 0, 0 }; - ippiGetSpatialMoment_64f(moment, 0, 0, 0, point, &m.m00); - ippiGetSpatialMoment_64f(moment, 1, 0, 0, point, &m.m10); - ippiGetSpatialMoment_64f(moment, 0, 1, 0, point, &m.m01); - - ippiGetSpatialMoment_64f(moment, 2, 0, 0, point, &m.m20); - ippiGetSpatialMoment_64f(moment, 1, 1, 0, point, &m.m11); - ippiGetSpatialMoment_64f(moment, 0, 2, 0, point, &m.m02); - - ippiGetSpatialMoment_64f(moment, 3, 0, 0, point, &m.m30); - ippiGetSpatialMoment_64f(moment, 2, 1, 0, point, &m.m21); - ippiGetSpatialMoment_64f(moment, 1, 2, 0, point, &m.m12); - ippiGetSpatialMoment_64f(moment, 0, 3, 0, point, &m.m03); - ippiGetCentralMoment_64f(moment, 2, 0, 0, &m.mu20); - ippiGetCentralMoment_64f(moment, 1, 1, 0, &m.mu11); - ippiGetCentralMoment_64f(moment, 0, 2, 0, &m.mu02); - ippiGetCentralMoment_64f(moment, 3, 0, 0, &m.mu30); - ippiGetCentralMoment_64f(moment, 2, 1, 0, &m.mu21); - ippiGetCentralMoment_64f(moment, 1, 2, 0, &m.mu12); - ippiGetCentralMoment_64f(moment, 0, 3, 0, &m.mu03); - ippiGetNormalizedCentralMoment_64f(moment, 2, 0, 0, &m.nu20); - ippiGetNormalizedCentralMoment_64f(moment, 1, 1, 0, &m.nu11); - ippiGetNormalizedCentralMoment_64f(moment, 0, 2, 0, &m.nu02); - ippiGetNormalizedCentralMoment_64f(moment, 3, 0, 0, &m.nu30); - ippiGetNormalizedCentralMoment_64f(moment, 2, 1, 0, &m.nu21); - ippiGetNormalizedCentralMoment_64f(moment, 1, 2, 0, &m.nu12); - ippiGetNormalizedCentralMoment_64f(moment, 0, 3, 0, &m.nu03); - - ippiMomentFree_64f(moment); - CV_IMPL_ADD(CV_IMPL_IPP); - return m; - } - setIppErrorStatus(); - } - ippiMomentFree_64f(moment); - } - else - setIppErrorStatus(); - CV_SUPPRESS_DEPRECATED_END + cv::Mat tmp(tileSize, CV_8U, nzbuf); + cv::compare( src, 0, tmp, CV_CMP_NE ); + src = tmp; } - } -#endif - if( binary || depth == CV_8U ) - func = momentsInTile; - else if( depth == CV_16U ) - func = momentsInTile; - else if( depth == CV_16S ) - func = momentsInTile; - else if( depth == CV_32F ) - func = momentsInTile; - else if( depth == CV_64F ) - func = momentsInTile; - else - CV_Error( CV_StsUnsupportedFormat, "" ); + double mom[10]; + func( src, mom ); - Mat src0(mat); - - for( int y = 0; y < size.height; y += TILE_SIZE ) - { - Size tileSize; - tileSize.height = std::min(TILE_SIZE, size.height - y); - - for( int x = 0; x < size.width; x += TILE_SIZE ) + if(binary) { - tileSize.width = std::min(TILE_SIZE, size.width - x); - Mat src(src0, cv::Rect(x, y, tileSize.width, tileSize.height)); - - if( binary ) - { - cv::Mat tmp(tileSize, CV_8U, nzbuf); - cv::compare( src, 0, tmp, CV_CMP_NE ); - src = tmp; - } - - double mom[10]; - func( src, mom ); - - if(binary) - { - double s = 1./255; - for( int k = 0; k < 10; k++ ) - mom[k] *= s; - } - - double xm = x * mom[0], ym = y * mom[0]; - - // accumulate moments computed in each tile - - // + m00 ( = m00' ) - m.m00 += mom[0]; - - // + m10 ( = m10' + x*m00' ) - m.m10 += mom[1] + xm; - - // + m01 ( = m01' + y*m00' ) - m.m01 += mom[2] + ym; - - // + m20 ( = m20' + 2*x*m10' + x*x*m00' ) - m.m20 += mom[3] + x * (mom[1] * 2 + xm); - - // + m11 ( = m11' + x*m01' + y*m10' + x*y*m00' ) - m.m11 += mom[4] + x * (mom[2] + ym) + y * mom[1]; - - // + m02 ( = m02' + 2*y*m01' + y*y*m00' ) - m.m02 += mom[5] + y * (mom[2] * 2 + ym); - - // + m30 ( = m30' + 3*x*m20' + 3*x*x*m10' + x*x*x*m00' ) - m.m30 += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm)); - - // + m21 ( = m21' + x*(2*m11' + 2*y*m10' + x*m01' + x*y*m00') + y*m20') - m.m21 += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3]; - - // + m12 ( = m12' + y*(2*m11' + 2*x*m01' + y*m10' + x*y*m00') + x*m02') - m.m12 += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5]; - - // + m03 ( = m03' + 3*y*m02' + 3*y*y*m01' + y*y*y*m00' ) - m.m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym)); + double s = 1./255; + for( int k = 0; k < 10; k++ ) + mom[k] *= s; } + + double xm = x * mom[0], ym = y * mom[0]; + + // accumulate moments computed in each tile + + // + m00 ( = m00' ) + m.m00 += mom[0]; + + // + m10 ( = m10' + x*m00' ) + m.m10 += mom[1] + xm; + + // + m01 ( = m01' + y*m00' ) + m.m01 += mom[2] + ym; + + // + m20 ( = m20' + 2*x*m10' + x*x*m00' ) + m.m20 += mom[3] + x * (mom[1] * 2 + xm); + + // + m11 ( = m11' + x*m01' + y*m10' + x*y*m00' ) + m.m11 += mom[4] + x * (mom[2] + ym) + y * mom[1]; + + // + m02 ( = m02' + 2*y*m01' + y*y*m00' ) + m.m02 += mom[5] + y * (mom[2] * 2 + ym); + + // + m30 ( = m30' + 3*x*m20' + 3*x*x*m10' + x*x*x*m00' ) + m.m30 += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm)); + + // + m21 ( = m21' + x*(2*m11' + 2*y*m10' + x*m01' + x*y*m00') + y*m20') + m.m21 += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3]; + + // + m12 ( = m12' + y*(2*m11' + 2*x*m01' + y*m10' + x*y*m00') + x*m02') + m.m12 += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5]; + + // + m03 ( = m03' + 3*y*m02' + 3*y*y*m01' + y*y*y*m00' ) + m.m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym)); } } diff --git a/modules/imgproc/src/pyramids.cpp b/modules/imgproc/src/pyramids.cpp index ff260d1783..86d376bbd2 100644 --- a/modules/imgproc/src/pyramids.cpp +++ b/modules/imgproc/src/pyramids.cpp @@ -1200,7 +1200,7 @@ static bool ipp_pyrdown( InputArray _src, OutputArray _dst, const Size& _dsz, in { CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if IPP_VERSION_X100 >= 810 && !IPP_DISABLE_PYRAMIDS_DOWN Size dsz = _dsz.area() == 0 ? Size((_src.cols() + 1)/2, (_src.rows() + 1)/2) : _dsz; bool isolated = (borderType & BORDER_ISOLATED) != 0; int borderTypeNI = borderType & ~BORDER_ISOLATED; @@ -1235,7 +1235,7 @@ static bool ipp_pyrdown( InputArray _src, OutputArray _dst, const Size& _dsz, in CV_SUPPRESS_DEPRECATED_END if (ok >= 0) { - Ipp8u* buffer = ippsMalloc_8u(bufferSize); + Ipp8u* buffer = ippsMalloc_8u_L(bufferSize); ok = pyrUpFunc(src.data, (int) src.step, dst.data, (int) dst.step, srcRoi, buffer); ippsFree(buffer); @@ -1388,7 +1388,7 @@ static bool ipp_pyrup( InputArray _src, OutputArray _dst, const Size& _dsz, int { CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if IPP_VERSION_X100 >= 810 && !IPP_DISABLE_PYRAMIDS_UP Size sz = _src.dims() <= 2 ? _src.size() : Size(); Size dsz = _dsz.area() == 0 ? Size(_src.cols()*2, _src.rows()*2) : _dsz; @@ -1421,7 +1421,7 @@ static bool ipp_pyrup( InputArray _src, OutputArray _dst, const Size& _dsz, int CV_SUPPRESS_DEPRECATED_END if (ok >= 0) { - Ipp8u* buffer = ippsMalloc_8u(bufferSize); + Ipp8u* buffer = ippsMalloc_8u_L(bufferSize); ok = pyrUpFunc(src.data, (int) src.step, dst.data, (int) dst.step, srcRoi, buffer); ippsFree(buffer); @@ -1496,7 +1496,7 @@ static bool ipp_buildpyramid( InputArray _src, OutputArrayOfArrays _dst, int max { CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if IPP_VERSION_X100 >= 810 && !IPP_DISABLE_PYRAMIDS_BUILD Mat src = _src.getMat(); _dst.create( maxlevel + 1, 1, 0 ); _dst.getMatRef(0) = src; @@ -1626,7 +1626,7 @@ void cv::buildPyramid( InputArray _src, OutputArrayOfArrays _dst, int maxlevel, int i=1; - CV_IPP_RUN(((IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK) && ((borderType & ~BORDER_ISOLATED) == BORDER_DEFAULT && (!_src.isSubmatrix() || ((borderType & BORDER_ISOLATED) != 0)))), + CV_IPP_RUN(((IPP_VERSION_X100 >= 810) && ((borderType & ~BORDER_ISOLATED) == BORDER_DEFAULT && (!_src.isSubmatrix() || ((borderType & BORDER_ISOLATED) != 0)))), ipp_buildpyramid( _src, _dst, maxlevel, borderType)); for( ; i <= maxlevel; i++ ) diff --git a/modules/imgproc/src/smooth.cpp b/modules/imgproc/src/smooth.cpp index ae6629f57c..81d3a7ccb0 100644 --- a/modules/imgproc/src/smooth.cpp +++ b/modules/imgproc/src/smooth.cpp @@ -1734,98 +1734,84 @@ namespace cv } #endif -// TODO: IPP performance regression -#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK +#if defined(HAVE_IPP) namespace cv { -static bool ipp_boxfilter( InputArray _src, OutputArray _dst, int ddepth, - Size ksize, Point anchor, - bool normalize, int borderType ) +static bool ipp_boxfilter(Mat &src, Mat &dst, Size ksize, Point anchor, bool normalize, int borderType) { CV_INSTRUMENT_REGION_IPP() - int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype); - if( ddepth < 0 ) - ddepth = sdepth; - int ippBorderType = borderType & ~BORDER_ISOLATED; + // Problem with SSE42 optimization for 16s +#if IPP_DISABLE_PERF_BOX16S_SSE42 + if(src.depth() == CV_16S && !(ipp::getIppFeatures()&ippCPUID_AVX)) + return false; +#endif + + int stype = src.type(), cn = CV_MAT_CN(stype); + IppiBorderType ippBorderType = ippiGetBorderType(borderType & ~BORDER_ISOLATED); + IppDataType ippType = ippiGetDataType(stype); Point ocvAnchor, ippAnchor; ocvAnchor.x = anchor.x < 0 ? ksize.width / 2 : anchor.x; ocvAnchor.y = anchor.y < 0 ? ksize.height / 2 : anchor.y; ippAnchor.x = ksize.width / 2 - (ksize.width % 2 == 0 ? 1 : 0); ippAnchor.y = ksize.height / 2 - (ksize.height % 2 == 0 ? 1 : 0); - Mat src = _src.getMat(); - _dst.create( src.size(), CV_MAKETYPE(ddepth, cn) ); - Mat dst = _dst.getMat(); - if( borderType != BORDER_CONSTANT && normalize && (borderType & BORDER_ISOLATED) != 0 ) + if(normalize && (!src.isSubmatrix() || borderType&BORDER_ISOLATED) && stype == dst.type() && + (ippBorderType == ippBorderRepl || /* returns ippStsStepErr: Step value is not valid */ + ippBorderType == ippBorderConst || + ippBorderType == ippBorderMirror) && ocvAnchor == ippAnchor) // returns ippStsMaskSizeErr: mask has an illegal value { - if( src.rows == 1 ) - ksize.height = 1; - if( src.cols == 1 ) - ksize.width = 1; - } + IppStatus status; + Ipp32s bufSize = 0; + IppiSize roiSize = { dst.cols, dst.rows }; + IppiSize maskSize = { ksize.width, ksize.height }; + IppAutoBuffer buffer; - { - if (normalize && !src.isSubmatrix() && ddepth == sdepth && - (/*ippBorderType == BORDER_REPLICATE ||*/ /* returns ippStsStepErr: Step value is not valid */ - ippBorderType == BORDER_CONSTANT) && ocvAnchor == ippAnchor && - dst.cols != ksize.width && dst.rows != ksize.height) // returns ippStsMaskSizeErr: mask has an illegal value - { - Ipp32s bufSize = 0; - IppiSize roiSize = { dst.cols, dst.rows }, maskSize = { ksize.width, ksize.height }; + if(ippiFilterBoxBorderGetBufferSize(roiSize, maskSize, ippType, cn, &bufSize) < 0) + return false; -#define IPP_FILTER_BOX_BORDER(ippType, ippDataType, flavor) \ - do \ - { \ - if (ippiFilterBoxBorderGetBufferSize(roiSize, maskSize, ippDataType, cn, &bufSize) >= 0) \ - { \ - Ipp8u * buffer = ippsMalloc_8u(bufSize); \ - ippType borderValue[4] = { 0, 0, 0, 0 }; \ - ippBorderType = ippBorderType == BORDER_CONSTANT ? ippBorderConst : ippBorderRepl; \ - IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiFilterBoxBorder_##flavor, src.ptr(), (int)src.step, dst.ptr(), \ - (int)dst.step, roiSize, maskSize, \ - (IppiBorderType)ippBorderType, borderValue, buffer); \ - ippsFree(buffer); \ - if (status >= 0) \ - { \ - CV_IMPL_ADD(CV_IMPL_IPP); \ - return true; \ - } \ - } \ - } while ((void)0, 0) + buffer.allocate(bufSize); - if (stype == CV_8UC1) - IPP_FILTER_BOX_BORDER(Ipp8u, ipp8u, 8u_C1R); - else if (stype == CV_8UC3) - IPP_FILTER_BOX_BORDER(Ipp8u, ipp8u, 8u_C3R); - else if (stype == CV_8UC4) - IPP_FILTER_BOX_BORDER(Ipp8u, ipp8u, 8u_C4R); - - // Oct 2014: performance with BORDER_CONSTANT - //else if (stype == CV_16UC1) - // IPP_FILTER_BOX_BORDER(Ipp16u, ipp16u, 16u_C1R); - else if (stype == CV_16UC3) - IPP_FILTER_BOX_BORDER(Ipp16u, ipp16u, 16u_C3R); - else if (stype == CV_16UC4) - IPP_FILTER_BOX_BORDER(Ipp16u, ipp16u, 16u_C4R); - - // Oct 2014: performance with BORDER_CONSTANT - //else if (stype == CV_16SC1) - // IPP_FILTER_BOX_BORDER(Ipp16s, ipp16s, 16s_C1R); - else if (stype == CV_16SC3) - IPP_FILTER_BOX_BORDER(Ipp16s, ipp16s, 16s_C3R); - else if (stype == CV_16SC4) - IPP_FILTER_BOX_BORDER(Ipp16s, ipp16s, 16s_C4R); - - else if (stype == CV_32FC1) - IPP_FILTER_BOX_BORDER(Ipp32f, ipp32f, 32f_C1R); - else if (stype == CV_32FC3) - IPP_FILTER_BOX_BORDER(Ipp32f, ipp32f, 32f_C3R); - else if (stype == CV_32FC4) - IPP_FILTER_BOX_BORDER(Ipp32f, ipp32f, 32f_C4R); + #define IPP_FILTER_BOX_BORDER(ippType, flavor)\ + {\ + ippType borderValue[4] = { 0, 0, 0, 0 };\ + status = CV_INSTRUMENT_FUN_IPP(ippiFilterBoxBorder_##flavor, src.ptr(), (int)src.step, dst.ptr(),\ + (int)dst.step, roiSize, maskSize,\ + ippBorderType, borderValue, buffer);\ } -#undef IPP_FILTER_BOX_BORDER + + if (stype == CV_8UC1) + IPP_FILTER_BOX_BORDER(Ipp8u, 8u_C1R) + else if (stype == CV_8UC3) + IPP_FILTER_BOX_BORDER(Ipp8u, 8u_C3R) + else if (stype == CV_8UC4) + IPP_FILTER_BOX_BORDER(Ipp8u, 8u_C4R) + else if (stype == CV_16UC1) + IPP_FILTER_BOX_BORDER(Ipp16u, 16u_C1R) + else if (stype == CV_16UC3) + IPP_FILTER_BOX_BORDER(Ipp16u, 16u_C3R) + else if (stype == CV_16UC4) + IPP_FILTER_BOX_BORDER(Ipp16u, 16u_C4R) + else if (stype == CV_16SC1) + IPP_FILTER_BOX_BORDER(Ipp16s, 16s_C1R) + else if (stype == CV_16SC3) + IPP_FILTER_BOX_BORDER(Ipp16s, 16s_C3R) + else if (stype == CV_16SC4) + IPP_FILTER_BOX_BORDER(Ipp16s, 16s_C4R) + else if (stype == CV_32FC1) + IPP_FILTER_BOX_BORDER(Ipp32f, 32f_C1R) + else if (stype == CV_32FC3) + IPP_FILTER_BOX_BORDER(Ipp32f, 32f_C3R) + else if (stype == CV_32FC4) + IPP_FILTER_BOX_BORDER(Ipp32f, 32f_C4R) + else + return false; + + if(status >= 0) + return true; } +#undef IPP_FILTER_BOX_BORDER + return false; } } @@ -1866,19 +1852,7 @@ void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth, return; #endif -#if defined HAVE_IPP && IPP_DISABLE_BLOCK - int ippBorderType = borderType & ~BORDER_ISOLATED; - Point ocvAnchor, ippAnchor; - ocvAnchor.x = anchor.x < 0 ? ksize.width / 2 : anchor.x; - ocvAnchor.y = anchor.y < 0 ? ksize.height / 2 : anchor.y; - ippAnchor.x = ksize.width / 2 - (ksize.width % 2 == 0 ? 1 : 0); - ippAnchor.y = ksize.height / 2 - (ksize.height % 2 == 0 ? 1 : 0); - CV_IPP_RUN((normalize && !_src.isSubmatrix() && ddepth == sdepth && - (/*ippBorderType == BORDER_REPLICATE ||*/ /* returns ippStsStepErr: Step value is not valid */ - ippBorderType == BORDER_CONSTANT) && ocvAnchor == ippAnchor && - _dst.cols() != ksize.width && _dst.rows() != ksize.height), - ipp_boxfilter( _src, _dst, ddepth, ksize, anchor, normalize, borderType)); -#endif + CV_IPP_RUN_FAST(ipp_boxfilter(src, dst, ksize, anchor, normalize, borderType)); Point ofs; Size wsz(src.cols, src.rows); @@ -3691,53 +3665,6 @@ private: float *space_weight, *color_weight; }; -#if defined (HAVE_IPP) && IPP_DISABLE_BLOCK -class IPPBilateralFilter_8u_Invoker : - public ParallelLoopBody -{ -public: - IPPBilateralFilter_8u_Invoker(Mat &_src, Mat &_dst, double _sigma_color, double _sigma_space, int _radius, bool *_ok) : - ParallelLoopBody(), src(_src), dst(_dst), sigma_color(_sigma_color), sigma_space(_sigma_space), radius(_radius), ok(_ok) - { - *ok = true; - } - - virtual void operator() (const Range& range) const - { - int d = radius * 2 + 1; - IppiSize kernel = {d, d}; - IppiSize roi={dst.cols, range.end - range.start}; - int bufsize=0; - if (0 > ippiFilterBilateralGetBufSize_8u_C1R( ippiFilterBilateralGauss, roi, kernel, &bufsize)) - { - *ok = false; - return; - } - AutoBuffer buf(bufsize); - IppiFilterBilateralSpec *pSpec = (IppiFilterBilateralSpec *)alignPtr(&buf[0], 32); - if (0 > ippiFilterBilateralInit_8u_C1R( ippiFilterBilateralGauss, kernel, (Ipp32f)sigma_color, (Ipp32f)sigma_space, 1, pSpec )) - { - *ok = false; - return; - } - if (0 > ippiFilterBilateral_8u_C1R( src.ptr(range.start) + radius * ((int)src.step[0] + 1), (int)src.step[0], dst.ptr(range.start), (int)dst.step[0], roi, kernel, pSpec )) - *ok = false; - else - { - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); - } - } -private: - Mat &src; - Mat &dst; - double sigma_color; - double sigma_space; - int radius; - bool *ok; - const IPPBilateralFilter_8u_Invoker& operator= (const IPPBilateralFilter_8u_Invoker&); -}; -#endif - #ifdef HAVE_OPENCL static bool ocl_bilateralFilter_8u(InputArray _src, OutputArray _dst, int d, @@ -3861,24 +3788,6 @@ bilateralFilter_8u( const Mat& src, Mat& dst, int d, Mat temp; copyMakeBorder( src, temp, radius, radius, radius, radius, borderType ); -#if defined HAVE_IPP && (IPP_VERSION_X100 >= 700) && IPP_DISABLE_BLOCK - CV_IPP_CHECK() - { - if( cn == 1 ) - { - bool ok; - IPPBilateralFilter_8u_Invoker body(temp, dst, sigma_color * sigma_color, sigma_space * sigma_space, radius, &ok ); - parallel_for_(Range(0, dst.rows), body, dst.total()/(double)(1<<16)); - if( ok ) - { - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); - return; - } - setIppErrorStatus(); - } - } -#endif - std::vector _color_weight(cn*256); std::vector _space_weight(d*d); std::vector _space_ofs(d*d); @@ -4293,6 +4202,107 @@ bilateralFilter_32f( const Mat& src, Mat& dst, int d, parallel_for_(Range(0, size.height), body, dst.total()/(double)(1<<16)); } +#ifdef HAVE_IPP +#define IPP_BILATERAL_PARALLEL 1 + +#ifdef HAVE_IPP_IW +class ipp_bilateralFilterParallel: public ParallelLoopBody +{ +public: + ipp_bilateralFilterParallel(::ipp::IwiImage &_src, ::ipp::IwiImage &_dst, int _radius, Ipp32f _valSquareSigma, Ipp32f _posSquareSigma, ::ipp::IwiBorderType _borderType, bool *_ok): + src(_src), dst(_dst) + { + pOk = _ok; + + radius = _radius; + valSquareSigma = _valSquareSigma; + posSquareSigma = _posSquareSigma; + borderType = _borderType; + + *pOk = true; + } + ~ipp_bilateralFilterParallel() {} + + virtual void operator() (const Range& range) const + { + if(*pOk == false) + return; + + try + { + ::ipp::IwiRoi roi = ::ipp::IwiRect(0, range.start, dst.m_size.width, range.end - range.start); + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterBilateral, &src, &dst, radius, valSquareSigma, posSquareSigma, ippiFilterBilateralGauss, ippDistNormL1, borderType, &roi); + } + catch(::ipp::IwException) + { + *pOk = false; + return; + } + } +private: + ::ipp::IwiImage &src; + ::ipp::IwiImage &dst; + + int radius; + Ipp32f valSquareSigma; + Ipp32f posSquareSigma; + ::ipp::IwiBorderType borderType; + + bool *pOk; + const ipp_bilateralFilterParallel& operator= (const ipp_bilateralFilterParallel&); +}; +#endif + +static bool ipp_bilateralFilter(Mat &src, Mat &dst, int d, double sigmaColor, double sigmaSpace, int borderType) +{ +#ifdef HAVE_IPP_IW + CV_INSTRUMENT_REGION_IPP() + + int radius = IPP_MAX(((d <= 0)?cvRound(sigmaSpace*1.5):d/2), 1); + Ipp32f valSquareSigma = (Ipp32f)((sigmaColor <= 0)?1:sigmaColor*sigmaColor); + Ipp32f posSquareSigma = (Ipp32f)((sigmaSpace <= 0)?1:sigmaSpace*sigmaSpace); + + // Acquire data and begin processing + try + { + ::ipp::IwiImage iwSrc = ippiGetImage(src); + ::ipp::IwiImage iwDst = ippiGetImage(dst); + ::ipp::IwiBorderSize borderSize(radius); + ::ipp::IwiBorderType ippBorder(ippiGetBorder(iwSrc, borderType, borderSize)); + if(!ippBorder.m_borderType) + return false; + + // IW 2017u2 has bug which doesn't allow use of partial inMem with tiling + if((((ippBorder.m_borderFlags)&ippBorderInMem) && ((ippBorder.m_borderFlags)&ippBorderInMem) != ippBorderInMem)) + return false; + + bool ok = true; + int threads = ippiSuggestThreadsNum(iwDst, 2); + Range range(0, (int)iwDst.m_size.height); + ipp_bilateralFilterParallel invoker(iwSrc, iwDst, radius, valSquareSigma, posSquareSigma, ippBorder, &ok); + if(!ok) + return false; + + if(IPP_BILATERAL_PARALLEL && threads > 1) + parallel_for_(range, invoker, threads*4); + else + invoker(range); + + if(!ok) + return false; + } + catch (::ipp::IwException) + { + return false; + } + return true; +#else + CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(d); CV_UNUSED(sigmaColor); CV_UNUSED(sigmaSpace); CV_UNUSED(borderType); + return false; +#endif +} +#endif + } void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d, @@ -4308,6 +4318,8 @@ void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d, Mat src = _src.getMat(), dst = _dst.getMat(); + CV_IPP_RUN_FAST(ipp_bilateralFilter(src, dst, d, sigmaColor, sigmaSpace, borderType)); + if( src.depth() == CV_8U ) bilateralFilter_8u( src, dst, d, sigmaColor, sigmaSpace, borderType ); else if( src.depth() == CV_32F ) diff --git a/modules/imgproc/src/sumpixels.cpp b/modules/imgproc/src/sumpixels.cpp index c9793b299a..d19ef3b0a9 100755 --- a/modules/imgproc/src/sumpixels.cpp +++ b/modules/imgproc/src/sumpixels.cpp @@ -405,58 +405,43 @@ static bool ipp_integral( const uchar* src, size_t srcstep, uchar* sum, size_t sumstep, uchar* sqsum, size_t sqsumstep, + uchar* tilted, size_t tstep, int width, int height, int cn) { CV_INSTRUMENT_REGION_IPP() -#if IPP_VERSION_X100 != 900 // Disabled on ICV due invalid results - if( sdepth <= 0 ) - sdepth = depth == CV_8U ? CV_32S : CV_64F; - if ( sqdepth <= 0 ) - sqdepth = CV_64F; - sdepth = CV_MAT_DEPTH(sdepth), sqdepth = CV_MAT_DEPTH(sqdepth); + IppiSize size = {width, height}; - if( ( depth == CV_8U ) && ( sdepth == CV_32F || sdepth == CV_32S ) && ( !sqsum || sqdepth == CV_64F ) && ( cn == 1 ) ) + if(cn > 1) + return false; + if(tilted) { - IppStatus status = ippStsErr; - IppiSize srcRoiSize = ippiSize( width, height ); - if( sdepth == CV_32F ) - { - if( sqsum ) - { - status = CV_INSTRUMENT_FUN_IPP(ippiSqrIntegral_8u32f64f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32f*)sum, (int)sumstep, (Ipp64f*)sqsum, (int)sqsumstep, srcRoiSize, 0, 0); - } - else - { - status = CV_INSTRUMENT_FUN_IPP(ippiIntegral_8u32f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32f*)sum, (int)sumstep, srcRoiSize, 0); - } - } - else if( sdepth == CV_32S ) - { - if( sqsum ) - { - status = CV_INSTRUMENT_FUN_IPP(ippiSqrIntegral_8u32s64f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32s*)sum, (int)sumstep, (Ipp64f*)sqsum, (int)sqsumstep, srcRoiSize, 0, 0); - } - else - { - status = CV_INSTRUMENT_FUN_IPP(ippiIntegral_8u32s_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32s*)sum, (int)sumstep, srcRoiSize, 0); - } - } - if (0 <= status) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return true; - } + CV_UNUSED(tstep); + return false; + } + + if(!sqsum) + { + if(depth == CV_8U && sdepth == CV_32S) + return CV_INSTRUMENT_FUN_IPP(ippiIntegral_8u32s_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32s*)sum, (int)sumstep, size, 0) >= 0; + else if(depth == CV_8UC1 && sdepth == CV_32F) + return CV_INSTRUMENT_FUN_IPP(ippiIntegral_8u32f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32f*)sum, (int)sumstep, size, 0) >= 0; + else if(depth == CV_32FC1 && sdepth == CV_32F) + return CV_INSTRUMENT_FUN_IPP(ippiIntegral_32f_C1R, (const Ipp32f*)src, (int)srcstep, (Ipp32f*)sum, (int)sumstep, size) >= 0; + else + return false; + } + else + { + if(depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32S) + return CV_INSTRUMENT_FUN_IPP(ippiSqrIntegral_8u32s_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32s*)sum, (int)sumstep, (Ipp32s*)sqsum, (int)sqsumstep, size, 0, 0) >= 0; + else if(depth == CV_8U && sdepth == CV_32S && sqdepth == CV_64F) + return CV_INSTRUMENT_FUN_IPP(ippiSqrIntegral_8u32s64f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32s*)sum, (int)sumstep, (Ipp64f*)sqsum, (int)sqsumstep, size, 0, 0) >= 0; + else if(depth == CV_8U && sdepth == CV_32F && sqdepth == CV_64F) + return CV_INSTRUMENT_FUN_IPP(ippiSqrIntegral_8u32f64f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32f*)sum, (int)sumstep, (Ipp64f*)sqsum, (int)sqsumstep, size, 0, 0) >= 0; + else + return false; } -#else - CV_UNUSED(depth); CV_UNUSED(sdepth); CV_UNUSED(sqdepth); - CV_UNUSED(src); CV_UNUSED(srcstep); - CV_UNUSED(sum); CV_UNUSED(sumstep); - CV_UNUSED(sqsum); CV_UNUSED(sqsumstep); - CV_UNUSED(tilted); CV_UNUSED(tstep); - CV_UNUSED(width); CV_UNUSED(height); CV_UNUSED(cn); -#endif - return false; } } #endif @@ -471,12 +456,7 @@ void integral(int depth, int sdepth, int sqdepth, int width, int height, int cn) { CALL_HAL(integral, cv_hal_integral, depth, sdepth, sqdepth, src, srcstep, sum, sumstep, sqsum, sqsumstep, tilted, tstep, width, height, cn); - CV_IPP_RUN(( depth == CV_8U ) - && ( sdepth == CV_32F || sdepth == CV_32S ) - && ( !tilted ) - && ( !sqsum || sqdepth == CV_64F ) - && ( cn == 1 ), - ipp_integral(depth, sdepth, sqdepth, src, srcstep, sum, sumstep, sqsum, sqsumstep, width, height, cn)); + CV_IPP_RUN_FAST(ipp_integral(depth, sdepth, sqdepth, src, srcstep, sum, sumstep, sqsum, sqsumstep, tilted, tstep, width, height, cn)); #define ONE_CALL(A, B, C) integral_((const A*)src, srcstep, (B*)sum, sumstep, (C*)sqsum, sqsumstep, (B*)tilted, tstep, width, height, cn) diff --git a/modules/imgproc/test/test_bilateral_filter.cpp b/modules/imgproc/test/test_bilateral_filter.cpp index 994f8544e8..48f066b6cd 100644 --- a/modules/imgproc/test/test_bilateral_filter.cpp +++ b/modules/imgproc/test/test_bilateral_filter.cpp @@ -251,20 +251,23 @@ namespace cvtest int CV_BilateralFilterTest::validate_test_results(int test_case_index) { - static const double eps = 4; - + double eps = (_src.depth() < CV_32F)?1:5e-3; + double e; Mat reference_dst, reference_src; if (_src.depth() == CV_32F) + { reference_bilateral_filter(_src, reference_dst, _d, _sigma_color, _sigma_space); + e = cvtest::norm(reference_dst, _parallel_dst, NORM_INF|NORM_RELATIVE); + } else { int type = _src.type(); _src.convertTo(reference_src, CV_32F); reference_bilateral_filter(reference_src, reference_dst, _d, _sigma_color, _sigma_space); reference_dst.convertTo(reference_dst, type); + e = cvtest::norm(reference_dst, _parallel_dst, NORM_INF); } - double e = cvtest::norm(reference_dst, _parallel_dst, NORM_L2); if (e > eps) { ts->printf(cvtest::TS::CONSOLE, "actual error: %g, expected: %g", e, eps); diff --git a/modules/imgproc/test/test_houghLines.cpp b/modules/imgproc/test/test_houghLines.cpp index 93a1202ee1..a233342ae2 100644 --- a/modules/imgproc/test/test_houghLines.cpp +++ b/modules/imgproc/test/test_houghLines.cpp @@ -189,7 +189,7 @@ void BaseHoughLineTest::run_test(int type) else if (type == PROBABILISTIC) count = countMatIntersection(exp_lines, lines, 1e-4f, 0.f); -#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK +#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_HOUGH EXPECT_GE( count, (int) (exp_lines.total() * 0.8) ); #else EXPECT_EQ( count, (int) exp_lines.total()); diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index 1670ddf69f..57994fc385 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -484,6 +484,8 @@ bool FeatureEvaluator::updateScaleData( Size imgsz, const std::vector& _s bool FeatureEvaluator::setImage( InputArray _image, const std::vector& _scales ) { + CV_INSTRUMENT_REGION() + Size imgsz = _image.size(); bool recalcOptFeatures = updateScaleData(imgsz, _scales); @@ -628,6 +630,8 @@ Ptr HaarEvaluator::clone() const void HaarEvaluator::computeChannels(int scaleIdx, InputArray img) { + CV_INSTRUMENT_REGION() + const ScaleData& s = scaleData->at(scaleIdx); sqofs = hasTiltedFeatures ? sbufSize.area() * 2 : sbufSize.area(); @@ -670,6 +674,8 @@ void HaarEvaluator::computeChannels(int scaleIdx, InputArray img) void HaarEvaluator::computeOptFeatures() { + CV_INSTRUMENT_REGION() + if (hasTiltedFeatures) tofs = sbufSize.area(); @@ -916,6 +922,8 @@ void CascadeClassifierImpl::read(const FileNode& node) int CascadeClassifierImpl::runAt( Ptr& evaluator, Point pt, int scaleIdx, double& weight ) { + CV_INSTRUMENT_REGION() + assert( !oldCascade && (data.featureType == FeatureEvaluator::HAAR || data.featureType == FeatureEvaluator::LBP || @@ -984,6 +992,8 @@ public: void operator()(const Range& range) const { + CV_INSTRUMENT_REGION() + Ptr evaluator = classifier->featureEvaluator->clone(); double gypWeight = 0.; Size origWinSize = classifier->data.origWinSize; diff --git a/modules/objdetect/src/cascadedetect.hpp b/modules/objdetect/src/cascadedetect.hpp index a395428d67..f359ef5623 100644 --- a/modules/objdetect/src/cascadedetect.hpp +++ b/modules/objdetect/src/cascadedetect.hpp @@ -489,6 +489,8 @@ template inline int predictOrdered( CascadeClassifierImpl& cascade, Ptr &_featureEvaluator, double& sum ) { + CV_INSTRUMENT_REGION() + int nstages = (int)cascade.data.stages.size(); int nodeOfs = 0, leafOfs = 0; FEval& featureEvaluator = (FEval&)*_featureEvaluator; @@ -529,6 +531,8 @@ template inline int predictCategorical( CascadeClassifierImpl& cascade, Ptr &_featureEvaluator, double& sum ) { + CV_INSTRUMENT_REGION() + int nstages = (int)cascade.data.stages.size(); int nodeOfs = 0, leafOfs = 0; FEval& featureEvaluator = (FEval&)*_featureEvaluator; @@ -571,6 +575,8 @@ template inline int predictOrderedStump( CascadeClassifierImpl& cascade, Ptr &_featureEvaluator, double& sum ) { + CV_INSTRUMENT_REGION() + CV_Assert(!cascade.data.stumps.empty()); FEval& featureEvaluator = (FEval&)*_featureEvaluator; const CascadeClassifierImpl::Data::Stump* cascadeStumps = &cascade.data.stumps[0]; @@ -608,6 +614,8 @@ template inline int predictCategoricalStump( CascadeClassifierImpl& cascade, Ptr &_featureEvaluator, double& sum ) { + CV_INSTRUMENT_REGION() + CV_Assert(!cascade.data.stumps.empty()); int nstages = (int)cascade.data.stages.size(); FEval& featureEvaluator = (FEval&)*_featureEvaluator; diff --git a/modules/objdetect/src/haar.cpp b/modules/objdetect/src/haar.cpp index bb37ee91e0..c66d4de329 100644 --- a/modules/objdetect/src/haar.cpp +++ b/modules/objdetect/src/haar.cpp @@ -340,8 +340,8 @@ icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) out->isStumpBased &= node_count == 1; } } -/* -#ifdef HAVE_IPP + +#if defined HAVE_IPP && !IPP_DISABLE_HAAR int can_use_ipp = CV_IPP_CHECK_COND && (!out->has_tilted_features && !out->is_tree && out->isStumpBased); if( can_use_ipp ) @@ -396,7 +396,7 @@ icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) } } #endif -*/ + cascade->hid_cascade = out; assert( (char*)haar_node_ptr - (char*)out <= datasize ); From 21be2aa677d8eaad48956b431260e64f626167a0 Mon Sep 17 00:00:00 2001 From: Pyotr Chekmaryov <4ekmah@gmail.com> Date: Tue, 25 Apr 2017 21:00:31 +0000 Subject: [PATCH 118/144] Memory repaired + Cleanup. --- modules/calib3d/src/stereosgbm.cpp | 596 ++++--------------- modules/calib3d/test/test_stereomatching.cpp | 39 +- 2 files changed, 144 insertions(+), 491 deletions(-) diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp index 5f841775ec..678f937abe 100644 --- a/modules/calib3d/src/stereosgbm.cpp +++ b/modules/calib3d/src/stereosgbm.cpp @@ -125,7 +125,6 @@ static void calcPixelCostBT( const Mat& img1, const Mat& img2, int y, int minD, int maxD, CostType* cost, PixType* buffer, const PixType* tab, int tabOfs, int , int xrange_min = 0, int xrange_max = DEFAULT_RIGHT_BORDER ) - //TODO: This function was changed and modified old function's behabior. Check they in tests { int x, c, width = img1.cols, cn = img1.channels(); int minX1 = std::max(maxD, 0), maxX1 = width + std::min(minD, 0); @@ -311,9 +310,9 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, const CostType MAX_COST = SHRT_MAX; int minD = params.minDisparity, maxD = minD + params.numDisparities; - Size SADWindowSize; //4e: SAD means Sum of Absolute Differences - SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; //4e: and this is always square - int ftzero = std::max(params.preFilterCap, 15) | 1; //4e:ftzero clips x-derivatives. I think, this story with arrays is about non-realized SIMD method + Size SADWindowSize; + SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; + int ftzero = std::max(params.preFilterCap, 15) | 1; int uniquenessRatio = params.uniquenessRatio >= 0 ? params.uniquenessRatio : 10; int disp12MaxDiff = params.disp12MaxDiff > 0 ? params.disp12MaxDiff : 1; int P1 = params.P1 > 0 ? params.P1 : 2, P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); @@ -323,11 +322,11 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, int INVALID_DISP = minD - 1, INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; int SW2 = SADWindowSize.width/2, SH2 = SADWindowSize.height/2; bool fullDP = params.mode == StereoSGBM::MODE_HH; - int npasses = fullDP ? 2 : 1; //4e: 2 passes with different behaviour for Hirshmueller method. - const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; //4e: array is such big due to derivative could be +-8*256 in worst cases + int npasses = fullDP ? 2 : 1; + const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; PixType clipTab[TAB_SIZE]; - for( k = 0; k < TAB_SIZE; k++ ) //4e: If ftzero would = 4, array containment will be = -4 -4 -4 ... -4 -3 -2 -1 0 1 2 3 4 ... 4 4 4 + for( k = 0; k < TAB_SIZE; k++ ) clipTab[k] = (PixType)(std::min(std::max(k - TAB_OFS, -ftzero), ftzero) + ftzero); if( minX1 >= maxX1 ) @@ -340,25 +339,25 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, // NR - the number of directions. the loop on x below that computes Lr assumes that NR == 8. // if you change NR, please, modify the loop as well. - int D2 = D+16, NRD2 = NR2*D2; //4e: Somewhere in code we need d+1, so D+1. One of simplest solutuons is increasing D-dimension on 1. But 1 is 16, when storage should be aligned. + int D2 = D+16, NRD2 = NR2*D2; // the number of L_r(.,.) and min_k L_r(.,.) lines in the buffer: // for 8-way dynamic programming we need the current row and // the previous row, i.e. 2 rows in total - const int NLR = 2; //4e: We assume, that we need one or more previous steps in our linear dynamic(one right here). - const int LrBorder = NLR - 1; //4e: for simplification of calculations we need border for taking previous dynamic solutions. + const int NLR = 2; + const int LrBorder = NLR - 1; // for each possible stereo match (img1(x,y) <=> img2(x-d,y)) // we keep pixel difference cost (C) and the summary cost over NR directions (S). // we also keep all the partial costs for the previous line L_r(x,d) and also min_k L_r(x, k) size_t costBufSize = width1*D; - size_t CSBufSize = costBufSize*(fullDP ? height : 1); //4e: For HH mode it's better to keep whole array of costs. - size_t minLrSize = (width1 + LrBorder*2)*NR2, LrSize = minLrSize*D2; //4e: TODO: Understand why NR2 per pass instead od NR2/2 (Probably, without any reason. That doesn't make code wrong) + size_t CSBufSize = costBufSize*(fullDP ? height : 1); + size_t minLrSize = (width1 + LrBorder*2)*NR2, LrSize = minLrSize*D2; int hsumBufNRows = SH2*2 + 2; size_t totalBufSize = (LrSize + minLrSize)*NLR*sizeof(CostType) + // minLr[] and Lr[] - costBufSize*(hsumBufNRows + 1)*sizeof(CostType) + // hsumBuf, pixdiff //4e: TODO: Why we should increase sum window height one more time? - CSBufSize*2*sizeof(CostType) + // C, S //4e: C is Block sum of costs, S is multidirectional dynamic sum with same size - width*16*img1.channels()*sizeof(PixType) + // temp buffer for computing per-pixel cost //4e: It is needed for calcPixelCostBT function, as "buffer" value + costBufSize*(hsumBufNRows + 1)*sizeof(CostType) + // hsumBuf, pixdiff + CSBufSize*2*sizeof(CostType) + // C, S + width*16*img1.channels()*sizeof(PixType) + // temp buffer for computing per-pixel cost width*(sizeof(CostType) + sizeof(DispType)) + 1024; // disp2cost + disp2 if( buffer.empty() || !buffer.isContinuous() || @@ -371,7 +370,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, CostType* hsumBuf = Sbuf + CSBufSize; CostType* pixDiff = hsumBuf + costBufSize*hsumBufNRows; - CostType* disp2cost = pixDiff + costBufSize + (LrSize + minLrSize)*NLR; //4e: It is containers for backwards disparity, made by S[d] too, but with other method + CostType* disp2cost = pixDiff + costBufSize + (LrSize + minLrSize)*NLR; DispType* disp2ptr = (DispType*)(disp2cost + width); PixType* tempBuf = (PixType*)(disp2ptr + width); @@ -383,21 +382,21 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, { int x1, y1, x2, y2, dx, dy; - if( pass == 1 ) //4e: on the first pass, we work down, so calculate directions down, diagdown and right + if( pass == 1 ) { y1 = 0; y2 = height; dy = 1; x1 = 0; x2 = width1; dx = 1; } - else //4e: on the second pass, we work up, so calculate directions up, diagup and up + else { y1 = height-1; y2 = -1; dy = -1; x1 = width1-1; x2 = -1; dx = -1; } - CostType *Lr[NLR]={0}, *minLr[NLR]={0}; //4e: arrays for L(x,y,r,d) of previous and current rows and minimums of them + CostType *Lr[NLR]={0}, *minLr[NLR]={0}; - for( k = 0; k < NLR; k++ ) //4e: One of them is needed, and one of them is stored. So, we need to swap pointer - { //4e: Yes, and this is done at the end of next cycle, not here. + for( k = 0; k < NLR; k++ ) + { // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, // and will occasionally use negative indices with the arrays // we need to shift Lr[k] pointers by 1, to give the space for d=-1. @@ -418,28 +417,28 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, if( pass == 1 ) // compute C on the first pass, and reuse it on the second pass, if any. { - int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; //4e: for first line's block sum we need calculate half-window of costs and only one for other + int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; for( k = dy1; k <= dy2; k++ ) { - CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; //4e: Ring buffer for horizontally summed lines + CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; if( k < height ) { calcPixelCostBT( img1, img2, k, minD, maxD, pixDiff, tempBuf, clipTab, TAB_OFS, ftzero ); memset(hsumAdd, 0, D*sizeof(CostType)); - for( x = 0; x <= SW2*D; x += D ) //4e: Calculation summed costs for all disparities in first pixel of line + for( x = 0; x <= SW2*D; x += D ) { int scale = x == 0 ? SW2 + 1 : 1; for( d = 0; d < D; d++ ) hsumAdd[d] = (CostType)(hsumAdd[d] + pixDiff[x + d]*scale); } - if( y > 0 ) //4e: We calculate horizontal sums and forming full block sums for y coord by adding this horsums to previous line's sums and subtracting stored lowest - { //4e: horsum in hsumBuf. Exception is case y=0, where we need many iterations per lines to create full blocking sum. + if( y > 0 ) + { const CostType* hsumSub = hsumBuf + (std::max(y - SH2 - 1, 0) % hsumBufNRows)*costBufSize; - const CostType* Cprev = !fullDP || y == 0 ? C : C - costBufSize; //4e: Well, actually y>0, so we don't need this check: y==0 + const CostType* Cprev = !fullDP || y == 0 ? C : C - costBufSize; for( x = D; x < width1*D; x += D ) { @@ -475,8 +474,8 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } else { - for( x = D; x < width1*D; x += D ) //4e: Calcluates horizontal sums if (y==0). This piece of code is calling SH2+1 times and then result is used in different way - { //4e: to create full blocks sum. That's why this code is isolated from upper case. + for( x = D; x < width1*D; x += D ) + { const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); @@ -486,7 +485,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } } - if( y == 0 ) //4e: Calculating first full block sum. + if( y == 0 ) { int scale = k == 0 ? SH2 + 1 : 1; for( x = 0; x < width1*D; x++ ) @@ -495,13 +494,13 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } // also, clear the S buffer - for( k = 0; k < width1*D; k++ ) //4e: only on first pass, so it keep old information, don't be confused + for( k = 0; k < width1*D; k++ ) S[k] = 0; } // clear the left and the right borders - memset( Lr[0] - NRD2*LrBorder - 8, 0, NRD2*LrBorder*sizeof(CostType) ); //4e: To understand this "8" shifts and how they could work it's simpler to imagine pixel dislocation in memory - memset( Lr[0] + width1*NRD2 - 8, 0, NRD2*LrBorder*sizeof(CostType) ); //4e: ...00000000|NRD2-16 of real costs value(and some of them are zeroes too)|00000000... + memset( Lr[0] - NRD2*LrBorder - 8, 0, NRD2*LrBorder*sizeof(CostType) ); + memset( Lr[0] + width1*NRD2 - 8, 0, NRD2*LrBorder*sizeof(CostType) ); memset( minLr[0] - NR2*LrBorder, 0, NR2*LrBorder*sizeof(CostType) ); memset( minLr[0] + width1*NR2, 0, NR2*LrBorder*sizeof(CostType) ); @@ -624,7 +623,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, for( d = 0; d < D; d++ ) { - int Cpd = Cp[d], L0, L1, L2, L3; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + int Cpd = Cp[d], L0, L1, L2, L3; L0 = Cpd + std::min((int)Lr_p0[d], std::min(Lr_p0[d-1] + P1, std::min(Lr_p0[d+1] + P1, delta0))) - delta0; L1 = Cpd + std::min((int)Lr_p1[d], std::min(Lr_p1[d-1] + P1, std::min(Lr_p1[d+1] + P1, delta1))) - delta1; @@ -665,7 +664,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, CostType* Sp = S + x*D; int minS = MAX_COST, bestDisp = -1; - if( npasses == 1 ) //4e: in this case we could take fifth direction almost for free(direction "left") + if( npasses == 1 ) { int xm = x*NR2, xd = xm*D2; @@ -815,7 +814,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, disp1ptr[x + minX1] = (DispType)(d + minD*DISP_SCALE); } - for( x = minX1; x < maxX1; x++ ) //4e: Left-right check itself + for( x = minX1; x < maxX1; x++ ) { // we round the computed disparity both towards -inf and +inf and check // if either of the corresponding disparities in disp2 is consistent. @@ -826,8 +825,8 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, int _d = d1 >> DISP_SHIFT; int d_ = (d1 + DISP_SCALE-1) >> DISP_SHIFT; int _x = x - _d, x_ = x - d_; - if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && //4e: To dismiss disparity, we should assure, that there is no any - 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) //4e: chance to understand this as correct. + if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && + 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) disp1ptr[x] = (DispType)INVALID_DISP_SCALED; } } @@ -840,8 +839,6 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } //////////////////////////////////////////////////////////////////////////////////////////// -//TODO: Assumation: Let's pretend, that we allocate memory for pixDiff and tempBuf independently in each thread, with full size, needed for original calcBT -//TODO: Redo size of this arrays even if situation with independent allocation will still. struct CalcVerticalSums: public ParallelLoopBody { CalcVerticalSums(const Mat& _img1, const Mat& _img2, const StereoSGBMParams& params, @@ -852,7 +849,7 @@ struct CalcVerticalSums: public ParallelLoopBody SW2 = SH2 = (params.SADWindowSize > 0 ? params.SADWindowSize : 5)/2; ftzero = std::max(params.preFilterCap, 15) | 1; P1 = params.P1 > 0 ? params.P1 : 2; - P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion + P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); height = img1.rows; width = img1.cols; int minX1 = std::max(maxD, 0), maxX1 = width + std::min(minD, 0); @@ -861,7 +858,7 @@ struct CalcVerticalSums: public ParallelLoopBody D2 = D + 16; costBufSize = width1*D; CSBufSize = costBufSize*height; - minLrSize = (width1 + LrBorder*2); + minLrSize = width1; LrSize = minLrSize*D2; hsumBufNRows = SH2*2 + 2; Cbuf = alignedBuf; @@ -874,10 +871,11 @@ struct CalcVerticalSums: public ParallelLoopBody static const CostType MAX_COST = SHRT_MAX; static const int ALIGN = 16; static const int TAB_OFS = 256*4; + static const int npasses = 2; int x1 = range.start, x2 = range.end, k; size_t pixDiffSize = ((x2 - x1) + 2*SW2)*D; size_t auxBufsSize = pixDiffSize*sizeof(CostType) + //pixdiff size - width*16*img1.channels()*sizeof(PixType) + 32; //tempBuf //TODO: Probably it's better 6 instead of 16(alignment?) + width*16*img1.channels()*sizeof(PixType) + 32; //tempBuf Mat auxBuff; auxBuff.create(1, (int)auxBufsSize, CV_8U); CostType* pixDiff = (CostType*)alignPtr(auxBuff.ptr(), ALIGN); @@ -886,7 +884,7 @@ struct CalcVerticalSums: public ParallelLoopBody // Simplification of index calculation pixDiff -= (x1>SW2 ? (x1 - SW2): 0)*D; - for( int pass = 1; pass <= 2; pass++ ) //TODO: rename this magic 2. + for( int pass = 1; pass <= npasses; pass++ ) { int y1, y2, dy; @@ -899,18 +897,18 @@ struct CalcVerticalSums: public ParallelLoopBody y1 = height-1; y2 = -1; dy = -1; } - CostType *Lr[NLR]={0}, *minLr[NLR]={0}; //4e: arrays for L(x,y,r,d) of previous and current rows and minimums of them + CostType *Lr[NLR]={0}, *minLr[NLR]={0}; - for( k = 0; k < NLR; k++ ) //4e: One of them is needed, and one of them is stored. So, we need to swap pointer - { //4e: Yes, and this is done at the end of next cycle, not here. + for( k = 0; k < NLR; k++ ) + { // shift Lr[k] and minLr[k] pointers, because we allocated them with the borders, // and will occasionally use negative indices with the arrays // we need to shift Lr[k] pointers by 1, to give the space for d=-1. // however, then the alignment will be imperfect, i.e. bad for SSE, // thus we shift the pointers by 8 (8*sizeof(short) == 16 - ideal alignment) - Lr[k] = hsumBuf + costBufSize*hsumBufNRows + LrSize*k + D2*LrBorder + 8; + Lr[k] = hsumBuf + costBufSize*hsumBufNRows + LrSize*k + 8; memset( Lr[k] + x1*D2 - 8, 0, (x2-x1)*D2*sizeof(CostType) ); - minLr[k] = hsumBuf + costBufSize*hsumBufNRows + LrSize*NLR + minLrSize*k + LrBorder; + minLr[k] = hsumBuf + costBufSize*hsumBufNRows + LrSize*NLR + minLrSize*k; memset( minLr[k] + x1, 0, (x2-x1)*sizeof(CostType) ); } @@ -922,60 +920,37 @@ struct CalcVerticalSums: public ParallelLoopBody if( pass == 1 ) // compute C on the first pass, and reuse it on the second pass, if any. { - int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; //4e: for first line's block sum we need calculate half-window of costs and only one for other + int dy1 = y == 0 ? 0 : y + SH2, dy2 = y == 0 ? SH2 : dy1; for( k = dy1; k <= dy2; k++ ) { - CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; //4e: Ring buffer for horizontally summed lines + CostType* hsumAdd = hsumBuf + (std::min(k, height-1) % hsumBufNRows)*costBufSize; if( k < height ) { calcPixelCostBT( img1, img2, k, minD, maxD, pixDiff, tempBuf, clipTab, TAB_OFS, ftzero, x1 - SW2, x2 + SW2); memset(hsumAdd + x1*D, 0, D*sizeof(CostType)); - for( x = (x1 - SW2)*D; x <= (x1 + SW2)*D; x += D ) //4e: Calculation summed costs for all disparities in first pixel of line + for( x = (x1 - SW2)*D; x <= (x1 + SW2)*D; x += D ) { int xbord = x <= 0 ? 0 : (x > (width1 - 1)*D? (width1 - 1)*D : x); for( d = 0; d < D; d++ ) hsumAdd[x1*D + d] = (CostType)(hsumAdd[x1*D + d] + pixDiff[xbord + d]); } - if( y > 0 ) //4e: We calculate horizontal sums and forming full block sums for y coord by adding this horsums to previous line's sums and subtracting stored lowest - { //4e: horsum in hsumBuf. Exception is case y=0, where we need many iterations per lines to create full blocking sum. + if( y > 0 ) + { const CostType* hsumSub = hsumBuf + (std::max(y - SH2 - 1, 0) % hsumBufNRows)*costBufSize; const CostType* Cprev = C - costBufSize; - // We need to calculate C[x1] in different way, because hsumadd is already calculated - // We don't doing then for x==0, because original function has forgotten to do this //TODO: Check: does this original still exist? - if(x1!=0) - { - for( d = 0; d < D; d++ ) - C[x1*D + d] = (CostType)(Cprev[x1*D + d] + hsumAdd[x1*D + d] - hsumSub[x1*D + d]); - } + for( d = 0; d < D; d++ ) + C[x1*D + d] = (CostType)(Cprev[x1*D + d] + hsumAdd[x1*D + d] - hsumSub[x1*D + d]); for( x = (x1+1)*D; x < x2*D; x += D ) { const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); -// #if CV_SIMD128 -// if( useSIMD ) -// { -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 hv = v_load(hsumAdd + x - D + d); -// v_int16x8 Cx = v_load(Cprev + x + d); -// v_int16x8 psub = v_load(pixSub + d); -// v_int16x8 padd = v_load(pixAdd + d); -// hv = (hv - psub + padd); -// psub = v_load(hsumSub + x + d); -// Cx = Cx - psub + hv; -// v_store(hsumAdd + x + d, hv); -// v_store(C + x + d, Cx); -// } -// } -// else -// #endif { for( d = 0; d < D; d++ ) { @@ -987,8 +962,8 @@ struct CalcVerticalSums: public ParallelLoopBody } else { - for( x = (x1+1)*D; x < x2*D; x += D ) //4e: Calcluates horizontal sums if (y==0). This piece of code is calling SH2+1 times and then result is used in different way - { //4e: to create full blocks sum. That's why this code is isolated from upper case. + for( x = (x1+1)*D; x < x2*D; x += D ) + { const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D); const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0); @@ -996,10 +971,9 @@ struct CalcVerticalSums: public ParallelLoopBody hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]); } } - // Return to coordinates, which is needed by CalcCostBT } - if( y == 0 ) //4e: Calculating first full block sum. + if( y == 0 ) { int scale = k == 0 ? SH2 + 1 : 1; for( x = x1*D; x < x2*D; x++ ) @@ -1008,26 +982,19 @@ struct CalcVerticalSums: public ParallelLoopBody } // also, clear the S buffer - for( k = x1*D; k < x2*D; k++ ) //4e: only on first pass, so it keep old information, don't be confused + for( k = x1*D; k < x2*D; k++ ) S[k] = 0; } -// [formula 13 in the paper] -// compute L_r(p, d) = C(p, d) + -// min(L_r(p-r, d), -// L_r(p-r, d-1) + P1, -// L_r(p-r, d+1) + P1, -// min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) -// where p = (x,y), r is one of the directions. -// we process all the directions at once: -// 0: r=(-dx, 0) -// 1: r=(-1, -dy) -// 2: r=(0, -dy) -// 3: r=(1, -dy) -// 4: r=(-2, -dy) -// 5: r=(-1, -dy*2) -// 6: r=(1, -dy*2) -// 7: r=(2, -dy) +// [formula 13 in the paper] +// compute L_r(p, d) = C(p, d) + +// min(L_r(p-r, d), +// L_r(p-r, d-1) + P1, +// L_r(p-r, d+1) + P1, +// min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) +// where p = (x,y), r is one of the directions. +// we process one directions on first pass and other on second: +// r=(0, dy), where dy=1 on first pass and dy=-1 on second for( x = x1; x != x2; x++ ) { @@ -1043,88 +1010,12 @@ struct CalcVerticalSums: public ParallelLoopBody const CostType* Cp = C + x*D; CostType* Sp = S + x*D; -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _P1 = v_setall_s16((short)P1); -// -// v_int16x8 _delta0 = v_setall_s16((short)delta0); -// v_int16x8 _delta1 = v_setall_s16((short)delta1); -// v_int16x8 _delta2 = v_setall_s16((short)delta2); -// v_int16x8 _delta3 = v_setall_s16((short)delta3); -// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); -// -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 Cpd = v_load(Cp + d); -// v_int16x8 L0, L1, L2, L3; -// -// L0 = v_load(Lr_p0 + d); -// L1 = v_load(Lr_p1 + d); -// L2 = v_load(Lr_ppr + d); -// L3 = v_load(Lr_p3 + d); -// -// L0 = v_min(L0, (v_load(Lr_p0 + d - 1) + _P1)); -// L0 = v_min(L0, (v_load(Lr_p0 + d + 1) + _P1)); -// -// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); -// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); -// -// L2 = v_min(L2, (v_load(Lr_ppr + d - 1) + _P1)); -// L2 = v_min(L2, (v_load(Lr_ppr + d + 1) + _P1)); -// -// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); -// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); -// -// L0 = v_min(L0, _delta0); -// L0 = ((L0 - _delta0) + Cpd); -// -// L1 = v_min(L1, _delta1); -// L1 = ((L1 - _delta1) + Cpd); -// -// L2 = v_min(L2, _delta2); -// L2 = ((L2 - _delta2) + Cpd); -// -// L3 = v_min(L3, _delta3); -// L3 = ((L3 - _delta3) + Cpd); -// -// v_store(Lr_p + d, L0); -// v_store(Lr_p + d + D2, L1); -// v_store(Lr_p + d + D2*2, L2); -// v_store(Lr_p + d + D2*3, L3); -// -// // Get minimum from in L0-L3 -// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; -// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... -// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... -// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... -// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... -// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... -// v_int16x8 t0 = v_min(t0123L, t0123H); -// _minL0 = v_min(_minL0, t0); -// -// v_int16x8 Sval = v_load(Sp + d); -// -// L0 = L0 + L1; -// L2 = L2 + L3; -// Sval = Sval + L0; -// Sval = Sval + L2; -// -// v_store(Sp + d, Sval); -// } -// -// v_int32x4 minL, minH; -// v_expand(_minL0, minL, minH); -// v_pack_store(&minLr[0][x], v_min(minL, minH)); -// } -// else -// #endif { int minL = MAX_COST; for( d = 0; d < D; d++ ) { - int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + int Cpd = Cp[d], L; L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; @@ -1144,7 +1035,6 @@ struct CalcVerticalSums: public ParallelLoopBody } } static const int NLR = 2; - static const int LrBorder = NLR - 1; const Mat& img1; const Mat& img2; CostType* Cbuf; @@ -1178,7 +1068,7 @@ struct CalcHorizontalSums: public ParallelLoopBody minD = params.minDisparity; maxD = minD + params.numDisparities; P1 = params.P1 > 0 ? params.P1 : 2; - P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion + P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); uniquenessRatio = params.uniquenessRatio >= 0 ? params.uniquenessRatio : 10; disp12MaxDiff = params.disp12MaxDiff > 0 ? params.disp12MaxDiff : 1; height = img1.rows; @@ -1192,7 +1082,7 @@ struct CalcHorizontalSums: public ParallelLoopBody costBufSize = width1*D; CSBufSize = costBufSize*height; D2 = D + 16; - LrSize = 2 * D2; //TODO: Check: do we need this value or not? + LrSize = 2 * D2; Cbuf = alignedBuf; Sbuf = Cbuf + CSBufSize; } @@ -1200,13 +1090,11 @@ struct CalcHorizontalSums: public ParallelLoopBody void operator()( const Range& range ) const { int y1 = range.start, y2 = range.end; - static const CostType MAX_COST = SHRT_MAX; - static const int ALIGN = 16; - size_t auxBufsSize = LrSize + width*(sizeof(CostType) + sizeof(DispType)) + 32; + size_t auxBufsSize = LrSize * sizeof(CostType) + width*(sizeof(CostType) + sizeof(DispType)) + 32; Mat auxBuff; auxBuff.create(1, (int)auxBufsSize, CV_8U); - CostType *Lr = (CostType*)alignPtr(auxBuff.ptr(), ALIGN) + 8; + CostType *Lr = ((CostType*)alignPtr(auxBuff.ptr(), ALIGN)) + 8; CostType* disp2cost = Lr + LrSize; DispType* disp2ptr = (DispType*)(disp2cost + width); @@ -1227,132 +1115,48 @@ struct CalcHorizontalSums: public ParallelLoopBody // clear buffers memset( Lr - 8, 0, LrSize*sizeof(CostType) ); + Lr[-1] = Lr[D] = Lr[D2 - 1] = Lr[D2 + D] = MAX_COST; + minLr = 0; - /* - [formula 13 in the paper] - compute L_r(p, d) = C(p, d) + - min(L_r(p-r, d), - L_r(p-r, d-1) + P1, - L_r(p-r, d+1) + P1, - min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) - where p = (x,y), r is one of the directions. - we process all the directions at once: - 0: r=(-dx, 0) - 1: r=(-1, -dy) - 2: r=(0, -dy) - 3: r=(1, -dy) - 4: r=(-2, -dy) - 5: r=(-1, -dy*2) - 6: r=(1, -dy*2) - 7: r=(2, -dy) - */ +// [formula 13 in the paper] +// compute L_r(p, d) = C(p, d) + +// min(L_r(p-r, d), +// L_r(p-r, d-1) + P1, +// L_r(p-r, d+1) + P1, +// min_k L_r(p-r, k) + P2) - min_k L_r(p-r, k) +// where p = (x,y), r is one of the directions. +// we process all the directions at once: +// we process one directions on first pass and other on second: +// r=(dx, 0), where dx=1 on first pass and dx=-1 on second for( x = 0; x != width1; x++) { int delta = minLr + P2; CostType* Lr_ppr = Lr + ((x&1)? 0 : D2); - Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; //TODO: Well, probably, it's better do this once before. - CostType* Lr_p = Lr + ((x&1)? D2 :0); const CostType* Cp = C + x*D; CostType* Sp = S + x*D; -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _P1 = v_setall_s16((short)P1); -// -// v_int16x8 _delta0 = v_setall_s16((short)delta0); -// v_int16x8 _delta1 = v_setall_s16((short)delta1); -// v_int16x8 _delta2 = v_setall_s16((short)delta2); -// v_int16x8 _delta3 = v_setall_s16((short)delta3); -// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); -// -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 Cpd = v_load(Cp + d); -// v_int16x8 L0, L1, L2, L3; -// -// L0 = v_load(Lr_ppr + d); -// L1 = v_load(Lr_p1 + d); -// L2 = v_load(Lr_p2 + d); -// L3 = v_load(Lr_p3 + d); -// -// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); -// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); -// -// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); -// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); -// -// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); -// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); -// -// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); -// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); -// -// L0 = v_min(L0, _delta0); -// L0 = ((L0 - _delta0) + Cpd); -// -// L1 = v_min(L1, _delta1); -// L1 = ((L1 - _delta1) + Cpd); -// -// L2 = v_min(L2, _delta2); -// L2 = ((L2 - _delta2) + Cpd); -// -// L3 = v_min(L3, _delta3); -// L3 = ((L3 - _delta3) + Cpd); -// -// v_store(Lr_p + d, L0); -// v_store(Lr_p + d + D2, L1); -// v_store(Lr_p + d + D2*2, L2); -// v_store(Lr_p + d + D2*3, L3); -// -// // Get minimum from in L0-L3 -// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; -// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... -// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... -// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... -// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... -// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... -// v_int16x8 t0 = v_min(t0123L, t0123H); -// _minL0 = v_min(_minL0, t0); -// -// v_int16x8 Sval = v_load(Sp + d); -// -// L0 = L0 + L1; -// L2 = L2 + L3; -// Sval = Sval + L0; -// Sval = Sval + L2; -// -// v_store(Sp + d, Sval); -// } -// -// v_int32x4 minL, minH; -// v_expand(_minL0, minL, minH); -// v_pack_store(&minLr[x], v_min(minL, minH)); -// } -// else -// #endif + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) { - int minL = MAX_COST; + int Cpd = Cp[d], L; - for( d = 0; d < D; d++ ) - { - int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; - L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + Lr_p[d] = (CostType)L; + minL = std::min(minL, L); - Lr_p[d] = (CostType)L; - minL = std::min(minL, L); - - Sp[d] = saturate_cast(Sp[d] + L); - } - minLr = (CostType)minL; + Sp[d] = saturate_cast(Sp[d] + L); } + minLr = (CostType)minL; } memset( Lr - 8, 0, LrSize*sizeof(CostType) ); + Lr[-1] = Lr[D] = Lr[D2 - 1] = Lr[D2 + D] = MAX_COST; + minLr = 0; for( x = width1-1; x != -1; x--) @@ -1361,136 +1165,30 @@ struct CalcHorizontalSums: public ParallelLoopBody CostType* Lr_ppr = Lr + ((x&1)? 0 :D2); - Lr_ppr[-1] = Lr_ppr[D] = MAX_COST; - CostType* Lr_p = Lr + ((x&1)? D2 :0); const CostType* Cp = C + x*D; CostType* Sp = S + x*D; int minS = MAX_COST, bestDisp = -1; -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _P1 = v_setall_s16((short)P1); -// -// v_int16x8 _delta0 = v_setall_s16((short)delta0); -// v_int16x8 _delta1 = v_setall_s16((short)delta1); -// v_int16x8 _delta2 = v_setall_s16((short)delta2); -// v_int16x8 _delta3 = v_setall_s16((short)delta3); -// v_int16x8 _minL0 = v_setall_s16((short)MAX_COST); -// -// for( d = 0; d < D; d += 8 ) -// { -// v_int16x8 Cpd = v_load(Cp + d); -// v_int16x8 L0, L1, L2, L3; -// -// L0 = v_load(Lr_ppr + d); -// L1 = v_load(Lr_p1 + d); -// L2 = v_load(Lr_p2 + d); -// L3 = v_load(Lr_p3 + d); -// -// L0 = v_min(L0, (v_load(Lr_ppr + d - 1) + _P1)); -// L0 = v_min(L0, (v_load(Lr_ppr + d + 1) + _P1)); -// -// L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1)); -// L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1)); -// -// L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1)); -// L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1)); -// -// L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1)); -// L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1)); -// -// L0 = v_min(L0, _delta0); -// L0 = ((L0 - _delta0) + Cpd); -// -// L1 = v_min(L1, _delta1); -// L1 = ((L1 - _delta1) + Cpd); -// -// L2 = v_min(L2, _delta2); -// L2 = ((L2 - _delta2) + Cpd); -// -// L3 = v_min(L3, _delta3); -// L3 = ((L3 - _delta3) + Cpd); -// -// v_store(Lr_p + d, L0); -// v_store(Lr_p + d + D2, L1); -// v_store(Lr_p + d + D2*2, L2); -// v_store(Lr_p + d + D2*3, L3); -// -// // Get minimum from in L0-L3 -// v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H; -// v_zip(L0, L2, t02L, t02H); // L0[0] L2[0] L0[1] L2[1]... -// v_zip(L1, L3, t13L, t13H); // L1[0] L3[0] L1[1] L3[1]... -// v_int16x8 t02 = v_min(t02L, t02H); // L0[i] L2[i] L0[i] L2[i]... -// v_int16x8 t13 = v_min(t13L, t13H); // L1[i] L3[i] L1[i] L3[i]... -// v_zip(t02, t13, t0123L, t0123H); // L0[i] L1[i] L2[i] L3[i]... -// v_int16x8 t0 = v_min(t0123L, t0123H); -// _minL0 = v_min(_minL0, t0); -// -// v_int16x8 Sval = v_load(Sp + d); -// -// L0 = L0 + L1; -// L2 = L2 + L3; -// Sval = Sval + L0; -// Sval = Sval + L2; -// -// v_store(Sp + d, Sval); -// } -// -// v_int32x4 minL, minH; -// v_expand(_minL0, minL, minH); -// v_pack_store(&minLr[x], v_min(minL, minH)); -// } -// else -// #endif -//TODO:Next piece of code is came from postprocessing. Be very careful with joining them!!! -// #if CV_SIMD128 -// if( useSIMD ) -// { -// v_int16x8 _minS = v_setall_s16(MAX_COST), _bestDisp = v_setall_s16(-1); -// v_int16x8 _d8 = v_int16x8(0, 1, 2, 3, 4, 5, 6, 7), _8 = v_setall_s16(8); -// -// for( d = 0; d < D; d+= 8 ) -// { -// v_int16x8 L0 = v_load(Sp + d); -// v_int16x8 mask = L0 < _minS; -// _minS = v_min( L0, _minS ); -// _bestDisp = _bestDisp ^ ((_bestDisp ^ _d8) & mask); -// _d8 = _d8 + _8; -// } -// v_int32x4 _d0, _d1; -// v_expand(_minS, _d0, _d1); -// minS = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); -// v_int16x8 v_mask = v_setall_s16((short)minS) == _minS; -// -// _bestDisp = (_bestDisp & v_mask) | (v_setall_s16(SHRT_MAX) & ~v_mask); -// v_expand(_bestDisp, _d0, _d1); -// bestDisp = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1)); -// } -// else -// #endif + int minL = MAX_COST; + + for( d = 0; d < D; d++ ) { - int minL = MAX_COST; + int Cpd = Cp[d], L; - for( d = 0; d < D; d++ ) + L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; + + Lr_p[d] = (CostType)L; + minL = std::min(minL, L); + + Sp[d] = saturate_cast(Sp[d] + L); + if( Sp[d] < minS ) { - int Cpd = Cp[d], L; //4e: Remember, that every Cp is increased on P2 in line number 369. That's why next 4 lines are paper-like actually - - L = Cpd + std::min((int)Lr_ppr[d], std::min(Lr_ppr[d-1] + P1, std::min(Lr_ppr[d+1] + P1, delta))) - delta; - - Lr_p[d] = (CostType)L; - minL = std::min(minL, L); - - Sp[d] = saturate_cast(Sp[d] + L); - if( Sp[d] < minS ) - { - minS = Sp[d]; - bestDisp = d; - } + minS = Sp[d]; + bestDisp = d; } - minLr = (CostType)minL; } + minLr = (CostType)minL; //Some postprocessing procedures and saving for( d = 0; d < D; d++ ) { @@ -1531,17 +1229,17 @@ struct CalcHorizontalSums: public ParallelLoopBody int _d = d1 >> DISP_SHIFT; int d_ = (d1 + DISP_SCALE-1) >> DISP_SHIFT; int _x = x - _d, x_ = x - d_; - if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && //4e: To dismiss disparity, we should assure, that there is no any - 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) //4e: chance to understand this as correct. + if( 0 <= _x && _x < width && disp2ptr[_x] >= minD && std::abs(disp2ptr[_x] - _d) > disp12MaxDiff && + 0 <= x_ && x_ < width && disp2ptr[x_] >= minD && std::abs(disp2ptr[x_] - d_) > disp12MaxDiff ) disp1ptr[x] = (DispType)INVALID_DISP_SCALED; } } } - static const int NLR = 2; - static const int LrBorder = NLR - 1; static const int DISP_SHIFT = StereoMatcher::DISP_SHIFT; static const int DISP_SCALE = (1 << DISP_SHIFT); + static const CostType MAX_COST = SHRT_MAX; + static const int ALIGN = 16; const Mat& img1; const Mat& img2; Mat& disp1; @@ -1567,68 +1265,41 @@ struct CalcHorizontalSums: public ParallelLoopBody int disp12MaxDiff; }; /* - This is new experimential version of disparity calculation, which should be parralled after -TODO: Don't forget to rewrire this commentaries after - computes disparity for "roi" in img1 w.r.t. img2 and write it to disp1buf. that is, disp1buf(x, y)=d means that img1(x+roi.x, y+roi.y) ~ img2(x+roi.x-d, y+roi.y). minD <= d < maxD. - disp2full is the reverse disparity map, that is: - disp2full(x+roi.x,y+roi.y)=d means that img2(x+roi.x, y+roi.y) ~ img1(x+roi.x+d, y+roi.y) note that disp1buf will have the same size as the roi and - disp2full will have the same size as img1 (or img2). - On exit disp2buf is not the final disparity, it is an intermediate result that becomes + On exit disp1buf is not the final disparity, it is an intermediate result that becomes final after all the tiles are processed. the disparity in disp1buf is written with sub-pixel accuracy (4 fractional bits, see StereoSGBM::DISP_SCALE), using quadratic interpolation, while the disparity in disp2buf is written as is, without interpolation. - - disp2cost also has the same size as img1 (or img2). - It contains the minimum current cost, used to find the best disparity, corresponding to the minimal cost. */ -static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, +static void computeDisparitySGBM_HH4( const Mat& img1, const Mat& img2, Mat& disp1, const StereoSGBMParams& params, Mat& buffer ) { -//#if CV_SIMD128 -// // maxDisparity is supposed to multiple of 16, so we can forget doing else -// static const uchar LSBTab[] = -// { -// 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -// 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 -// }; -// static const v_uint16x8 v_LSB = v_uint16x8(0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); -// -// bool useSIMD = hasSIMD128(); -//#endif - const int ALIGN = 16; const int DISP_SHIFT = StereoMatcher::DISP_SHIFT; const int DISP_SCALE = (1 << DISP_SHIFT); int minD = params.minDisparity, maxD = minD + params.numDisparities; - Size SADWindowSize; //4e: SAD means Sum of Absolute Differences - SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; //4e: and this is always square - int ftzero = std::max(params.preFilterCap, 15) | 1; //4e:ftzero clips x-derivatives. I think, this story with arrays is about non-realized SIMD method - int P1 = params.P1 > 0 ? params.P1 : 2, P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); //TODO: think about P1/S(x,y) Proportion + Size SADWindowSize; + SADWindowSize.width = SADWindowSize.height = params.SADWindowSize > 0 ? params.SADWindowSize : 5; + int ftzero = std::max(params.preFilterCap, 15) | 1; + int P1 = params.P1 > 0 ? params.P1 : 2, P2 = std::max(params.P2 > 0 ? params.P2 : 5, P1+1); int k, width = disp1.cols, height = disp1.rows; int minX1 = std::max(maxD, 0), maxX1 = width + std::min(minD, 0); int D = maxD - minD, width1 = maxX1 - minX1; int SH2 = SADWindowSize.height/2; int INVALID_DISP = minD - 1; int INVALID_DISP_SCALED = INVALID_DISP*DISP_SCALE; - const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; //4e: array is such big due to derivative could be +-8*256 in worst cases + const int TAB_OFS = 256*4, TAB_SIZE = 256 + TAB_OFS*2; PixType clipTab[TAB_SIZE]; - for( k = 0; k < TAB_SIZE; k++ ) //4e: If ftzero would = 4, array containment will be = -4 -4 -4 ... -4 -3 -2 -1 0 1 2 3 4 ... 4 4 4 + for( k = 0; k < TAB_SIZE; k++ ) clipTab[k] = (PixType)(std::min(std::max(k - TAB_OFS, -ftzero), ftzero) + ftzero); if( minX1 >= maxX1 ) @@ -1637,28 +1308,25 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, return; } - CV_Assert( D % 16 == 0 ); //TODO: Are you sure? By the way, why not 8? + CV_Assert( D % 16 == 0 ); - // NR - the number of directions. the loop on x below that computes Lr assumes that NR == 8. - // if you change NR, please, modify the loop as well. - int D2 = D+16; //4e: Somewhere in code we need d+1, so D+1. One of simplest solutuons is increasing D-dimension on 1. But 1 is 16, when storage should be aligned. + int D2 = D+16; // the number of L_r(.,.) and min_k L_r(.,.) lines in the buffer: - // for 8-way dynamic programming we need the current row and + // for dynamic programming we need the current row and // the previous row, i.e. 2 rows in total - const int NLR = 2; //4e: We assume, that we need one or more previous steps in our linear dynamic(one right here). - const int LrBorder = NLR - 1; //4e: for simplification of calculations we need border for taking previous dynamic solutions. + const int NLR = 2; // for each possible stereo match (img1(x,y) <=> img2(x-d,y)) - // we keep pixel difference cost (C) and the summary cost over NR directions (S). + // we keep pixel difference cost (C) and the summary cost over 4 directions (S). // we also keep all the partial costs for the previous line L_r(x,d) and also min_k L_r(x, k) size_t costBufSize = width1*D; size_t CSBufSize = costBufSize*height; - size_t minLrSize = (width1 + LrBorder*2), LrSize = minLrSize*D2; //TODO: We don't need LrBorder for vertical passes and we don't need Lr buffer for horizontal passes. + size_t minLrSize = width1 , LrSize = minLrSize*D2; int hsumBufNRows = SH2*2 + 2; size_t totalBufSize = (LrSize + minLrSize)*NLR*sizeof(CostType) + // minLr[] and Lr[] - costBufSize*hsumBufNRows*sizeof(CostType) + // hsumBuf //4e: TODO: Why we should increase sum window height one more time? - CSBufSize*2*sizeof(CostType) + 1024; // C, S //4e: C is Block sum of costs, S is multidirectional dynamic sum with same size + costBufSize*hsumBufNRows*sizeof(CostType) + // hsumBuf + CSBufSize*2*sizeof(CostType) + 1024; // C, S if( buffer.empty() || !buffer.isContinuous() || buffer.cols*buffer.rows*buffer.elemSize() < totalBufSize ) @@ -1671,8 +1339,8 @@ static void computeDisparitySGBMParallel( const Mat& img1, const Mat& img2, for(k = 0; k < (int)CSBufSize; k++ ) Cbuf[k] = (CostType)P2; - parallel_for_(Range(0,width1),CalcVerticalSums(img1, img2, params, Cbuf, clipTab)); - parallel_for_(Range(0,height),CalcHorizontalSums(img1, img2, disp1, params, Cbuf)); + parallel_for_(Range(0,width1),CalcVerticalSums(img1, img2, params, Cbuf, clipTab),8); + parallel_for_(Range(0,height),CalcHorizontalSums(img1, img2, disp1, params, Cbuf),8); } @@ -2331,7 +1999,7 @@ public: if(params.mode==MODE_SGBM_3WAY) computeDisparity3WaySGBM( left, right, disp, params, buffers, num_stripes ); else if(params.mode==MODE_HH4) - computeDisparitySGBMParallel( left, right, disp, params, buffer ); + computeDisparitySGBM_HH4( left, right, disp, params, buffer ); else computeDisparitySGBM( left, right, disp, params, buffer ); diff --git a/modules/calib3d/test/test_stereomatching.cpp b/modules/calib3d/test/test_stereomatching.cpp index 9a338bb11f..08a955bb3a 100644 --- a/modules/calib3d/test/test_stereomatching.cpp +++ b/modules/calib3d/test/test_stereomatching.cpp @@ -785,37 +785,22 @@ protected: TEST(Calib3d_StereoBM, regression) { CV_StereoBMTest test; test.safe_run(); } TEST(Calib3d_StereoSGBM, regression) { CV_StereoSGBMTest test; test.safe_run(); } -TEST(Calib3d_StereoSGBMPar, idontknowhowtotesthere) +TEST(Calib3d_StereoSGBM_HH4, regression) { -// -// case_teddy_2 teddy "48" "3" "MODE_HH" - -//Ptr StereoSGBM::create(int minDisparity, int numDisparities, int SADWindowSize, -// int P1, int P2, int disp12MaxDiff, -// int preFilterCap, int uniquenessRatio, -// int speckleWindowSize, int speckleRange, -// int mode) - Mat leftImg = imread("/home/q/Work/GitVault/opencv_extra/testdata/cv/stereomatching/datasets/teddy/im2.png"); - Mat rightImg = imread("/home/q/Work/GitVault/opencv_extra/testdata/cv/stereomatching/datasets/teddy/im6.png"); -// Mat leftDisp_old, leftDisp_new; + String path = cvtest::TS::ptr()->get_data_path() + "cv/stereomatching/datasets/teddy/"; + Mat leftImg = imread(path + "im2.png", 0); + Mat rightImg = imread(path + "im6.png", 0); + Mat testData = imread(path + "disp2_hh4.png",-1); + Mat leftDisp; + Mat toCheck; { - Mat leftDisp; - Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH); - sgbm->compute( leftImg, rightImg, leftDisp); - CV_Assert( leftDisp.type() == CV_16SC1 ); - leftDisp/=8; - imwrite( "/home/q/Work/GitVault/modehh4_new.jpg", leftDisp); - } - { - Mat leftDisp; Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH4); sgbm->compute( leftImg, rightImg, leftDisp); CV_Assert( leftDisp.type() == CV_16SC1 ); - leftDisp/=8; - imwrite( "/home/q/Work/GitVault/modehh4_old.jpg", leftDisp); + leftDisp.convertTo(toCheck, CV_16UC1); +// imwrite("/home/q/Work/GitVault/disp2_hh4.png",toCheck); } -// Mat diff; -// absdiff(leftDisp_old,leftDisp_new,diff); -// CV_Assert( countNonZero(diff)==0); -// + Mat diff; + absdiff(toCheck, testData,diff); + CV_Assert( countNonZero(diff)==0); } From f3eff00bf7615e31e36b4dbf82db86af3711f842 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 25 Apr 2017 16:48:50 +0300 Subject: [PATCH 119/144] cmake: update handling of IPPICV/IPPIW --- cmake/OpenCVFindIPPIW.cmake | 19 ++++++++- cmake/OpenCVGenConfig.cmake | 16 +++++++- cmake/OpenCVUtils.cmake | 44 +++++++++++++++------ cmake/templates/OpenCVConfig-IPPIW.cmake.in | 7 ++++ cmake/templates/OpenCVConfig.cmake.in | 1 + 5 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 cmake/templates/OpenCVConfig-IPPIW.cmake.in diff --git a/cmake/OpenCVFindIPPIW.cmake b/cmake/OpenCVFindIPPIW.cmake index e74c2fb324..c7927f58e2 100644 --- a/cmake/OpenCVFindIPPIW.cmake +++ b/cmake/OpenCVFindIPPIW.cmake @@ -68,6 +68,7 @@ macro(ippiw_setup PATH BUILD) set(IPP_IW_LIBRARIES ${IPP_IW_LIBRARY}) execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OpenCV_SOURCE_DIR}/3rdparty/ippicv/CMakeLists.txt" "${IPP_IW_PATH}/") add_subdirectory("${IPP_IW_PATH}/" ${OpenCV_BINARY_DIR}/3rdparty/ippiw) + set(HAVE_IPP_IW 1) return() endif() @@ -84,8 +85,22 @@ macro(ippiw_setup PATH BUILD) message(STATUS "found Intel IPP IW binaries: ${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE}") message(STATUS "at: ${IPP_IW_PATH}") + add_library(ippiw STATIC IMPORTED) + set_target_properties(ippiw PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES "" + IMPORTED_LOCATION "${FILE}" + ) + if (NOT BUILD_SHARED_LIBS) + # CMake doesn't support "install(TARGETS ${name} ...)" command with imported targets + install(FILES "${FILE}" + DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) + set(IPPIW_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}/${OPENCV_3P_LIB_INSTALL_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}ipp_iw${CMAKE_STATIC_LIBRARY_SUFFIX}" CACHE INTERNAL "" FORCE) + set(IPPIW_LOCATION_PATH "${FILE}" CACHE INTERNAL "" FORCE) + endif() + set(IPP_IW_INCLUDES "${IPP_IW_PATH}/include") - set(IPP_IW_LIBRARIES ${FILE}) + set(IPP_IW_LIBRARIES ippiw) + set(HAVE_IPP_IW 1) set(BUILD_IPP_IW 0) return() @@ -104,7 +119,7 @@ elseif((UNIX AND NOT ANDROID) OR (UNIX AND ANDROID_ABI MATCHES "x86")) elseif(WIN32 AND NOT ARM) set(IW_PACKAGE_SUBDIR "ippiw_win") else() - message(SEND_ERROR "Improper system for Intel IPP Integrations Wrappers. This message shouldn't appera. Check Intel IPP configurations steps") + message(SEND_ERROR "Improper system for Intel IPP Integrations Wrappers. This message shouldn't appear. Check Intel IPP configurations steps") return() endif() diff --git a/cmake/OpenCVGenConfig.cmake b/cmake/OpenCVGenConfig.cmake index 206acfdad9..fb62638b4b 100644 --- a/cmake/OpenCVGenConfig.cmake +++ b/cmake/OpenCVGenConfig.cmake @@ -45,12 +45,20 @@ export(TARGETS ${OpenCVModules_TARGETS} FILE "${CMAKE_BINARY_DIR}/OpenCVModules. if(TARGET ippicv AND NOT BUILD_SHARED_LIBS) set(USE_IPPICV TRUE) - file(RELATIVE_PATH IPPICV_INSTALL_PATH_RELATIVE_CONFIGCMAKE ${CMAKE_BINARY_DIR} ${IPPICV_LOCATION_PATH}) + file(RELATIVE_PATH IPPICV_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_BINARY_DIR}" "${IPPICV_LOCATION_PATH}") ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-IPPICV.cmake.in" IPPICV_CONFIGCMAKE @ONLY) else() set(USE_IPPICV FALSE) endif() +if(TARGET ippiw AND NOT BUILD_SHARED_LIBS AND IPPIW_INSTALL_PATH) + set(USE_IPPIW TRUE) + file(RELATIVE_PATH IPPIW_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_BINARY_DIR}" "${IPPIW_LOCATION_PATH}") + ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-IPPIW.cmake.in" IPPIW_CONFIGCMAKE @ONLY) +else() + set(USE_IPPIW FALSE) +endif() + configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig.cmake" @ONLY) #support for version checking when finding opencv. find_package(OpenCV 2.3.1 EXACT) should now work. configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig-version.cmake" @ONLY) @@ -62,9 +70,13 @@ file(RELATIVE_PATH OpenCV_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_INSTALL_PRE set(OpenCV_INCLUDE_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_INSTALL_PATH}\" \"\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_INSTALL_PATH}/opencv\"") if(USE_IPPICV) - file(RELATIVE_PATH IPPICV_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_INSTALL_PREFIX}" ${IPPICV_INSTALL_PATH}) + file(RELATIVE_PATH IPPICV_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_INSTALL_PREFIX}" "${IPPICV_INSTALL_PATH}") ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-IPPICV.cmake.in" IPPICV_CONFIGCMAKE @ONLY) endif() +if(USE_IPPIW) + file(RELATIVE_PATH IPPIW_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_INSTALL_PREFIX}" "${IPPIW_INSTALL_PATH}") + ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-IPPIW.cmake.in" IPPIW_CONFIGCMAKE @ONLY) +endif() function(ocv_gen_config TMP_DIR NESTED_PATH ROOT_NAME) ocv_path_join(__install_nested "${OPENCV_CONFIG_INSTALL_PATH}" "${NESTED_PATH}") diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index ccb87311f5..4879eb699c 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -1003,6 +1003,13 @@ function(ocv_add_library target) _ocv_append_target_includes(${target}) endfunction() + +macro(ocv_get_libname var_name) + get_filename_component(__libname "${ARGN}" NAME) + string(REGEX REPLACE "^lib(.+).(a|so)(.[.0-9]+)?$" "\\1" __libname "${__libname}") + set(${var_name} "${__libname}") +endmacro() + # build the list of opencv libs and dependencies for all modules # _modules - variable to hold list of all modules # _extra - variable to hold list of extra dependencies @@ -1030,11 +1037,31 @@ macro(ocv_get_all_libs _modules _extra _3rdparty) foreach (dep ${deps} ${OPENCV_LINKER_LIBS}) if (NOT DEFINED OPENCV_MODULE_${dep}_LOCATION) if (TARGET ${dep}) - get_target_property(_output ${dep} ARCHIVE_OUTPUT_DIRECTORY) - if ("${_output}" STREQUAL "${3P_LIBRARY_OUTPUT_PATH}") - list(INSERT ${_3rdparty} 0 ${dep}) + get_target_property(_type ${dep} TYPE) + if(_type STREQUAL "STATIC_LIBRARY" AND BUILD_SHARED_LIBS) + # nothing else() - list(INSERT ${_extra} 0 ${dep}) + get_target_property(_output ${dep} IMPORTED_LOCATION) + if(NOT _output) + get_target_property(_output ${dep} ARCHIVE_OUTPUT_DIRECTORY) + get_target_property(_output_name ${dep} OUTPUT_NAME) + if(NOT _output_name) + set(_output_name "${dep}") + endif() + else() + get_filename_component(_output_name "${_output}" NAME) + endif() + string(FIND "${_output}" "${CMAKE_BINARY_DIR}" _POS) + if (_POS EQUAL 0) + ocv_get_libname(_libname "${_output_name}") + list(INSERT ${_3rdparty} 0 ${_libname}) + else() + if(_output) + list(INSERT ${_extra} 0 ${_output}) + else() + list(INSERT ${_extra} 0 ${dep}) + endif() + endif() endif() else() list(INSERT ${_extra} 0 ${dep}) @@ -1043,15 +1070,6 @@ macro(ocv_get_all_libs _modules _extra _3rdparty) endforeach() endforeach() - # ippicv specific handling - list(FIND ${_extra} "ippicv" ippicv_idx) - if (${ippicv_idx} GREATER -1) - list(REMOVE_ITEM ${_extra} "ippicv") - if(NOT BUILD_SHARED_LIBS) - list(INSERT ${_3rdparty} 0 "ippicv") - endif() - endif() - ocv_list_filterout(${_modules} "^[\$]<") ocv_list_filterout(${_3rdparty} "^[\$]<") ocv_list_filterout(${_extra} "^[\$]<") diff --git a/cmake/templates/OpenCVConfig-IPPIW.cmake.in b/cmake/templates/OpenCVConfig-IPPIW.cmake.in new file mode 100644 index 0000000000..36cfed060b --- /dev/null +++ b/cmake/templates/OpenCVConfig-IPPIW.cmake.in @@ -0,0 +1,7 @@ +if(NOT TARGET ippiw) + add_library(ippiw STATIC IMPORTED) + set_target_properties(ippiw PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES "" + IMPORTED_LOCATION "${OpenCV_INSTALL_PATH}/@IPPIW_INSTALL_PATH_RELATIVE_CONFIGCMAKE@" + ) +endif() diff --git a/cmake/templates/OpenCVConfig.cmake.in b/cmake/templates/OpenCVConfig.cmake.in index 47751f55cf..c0a58389ff 100644 --- a/cmake/templates/OpenCVConfig.cmake.in +++ b/cmake/templates/OpenCVConfig.cmake.in @@ -97,6 +97,7 @@ endif() @ANDROID_CONFIGCMAKE@ @IPPICV_CONFIGCMAKE@ +@IPPIW_CONFIGCMAKE@ # Some additional settings are required if OpenCV is built as static libs set(OpenCV_SHARED @BUILD_SHARED_LIBS@) From 133b91a0269c0483412364be56d3c996a06fae7d Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 26 Apr 2017 13:58:35 +0300 Subject: [PATCH 120/144] android: build fixes - eliminate CMake 3.5+ warnings - removed usage of dropped "OPENCV_CAMERA_MODULES" variable - partial support for Android NDK 11+ --- cmake/templates/OpenCV.mk.in | 2 ++ modules/java/android_lib/jni/Android.mk | 1 - platforms/android/android.toolchain.cmake | 10 ++++++--- .../android/build-tests/test_ndk_build.py | 21 +++++++++++-------- samples/android/face-detection/jni/Android.mk | 1 - 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/cmake/templates/OpenCV.mk.in b/cmake/templates/OpenCV.mk.in index e99b1ad8bd..addde3a268 100644 --- a/cmake/templates/OpenCV.mk.in +++ b/cmake/templates/OpenCV.mk.in @@ -94,6 +94,8 @@ LOCAL_CFLAGS += $(OPENCV_LOCAL_CFLAGS) ifeq ($(OPENCV_INSTALL_MODULES),on) LOCAL_$(OPENCV_LIB_TYPE)_LIBRARIES += $(foreach mod, $(OPENCV_LIBS), opencv_$(mod)) else + $(call __ndk_info,OpenCV: You should ignore warning about 'non-system libraries in linker flags' and 'opencv_java' library.) + $(call __ndk_info, 'OPENCV_INSTALL_MODULES:=on' can be used to build APK with included OpenCV binaries) LOCAL_LDLIBS += -L$(call host-path,$(LOCAL_PATH)/$(OPENCV_LIBS_DIR)) $(foreach lib, $(OPENCV_LIBS), -lopencv_$(lib)) endif diff --git a/modules/java/android_lib/jni/Android.mk b/modules/java/android_lib/jni/Android.mk index 72418c893f..129f567a6d 100644 --- a/modules/java/android_lib/jni/Android.mk +++ b/modules/java/android_lib/jni/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -OPENCV_CAMERA_MODULES := off include OpenCV.mk LOCAL_MODULE := opencv_java diff --git a/platforms/android/android.toolchain.cmake b/platforms/android/android.toolchain.cmake index 1d69b7504a..6d64f92148 100644 --- a/platforms/android/android.toolchain.cmake +++ b/platforms/android/android.toolchain.cmake @@ -1150,8 +1150,10 @@ if( APPLE ) endif() # Force set compilers because standard identification works badly for us -include( CMakeForceCompiler ) -CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU ) +if( CMAKE_VERSION VERSION_LESS 3.5.0 ) + include( CMakeForceCompiler ) + CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU ) +endif() if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER_ID Clang ) endif() @@ -1163,7 +1165,9 @@ else() endif() set( CMAKE_C_HAS_ISYSROOT 1 ) set( CMAKE_C_COMPILER_ABI ELF ) -CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) +if( CMAKE_VERSION VERSION_LESS 3.5.0 ) + CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) +endif() if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_CXX_COMPILER_ID Clang) endif() diff --git a/platforms/android/build-tests/test_ndk_build.py b/platforms/android/build-tests/test_ndk_build.py index 60b76e7df7..cbc2b7c6ab 100644 --- a/platforms/android/build-tests/test_ndk_build.py +++ b/platforms/android/build-tests/test_ndk_build.py @@ -73,12 +73,12 @@ class TestNDKBuild(unittest.TestCase): p = [] if self.libtype == "static": p.append("OPENCV_LIB_TYPE := STATIC") - elif self.libtype == "shared_debug": - p.append("OPENCV_LIB_TYPE := SHARED") - p.append("OPENCV_CAMERA_MODULES:=on") - p.append("OPENCV_INSTALL_MODULES:=on") elif self.libtype == "shared": p.append("OPENCV_LIB_TYPE := SHARED") + p.append("OPENCV_INSTALL_MODULES:=on") + elif self.libtype == "shared_opencv_manager": + p.append("OPENCV_LIB_TYPE := SHARED") + p.append("OPENCV_INSTALL_MODULES:=off") p.append("include %s" % os.path.join(self.opencv_mk_path, "OpenCV.mk")) return TEMPLATE_ANDROID_MK.format(cut = "\n".join(p), cpp1 = self.cpp1, cpp2 = self.cpp2) @@ -115,14 +115,17 @@ class TestNDKBuild(unittest.TestCase): def suite(workdir, opencv_mk_path): abis = ["armeabi", "armeabi-v7a", "x86", "mips"] ndk_path = os.environ["ANDROID_NDK"] - with open(os.path.join(ndk_path, "RELEASE.TXT"), "r") as f: - s = f.read() - if re.search(r'r10[b-e]', s): - abis.extend(["arm64-v8a", "x86", "x86_64"]) + if os.path.exists(os.path.join(ndk_path, "RELEASE.TXT")): + with open(os.path.join(ndk_path, "RELEASE.TXT"), "r") as f: + s = f.read() + if re.search(r'r10[b-e]', s): + abis.extend(["arm64-v8a", "x86_64"]) + if os.path.exists(os.path.join(ndk_path, "source.properties")): # Android NDK 11+ + abis.extend(["arm64-v8a", "x86_64"]) abis.append("all") suite = unittest.TestSuite() - for libtype in ["static", "shared", "shared_debug"]: + for libtype in ["static", "shared", "shared_opencv_manager"]: for abi in abis: suite.addTest(TestNDKBuild(abi, libtype, opencv_mk_path, workdir)) return suite diff --git a/samples/android/face-detection/jni/Android.mk b/samples/android/face-detection/jni/Android.mk index 0686b22d86..e882cac0c1 100644 --- a/samples/android/face-detection/jni/Android.mk +++ b/samples/android/face-detection/jni/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -#OPENCV_CAMERA_MODULES:=off #OPENCV_INSTALL_MODULES:=off #OPENCV_LIB_TYPE:=SHARED ifdef OPENCV_ANDROID_SDK From 75f28245a8c67b578e590b89221d63a1e6d63db8 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 26 Apr 2017 17:19:26 +0300 Subject: [PATCH 121/144] core: fix persistence bug in RAW I/O code - persistence.cpp code expects special sizeof value for passed structures - this assumption is lead to memory corruption problems - fixed/workarounded test to prevent memory corruption on Linux 32-bit systems --- modules/core/src/persistence.cpp | 5 +- modules/core/test/test_io.cpp | 84 ++++++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp index 2e834f67fd..d7aa1445e7 100644 --- a/modules/core/src/persistence.cpp +++ b/modules/core/src/persistence.cpp @@ -4907,7 +4907,7 @@ cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, { char* data0 = (char*)_data; int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k = 0, fmt_pair_count; - int i = 0, offset = 0, count = 0; + int i = 0, count = 0; CV_CHECK_FILE_STORAGE( fs ); @@ -4918,9 +4918,11 @@ cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, CV_Error( CV_StsBadSize, "The readed sequence is a scalar, thus len must be 1" ); fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + size_t step = ::icvCalcStructSize(dt, 0); for(;;) { + int offset = 0; for( k = 0; k < fmt_pair_count; k++ ) { int elem_type = fmt_pairs[k*2+1]; @@ -5038,6 +5040,7 @@ cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, offset = (int)(data - data0); } + data0 += step; } end_loop: diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp index 33af4c8b76..1e3ea4935d 100644 --- a/modules/core/test/test_io.cpp +++ b/modules/core/test/test_io.cpp @@ -614,13 +614,41 @@ struct data_t typedef float f; typedef double d; - u u1 ;u u2 ; i i1 ; - i i2 ;i i3 ; - d d1 ; - d d2 ; - i i4 ; + /*0x00*/ u u1 ;u u2 ; i i1 ; + /*0x08*/ i i2 ;i i3 ; + /*0x10*/ d d1 ; + /*0x18*/ d d2 ; + /*0x20*/ i i4 ;i required_alignment_field_for_linux32; + /* + * OpenCV persistence.cpp stuff expects: sizeof(data_t) = alignSize(36, sizeof(largest type = double)) = 40 + * Some compilers on some archs returns sizeof(data_t) = 36 due struct packaging UB + */ - static inline const char * signature() { return "2u3i2di"; } + static inline const char * signature() { + if (sizeof(data_t) != 40) + { + printf("sizeof(data_t)=%d, u1=%p u2=%p i1=%p i2=%p i3=%p d1=%p d2=%p i4=%p\n", (int)sizeof(data_t), + &(((data_t*)0)->u1), + &(((data_t*)0)->u2), + &(((data_t*)0)->i1), + &(((data_t*)0)->i2), + &(((data_t*)0)->i3), + &(((data_t*)0)->d1), + &(((data_t*)0)->d2), + &(((data_t*)0)->i4) + ); + } + CV_Assert(sizeof(data_t) == 40); + CV_Assert((size_t)&(((data_t*)0)->u1) == 0x0); + CV_Assert((size_t)&(((data_t*)0)->u2) == 0x1); + CV_Assert((size_t)&(((data_t*)0)->i1) == 0x4); + CV_Assert((size_t)&(((data_t*)0)->i2) == 0x8); + CV_Assert((size_t)&(((data_t*)0)->i3) == 0xc); + CV_Assert((size_t)&(((data_t*)0)->d1) == 0x10); + CV_Assert((size_t)&(((data_t*)0)->d2) == 0x18); + CV_Assert((size_t)&(((data_t*)0)->i4) == 0x20); + return "2u3i2di"; + } }; TEST(Core_InputOutput, filestorage_base64_basic) @@ -718,16 +746,24 @@ TEST(Core_InputOutput, filestorage_base64_basic) fs.release(); } - for (int i = 0; i < 1000; i++) { - // TODO: Solve this bug in `cvReadRawData` - //EXPECT_EQ(rawdata[i].u1, 1); - //EXPECT_EQ(rawdata[i].u2, 2); - //EXPECT_EQ(rawdata[i].i1, 1); - //EXPECT_EQ(rawdata[i].i2, 2); - //EXPECT_EQ(rawdata[i].i3, 3); - //EXPECT_EQ(rawdata[i].d1, 0.1); - //EXPECT_EQ(rawdata[i].d2, 0.2); - //EXPECT_EQ(rawdata[i].i4, i); + int errors = 0; + for (int i = 0; i < 1000; i++) + { + EXPECT_EQ((int)rawdata[i].u1, 1); + EXPECT_EQ((int)rawdata[i].u2, 2); + EXPECT_EQ((int)rawdata[i].i1, 1); + EXPECT_EQ((int)rawdata[i].i2, 2); + EXPECT_EQ((int)rawdata[i].i3, 3); + EXPECT_EQ(rawdata[i].d1, 0.1); + EXPECT_EQ(rawdata[i].d2, 0.2); + EXPECT_EQ((int)rawdata[i].i4, i); + if (::testing::Test::HasNonfatalFailure()) + { + printf("i = %d\n", i); + errors++; + } + if (errors >= 3) + break; } EXPECT_TRUE(no_type_id); @@ -741,9 +777,25 @@ TEST(Core_InputOutput, filestorage_base64_basic) EXPECT_EQ(_2d_in.cols , _2d_out.cols); EXPECT_EQ(_2d_in.dims , _2d_out.dims); EXPECT_EQ(_2d_in.depth(), _2d_out.depth()); + + errors = 0; for(int i = 0; i < _2d_out.rows; ++i) + { for (int j = 0; j < _2d_out.cols; ++j) + { EXPECT_EQ(_2d_in.at(i, j), _2d_out.at(i, j)); + if (::testing::Test::HasNonfatalFailure()) + { + printf("i = %d, j = %d\n", i, j); + errors++; + } + if (errors >= 3) + { + i = _2d_out.rows; + break; + } + } + } EXPECT_EQ(_nd_in.rows , _nd_out.rows); EXPECT_EQ(_nd_in.cols , _nd_out.cols); From 4c2858fd61edebb351929f1272999deb34889f77 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 26 Apr 2017 18:54:08 +0300 Subject: [PATCH 122/144] cmake: fix POPCNT & SSE4.2 detection code --- cmake/checks/cpu_popcnt.cpp | 24 +++++++++++++++++++----- cmake/checks/cpu_sse42.cpp | 6 ++++-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/cmake/checks/cpu_popcnt.cpp b/cmake/checks/cpu_popcnt.cpp index f55c9f3c54..16e5575108 100644 --- a/cmake/checks/cpu_popcnt.cpp +++ b/cmake/checks/cpu_popcnt.cpp @@ -1,8 +1,22 @@ -#include -#ifndef _MSC_VER -#include +#ifdef _MSC_VER +# include +# if defined(_M_X64) +# define CV_POPCNT_U64 _mm_popcnt_u64 +# endif +# define CV_POPCNT_U32 _mm_popcnt_u32 +#else +# include +# if defined(__x86_64__) +# define CV_POPCNT_U64 __builtin_popcountll +# endif +# define CV_POPCNT_U32 __builtin_popcount #endif -int main() { - int i = _mm_popcnt_u64(1); + +int main() +{ +#ifdef CV_POPCNT_U64 + int i = CV_POPCNT_U64(1); +#endif + int j = CV_POPCNT_U32(1); return 0; } diff --git a/cmake/checks/cpu_sse42.cpp b/cmake/checks/cpu_sse42.cpp index 56f56658ab..2a1ce992df 100644 --- a/cmake/checks/cpu_sse42.cpp +++ b/cmake/checks/cpu_sse42.cpp @@ -1,5 +1,7 @@ #include -int main() { - int i = _mm_popcnt_u64(1); + +int main() +{ + unsigned int res = _mm_crc32_u8(1, 2); return 0; } From 930611dfa8776e0009242e07810a0224c6c0324e Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Wed, 26 Apr 2017 14:22:14 +0200 Subject: [PATCH 123/144] python: move Ptr specializations above generic_vec to allow vector_Ptr_T --- modules/python/src2/cv2.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 1eb4533812..a64ff50a43 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -394,6 +394,15 @@ bool pyopencv_to(PyObject* o, Mat& m, const char* name) return pyopencv_to(o, m, ArgInfo(name, 0)); } +template +bool pyopencv_to(PyObject *o, Ptr& p, const char *name) +{ + if (!o || o == Py_None) + return true; + p = makePtr(); + return pyopencv_to(o, *p, name); +} + template<> PyObject* pyopencv_from(const Mat& m) { @@ -417,6 +426,14 @@ PyObject* pyopencv_from(const Matx<_Tp, m, n>& matx) return pyopencv_from(Mat(matx)); } +template +PyObject* pyopencv_from(const cv::Ptr& p) +{ + if (!p) + Py_RETURN_NONE; + return pyopencv_from(*p); +} + typedef struct { PyObject_HEAD UMat* um; @@ -1329,23 +1346,6 @@ PyObject* pyopencv_from(const Moments& m) "nu30", m.nu30, "nu21", m.nu21, "nu12", m.nu12, "nu03", m.nu03); } -template -PyObject* pyopencv_from(const cv::Ptr& p) -{ - if (!p) - Py_RETURN_NONE; - return pyopencv_from(*p); -} - -template -bool pyopencv_to(PyObject *o, Ptr& p, const char *name) -{ - if (!o || o == Py_None) - return true; - p = makePtr(); - return pyopencv_to(o, *p, name); -} - #include "pyopencv_custom_headers.h" static void OnMouse(int event, int x, int y, int flags, void* param) From 2492c299f36d1c6a140f716f99b2293c6e02a27f Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Fri, 14 Apr 2017 13:35:07 +0300 Subject: [PATCH 124/144] Extended set of existing performance test to OpenVX HAL suitable execution modes --- modules/core/perf/perf_lut.cpp | 26 +++++++ modules/features2d/perf/perf_fast.cpp | 23 ++++++ modules/imgproc/perf/perf_accumulate.cpp | 96 ++++++++++++++++++++++++ modules/imgproc/perf/perf_filter2d.cpp | 27 +++++++ modules/imgproc/perf/perf_pyramids.cpp | 21 ++++++ modules/imgproc/perf/perf_warp.cpp | 68 +++++++++++++++++ modules/video/perf/perf_optflowpyrlk.cpp | 52 +++++++++++++ 7 files changed, 313 insertions(+) create mode 100644 modules/core/perf/perf_lut.cpp create mode 100644 modules/imgproc/perf/perf_accumulate.cpp diff --git a/modules/core/perf/perf_lut.cpp b/modules/core/perf/perf_lut.cpp new file mode 100644 index 0000000000..50ef04592c --- /dev/null +++ b/modules/core/perf/perf_lut.cpp @@ -0,0 +1,26 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; + +typedef perf::TestBaseWithParam SizePrm; + +PERF_TEST_P( SizePrm, LUT, + testing::Values(szQVGA, szVGA, sz1080p) + ) +{ + Size sz = GetParam(); + + int maxValue = 255; + + Mat src(sz, CV_8UC1); + randu(src, 0, maxValue); + Mat lut(1, 256, CV_8UC1); + randu(lut, 0, maxValue); + Mat dst(sz, CV_8UC1); + + TEST_CYCLE() LUT(src, lut, dst); + + SANITY_CHECK(dst, 0.1); +} diff --git a/modules/features2d/perf/perf_fast.cpp b/modules/features2d/perf/perf_fast.cpp index f706364004..709ae8296e 100644 --- a/modules/features2d/perf/perf_fast.cpp +++ b/modules/features2d/perf/perf_fast.cpp @@ -38,3 +38,26 @@ PERF_TEST_P(fast, detect, testing::Combine( SANITY_CHECK_KEYPOINTS(points); } + +PERF_TEST_P(fast, detect_ovx, testing::Combine( + testing::Values(FAST_IMAGES), + FastType::all() +)) +{ + string filename = getDataPath(get<0>(GetParam())); + int type = get<1>(GetParam()); + Mat frame = imread(filename, IMREAD_GRAYSCALE); + + if (frame.empty()) + FAIL() << "Unable to load source image " << filename; + + declare.in(frame); + + Ptr fd = FastFeatureDetector::create(20, false, type); + ASSERT_FALSE(fd.empty()); + vector points; + + TEST_CYCLE() fd->detect(frame, points); + + SANITY_CHECK_KEYPOINTS(points); +} diff --git a/modules/imgproc/perf/perf_accumulate.cpp b/modules/imgproc/perf/perf_accumulate.cpp new file mode 100644 index 0000000000..fe2111ae88 --- /dev/null +++ b/modules/imgproc/perf/perf_accumulate.cpp @@ -0,0 +1,96 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::get; + +#ifdef HAVE_OPENVX +PERF_TEST_P(Size_MatType, Accumulate, + testing::Combine( + testing::Values(::perf::szODD, ::perf::szQVGA, ::perf::szVGA, ::perf::sz1080p), + testing::Values(CV_16SC1, CV_32FC1) + ) +) +#else +PERF_TEST_P( Size_MatType, Accumulate, + testing::Combine( + testing::Values(::perf::szODD, ::perf::szQVGA, ::perf::szVGA, ::perf::sz1080p), + testing::Values(CV_32FC1) + ) + ) +#endif +{ + Size sz = get<0>(GetParam()); + int dstType = get<1>(GetParam()); + + Mat src(sz, CV_8UC1); + Mat dst(sz, dstType); + + declare.time(100); + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() accumulate(src, dst); + + SANITY_CHECK(dst); +} + +#ifdef HAVE_OPENVX +PERF_TEST_P(Size_MatType, AccumulateSquare, + testing::Combine( + testing::Values(::perf::szODD, ::perf::szQVGA, ::perf::szVGA, ::perf::sz1080p), + testing::Values(CV_16SC1, CV_32FC1) + ) +) +#else +PERF_TEST_P( Size_MatType, AccumulateSquare, + testing::Combine( + testing::Values(::perf::szODD, ::perf::szQVGA, ::perf::szVGA, ::perf::sz1080p), + testing::Values(CV_32FC1) + ) + ) +#endif +{ + Size sz = get<0>(GetParam()); + int dstType = get<1>(GetParam()); + + Mat src(sz, CV_8UC1); + Mat dst(sz, dstType); + + declare.time(100); + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() accumulateSquare(src, dst); + + SANITY_CHECK(dst); +} + +#ifdef HAVE_OPENVX +PERF_TEST_P(Size_MatType, AccumulateWeighted, + testing::Combine( + testing::Values(::perf::szODD, ::perf::szQVGA, ::perf::szVGA, ::perf::sz1080p), + testing::Values(CV_8UC1, CV_32FC1) + ) +) +#else +PERF_TEST_P( Size_MatType, AccumulateWeighted, + testing::Combine( + testing::Values(::perf::szODD, ::perf::szQVGA, ::perf::szVGA, ::perf::sz1080p), + testing::Values(CV_32FC1) + ) + ) +#endif +{ + Size sz = get<0>(GetParam()); + int dstType = get<1>(GetParam()); + + Mat src(sz, CV_8UC1); + Mat dst(sz, dstType); + + declare.time(100); + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() accumulateWeighted(src, dst, 0.314); + + SANITY_CHECK(dst); +} diff --git a/modules/imgproc/perf/perf_filter2d.cpp b/modules/imgproc/perf/perf_filter2d.cpp index 1eec745560..44c8d32cdb 100644 --- a/modules/imgproc/perf/perf_filter2d.cpp +++ b/modules/imgproc/perf/perf_filter2d.cpp @@ -42,6 +42,33 @@ PERF_TEST_P( TestFilter2d, Filter2d, SANITY_CHECK(dst, 1); } +PERF_TEST_P(TestFilter2d, Filter2d_ovx, + Combine( + Values(Size(320, 240), sz1080p), + Values(3, 5), + Values(BORDER_CONSTANT, BORDER_REPLICATE) + ) +) +{ + Size sz; + int borderMode, kSize; + sz = get<0>(GetParam()); + kSize = get<1>(GetParam()); + borderMode = get<2>(GetParam()); + + Mat src(sz, CV_8UC1); + Mat dst(sz, CV_16SC1); + + Mat kernel(kSize, kSize, CV_16SC1); + randu(kernel, -3, 10); + + declare.in(src, WARMUP_RNG).out(dst).time(20); + + TEST_CYCLE() filter2D(src, dst, CV_16SC1, kernel, Point(kSize / 2, kSize / 2), 0., borderMode); + + SANITY_CHECK(dst, 1); +} + PERF_TEST_P( Image_KernelSize, GaborFilter2d, Combine( Values("stitching/a1.png", "cv/shared/pic5.png"), diff --git a/modules/imgproc/perf/perf_pyramids.cpp b/modules/imgproc/perf/perf_pyramids.cpp index e23af8eade..6b5b7592b7 100644 --- a/modules/imgproc/perf/perf_pyramids.cpp +++ b/modules/imgproc/perf/perf_pyramids.cpp @@ -27,6 +27,27 @@ PERF_TEST_P(Size_MatType, pyrDown, testing::Combine( SANITY_CHECK(dst, eps, error_type); } +PERF_TEST_P(Size_MatType, pyrDown_ovx, testing::Combine( + testing::Values(sz1080p, sz720p, szVGA, szQVGA, szODD), + testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16SC1, CV_16SC3, CV_16SC4, CV_32FC1, CV_32FC3, CV_32FC4) +) +) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + const double eps = CV_MAT_DEPTH(matType) <= CV_32S ? 1 : 1e-5; + perf::ERROR_TYPE error_type = CV_MAT_DEPTH(matType) <= CV_32S ? ERROR_ABSOLUTE : ERROR_RELATIVE; + + Mat src(sz, matType); + Mat dst((sz.height + 1) / 2, (sz.width + 1) / 2, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() pyrDown(src, dst, cv::Size(), BORDER_REPLICATE); + + SANITY_CHECK(dst, eps, error_type); +} + PERF_TEST_P(Size_MatType, pyrUp, testing::Combine( testing::Values(sz720p, szVGA, szQVGA, szODD), testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16SC1, CV_16SC3, CV_16SC4, CV_32FC1, CV_32FC3, CV_32FC4) diff --git a/modules/imgproc/perf/perf_warp.cpp b/modules/imgproc/perf/perf_warp.cpp index 146528b6bb..dda5552d1e 100644 --- a/modules/imgproc/perf/perf_warp.cpp +++ b/modules/imgproc/perf/perf_warp.cpp @@ -50,6 +50,36 @@ PERF_TEST_P( TestWarpAffine, WarpAffine, #endif } +PERF_TEST_P(TestWarpAffine, WarpAffine_ovx, + Combine( + Values(szVGA, sz720p, sz1080p), + InterType::all(), + BorderMode::all() + ) +) +{ + Size sz, szSrc(512, 512); + int borderMode, interType; + sz = get<0>(GetParam()); + interType = get<1>(GetParam()); + borderMode = get<2>(GetParam()); + Scalar borderColor = Scalar::all(150); + + Mat src(szSrc, CV_8UC1), dst(sz, CV_8UC1); + cvtest::fillGradient(src); + if (borderMode == BORDER_CONSTANT) cvtest::smoothBorder(src, borderColor, 1); + Mat warpMat = getRotationMatrix2D(Point2f(src.cols / 2.f, src.rows / 2.f), 30., 2.2); + declare.in(src).out(dst); + + TEST_CYCLE() warpAffine(src, dst, warpMat, sz, interType, borderMode, borderColor); + +#ifdef ANDROID + SANITY_CHECK(dst, interType == INTER_LINEAR ? 5 : 10); +#else + SANITY_CHECK(dst, 1); +#endif +} + PERF_TEST_P( TestWarpPerspective, WarpPerspective, Combine( Values( szVGA, sz720p, sz1080p ), @@ -88,6 +118,44 @@ PERF_TEST_P( TestWarpPerspective, WarpPerspective, #endif } +PERF_TEST_P(TestWarpPerspective, WarpPerspective_ovx, + Combine( + Values(szVGA, sz720p, sz1080p), + InterType::all(), + BorderMode::all() + ) +) +{ + Size sz, szSrc(512, 512); + int borderMode, interType; + sz = get<0>(GetParam()); + interType = get<1>(GetParam()); + borderMode = get<2>(GetParam()); + Scalar borderColor = Scalar::all(150); + + Mat src(szSrc, CV_8UC1), dst(sz, CV_8UC1); + cvtest::fillGradient(src); + if (borderMode == BORDER_CONSTANT) cvtest::smoothBorder(src, borderColor, 1); + Mat rotMat = getRotationMatrix2D(Point2f(src.cols / 2.f, src.rows / 2.f), 30., 2.2); + Mat warpMat(3, 3, CV_64FC1); + for (int r = 0; r<2; r++) + for (int c = 0; c<3; c++) + warpMat.at(r, c) = rotMat.at(r, c); + warpMat.at(2, 0) = .3 / sz.width; + warpMat.at(2, 1) = .3 / sz.height; + warpMat.at(2, 2) = 1; + + declare.in(src).out(dst); + + TEST_CYCLE() warpPerspective(src, dst, warpMat, sz, interType, borderMode, borderColor); + +#ifdef ANDROID + SANITY_CHECK(dst, interType == INTER_LINEAR ? 5 : 10); +#else + SANITY_CHECK(dst, 1); +#endif +} + PERF_TEST_P( TestWarpPerspectiveNear_t, WarpPerspectiveNear, Combine( Values( Size(640,480), Size(1920,1080), Size(2592,1944) ), diff --git a/modules/video/perf/perf_optflowpyrlk.cpp b/modules/video/perf/perf_optflowpyrlk.cpp index 08ffd04d4d..a17a0f318d 100644 --- a/modules/video/perf/perf_optflowpyrlk.cpp +++ b/modules/video/perf/perf_optflowpyrlk.cpp @@ -97,6 +97,58 @@ PERF_TEST_P(Path_Idx_Cn_NPoints_WSize, OpticalFlowPyrLK_full, testing::Combine( SANITY_CHECK(err, 2); } +typedef tr1::tuple, int> Path_Idx_NPoints_WSize_t; +typedef TestBaseWithParam Path_Idx_NPoints_WSize; + +PERF_TEST_P(Path_Idx_NPoints_WSize, OpticalFlowPyrLK_ovx, testing::Combine( + testing::Values("cv/optflow/frames/VGA_%02d.png", "cv/optflow/frames/720p_%02d.png"), + testing::Range(1, 3), + testing::Values(make_tuple(9, 9), make_tuple(15, 15)), + testing::Values(7, 11) + ) + ) +{ + string filename1 = getDataPath(cv::format(get<0>(GetParam()).c_str(), get<1>(GetParam()))); + string filename2 = getDataPath(cv::format(get<0>(GetParam()).c_str(), get<1>(GetParam()) + 1)); + Mat img1 = imread(filename1); + Mat img2 = imread(filename2); + if (img1.empty()) FAIL() << "Unable to load source image " << filename1; + if (img2.empty()) FAIL() << "Unable to load source image " << filename2; + + int nPointsX = min(get<0>(get<2>(GetParam())), img1.cols); + int nPointsY = min(get<1>(get<2>(GetParam())), img1.rows); + int winSize = get<3>(GetParam()); + + int maxLevel = 2; + TermCriteria criteria(TermCriteria::COUNT|TermCriteria::EPS, 7, 0.001); + int flags = 0; + double minEigThreshold = 1e-4; + + Mat frame1, frame2; + cvtColor(img1, frame1, COLOR_BGR2GRAY, 1); + cvtColor(img2, frame2, COLOR_BGR2GRAY, 1); + + vector inPoints; + vector outPoints; + vector status; + + FormTrackingPointsArray(inPoints, frame1.cols, frame1.rows, nPointsX, nPointsY); + outPoints.resize(inPoints.size()); + status.resize(inPoints.size()); + + declare.in(frame1, frame2, inPoints).out(outPoints); + + TEST_CYCLE_N(30) + { + calcOpticalFlowPyrLK(frame1, frame2, inPoints, outPoints, status, cv::noArray(), + Size(winSize, winSize), maxLevel, criteria, + flags, minEigThreshold); + } + + SANITY_CHECK(outPoints, 0.3); + SANITY_CHECK(status); +} + typedef tr1::tuple, int, bool> Path_Idx_Cn_NPoints_WSize_Deriv_t; typedef TestBaseWithParam Path_Idx_Cn_NPoints_WSize_Deriv; From d6bc6895a6ea2c5958bc9722e0adaeab4e37b4f1 Mon Sep 17 00:00:00 2001 From: Pyotr Chekmaryov <4ekmah@gmail.com> Date: Thu, 27 Apr 2017 10:05:55 +0000 Subject: [PATCH 125/144] Test data correction. --- modules/calib3d/test/test_stereomatching.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/calib3d/test/test_stereomatching.cpp b/modules/calib3d/test/test_stereomatching.cpp index 08a955bb3a..d4f20b163d 100644 --- a/modules/calib3d/test/test_stereomatching.cpp +++ b/modules/calib3d/test/test_stereomatching.cpp @@ -797,8 +797,7 @@ TEST(Calib3d_StereoSGBM_HH4, regression) Ptr sgbm = StereoSGBM::create( 0, 48, 3, 90, 360, 1, 63, 10, 100, 32, StereoSGBM::MODE_HH4); sgbm->compute( leftImg, rightImg, leftDisp); CV_Assert( leftDisp.type() == CV_16SC1 ); - leftDisp.convertTo(toCheck, CV_16UC1); -// imwrite("/home/q/Work/GitVault/disp2_hh4.png",toCheck); + leftDisp.convertTo(toCheck, CV_16UC1,1,16); } Mat diff; absdiff(toCheck, testData,diff); From 8f5ea7dedadfbc71b7a2b1368828fa92655cb110 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 27 Apr 2017 14:32:06 +0100 Subject: [PATCH 126/144] core: avoid clash with _N define from ctype.h in headers This updates the public headers to use _Nm instead of _N in templates since _N is defined by the widely used ctype.h. --- modules/core/include/opencv2/core/mat.hpp | 28 +++---- modules/core/include/opencv2/core/mat.inl.hpp | 80 +++++++++---------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index cb77ed4edc..cba830c945 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -192,8 +192,8 @@ public: _InputArray(const std::vector& umv); #ifdef CV_CXX_STD_ARRAY - template _InputArray(const std::array<_Tp, _N>& arr); - template _InputArray(const std::array& arr); + template _InputArray(const std::array<_Tp, _Nm>& arr); + template _InputArray(const std::array& arr); #endif Mat getMat(int idx=-1) const; @@ -324,10 +324,10 @@ public: _OutputArray(const std::vector& vec); #ifdef CV_CXX_STD_ARRAY - template _OutputArray(std::array<_Tp, _N>& arr); - template _OutputArray(const std::array<_Tp, _N>& arr); - template _OutputArray(std::array& arr); - template _OutputArray(const std::array& arr); + template _OutputArray(std::array<_Tp, _Nm>& arr); + template _OutputArray(const std::array<_Tp, _Nm>& arr); + template _OutputArray(std::array& arr); + template _OutputArray(const std::array& arr); #endif bool fixedSize() const; @@ -390,10 +390,10 @@ public: _InputOutputArray(const std::vector& vec); #ifdef CV_CXX_STD_ARRAY - template _InputOutputArray(std::array<_Tp, _N>& arr); - template _InputOutputArray(const std::array<_Tp, _N>& arr); - template _InputOutputArray(std::array& arr); - template _InputOutputArray(const std::array& arr); + template _InputOutputArray(std::array<_Tp, _Nm>& arr); + template _InputOutputArray(const std::array<_Tp, _Nm>& arr); + template _InputOutputArray(std::array& arr); + template _InputOutputArray(const std::array& arr); #endif }; @@ -980,7 +980,7 @@ public: #ifdef CV_CXX_STD_ARRAY /** @overload */ - template explicit Mat(const std::array<_Tp, _N>& arr, bool copyData=false); + template explicit Mat(const std::array<_Tp, _Nm>& arr, bool copyData=false); #endif /** @overload @@ -1607,7 +1607,7 @@ public: template operator Matx<_Tp, m, n>() const; #ifdef CV_CXX_STD_ARRAY - template operator std::array<_Tp, _N>() const; + template operator std::array<_Tp, _Nm>() const; #endif /** @brief Reports whether the matrix is continuous or not. @@ -2156,7 +2156,7 @@ public: explicit Mat_(const MatCommaInitializer_<_Tp>& commaInitializer); #ifdef CV_CXX_STD_ARRAY - template explicit Mat_(const std::array<_Tp, _N>& arr, bool copyData=false); + template explicit Mat_(const std::array<_Tp, _Nm>& arr, bool copyData=false); #endif Mat_& operator = (const Mat& m); @@ -2255,7 +2255,7 @@ public: #ifdef CV_CXX_STD_ARRAY //! conversion to array. - template operator std::array<_Tp, _N>() const; + template operator std::array<_Tp, _Nm>() const; #endif //! conversion to Vec diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 72bc915abf..b92cc360e6 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -78,13 +78,13 @@ _InputArray::_InputArray(const std::vector<_Tp>& vec) { init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); } #ifdef CV_CXX_STD_ARRAY -template inline -_InputArray::_InputArray(const std::array<_Tp, _N>& arr) -{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_READ, arr.data(), Size(1, _N)); } +template inline +_InputArray::_InputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_READ, arr.data(), Size(1, _Nm)); } -template inline -_InputArray::_InputArray(const std::array& arr) -{ init(STD_ARRAY_MAT + ACCESS_READ, arr.data(), Size(1, _N)); } +template inline +_InputArray::_InputArray(const std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_READ, arr.data(), Size(1, _Nm)); } #endif inline @@ -162,13 +162,13 @@ _OutputArray::_OutputArray(std::vector<_Tp>& vec) { init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } #ifdef CV_CXX_STD_ARRAY -template inline -_OutputArray::_OutputArray(std::array<_Tp, _N>& arr) -{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_WRITE, arr.data(), Size(1, _N)); } +template inline +_OutputArray::_OutputArray(std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } -template inline -_OutputArray::_OutputArray(std::array& arr) -{ init(STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _N)); } +template inline +_OutputArray::_OutputArray(std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } #endif inline @@ -200,13 +200,13 @@ _OutputArray::_OutputArray(const std::vector<_Tp>& vec) { init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); } #ifdef CV_CXX_STD_ARRAY -template inline -_OutputArray::_OutputArray(const std::array<_Tp, _N>& arr) -{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_WRITE, arr.data(), Size(1, _N)); } +template inline +_OutputArray::_OutputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } -template inline -_OutputArray::_OutputArray(const std::array& arr) -{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _N)); } +template inline +_OutputArray::_OutputArray(const std::array& arr) +{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } #endif template inline @@ -277,13 +277,13 @@ _InputOutputArray::_InputOutputArray(std::vector<_Tp>& vec) { init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } #ifdef CV_CXX_STD_ARRAY -template inline -_InputOutputArray::_InputOutputArray(std::array<_Tp, _N>& arr) -{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_RW, arr.data(), Size(1, _N)); } +template inline +_InputOutputArray::_InputOutputArray(std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_RW, arr.data(), Size(1, _Nm)); } -template inline -_InputOutputArray::_InputOutputArray(std::array& arr) -{ init(STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _N)); } +template inline +_InputOutputArray::_InputOutputArray(std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _Nm)); } #endif inline _InputOutputArray::_InputOutputArray(std::vector&) @@ -314,13 +314,13 @@ _InputOutputArray::_InputOutputArray(const std::vector<_Tp>& vec) { init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); } #ifdef CV_CXX_STD_ARRAY -template inline -_InputOutputArray::_InputOutputArray(const std::array<_Tp, _N>& arr) -{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_RW, arr.data(), Size(1, _N)); } +template inline +_InputOutputArray::_InputOutputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + DataType<_Tp>::type + ACCESS_RW, arr.data(), Size(1, _Nm)); } -template inline -_InputOutputArray::_InputOutputArray(const std::array& arr) -{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _N)); } +template inline +_InputOutputArray::_InputOutputArray(const std::array& arr) +{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _Nm)); } #endif template inline @@ -558,8 +558,8 @@ Mat::Mat(const std::vector<_Tp>& vec, bool copyData) } #ifdef CV_CXX_STD_ARRAY -template inline -Mat::Mat(const std::array<_Tp, _N>& arr, bool copyData) +template inline +Mat::Mat(const std::array<_Tp, _Nm>& arr, bool copyData) : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows((int)arr.size()), cols(1), data(0), datastart(0), dataend(0), allocator(0), u(0), size(&rows) { @@ -1197,10 +1197,10 @@ Mat::operator std::vector<_Tp>() const } #ifdef CV_CXX_STD_ARRAY -template inline -Mat::operator std::array<_Tp, _N>() const +template inline +Mat::operator std::array<_Tp, _Nm>() const { - std::array<_Tp, _N> v; + std::array<_Tp, _Nm> v; copyTo(v); return v; } @@ -1561,8 +1561,8 @@ Mat_<_Tp>::Mat_(const std::vector<_Tp>& vec, bool copyData) {} #ifdef CV_CXX_STD_ARRAY -template template inline -Mat_<_Tp>::Mat_(const std::array<_Tp, _N>& arr, bool copyData) +template template inline +Mat_<_Tp>::Mat_(const std::array<_Tp, _Nm>& arr, bool copyData) : Mat(arr, copyData) {} #endif @@ -1845,10 +1845,10 @@ Mat_<_Tp>::operator std::vector<_Tp>() const } #ifdef CV_CXX_STD_ARRAY -template template inline -Mat_<_Tp>::operator std::array<_Tp, _N>() const +template template inline +Mat_<_Tp>::operator std::array<_Tp, _Nm>() const { - std::array<_Tp, _N> a; + std::array<_Tp, _Nm> a; copyTo(a); return a; } From cdc7f10767d1474a1b939b362b1a439cbe8ed4ad Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 27 Apr 2017 18:06:04 +0300 Subject: [PATCH 127/144] cmake: dispatcher: add handling of include dirs from linked targets of base modules --- cmake/OpenCVCompilerOptimizations.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/OpenCVCompilerOptimizations.cmake b/cmake/OpenCVCompilerOptimizations.cmake index 6758fdf628..eb0d4ade21 100644 --- a/cmake/OpenCVCompilerOptimizations.cmake +++ b/cmake/OpenCVCompilerOptimizations.cmake @@ -587,6 +587,7 @@ macro(ocv_compiler_optimization_process_sources SOURCES_VAR_NAME LIBS_VAR_NAME T ocv_append_dependant_targets(${TARGET_BASE_NAME} ${TARGET_BASE_NAME}_${OPT}) set_target_properties(${TARGET_BASE_NAME}_${OPT} PROPERTIES COMPILE_DEFINITIONS "${CPU_DISPATCH_DEFINITIONS_${OPT}}") set_target_properties(${TARGET_BASE_NAME}_${OPT} PROPERTIES COMPILE_FLAGS "${CPU_DISPATCH_FLAGS_${OPT}}") + target_include_directories(${TARGET_BASE_NAME}_${OPT} PRIVATE $) #list(APPEND __result_libs ${TARGET_BASE_NAME}_${OPT}) list(APPEND __result "$") else() From 39874d72546ddecef1e51c708f0d025656fb670b Mon Sep 17 00:00:00 2001 From: Louie Helm Date: Thu, 27 Apr 2017 16:28:36 -0700 Subject: [PATCH 128/144] Fix Farneback GPU Sample in GCC6 --- samples/gpu/farneback_optical_flow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/gpu/farneback_optical_flow.cpp b/samples/gpu/farneback_optical_flow.cpp index 798b108a62..b3d67b6738 100644 --- a/samples/gpu/farneback_optical_flow.cpp +++ b/samples/gpu/farneback_optical_flow.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "opencv2/core.hpp" #include "opencv2/core/utility.hpp" From 7885ef2ac88e3f6c58c5b0fffc6161c7eeed7e13 Mon Sep 17 00:00:00 2001 From: "Ninad P.Chaudhari" Date: Sat, 29 Apr 2017 20:03:47 +0530 Subject: [PATCH 129/144] Spell correction Corrected the spelling which was used in explanation for parameters. --- .../imgproc/imgtrans/hough_circle/hough_circle.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown index 9f3951927c..36c03cd143 100644 --- a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown +++ b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown @@ -66,7 +66,7 @@ Explanation - *min_dist = gray.rows/16*: Minimum distance between detected centers. - *param_1 = 200*: Upper threshold for the internal Canny edge detector. - *param_2* = 100\*: Threshold for center detection. - - *min_radius = 0*: Minimum radio to be detected. If unknown, put zero as default. + - *min_radius = 0*: Minimum radius to be detected. If unknown, put zero as default. - *max_radius = 0*: Maximum radius to be detected. If unknown, put zero as default. -# Draw the detected circles: From 369bfbfd230b702a666197aad3c9cc3342981033 Mon Sep 17 00:00:00 2001 From: jveitchmichaelis Date: Sat, 29 Apr 2017 20:38:06 +0100 Subject: [PATCH 130/144] Add default parameters for SGBM::create Added default parameters for minDisparity, numDisparities and blockSize. This fixes a bug where SGBM::load would not compile. --- modules/calib3d/include/opencv2/calib3d.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index c58daab027..9729012b11 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -1917,7 +1917,7 @@ public: set StereoSGBM::numDisparities at minimum. The second constructor enables you to set each parameter to a custom value. */ - CV_WRAP static Ptr create(int minDisparity, int numDisparities, int blockSize, + CV_WRAP static Ptr create(int minDisparity = 0, int numDisparities = 16, int blockSize = 3, int P1 = 0, int P2 = 0, int disp12MaxDiff = 0, int preFilterCap = 0, int uniquenessRatio = 0, int speckleWindowSize = 0, int speckleRange = 0, From bbb785e43c6effb7ae948c2c88107f42a8b57d86 Mon Sep 17 00:00:00 2001 From: saskatchewancatch Date: Tue, 25 Apr 2017 21:54:37 -0600 Subject: [PATCH 131/144] Issue 8647: Updated doc for cv::matchTemplate to reflect current support for methods when mast template is supplied. --- modules/imgproc/include/opencv2/imgproc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index fea89a886a..4df93a0cef 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -3687,7 +3687,7 @@ data type. is \f$W \times H\f$ and templ is \f$w \times h\f$ , then result is \f$(W-w+1) \times (H-h+1)\f$ . @param method Parameter specifying the comparison method, see cv::TemplateMatchModes @param mask Mask of searched template. It must have the same datatype and size with templ. It is -not set by default. +not set by default. Currently, only the TM_SQDIFF and TM_CCORR_NORMED methods are supported. */ CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, OutputArray result, int method, InputArray mask = noArray() ); From bf62be7f63e182b8d9cc104e22de7854f60a7266 Mon Sep 17 00:00:00 2001 From: Vladislav Sovrasov Date: Tue, 18 Apr 2017 11:28:26 +0300 Subject: [PATCH 132/144] java: allow to wrap functions which take cv::Ptr --- modules/java/generator/gen_java.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index c18b9d5f18..a91d0756a6 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -649,6 +649,7 @@ public class $jname { protected final long nativeObj; protected $jname(long addr) { nativeObj = addr; } + public long getNativeObjAddr() { return nativeObj; } """ T_JAVA_START_MODULE = """ @@ -1004,7 +1005,7 @@ class JavaWrapperGenerator(object): classinfo.addImports(classinfo.base) type_dict["Ptr_"+name] = \ { "j_type" : classinfo.jname, - "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),), + "jn_type" : "long", "jn_args" : (("__int64", ".getNativeObjAddr()"),), "jni_name" : "*((Ptr<"+classinfo.fullName(isCPP=True)+">*)%(n)s_nativeObj)", "jni_type" : "jlong", "suffix" : "J" } logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base) @@ -1228,7 +1229,7 @@ class JavaWrapperGenerator(object): if "I" in a.out or not a.out or self.isWrapped(a.ctype): # input arg, pass by primitive fields for f in fields: jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) ) - jni_args.append( ArgInfo([ f[0], a.name + f[1].replace(".","_").replace("[","").replace("]",""), "", [], "" ]) ) + jni_args.append( ArgInfo([ f[0], a.name + f[1].replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj"), "", [], "" ]) ) if a.out and not self.isWrapped(a.ctype): # out arg, pass as double[] jn_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) ) jni_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) ) @@ -1276,7 +1277,7 @@ class JavaWrapperGenerator(object): " private static native $type $name($args);\n").substitute(\ type = type_dict[fi.ctype].get("jn_type", "double[]"), \ name = fi.jname + '_' + str(suffix_counter), \ - args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], a.name.replace(".","_").replace("[","").replace("]","")) for a in jn_args]) + args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], a.name.replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj")) for a in jn_args]) ) ); # java part: From 70e6391f38632f65427c7dbc6bdae4752893e147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mewes?= Date: Thu, 13 Apr 2017 14:39:10 +0200 Subject: [PATCH 133/144] create homogeneous affine matrix when constructing from 4x3 cv::Mat --- modules/core/include/opencv2/core/affine.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/core/include/opencv2/core/affine.hpp b/modules/core/include/opencv2/core/affine.hpp index 311ff62637..41de5c6b57 100644 --- a/modules/core/include/opencv2/core/affine.hpp +++ b/modules/core/include/opencv2/core/affine.hpp @@ -213,11 +213,13 @@ cv::Affine3::Affine3(const cv::Mat& data, const Vec3& t) { rotation(data(Rect(0, 0, 3, 3))); translation(data(Rect(3, 0, 1, 3))); - return; + } + else + { + rotation(data); + translation(t); } - rotation(data); - translation(t); matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; matrix.val[15] = 1; } From 4f6238aa048c43b03b0e115bbdc3f942ecba17a5 Mon Sep 17 00:00:00 2001 From: Yuriy Solovyov Date: Tue, 2 May 2017 18:48:54 +0300 Subject: [PATCH 134/144] Use all available cpu cores in iOS/OSX build procedure --- platforms/ios/build_framework.py | 4 ++-- platforms/osx/build_framework.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platforms/ios/build_framework.py b/platforms/ios/build_framework.py index a09c2fa916..e6557b4dca 100644 --- a/platforms/ios/build_framework.py +++ b/platforms/ios/build_framework.py @@ -28,7 +28,7 @@ Adding --dynamic parameter will build opencv2.framework as App Store dynamic fra """ from __future__ import print_function -import glob, re, os, os.path, shutil, string, sys, argparse, traceback +import glob, re, os, os.path, shutil, string, sys, argparse, traceback, multiprocessing from subprocess import check_call, check_output, CalledProcessError def execute(cmd, cwd = None): @@ -166,7 +166,7 @@ class Builder: "-sdk", target.lower(), "-configuration", "Release", "-parallelizeTargets", - "-jobs", "4", + "-jobs", multiprocessing.cpu_count(), ] + (["-target","ALL_BUILD"] if self.dynamic else []) return buildcmd diff --git a/platforms/osx/build_framework.py b/platforms/osx/build_framework.py index 6e23931266..90affab33e 100644 --- a/platforms/osx/build_framework.py +++ b/platforms/osx/build_framework.py @@ -4,7 +4,7 @@ The script builds OpenCV.framework for OSX. """ from __future__ import print_function -import os, os.path, sys, argparse, traceback +import os, os.path, sys, argparse, traceback, multiprocessing # import common code sys.path.insert(0, os.path.abspath(os.path.abspath(os.path.dirname(__file__))+'/../ios')) @@ -23,7 +23,7 @@ class OSXBuilder(Builder): "-sdk", target.lower(), "-configuration", "Release", "-parallelizeTargets", - "-jobs", "4" + "-jobs", multiprocessing.cpu_count() ] return buildcmd From 96f1ef1347f72eca8d82a97de50364a7b2a99101 Mon Sep 17 00:00:00 2001 From: Yuriy Solovyov Date: Tue, 2 May 2017 18:59:37 +0300 Subject: [PATCH 135/144] Fix buildcmd --- platforms/ios/build_framework.py | 2 +- platforms/osx/build_framework.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platforms/ios/build_framework.py b/platforms/ios/build_framework.py index e6557b4dca..78d9ec6441 100644 --- a/platforms/ios/build_framework.py +++ b/platforms/ios/build_framework.py @@ -166,7 +166,7 @@ class Builder: "-sdk", target.lower(), "-configuration", "Release", "-parallelizeTargets", - "-jobs", multiprocessing.cpu_count(), + "-jobs", str(multiprocessing.cpu_count()), ] + (["-target","ALL_BUILD"] if self.dynamic else []) return buildcmd diff --git a/platforms/osx/build_framework.py b/platforms/osx/build_framework.py index 90affab33e..2db5cd2564 100644 --- a/platforms/osx/build_framework.py +++ b/platforms/osx/build_framework.py @@ -23,7 +23,7 @@ class OSXBuilder(Builder): "-sdk", target.lower(), "-configuration", "Release", "-parallelizeTargets", - "-jobs", multiprocessing.cpu_count() + "-jobs", str(multiprocessing.cpu_count()) ] return buildcmd From 986d57c7b299dacb37eb58ae4c70086ea657d2fc Mon Sep 17 00:00:00 2001 From: vskarlsruhe Date: Wed, 3 May 2017 14:46:34 +0200 Subject: [PATCH 136/144] Update canny_detector.markdown (#8684) --- .../imgtrans/canny_detector/canny_detector.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.markdown b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.markdown index f9f2a2a2b7..79542415a8 100644 --- a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.markdown +++ b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.markdown @@ -68,7 +68,7 @@ Code -# **What does this program do?** - Asks the user to enter a numerical value to set the lower threshold for our *Canny Edge - Detector* (by means of a Trackbar) + Detector* (by means of a Trackbar). - Applies the *Canny Detector* and generates a **mask** (bright lines representing the edges on a black background). - Applies the mask obtained on the original image and display it in a window. @@ -85,19 +85,19 @@ Explanation Note the following: - -# We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*) + -# We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*). -# We set the kernel size of \f$3\f$ (for the Sobel operations to be performed internally by the - Canny function) + Canny function). -# We set a maximum value for the lower Threshold of \f$100\f$. -# Loads the source image: @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp load --# Create a matrix of the same type and size of *src* (to be *dst*) +-# Create a matrix of the same type and size of *src* (to be *dst*): @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_mat --# Convert the image to grayscale (using the function @ref cv::cvtColor : +-# Convert the image to grayscale (using the function @ref cv::cvtColor ): @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp convert_to_gray --# Create a window to display the results +-# Create a window to display the results: @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_window -# Create a Trackbar for the user to enter the lower threshold for our Canny detector: @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_trackbar From 256b6bb3dbab5a2c02f8bbc0a2aa674277ac29b8 Mon Sep 17 00:00:00 2001 From: nnorwitz Date: Sun, 16 Apr 2017 22:21:35 -0700 Subject: [PATCH 137/144] Don't blow out the stack. Use a smaller buffer and prevent buffer overruns with snprintf. --- modules/core/src/system.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index e5402614eb..1951af0c4d 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -859,9 +859,10 @@ void error( const Exception& exc ) else { const char* errorStr = cvErrorStr(exc.code); - char buf[1 << 16]; + char buf[1 << 12]; - sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d", + snprintf( buf, sizeof(buf), + "OpenCV Error: %s (%s) in %s, file %s, line %d", errorStr, exc.err.c_str(), exc.func.size() > 0 ? exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line ); fprintf( stderr, "%s\n", buf ); From 65be9e1978eecd51c86725ec185148069fb1d053 Mon Sep 17 00:00:00 2001 From: LukeZhu Date: Wed, 19 Apr 2017 15:49:42 +0800 Subject: [PATCH 138/144] Fix OpenCL's wrong output of calcOpticalFlowPyrLK function's output vector of err. Improve err's precison of the calcOpticalFlowPyrLK OpenCL function and add the relative test. --- modules/video/src/lkpyramid.cpp | 3 +++ modules/video/src/opencl/pyrlk.cl | 4 ++-- modules/video/test/ocl/test_optflowpyrlk.cpp | 12 ++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/modules/video/src/lkpyramid.cpp b/modules/video/src/lkpyramid.cpp index 739bb10780..8979d74437 100644 --- a/modules/video/src/lkpyramid.cpp +++ b/modules/video/src/lkpyramid.cpp @@ -849,6 +849,9 @@ namespace return false; if (maxLevel < 0 || winSize.width <= 2 || winSize.height <= 2) return false; + if (winSize.width < 16 || winSize.height < 16 || + winSize.width > 24 || winSize.height > 24) + return false; calcPatchSize(); if (patch.x <= 0 || patch.x >= 6 || patch.y <= 0 || patch.y >= 6) return false; diff --git a/modules/video/src/opencl/pyrlk.cl b/modules/video/src/opencl/pyrlk.cl index 80ec48a74e..dd8f368fb5 100644 --- a/modules/video/src/opencl/pyrlk.cl +++ b/modules/video/src/opencl/pyrlk.cl @@ -260,7 +260,7 @@ inline void GetPatch(image2d_t J, float x, float y, inline void GetError(image2d_t J, const float x, const float y, const float* Pch, float* errval) { - float diff = read_imagef(J, sampler, (float2)(x,y)).x-*Pch; + float diff = (((read_imagef(J, sampler, (float2)(x,y)).x * 16384) + 256) / 512) - (((*Pch * 16384) + 256) /512); *errval += fabs(diff); } @@ -526,6 +526,6 @@ __kernel void lkSparse(image2d_t I, image2d_t J, nextPts[gid] = prevPt; if (calcErr) - err[gid] = smem1[0] / (float)(c_winSize_x * c_winSize_y); + err[gid] = smem1[0] / (float)(32 * c_winSize_x * c_winSize_y); } } diff --git a/modules/video/test/ocl/test_optflowpyrlk.cpp b/modules/video/test/ocl/test_optflowpyrlk.cpp index 3c264a5e41..40b626150c 100644 --- a/modules/video/test/ocl/test_optflowpyrlk.cpp +++ b/modules/video/test/ocl/test_optflowpyrlk.cpp @@ -77,6 +77,7 @@ OCL_TEST_P(PyrLKOpticalFlow, Mat) { static const int npoints = 1000; static const float eps = 0.03f; + static const float erreps = 0.1f; cv::Mat frame0 = readImage("optflow/RubberWhale1.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); @@ -104,6 +105,8 @@ OCL_TEST_P(PyrLKOpticalFlow, Mat) ASSERT_EQ(cpuStatusCPU.size(), status.size()); size_t mistmatch = 0; + size_t errmatch = 0; + for (size_t i = 0; i < nextPts.size(); ++i) { if (status[i] != cpuStatusCPU[i]) @@ -121,13 +124,22 @@ OCL_TEST_P(PyrLKOpticalFlow, Mat) float errdiff = 0.0f; if (!eq || errdiff > 1e-1) + { ++mistmatch; + continue; + } + + eq = std::abs(cpuErr[i] - err[i]) < 0.01; + if(!eq) + ++errmatch; } } double bad_ratio = static_cast(mistmatch) / (nextPts.size()); + double err_ratio = static_cast(errmatch) / (nextPts.size()); ASSERT_LE(bad_ratio, eps); + ASSERT_LE(err_ratio, erreps); } OCL_INSTANTIATE_TEST_CASE_P(Video, PyrLKOpticalFlow, From dcd8589b678824beeba4f5741c975ec78f943c8a Mon Sep 17 00:00:00 2001 From: Philipp Hasper Date: Wed, 10 May 2017 18:25:39 +0200 Subject: [PATCH 139/144] Fixed exp32f() compilation on MSVC --- modules/core/src/mathfuncs_core.simd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/mathfuncs_core.simd.hpp b/modules/core/src/mathfuncs_core.simd.hpp index ad5176e192..b10bab6d63 100644 --- a/modules/core/src/mathfuncs_core.simd.hpp +++ b/modules/core/src/mathfuncs_core.simd.hpp @@ -550,7 +550,7 @@ void exp32f( const float *_x, float *y, int n ) __m256 yf = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm256_cvtpd_ps(yd0)), _mm256_cvtpd_ps(yd1), 1); //_mm256_set_m128i(xi1, xi0) - __m256i temp = (__m256i)_mm256_insertf128_ps(_mm256_castps128_ps256((__m128)xi0), (__m128)xi1, 1); + __m256i temp = _mm256_castps_si256(_mm256_insertf128_ps(_mm256_castps128_ps256(_mm_castsi128_ps(xi0)), _mm_castsi128_ps(xi1), 1)); yf = _mm256_mul_ps(yf, _mm256_castsi256_ps(_mm256_slli_epi32(temp, 23))); From 7b05d52f7b4f8b8eb80e5789c46c49203314727e Mon Sep 17 00:00:00 2001 From: berak Date: Thu, 11 May 2017 08:34:21 +0200 Subject: [PATCH 140/144] py_samples: fix digits.py --- samples/python/digits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/python/digits.py b/samples/python/digits.py index 5cc98b713c..16d76a13b0 100755 --- a/samples/python/digits.py +++ b/samples/python/digits.py @@ -109,7 +109,7 @@ def evaluate_model(model, digits, samples, labels): confusion = np.zeros((10, 10), np.int32) for i, j in zip(labels, resp): - confusion[i, j] += 1 + confusion[i, int(j)] += 1 print('confusion matrix:') print(confusion) print() From 2055bcc807714c01b5d1fe8d169f894d5b3d5302 Mon Sep 17 00:00:00 2001 From: Cartucho Date: Thu, 11 May 2017 22:42:04 +0100 Subject: [PATCH 141/144] Extending template_matching tutorial with Java (#8043) * Extending template_matching tutorial with Java * adding mask to java version of the tutorial * adding the python toggle and code * updating table of content * adding py and java to table of content * adding mask to python * going back to markdown with duplicated text * non duplicated text --- doc/footer.html | 2 +- .../template_matching.markdown | 249 +++++++++++------- .../imgproc/table_of_content_imgproc.markdown | 2 + .../MatchTemplate_Demo.cpp | 25 +- .../MatchTemplateDemo.java | 196 ++++++++++++++ .../imgProc/match_template/match_template.py | 96 +++++++ 6 files changed, 473 insertions(+), 97 deletions(-) create mode 100644 samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java create mode 100644 samples/python/tutorial_code/imgProc/match_template/match_template.py diff --git a/doc/footer.html b/doc/footer.html index c6361449f5..a0b4d5ce32 100644 --- a/doc/footer.html +++ b/doc/footer.html @@ -67,7 +67,7 @@ $("h2").each(function() { $smallerHeadings = $(this).nextUntil("h2").filter("h3").add($(this).nextUntil("h2").find("h3")); if ($smallerHeadings.length) { $smallerHeadings.each(function() { - var $elements = $(this).nextUntil("h3").filter("div.newInnerHTML"); + var $elements = $(this).nextUntil("h2,h3").filter("div.newInnerHTML"); buttonsToAdd($elements, $(this), "h3"); }); } else { diff --git a/doc/tutorials/imgproc/histograms/template_matching/template_matching.markdown b/doc/tutorials/imgproc/histograms/template_matching/template_matching.markdown index 1dc3ca8e82..1189923a98 100644 --- a/doc/tutorials/imgproc/histograms/template_matching/template_matching.markdown +++ b/doc/tutorials/imgproc/histograms/template_matching/template_matching.markdown @@ -1,14 +1,17 @@ Template Matching {#tutorial_template_matching} ================= +@prev_tutorial{tutorial_back_projection} +@next_tutorial{tutorial_find_contours} + Goal ---- In this tutorial you will learn how to: -- Use the OpenCV function @ref cv::matchTemplate to search for matches between an image patch and +- Use the OpenCV function **matchTemplate()** to search for matches between an image patch and an input image -- Use the OpenCV function @ref cv::minMaxLoc to find the maximum and minimum values (as well as +- Use the OpenCV function **minMaxLoc()** to find the maximum and minimum values (as well as their positions) in a given array. Theory @@ -42,7 +45,7 @@ that should be used to find the match. - By **sliding**, we mean moving the patch one pixel at a time (left to right, up to down). At each location, a metric is calculated so it represents how "good" or "bad" the match at that location is (or how similar the patch is to that particular area of the source image). -- For each location of **T** over **I**, you *store* the metric in the *result matrix* **(R)**. +- For each location of **T** over **I**, you *store* the metric in the *result matrix* **R**. Each location \f$(x,y)\f$ in **R** contains the match metric: ![](images/Template_Matching_Template_Theory_Result.jpg) @@ -51,9 +54,8 @@ that should be used to find the match. The brightest locations indicate the highest matches. As you can see, the location marked by the red circle is probably the one with the highest value, so that location (the rectangle formed by that point as a corner and width and height equal to the patch image) is considered the match. - -- In practice, we use the function @ref cv::minMaxLoc to locate the highest value (or lower, - depending of the type of matching method) in the *R* matrix. +- In practice, we locate the highest value (or lower, depending of the type of matching method) in + the *R* matrix, using the function **minMaxLoc()** ### How does the mask work? - If masking is needed for the match, three components are required: @@ -81,7 +83,7 @@ that should be used to find the match. ### Which are the matching methods available in OpenCV? -Good question. OpenCV implements Template matching in the function @ref cv::matchTemplate . The +Good question. OpenCV implements Template matching in the function **matchTemplate()**. The available methods are 6: -# **method=CV_TM_SQDIFF** @@ -117,119 +119,176 @@ Code - **What does this program do?** - Loads an input image, an image patch (*template*), and optionally a mask - - Perform a template matching procedure by using the OpenCV function @ref cv::matchTemplate + - Perform a template matching procedure by using the OpenCV function **matchTemplate()** with any of the 6 matching methods described before. The user can choose the method by entering its selection in the Trackbar. If a mask is supplied, it will only be used for the methods that support masking - Normalize the output of the matching procedure - Localize the location with higher matching probability - Draw a rectangle around the area corresponding to the highest match + +@add_toggle_cpp + - **Downloadable code**: Click [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp) - **Code at glance:** @include samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp +@end_toggle + +@add_toggle_java + +- **Downloadable code**: Click + [here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java) +- **Code at glance:** + @include samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java + +@end_toggle + +@add_toggle_python + +- **Downloadable code**: Click + [here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/imgProc/match_template/match_template.py) +- **Code at glance:** + @include samples/python/tutorial_code/imgProc/match_template/match_template.py + +@end_toggle + Explanation ----------- --# Declare some global variables, such as the image, template and result matrices, as well as the +- Declare some global variables, such as the image, template and result matrices, as well as the match method and the window names: - @code{.cpp} - Mat img; Mat templ; Mat result; - char* image_window = "Source Image"; - char* result_window = "Result window"; - int match_method; - int max_Trackbar = 5; - @endcode --# Load the source image, template, and optionally, if supported for the matching method, a mask: - @code{.cpp} - bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED); - if (use_mask && method_accepts_mask) - { matchTemplate( img, templ, result, match_method, mask); } - else - { matchTemplate( img, templ, result, match_method); } + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp declare + @end_toggle - @endcode --# Create the windows to show the results: - @code{.cpp} - namedWindow( image_window, WINDOW_AUTOSIZE ); - namedWindow( result_window, WINDOW_AUTOSIZE ); - @endcode --# Create the Trackbar to enter the kind of matching method to be used. When a change is detected - the callback function **MatchingMethod** is called. - @code{.cpp} - char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED"; - createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod ); - @endcode --# Wait until user exits the program. - @code{.cpp} - waitKey(0); - return 0; - @endcode --# Let's check out the callback function. First, it makes a copy of the source image: - @code{.cpp} - Mat img_display; - img.copyTo( img_display ); - @endcode --# Next, it creates the result matrix that will store the matching results for each template - location. Observe in detail the size of the result matrix (which matches all possible locations - for it) - @code{.cpp} - int result_cols = img.cols - templ.cols + 1; - int result_rows = img.rows - templ.rows + 1; + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java declare + @end_toggle - result.create( result_rows, result_cols, CV_32FC1 ); - @endcode --# Perform the template matching operation: - @code{.cpp} - bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED); - if (use_mask && method_accepts_mask) - { matchTemplate( img, templ, result, match_method, mask); } - else - { matchTemplate( img, templ, result, match_method); } - @endcode - the arguments are naturally the input image **I**, the template **T**, the result **R**, the - match_method (given by the Trackbar), and optionally the mask image **M** + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py global_variables + @end_toggle --# We normalize the results: - @code{.cpp} - normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); - @endcode --# We localize the minimum and maximum values in the result matrix **R** by using @ref - cv::minMaxLoc . - @code{.cpp} - double minVal; double maxVal; Point minLoc; Point maxLoc; - Point matchLoc; +- Load the source image, template, and optionally, if supported for the matching method, a mask: - minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() ); - @endcode - the function calls as arguments: + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp load_image + @end_toggle - - **result:** The source array - - **&minVal** and **&maxVal:** Variables to save the minimum and maximum values in **result** - - **&minLoc** and **&maxLoc:** The Point locations of the minimum and maximum values in the - array. - - **Mat():** Optional mask + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java load_image + @end_toggle --# For the first two methods ( TM_SQDIFF and MT_SQDIFF_NORMED ) the best match are the lowest + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py load_image + @end_toggle + +- Create the Trackbar to enter the kind of matching method to be used. When a change is detected + the callback function is called. + + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp create_trackbar + @end_toggle + + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java create_trackbar + @end_toggle + + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py create_trackbar + @end_toggle + +- Let's check out the callback function. First, it makes a copy of the source image: + + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp copy_source + @end_toggle + + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java copy_source + @end_toggle + + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py copy_source + @end_toggle + +- Perform the template matching operation. The arguments are naturally the input image **I**, + the template **T**, the result **R** and the match_method (given by the Trackbar), + and optionally the mask image **M**. + + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp match_template + @end_toggle + + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java match_template + @end_toggle + + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py match_template + @end_toggle + +- We normalize the results: + + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp normalize + @end_toggle + + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java normalize + @end_toggle + + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py normalize + @end_toggle + +- We localize the minimum and maximum values in the result matrix **R** by using **minMaxLoc()**. + + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp best_match + @end_toggle + + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java best_match + @end_toggle + + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py best_match + @end_toggle + +- For the first two methods ( TM_SQDIFF and MT_SQDIFF_NORMED ) the best match are the lowest values. For all the others, higher values represent better matches. So, we save the corresponding value in the **matchLoc** variable: - @code{.cpp} - if( match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED ) - { matchLoc = minLoc; } - else - { matchLoc = maxLoc; } - @endcode --# Display the source image and the result matrix. Draw a rectangle around the highest possible - matching area: - @code{.cpp} - rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); - rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); - imshow( image_window, img_display ); - imshow( result_window, result ); - @endcode + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp match_loc + @end_toggle + + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java match_loc + @end_toggle + + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py match_loc + @end_toggle + +- Display the source image and the result matrix. Draw a rectangle around the highest possible + matching area: + + @add_toggle_cpp + @snippet samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp imshow + @end_toggle + + @add_toggle_java + @snippet samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java imshow + @end_toggle + + @add_toggle_python + @snippet samples/python/tutorial_code/imgProc/match_template/match_template.py imshow + @end_toggle Results ------- diff --git a/doc/tutorials/imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown index 05b311061a..42dd4ce3bf 100644 --- a/doc/tutorials/imgproc/table_of_content_imgproc.markdown +++ b/doc/tutorials/imgproc/table_of_content_imgproc.markdown @@ -173,6 +173,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_template_matching + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán diff --git a/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp b/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp index 1042e2cff2..c60e45b154 100644 --- a/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp +++ b/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp @@ -12,6 +12,7 @@ using namespace std; using namespace cv; +//! [declare] /// Global Variables bool use_mask; Mat img; Mat templ; Mat mask; Mat result; @@ -20,6 +21,7 @@ const char* result_window = "Result window"; int match_method; int max_Trackbar = 5; +//! [declare] /// Function Headers void MatchingMethod( int, void* ); @@ -36,6 +38,7 @@ int main( int argc, char** argv ) return -1; } + //! [load_image] /// Load image and template img = imread( argv[1], IMREAD_COLOR ); templ = imread( argv[2], IMREAD_COLOR ); @@ -50,19 +53,26 @@ int main( int argc, char** argv ) cout << "Can't read one of the images" << endl; return -1; } + //! [load_image] + //! [create_windows] /// Create windows namedWindow( image_window, WINDOW_AUTOSIZE ); namedWindow( result_window, WINDOW_AUTOSIZE ); + //! [create_windows] + //! [create_trackbar] /// Create Trackbar const char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED"; createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod ); + //! [create_trackbar] MatchingMethod( 0, 0 ); + //! [wait_key] waitKey(0); return 0; + //! [wait_key] } /** @@ -71,44 +81,57 @@ int main( int argc, char** argv ) */ void MatchingMethod( int, void* ) { + //! [copy_source] /// Source image to display Mat img_display; img.copyTo( img_display ); + //! [copy_source] + //! [create_result_matrix] /// Create the result matrix int result_cols = img.cols - templ.cols + 1; int result_rows = img.rows - templ.rows + 1; result.create( result_rows, result_cols, CV_32FC1 ); + //! [create_result_matrix] + //! [match_template] /// Do the Matching and Normalize bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED); if (use_mask && method_accepts_mask) { matchTemplate( img, templ, result, match_method, mask); } else { matchTemplate( img, templ, result, match_method); } + //! [match_template] + //! [normalize] normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); + //! [normalize] + //! [best_match] /// Localizing the best match with minMaxLoc double minVal; double maxVal; Point minLoc; Point maxLoc; Point matchLoc; minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() ); + //! [best_match] - + //! [match_loc] /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better if( match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED ) { matchLoc = minLoc; } else { matchLoc = maxLoc; } + //! [match_loc] + //! [imshow] /// Show me what you got rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); imshow( image_window, img_display ); imshow( result_window, result ); + //! [imshow] return; } diff --git a/samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java b/samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java new file mode 100644 index 0000000000..b323aebc59 --- /dev/null +++ b/samples/java/tutorial_code/ImgProc/tutorial_template_matching/MatchTemplateDemo.java @@ -0,0 +1,196 @@ +import org.opencv.core.*; +import org.opencv.core.Point; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; + +import java.util.*; + +class MatchTemplateDemoRun implements ChangeListener{ + + //! [declare] + /// Global Variables + Boolean use_mask = false; + Mat img = new Mat(), templ = new Mat(); + Mat mask = new Mat(); + + int match_method; + + JLabel imgDisplay = new JLabel(), resultDisplay = new JLabel(); + //! [declare] + + public void run(String[] args) { + + if (args.length < 2) + { + System.out.println("Not enough parameters"); + System.out.println("Program arguments:\n []"); + System.exit(-1); + } + + //! [load_image] + /// Load image and template + img = Imgcodecs.imread( args[0], Imgcodecs.IMREAD_COLOR ); + templ = Imgcodecs.imread( args[1], Imgcodecs.IMREAD_COLOR ); + //! [load_image] + + if(args.length > 2) { + use_mask = true; + mask = Imgcodecs.imread( args[2], Imgcodecs.IMREAD_COLOR ); + } + + if(img.empty() || templ.empty() || (use_mask && mask.empty())) + { + System.out.println("Can't read one of the images"); + System.exit(-1); + } + + matchingMethod(); + createJFrame(); + + } + + private void matchingMethod() { + + Mat result = new Mat(); + + //! [copy_source] + /// Source image to display + Mat img_display = new Mat(); + img.copyTo( img_display ); + //! [copy_source] + + //! [create_result_matrix] + /// Create the result matrix + int result_cols = img.cols() - templ.cols() + 1; + int result_rows = img.rows() - templ.rows() + 1; + + result.create( result_rows, result_cols, CvType.CV_32FC1 ); + //! [create_result_matrix] + + //! [match_template] + /// Do the Matching and Normalize + Boolean method_accepts_mask = (Imgproc.TM_SQDIFF == match_method || + match_method == Imgproc.TM_CCORR_NORMED); + if (use_mask && method_accepts_mask) + { Imgproc.matchTemplate( img, templ, result, match_method, mask); } + else + { Imgproc.matchTemplate( img, templ, result, match_method); } + //! [match_template] + + //! [normalize] + Core.normalize( result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat() ); + //! [normalize] + + //! [best_match] + /// Localizing the best match with minMaxLoc + double minVal; double maxVal; + Point matchLoc; + + Core.MinMaxLocResult mmr = Core.minMaxLoc( result ); + //! [best_match] + + //! [match_loc] + /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. + // For all the other methods, the higher the better + if( match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED ) + { matchLoc = mmr.minLoc; } + else + { matchLoc = mmr.maxLoc; } + //! [match_loc] + + //! [imshow] + /// Show me what you got + Imgproc.rectangle(img_display, matchLoc, new Point(matchLoc.x + templ.cols(), + matchLoc.y + templ.rows()), new Scalar(0, 0, 0), 2, 8, 0); + Imgproc.rectangle(result, matchLoc, new Point(matchLoc.x + templ.cols(), + matchLoc.y + templ.rows()), new Scalar(0, 0, 0), 2, 8, 0); + + Image tmpImg = toBufferedImage(img_display); + ImageIcon icon = new ImageIcon(tmpImg); + imgDisplay.setIcon(icon); + + result.convertTo(result, CvType.CV_8UC1, 255.0); + tmpImg = toBufferedImage(result); + icon = new ImageIcon(tmpImg); + resultDisplay.setIcon(icon); + //! [imshow] + } + + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + if (!source.getValueIsAdjusting()) { + match_method = (int)source.getValue(); + matchingMethod(); + } + } + + public Image toBufferedImage(Mat m) { + int type = BufferedImage.TYPE_BYTE_GRAY; + if ( m.channels() > 1 ) { + type = BufferedImage.TYPE_3BYTE_BGR; + } + int bufferSize = m.channels()*m.cols()*m.rows(); + byte [] b = new byte[bufferSize]; + m.get(0,0,b); // get all the pixels + BufferedImage image = new BufferedImage(m.cols(),m.rows(), type); + final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); + System.arraycopy(b, 0, targetPixels, 0, b.length); + return image; + } + + private void createJFrame() { + + String title = "Source image; Control; Result image"; + JFrame frame = new JFrame(title); + frame.setLayout(new GridLayout(2, 2)); + frame.add(imgDisplay); + + //! [create_trackbar] + int min = 0, max = 5; + JSlider slider = new JSlider(JSlider.VERTICAL, min, max, match_method); + //! [create_trackbar] + + slider.setPaintTicks(true); + slider.setPaintLabels(true); + + // Set the spacing for the minor tick mark + slider.setMinorTickSpacing(1); + + // Customizing the labels + Hashtable labelTable = new Hashtable(); + labelTable.put( new Integer( 0 ), new JLabel("0 - SQDIFF") ); + labelTable.put( new Integer( 1 ), new JLabel("1 - SQDIFF NORMED") ); + labelTable.put( new Integer( 2 ), new JLabel("2 - TM CCORR") ); + labelTable.put( new Integer( 3 ), new JLabel("3 - TM CCORR NORMED") ); + labelTable.put( new Integer( 4 ), new JLabel("4 - TM COEFF") ); + labelTable.put( new Integer( 5 ), new JLabel("5 - TM COEFF NORMED : (Method)") ); + slider.setLabelTable( labelTable ); + + slider.addChangeListener(this); + + frame.add(slider); + + frame.add(resultDisplay); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } +} + +public class MatchTemplateDemo +{ + public static void main(String[] args) { + // load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + // run code + new MatchTemplateDemoRun().run(args); + } +} diff --git a/samples/python/tutorial_code/imgProc/match_template/match_template.py b/samples/python/tutorial_code/imgProc/match_template/match_template.py new file mode 100644 index 0000000000..5c649a0429 --- /dev/null +++ b/samples/python/tutorial_code/imgProc/match_template/match_template.py @@ -0,0 +1,96 @@ +import sys +import cv2 + +## [global_variables] +use_mask = False +img = None +templ = None +mask = None +image_window = "Source Image" +result_window = "Result window" + +match_method = 0 +max_Trackbar = 5 +## [global_variables] + +def main(argv): + + if (len(sys.argv) < 3): + print 'Not enough parameters' + print 'Usage:\nmatch_template_demo.py []' + return -1 + + ## [load_image] + global img + global templ + img = cv2.imread(sys.argv[1], cv2.IMREAD_COLOR) + templ = cv2.imread(sys.argv[2], cv2.IMREAD_COLOR) + + if (len(sys.argv) > 3): + global use_mask + use_mask = True + global mask + mask = cv2.imread( sys.argv[3], cv2.IMREAD_COLOR ) + + if ((img is None) or (templ is None) or (use_mask and (mask is None))): + print 'Can\'t read one of the images' + return -1 + ## [load_image] + + ## [create_windows] + cv2.namedWindow( image_window, cv2.WINDOW_AUTOSIZE ) + cv2.namedWindow( result_window, cv2.WINDOW_AUTOSIZE ) + ## [create_windows] + + ## [create_trackbar] + trackbar_label = 'Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED' + cv2.createTrackbar( trackbar_label, image_window, match_method, max_Trackbar, MatchingMethod ) + ## [create_trackbar] + + MatchingMethod(match_method) + + ## [wait_key] + cv2.waitKey(0) + return 0 + ## [wait_key] + +def MatchingMethod(param): + + global match_method + match_method = param + + ## [copy_source] + img_display = img.copy() + ## [copy_source] + ## [match_template] + method_accepts_mask = (cv2.TM_SQDIFF == match_method or match_method == cv2.TM_CCORR_NORMED) + if (use_mask and method_accepts_mask): + result = cv2.matchTemplate(img, templ, match_method, None, mask) + else: + result = cv2.matchTemplate(img, templ, match_method) + ## [match_template] + + ## [normalize] + cv2.normalize( result, result, 0, 1, cv2.NORM_MINMAX, -1 ) + ## [normalize] + ## [best_match] + minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(result, None) + ## [best_match] + + ## [match_loc] + if (match_method == cv2.TM_SQDIFF or match_method == cv2.TM_SQDIFF_NORMED): + matchLoc = minLoc + else: + matchLoc = maxLoc + ## [match_loc] + + ## [imshow] + cv2.rectangle(img_display, matchLoc, (matchLoc[0] + templ.shape[0], matchLoc[1] + templ.shape[1]), (0,0,0), 2, 8, 0 ) + cv2.rectangle(result, matchLoc, (matchLoc[0] + templ.shape[0], matchLoc[1] + templ.shape[1]), (0,0,0), 2, 8, 0 ) + cv2.imshow(image_window, img_display) + cv2.imshow(result_window, result) + ## [imshow] + pass + +if __name__ == "__main__": + main(sys.argv[1:]) From e4cb8a6f0972b18768ec4db7db69bce0ba516524 Mon Sep 17 00:00:00 2001 From: saskatchewancatch Date: Fri, 12 May 2017 00:01:38 -0600 Subject: [PATCH 142/144] issue 8723: Changed doc for cv::imwrite to reflect correct default flag used for png compression strategy. --- modules/imgcodecs/include/opencv2/imgcodecs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgcodecs/include/opencv2/imgcodecs.hpp b/modules/imgcodecs/include/opencv2/imgcodecs.hpp index 79805b2ed3..ff6bbcab07 100644 --- a/modules/imgcodecs/include/opencv2/imgcodecs.hpp +++ b/modules/imgcodecs/include/opencv2/imgcodecs.hpp @@ -86,7 +86,7 @@ enum ImwriteFlags { IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is 0 - don't use. IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is 0 - don't use. IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting). - IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_DEFAULT. + IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE. IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0. IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1. IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used. From 42a2454f1a1d6b76716a490f5b945fde1b107e1f Mon Sep 17 00:00:00 2001 From: Anupam Sobti Date: Fri, 12 May 2017 21:55:35 +0530 Subject: [PATCH 143/144] Fix for issue #8615. Added cudawarping to optional modules and removed opencv_cudafilters --- modules/stitching/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/stitching/CMakeLists.txt b/modules/stitching/CMakeLists.txt index 2802ab8be7..7dfdd08976 100644 --- a/modules/stitching/CMakeLists.txt +++ b/modules/stitching/CMakeLists.txt @@ -9,5 +9,5 @@ if(BUILD_SHARED_LIBS AND BUILD_opencv_world AND OPENCV_WORLD_EXCLUDE_EXTRA_MODUL set(STITCHING_CONTRIB_DEPS "") endif() ocv_define_module(stitching opencv_imgproc opencv_features2d opencv_calib3d - OPTIONAL opencv_cudaarithm opencv_cudafilters opencv_cudafeatures2d opencv_cudalegacy ${STITCHING_CONTRIB_DEPS} + OPTIONAL opencv_cudaarithm opencv_cudawarping opencv_cudafeatures2d opencv_cudalegacy ${STITCHING_CONTRIB_DEPS} WRAP python) From 9edcd9b4ef2fbaf5bb470143f1a9772245a47486 Mon Sep 17 00:00:00 2001 From: Arek Date: Fri, 12 May 2017 22:46:46 +0200 Subject: [PATCH 144/144] Merge pull request #8711 from ArkadiuszRaj:aravis_autoexposure_correction Aravis: Use of std::fabs, added support for 16-bit mono files and exposure compensation (#8711) * Use of std::fabs, added support for 16-bit mono files * Correction in priority2 stage & adding exposure compensation --- modules/videoio/src/cap_aravis.cpp | 36 ++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/modules/videoio/src/cap_aravis.cpp b/modules/videoio/src/cap_aravis.cpp index c272bee726..b5c71a86a3 100644 --- a/modules/videoio/src/cap_aravis.cpp +++ b/modules/videoio/src/cap_aravis.cpp @@ -64,6 +64,7 @@ // read/write // CAP_PROP_AUTO_EXPOSURE(0|1) // CAP_PROP_EXPOSURE(t), t in seconds +// CAP_PROP_BRIGHTNESS (ev), exposure compensation in EV for auto exposure algorithm // CAP_PROP_GAIN(g), g >=0 or -1 for automatic control if CAP_PROP_AUTO_EXPOSURE is true // CAP_PROP_FPS(f) // CAP_PROP_FOURCC(type) @@ -77,11 +78,13 @@ // video/x-raw, fourcc:'GREY' -> 8bit, 1 channel // video/x-raw, fourcc:'Y800' -> 8bit, 1 channel // video/x-raw, fourcc:'Y12 ' -> 12bit, 1 channel +// video/x-raw, fourcc:'Y16 ' -> 16bit, 1 channel // #define MODE_GREY CV_FOURCC_MACRO('G','R','E','Y') #define MODE_Y800 CV_FOURCC_MACRO('Y','8','0','0') #define MODE_Y12 CV_FOURCC_MACRO('Y','1','2',' ') +#define MODE_Y16 CV_FOURCC_MACRO('Y','1','6',' ') #define CLIP(a,b,c) (cv::max(cv::min((a),(c)),(b))) @@ -139,6 +142,7 @@ protected: double exposureMax; // Camera's maximum exposure time. bool controlExposure; // Flag if automatic exposure shall be done by this SW + double exposureCompensation; bool autoGain; double targetGrey; // Target grey value (mid grey)) @@ -179,10 +183,11 @@ CvCaptureCAM_Aravis::CvCaptureCAM_Aravis() xoffset = yoffset = width = height = 0; fpsMin = fpsMax = gainMin = gainMax = exposureMin = exposureMax = 0; controlExposure = false; + exposureCompensation = 0; targetGrey = 0; frameID = prevFrameID = 0; - num_buffers = 50; + num_buffers = 10; frame = NULL; } @@ -314,6 +319,7 @@ IplImage* CvCaptureCAM_Aravis::retrieveFrame(int) channels = 1; break; case ARV_PIXEL_FORMAT_MONO_12: + case ARV_PIXEL_FORMAT_MONO_16: depth = IPL_DEPTH_16U; channels = 1; break; @@ -334,8 +340,8 @@ IplImage* CvCaptureCAM_Aravis::retrieveFrame(int) } cvCopy(&src, frame); - if(controlExposure && ((frameID - prevFrameID) > 1)) { - // control exposure every second frame + if(controlExposure && ((frameID - prevFrameID) >= 3)) { + // control exposure every third frame // i.e. skip frame taken with previous exposure setup autoExposureControl(frame); } @@ -372,15 +378,15 @@ void CvCaptureCAM_Aravis::autoExposureControl(IplImage* image) midGrey = brightness; double maxe = 1e6 / fps; - double ne = CLIP( ( exposure * d ) / dmid, exposureMin, maxe); + double ne = CLIP( ( exposure * d ) / ( dmid * pow(sqrt(2), -2 * exposureCompensation) ), exposureMin, maxe); // if change of value requires intervention - if(fabs(d-dmid) > 5) { + if(std::fabs(d-dmid) > 5) { double ev, ng = 0; if(gainAvailable && autoGain) { ev = log( d / dmid ) / log(2); - ng = CLIP( gain + ev, gainMin, gainMax); + ng = CLIP( gain + ev + exposureCompensation, gainMin, gainMax); if( ng < gain ) { // piority 1 - reduce gain @@ -390,8 +396,9 @@ void CvCaptureCAM_Aravis::autoExposureControl(IplImage* image) } if(exposureAvailable) { - if(abs(exposure - ne) > 2) { - // priority 2 - control of exposure time + // priority 2 - control of exposure time + if(std::fabs(exposure - ne) > 2) { + // we have not yet reach the max-e level arv_camera_set_exposure_time(camera, (exposure = ne) ); return; } @@ -436,6 +443,9 @@ double CvCaptureCAM_Aravis::getProperty( int property_id ) const case CV_CAP_PROP_AUTO_EXPOSURE: return (controlExposure ? 1 : 0); + case CV_CAP_PROP_BRIGHTNESS: + return exposureCompensation; + case CV_CAP_PROP_EXPOSURE: if(exposureAvailable) { /* exposure time in seconds, like 1/100 s */ @@ -463,6 +473,8 @@ double CvCaptureCAM_Aravis::getProperty( int property_id ) const return MODE_Y800; case ARV_PIXEL_FORMAT_MONO_12: return MODE_Y12; + case ARV_PIXEL_FORMAT_MONO_16: + return MODE_Y16; } } break; @@ -490,6 +502,9 @@ bool CvCaptureCAM_Aravis::setProperty( int property_id, double value ) } } break; + case CV_CAP_PROP_BRIGHTNESS: + exposureCompensation = CLIP(value, -3., 3.); + break; case CV_CAP_PROP_EXPOSURE: if(exposureAvailable) { @@ -528,6 +543,10 @@ bool CvCaptureCAM_Aravis::setProperty( int property_id, double value ) newFormat = ARV_PIXEL_FORMAT_MONO_12; targetGrey = 2048; break; + case MODE_Y16: + newFormat = ARV_PIXEL_FORMAT_MONO_16; + targetGrey = 32768; + break; } if(newFormat != pixelFormat) { stopCapture(); @@ -570,7 +589,6 @@ bool CvCaptureCAM_Aravis::startCapture() { if(init_buffers() ) { arv_camera_set_acquisition_mode(camera, ARV_ACQUISITION_MODE_CONTINUOUS); - arv_device_set_string_feature_value(arv_camera_get_device (camera), "TriggerMode" , "Off"); arv_camera_start_acquisition(camera); return true;