mirror of
https://github.com/opencv/opencv.git
synced 2026-07-25 13:23:02 +04:00
Compare commits
16 Commits
3.3.0-rc
...
3.3.0-cvsdk
| Author | SHA1 | Date | |
|---|---|---|---|
| e8357c0544 | |||
| 95a438d233 | |||
| 4238add35b | |||
| 4784c7be5f | |||
| c3e6de293f | |||
| 544908d06c | |||
| 520da7aaaf | |||
| ed4de20fd1 | |||
| 9b9e685dbc | |||
| 49bb0bf9c8 | |||
| d6c5e18e24 | |||
| 617e6b4cc9 | |||
| 5ebfb52a4a | |||
| e7cc2eea1d | |||
| ed9564106c | |||
| b32d914aab |
@@ -108,7 +108,7 @@ struct VZeroUpperGuard {
|
||||
#endif
|
||||
inline ~VZeroUpperGuard() { _mm256_zeroupper(); }
|
||||
};
|
||||
#define __CV_AVX_GUARD VZeroUpperGuard __vzeroupper_guard;
|
||||
#define __CV_AVX_GUARD VZeroUpperGuard __vzeroupper_guard; (void)__vzeroupper_guard;
|
||||
#endif
|
||||
|
||||
#endif // __OPENCV_BUILD
|
||||
|
||||
@@ -48,6 +48,23 @@
|
||||
//! @addtogroup core_utils
|
||||
//! @{
|
||||
|
||||
#if !defined CV_DOXYGEN && !defined CV_IGNORE_DEBUG_BUILD_GUARD
|
||||
#if (defined(_MSC_VER) && (defined(DEBUG) || defined(_DEBUG))) || \
|
||||
(defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_DEBUG_PEDANTIC))
|
||||
// Guard to prevent using of binary incompatible binaries / runtimes
|
||||
// https://github.com/opencv/opencv/pull/9161
|
||||
#define CV__DEBUG_NS_BEGIN namespace debug_build_guard {
|
||||
#define CV__DEBUG_NS_END }
|
||||
namespace cv { namespace debug_build_guard { } using namespace debug_build_guard; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CV__DEBUG_NS_BEGIN
|
||||
#define CV__DEBUG_NS_BEGIN
|
||||
#define CV__DEBUG_NS_END
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __OPENCV_BUILD
|
||||
#include "cvconfig.h"
|
||||
#endif
|
||||
|
||||
@@ -62,6 +62,8 @@ namespace cv
|
||||
enum { ACCESS_READ=1<<24, ACCESS_WRITE=1<<25,
|
||||
ACCESS_RW=3<<24, ACCESS_MASK=ACCESS_RW, ACCESS_FAST=1<<26 };
|
||||
|
||||
CV__DEBUG_NS_BEGIN
|
||||
|
||||
class CV_EXPORTS _OutputArray;
|
||||
|
||||
//////////////////////// Input/Output Array Arguments /////////////////////////////////
|
||||
@@ -400,6 +402,8 @@ public:
|
||||
|
||||
};
|
||||
|
||||
CV__DEBUG_NS_END
|
||||
|
||||
typedef const _InputArray& InputArray;
|
||||
typedef InputArray InputArrayOfArrays;
|
||||
typedef const _OutputArray& OutputArray;
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
|
||||
namespace cv
|
||||
{
|
||||
CV__DEBUG_NS_BEGIN
|
||||
|
||||
|
||||
//! @cond IGNORED
|
||||
|
||||
@@ -392,6 +394,8 @@ inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf)
|
||||
inline _InputOutputArray::_InputOutputArray(const cuda::HostMem& cuda_mem)
|
||||
{ init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_RW, &cuda_mem); }
|
||||
|
||||
CV__DEBUG_NS_END
|
||||
|
||||
//////////////////////////////////////////// Mat //////////////////////////////////////////
|
||||
|
||||
inline
|
||||
|
||||
@@ -209,6 +209,8 @@ CV_EXPORTS void scalarToRawData(const cv::Scalar& s, void* buf, int type, int un
|
||||
#define IPP_DISABLE_RESIZE_NEAREST 1 // Accuracy mismatch (max diff 1)
|
||||
#define IPP_DISABLE_RESIZE_AREA 1 // Accuracy mismatch (max diff 1)
|
||||
|
||||
#define IPP_DISABLE_MINMAX_NAN_SSE42 1 // cv::minMaxIdx problem with NaN input
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
#define CV_VERSION_MAJOR 3
|
||||
#define CV_VERSION_MINOR 3
|
||||
#define CV_VERSION_REVISION 0
|
||||
#define CV_VERSION_STATUS "-rc"
|
||||
#define CV_VERSION_STATUS "-cvsdk"
|
||||
|
||||
#define CVAUX_STR_EXP(__A) #__A
|
||||
#define CVAUX_STR(__A) CVAUX_STR_EXP(__A)
|
||||
|
||||
@@ -2534,6 +2534,12 @@ static bool ipp_minMaxIdx(Mat &src, double* _minVal, double* _maxVal, int* _minI
|
||||
#if IPP_VERSION_X100 >= 700
|
||||
CV_INSTRUMENT_REGION_IPP()
|
||||
|
||||
#if IPP_DISABLE_MINMAX_NAN_SSE42
|
||||
// Disable 32F processing only
|
||||
if(src.depth() == CV_32F && !(ipp::getIppFeatures()&ippCPUID_AVX))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
IppStatus status;
|
||||
IppDataType dataType = ippiGetDataType(src.depth());
|
||||
float minVal = 0;
|
||||
|
||||
@@ -1639,6 +1639,14 @@ PARAM_TEST_CASE(ConvertFp16, Channels, bool)
|
||||
Size roiSize = randomSize(1, MAX_VALUE);
|
||||
Border srcBorder = randomBorder(0, 0);
|
||||
randomSubMat(src, src_roi, roiSize, srcBorder, stype, -11, 11); // FIXIT: Test with minV, maxV
|
||||
if (stype == CV_MAKE_TYPE(CV_16S, cn)) // eliminate NaN/Inf FP16 values
|
||||
{
|
||||
RNG dataRng(rng.next());
|
||||
Mat src_i32 = cvtest::randomMat(dataRng, roiSize, CV_MAKE_TYPE(CV_32S, cn), 0, 0x7c00, false);
|
||||
Mat shift_i32 = cvtest::randomMat(dataRng, roiSize, src_i32.type(), -1, 1, false); // values: -1, 0
|
||||
src_i32 = src_i32 + (shift_i32 * 0x8000);
|
||||
src_i32.convertTo(src_roi, stype);
|
||||
}
|
||||
|
||||
Border dstBorder = randomBorder(0, 0);
|
||||
randomSubMat(dst, dst_roi, roiSize, dstBorder, dtype, 5, 16);
|
||||
|
||||
@@ -9,6 +9,8 @@ endif()
|
||||
|
||||
set(the_description "Deep neural network module. It allows to load models from different frameworks and to make forward pass")
|
||||
|
||||
ocv_add_dispatched_file("layers/layers_common" AVX AVX2)
|
||||
|
||||
ocv_add_module(dnn opencv_core opencv_imgproc WRAP python matlab java)
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-shadow -Wno-parentheses -Wmaybe-uninitialized -Wsign-promo
|
||||
-Wmissing-declarations -Wmissing-prototypes
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
// This is an umbrealla header to include into you project.
|
||||
// We are free to change headers layout in dnn subfolder, so please include
|
||||
// this header for future compartibility
|
||||
// this header for future compatibility
|
||||
|
||||
|
||||
/** @defgroup dnn Deep Neural Network module
|
||||
|
||||
@@ -152,7 +152,19 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
|
||||
int outputNameToIndex(String outputName);
|
||||
};
|
||||
|
||||
//! Classical recurrent layer
|
||||
/** @brief Classical recurrent layer
|
||||
|
||||
Accepts two inputs @f$x_t@f$ and @f$h_{t-1}@f$ and compute two outputs @f$o_t@f$ and @f$h_t@f$.
|
||||
|
||||
- input: should contain packed input @f$x_t@f$.
|
||||
- output: should contain output @f$o_t@f$ (and @f$h_t@f$ if setProduceHiddenOutput() is set to true).
|
||||
|
||||
input[0] should have shape [`T`, `N`, `data_dims`] where `T` and `N` is number of timestamps and number of independent samples of @f$x_t@f$ respectively.
|
||||
|
||||
output[0] will have shape [`T`, `N`, @f$N_o@f$], where @f$N_o@f$ is number of rows in @f$ W_{xo} @f$ matrix.
|
||||
|
||||
If setProduceHiddenOutput() is set to true then @p output[1] will contain a Mat with shape [`T`, `N`, @f$N_h@f$], where @f$N_h@f$ is number of rows in @f$ W_{hh} @f$ matrix.
|
||||
*/
|
||||
class CV_EXPORTS RNNLayer : public Layer
|
||||
{
|
||||
public:
|
||||
@@ -180,17 +192,6 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
|
||||
*/
|
||||
virtual void setProduceHiddenOutput(bool produce = false) = 0;
|
||||
|
||||
/** Accepts two inputs @f$x_t@f$ and @f$h_{t-1}@f$ and compute two outputs @f$o_t@f$ and @f$h_t@f$.
|
||||
|
||||
@param input should contain packed input @f$x_t@f$.
|
||||
@param output should contain output @f$o_t@f$ (and @f$h_t@f$ if setProduceHiddenOutput() is set to true).
|
||||
|
||||
@p input[0] should have shape [`T`, `N`, `data_dims`] where `T` and `N` is number of timestamps and number of independent samples of @f$x_t@f$ respectively.
|
||||
|
||||
@p output[0] will have shape [`T`, `N`, @f$N_o@f$], where @f$N_o@f$ is number of rows in @f$ W_{xo} @f$ matrix.
|
||||
|
||||
If setProduceHiddenOutput() is set to true then @p output[1] will contain a Mat with shape [`T`, `N`, @f$N_h@f$], where @f$N_h@f$ is number of rows in @f$ W_{hh} @f$ matrix.
|
||||
*/
|
||||
};
|
||||
|
||||
class CV_EXPORTS BaseConvolutionLayer : public Layer
|
||||
|
||||
@@ -371,28 +371,28 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
|
||||
/** @brief Runs forward pass to compute output of layer with name @p outputName.
|
||||
* @param outputName name for layer which output is needed to get
|
||||
* @return blob for first output of specified layer.
|
||||
* @details By default runs forward pass for the whole network.
|
||||
*/
|
||||
* @details By default runs forward pass for the whole network.
|
||||
*/
|
||||
CV_WRAP Mat forward(const String& outputName = String());
|
||||
|
||||
/** @brief Runs forward pass to compute output of layer with name @p outputName.
|
||||
* @param outputBlobs contains all output blobs for specified layer.
|
||||
* @param outputName name for layer which output is needed to get
|
||||
* @details If @p outputName is empty, runs forward pass for the whole network.
|
||||
*/
|
||||
* @details If @p outputName is empty, runs forward pass for the whole network.
|
||||
*/
|
||||
CV_WRAP void forward(std::vector<Mat>& outputBlobs, const String& outputName = String());
|
||||
|
||||
/** @brief Runs forward pass to compute outputs of layers listed in @p outBlobNames.
|
||||
* @param outputBlobs contains blobs for first outputs of specified layers.
|
||||
* @param outBlobNames names for layers which outputs are needed to get
|
||||
*/
|
||||
*/
|
||||
CV_WRAP void forward(std::vector<Mat>& outputBlobs,
|
||||
const std::vector<String>& outBlobNames);
|
||||
|
||||
/** @brief Runs forward pass to compute outputs of layers listed in @p outBlobNames.
|
||||
* @param outputBlobs contains all output blobs for each layer specified in @p outBlobNames.
|
||||
* @param outBlobNames names for layers which outputs are needed to get
|
||||
*/
|
||||
*/
|
||||
CV_WRAP void forward(std::vector<std::vector<Mat> >& outputBlobs,
|
||||
const std::vector<String>& outBlobNames);
|
||||
|
||||
@@ -460,103 +460,103 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
|
||||
*/
|
||||
CV_WRAP std::vector<int> getUnconnectedOutLayers() const;
|
||||
/** @brief Returns input and output shapes for all layers in loaded model;
|
||||
* preliminary inferencing isn't necessary.
|
||||
* @param netInputShapes shapes for all input blobs in net input layer.
|
||||
* @param layersIds output parameter for layer IDs.
|
||||
* @param inLayersShapes output parameter for input layers shapes;
|
||||
* order is the same as in layersIds
|
||||
* @param outLayersShapes output parameter for output layers shapes;
|
||||
* order is the same as in layersIds
|
||||
*/
|
||||
CV_WRAP void getLayersShapes(const std::vector<MatShape>& netInputShapes,
|
||||
std::vector<int>* layersIds,
|
||||
std::vector<std::vector<MatShape> >* inLayersShapes,
|
||||
std::vector<std::vector<MatShape> >* outLayersShapes) const;
|
||||
* preliminary inferencing isn't necessary.
|
||||
* @param netInputShapes shapes for all input blobs in net input layer.
|
||||
* @param layersIds output parameter for layer IDs.
|
||||
* @param inLayersShapes output parameter for input layers shapes;
|
||||
* order is the same as in layersIds
|
||||
* @param outLayersShapes output parameter for output layers shapes;
|
||||
* order is the same as in layersIds
|
||||
*/
|
||||
CV_WRAP void getLayersShapes(const std::vector<MatShape>& netInputShapes,
|
||||
std::vector<int>* layersIds,
|
||||
std::vector<std::vector<MatShape> >* inLayersShapes,
|
||||
std::vector<std::vector<MatShape> >* outLayersShapes) const;
|
||||
|
||||
/** @overload */
|
||||
CV_WRAP void getLayersShapes(const MatShape& netInputShape,
|
||||
std::vector<int>* layersIds,
|
||||
std::vector<std::vector<MatShape> >* inLayersShapes,
|
||||
std::vector<std::vector<MatShape> >* outLayersShapes) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getLayersShapes(const MatShape& netInputShape,
|
||||
std::vector<int>* layersIds,
|
||||
std::vector<std::vector<MatShape> >* inLayersShapes,
|
||||
std::vector<std::vector<MatShape> >* outLayersShapes) const;
|
||||
|
||||
/** @brief Returns input and output shapes for layer with specified
|
||||
* id in loaded model; preliminary inferencing isn't necessary.
|
||||
* @param netInputShape shape input blob in net input layer.
|
||||
* @param layerId id for layer.
|
||||
* @param inLayerShapes output parameter for input layers shapes;
|
||||
* order is the same as in layersIds
|
||||
* @param outLayerShapes output parameter for output layers shapes;
|
||||
* order is the same as in layersIds
|
||||
*/
|
||||
CV_WRAP void getLayerShapes(const MatShape& netInputShape,
|
||||
/** @brief Returns input and output shapes for layer with specified
|
||||
* id in loaded model; preliminary inferencing isn't necessary.
|
||||
* @param netInputShape shape input blob in net input layer.
|
||||
* @param layerId id for layer.
|
||||
* @param inLayerShapes output parameter for input layers shapes;
|
||||
* order is the same as in layersIds
|
||||
* @param outLayerShapes output parameter for output layers shapes;
|
||||
* order is the same as in layersIds
|
||||
*/
|
||||
CV_WRAP void getLayerShapes(const MatShape& netInputShape,
|
||||
const int layerId,
|
||||
std::vector<MatShape>* inLayerShapes,
|
||||
std::vector<MatShape>* outLayerShapes) const;
|
||||
|
||||
/** @overload */
|
||||
CV_WRAP void getLayerShapes(const std::vector<MatShape>& netInputShapes,
|
||||
const int layerId,
|
||||
std::vector<MatShape>* inLayerShapes,
|
||||
std::vector<MatShape>* outLayerShapes) const;
|
||||
/** @brief Computes FLOP for whole loaded model with specified input shapes.
|
||||
* @param netInputShapes vector of shapes for all net inputs.
|
||||
* @returns computed FLOP.
|
||||
*/
|
||||
CV_WRAP int64 getFLOPS(const std::vector<MatShape>& netInputShapes) const;
|
||||
/** @overload */
|
||||
CV_WRAP int64 getFLOPS(const MatShape& netInputShape) const;
|
||||
/** @overload */
|
||||
CV_WRAP int64 getFLOPS(const int layerId,
|
||||
const std::vector<MatShape>& netInputShapes) const;
|
||||
/** @overload */
|
||||
CV_WRAP int64 getFLOPS(const int layerId,
|
||||
const MatShape& netInputShape) const;
|
||||
|
||||
/** @overload */
|
||||
CV_WRAP void getLayerShapes(const std::vector<MatShape>& netInputShapes,
|
||||
const int layerId,
|
||||
std::vector<MatShape>* inLayerShapes,
|
||||
std::vector<MatShape>* outLayerShapes) const;
|
||||
/** @brief Computes FLOP for whole loaded model with specified input shapes.
|
||||
* @param netInputShapes vector of shapes for all net inputs.
|
||||
* @returns computed FLOP.
|
||||
*/
|
||||
CV_WRAP int64 getFLOPS(const std::vector<MatShape>& netInputShapes) const;
|
||||
/** @overload */
|
||||
CV_WRAP int64 getFLOPS(const MatShape& netInputShape) const;
|
||||
/** @overload */
|
||||
CV_WRAP int64 getFLOPS(const int layerId,
|
||||
const std::vector<MatShape>& netInputShapes) const;
|
||||
/** @overload */
|
||||
CV_WRAP int64 getFLOPS(const int layerId,
|
||||
const MatShape& netInputShape) const;
|
||||
/** @brief Returns list of types for layer used in model.
|
||||
* @param layersTypes output parameter for returning types.
|
||||
*/
|
||||
CV_WRAP void getLayerTypes(CV_OUT std::vector<String>& layersTypes) const;
|
||||
|
||||
/** @brief Returns list of types for layer used in model.
|
||||
* @param layersTypes output parameter for returning types.
|
||||
*/
|
||||
CV_WRAP void getLayerTypes(CV_OUT std::vector<String>& layersTypes) const;
|
||||
/** @brief Returns count of layers of specified type.
|
||||
* @param layerType type.
|
||||
* @returns count of layers
|
||||
*/
|
||||
CV_WRAP int getLayersCount(const String& layerType) const;
|
||||
|
||||
/** @brief Returns count of layers of specified type.
|
||||
* @param layerType type.
|
||||
* @returns count of layers
|
||||
*/
|
||||
CV_WRAP int getLayersCount(const String& layerType) const;
|
||||
/** @brief Computes bytes number which are requered to store
|
||||
* all weights and intermediate blobs for model.
|
||||
* @param netInputShapes vector of shapes for all net inputs.
|
||||
* @param weights output parameter to store resulting bytes for weights.
|
||||
* @param blobs output parameter to store resulting bytes for intermediate blobs.
|
||||
*/
|
||||
CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
|
||||
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getMemoryConsumption(const MatShape& netInputShape,
|
||||
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getMemoryConsumption(const int layerId,
|
||||
const std::vector<MatShape>& netInputShapes,
|
||||
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getMemoryConsumption(const int layerId,
|
||||
const MatShape& netInputShape,
|
||||
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
|
||||
|
||||
/** @brief Computes bytes number which are requered to store
|
||||
* all weights and intermediate blobs for model.
|
||||
* @param netInputShapes vector of shapes for all net inputs.
|
||||
* @param weights output parameter to store resulting bytes for weights.
|
||||
* @param blobs output parameter to store resulting bytes for intermediate blobs.
|
||||
*/
|
||||
CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
|
||||
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getMemoryConsumption(const MatShape& netInputShape,
|
||||
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getMemoryConsumption(const int layerId,
|
||||
const std::vector<MatShape>& netInputShapes,
|
||||
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getMemoryConsumption(const int layerId,
|
||||
const MatShape& netInputShape,
|
||||
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
|
||||
|
||||
/** @brief Computes bytes number which are requered to store
|
||||
* all weights and intermediate blobs for each layer.
|
||||
* @param netInputShapes vector of shapes for all net inputs.
|
||||
* @param layerIds output vector to save layer IDs.
|
||||
* @param weights output parameter to store resulting bytes for weights.
|
||||
* @param blobs output parameter to store resulting bytes for intermediate blobs.
|
||||
*/
|
||||
CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
|
||||
CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
|
||||
CV_OUT std::vector<size_t>& blobs) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getMemoryConsumption(const MatShape& netInputShape,
|
||||
CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
|
||||
CV_OUT std::vector<size_t>& blobs) const;
|
||||
/** @brief Computes bytes number which are requered to store
|
||||
* all weights and intermediate blobs for each layer.
|
||||
* @param netInputShapes vector of shapes for all net inputs.
|
||||
* @param layerIds output vector to save layer IDs.
|
||||
* @param weights output parameter to store resulting bytes for weights.
|
||||
* @param blobs output parameter to store resulting bytes for intermediate blobs.
|
||||
*/
|
||||
CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
|
||||
CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
|
||||
CV_OUT std::vector<size_t>& blobs) const;
|
||||
/** @overload */
|
||||
CV_WRAP void getMemoryConsumption(const MatShape& netInputShape,
|
||||
CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
|
||||
CV_OUT std::vector<size_t>& blobs) const;
|
||||
private:
|
||||
|
||||
struct Impl;
|
||||
|
||||
@@ -969,9 +969,6 @@ struct Net::Impl
|
||||
}
|
||||
}
|
||||
|
||||
#define CV_RETHROW_ERROR(err, newmsg)\
|
||||
cv::error(err.code, newmsg, err.func.c_str(), err.file.c_str(), err.line)
|
||||
|
||||
void allocateLayer(int lid, const LayersShapesMap& layersShapes)
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
@@ -285,11 +285,12 @@ public:
|
||||
const std::vector<float>* reluslope_;
|
||||
const ActivationLayer* activ_;
|
||||
bool is1x1_;
|
||||
bool useAVX;
|
||||
bool useAVX2;
|
||||
|
||||
ParallelConv()
|
||||
: input_(0), weights_(0), output_(0), ngroups_(0), nstripes_(0),
|
||||
biasvec_(0), reluslope_(0), activ_(0), is1x1_(false), useAVX2(false)
|
||||
biasvec_(0), reluslope_(0), activ_(0), is1x1_(false), useAVX(false), useAVX2(false)
|
||||
{}
|
||||
|
||||
static void run( const Mat& input, Mat& output, const Mat& weights,
|
||||
@@ -322,6 +323,7 @@ public:
|
||||
int inpCnAll = input.size[1], width = input.size[3], height = input.size[2];
|
||||
int inpCn = inpCnAll / ngroups;
|
||||
p.is1x1_ = kernel == Size(0,0) && pad == Size(0, 0);
|
||||
p.useAVX = checkHardwareSupport(CPU_AVX);
|
||||
p.useAVX2 = checkHardwareSupport(CPU_AVX2);
|
||||
|
||||
int ncn = std::min(inpCn, (int)BLK_SIZE_CN);
|
||||
@@ -504,9 +506,15 @@ public:
|
||||
int bsz = ofs1 - ofs0;
|
||||
#if CV_TRY_AVX2
|
||||
if(useAVX2)
|
||||
fastConv_avx2(wptr, wstep, biasptr, rowbuf0, data_out0 + ofs0,
|
||||
opt_AVX2::fastConv(wptr, wstep, biasptr, rowbuf0, data_out0 + ofs0,
|
||||
outShape, bsz, vsz, vsz_a, relu, cn0 == 0);
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_AVX
|
||||
if(useAVX)
|
||||
opt_AVX::fastConv(wptr, wstep, biasptr, rowbuf0, data_out0 + ofs0,
|
||||
outShape, bsz, vsz, vsz_a, relu, cn0 == 0);
|
||||
else
|
||||
#endif
|
||||
for( int i = 0; i < outCn; i += 2 )
|
||||
{
|
||||
@@ -795,6 +803,7 @@ public:
|
||||
b_ = &b;
|
||||
c_ = &c;
|
||||
nstripes_ = nstripes;
|
||||
useAVX = checkHardwareSupport(CPU_AVX);
|
||||
useAVX2 = checkHardwareSupport(CPU_AVX2);
|
||||
}
|
||||
|
||||
@@ -815,7 +824,12 @@ public:
|
||||
|
||||
#if CV_TRY_AVX2
|
||||
if( useAVX2 )
|
||||
fastGEMM_avx2( aptr, astep, bptr, bstep, cptr, cstep, mmax, kmax, nmax );
|
||||
opt_AVX2::fastGEMM( aptr, astep, bptr, bstep, cptr, cstep, mmax, kmax, nmax );
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_AVX
|
||||
if( useAVX )
|
||||
opt_AVX::fastGEMM( aptr, astep, bptr, bstep, cptr, cstep, mmax, kmax, nmax );
|
||||
else
|
||||
#endif
|
||||
for( m = 0; m < mmax; m += 2 )
|
||||
@@ -910,6 +924,7 @@ public:
|
||||
const Mat *a_, *b_;
|
||||
Mat* c_;
|
||||
int nstripes_;
|
||||
bool useAVX;
|
||||
bool useAVX2;
|
||||
};
|
||||
|
||||
|
||||
@@ -55,29 +55,13 @@ namespace util
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
std::string to_string(T value)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << value;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void make_error(const std::string& message1, const T& message2)
|
||||
{
|
||||
std::string error(message1);
|
||||
error += std::string(util::to_string<int>(message2));
|
||||
CV_Error(Error::StsBadArg, error.c_str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SortScorePairDescend(const std::pair<float, T>& pair1,
|
||||
static inline bool SortScorePairDescend(const std::pair<float, T>& pair1,
|
||||
const std::pair<float, T>& pair2)
|
||||
{
|
||||
return pair1.first > pair2.first;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class DetectionOutputLayerImpl : public DetectionOutputLayer
|
||||
{
|
||||
@@ -133,7 +117,7 @@ public:
|
||||
message += " layer parameter does not contain ";
|
||||
message += parameterName;
|
||||
message += " parameter.";
|
||||
CV_Error(Error::StsBadArg, message);
|
||||
CV_ErrorNoReturn(Error::StsBadArg, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -209,180 +193,173 @@ public:
|
||||
CV_TRACE_FUNCTION();
|
||||
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
|
||||
|
||||
const float* locationData = inputs[0]->ptr<float>();
|
||||
const float* confidenceData = inputs[1]->ptr<float>();
|
||||
const float* priorData = inputs[2]->ptr<float>();
|
||||
std::vector<LabelBBox> allDecodedBBoxes;
|
||||
std::vector<std::vector<std::vector<float> > > allConfidenceScores;
|
||||
|
||||
int num = inputs[0]->size[0];
|
||||
int numPriors = inputs[2]->size[2] / 4;
|
||||
|
||||
// Retrieve all location predictions.
|
||||
std::vector<LabelBBox> allLocationPredictions;
|
||||
GetLocPredictions(locationData, num, numPriors, _numLocClasses,
|
||||
_shareLocation, &allLocationPredictions);
|
||||
// extract predictions from input layers
|
||||
{
|
||||
int numPriors = inputs[2]->size[2] / 4;
|
||||
|
||||
// Retrieve all confidences.
|
||||
std::vector<std::vector<std::vector<float> > > allConfidenceScores;
|
||||
GetConfidenceScores(confidenceData, num, numPriors, _numClasses,
|
||||
&allConfidenceScores);
|
||||
const float* locationData = inputs[0]->ptr<float>();
|
||||
const float* confidenceData = inputs[1]->ptr<float>();
|
||||
const float* priorData = inputs[2]->ptr<float>();
|
||||
|
||||
// Retrieve all prior bboxes. It is same within a batch since we assume all
|
||||
// images in a batch are of same dimension.
|
||||
std::vector<caffe::NormalizedBBox> priorBBoxes;
|
||||
std::vector<std::vector<float> > priorVariances;
|
||||
GetPriorBBoxes(priorData, numPriors, &priorBBoxes, &priorVariances);
|
||||
// Retrieve all location predictions
|
||||
std::vector<LabelBBox> allLocationPredictions;
|
||||
GetLocPredictions(locationData, num, numPriors, _numLocClasses,
|
||||
_shareLocation, allLocationPredictions);
|
||||
|
||||
const bool clip_bbox = false;
|
||||
// Decode all loc predictions to bboxes.
|
||||
std::vector<LabelBBox> allDecodedBBoxes;
|
||||
DecodeBBoxesAll(allLocationPredictions, priorBBoxes, priorVariances, num,
|
||||
_shareLocation, _numLocClasses, _backgroundLabelId,
|
||||
_codeType, _varianceEncodedInTarget, clip_bbox, &allDecodedBBoxes);
|
||||
// Retrieve all confidences
|
||||
GetConfidenceScores(confidenceData, num, numPriors, _numClasses, allConfidenceScores);
|
||||
|
||||
int numKept = 0;
|
||||
// Retrieve all prior bboxes
|
||||
std::vector<caffe::NormalizedBBox> priorBBoxes;
|
||||
std::vector<std::vector<float> > priorVariances;
|
||||
GetPriorBBoxes(priorData, numPriors, priorBBoxes, priorVariances);
|
||||
|
||||
// Decode all loc predictions to bboxes
|
||||
DecodeBBoxesAll(allLocationPredictions, priorBBoxes, priorVariances, num,
|
||||
_shareLocation, _numLocClasses, _backgroundLabelId,
|
||||
_codeType, _varianceEncodedInTarget, false, allDecodedBBoxes);
|
||||
}
|
||||
|
||||
size_t numKept = 0;
|
||||
std::vector<std::map<int, std::vector<int> > > allIndices;
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
const LabelBBox& decodeBBoxes = allDecodedBBoxes[i];
|
||||
const std::vector<std::vector<float> >& confidenceScores =
|
||||
allConfidenceScores[i];
|
||||
std::map<int, std::vector<int> > indices;
|
||||
int numDetections = 0;
|
||||
for (int c = 0; c < (int)_numClasses; ++c)
|
||||
{
|
||||
if (c == _backgroundLabelId)
|
||||
{
|
||||
// Ignore background class.
|
||||
continue;
|
||||
}
|
||||
if (confidenceScores.size() <= c)
|
||||
{
|
||||
// Something bad happened if there are no predictions for current label.
|
||||
util::make_error<int>("Could not find confidence predictions for label ", c);
|
||||
}
|
||||
|
||||
const std::vector<float>& scores = confidenceScores[c];
|
||||
int label = _shareLocation ? -1 : c;
|
||||
if (decodeBBoxes.find(label) == decodeBBoxes.end())
|
||||
{
|
||||
// Something bad happened if there are no predictions for current label.
|
||||
util::make_error<int>("Could not find location predictions for label ", label);
|
||||
continue;
|
||||
}
|
||||
const std::vector<caffe::NormalizedBBox>& bboxes =
|
||||
decodeBBoxes.find(label)->second;
|
||||
ApplyNMSFast(bboxes, scores, _confidenceThreshold, _nmsThreshold, 1.0,
|
||||
_topK, &(indices[c]));
|
||||
numDetections += indices[c].size();
|
||||
}
|
||||
if (_keepTopK > -1 && numDetections > _keepTopK)
|
||||
{
|
||||
std::vector<std::pair<float, std::pair<int, int> > > scoreIndexPairs;
|
||||
for (std::map<int, std::vector<int> >::iterator it = indices.begin();
|
||||
it != indices.end(); ++it)
|
||||
{
|
||||
int label = it->first;
|
||||
const std::vector<int>& labelIndices = it->second;
|
||||
if (confidenceScores.size() <= label)
|
||||
{
|
||||
// Something bad happened for current label.
|
||||
util::make_error<int>("Could not find location predictions for label ", label);
|
||||
continue;
|
||||
}
|
||||
const std::vector<float>& scores = confidenceScores[label];
|
||||
for (size_t j = 0; j < labelIndices.size(); ++j)
|
||||
{
|
||||
size_t idx = labelIndices[j];
|
||||
CV_Assert(idx < scores.size());
|
||||
scoreIndexPairs.push_back(
|
||||
std::make_pair(scores[idx], std::make_pair(label, idx)));
|
||||
}
|
||||
}
|
||||
// Keep outputs k results per image.
|
||||
std::sort(scoreIndexPairs.begin(), scoreIndexPairs.end(),
|
||||
util::SortScorePairDescend<std::pair<int, int> >);
|
||||
scoreIndexPairs.resize(_keepTopK);
|
||||
// Store the new indices.
|
||||
std::map<int, std::vector<int> > newIndices;
|
||||
for (size_t j = 0; j < scoreIndexPairs.size(); ++j)
|
||||
{
|
||||
int label = scoreIndexPairs[j].second.first;
|
||||
int idx = scoreIndexPairs[j].second.second;
|
||||
newIndices[label].push_back(idx);
|
||||
}
|
||||
allIndices.push_back(newIndices);
|
||||
numKept += _keepTopK;
|
||||
}
|
||||
else
|
||||
{
|
||||
allIndices.push_back(indices);
|
||||
numKept += numDetections;
|
||||
}
|
||||
numKept += processDetections_(allDecodedBBoxes[i], allConfidenceScores[i], allIndices);
|
||||
}
|
||||
|
||||
if (numKept == 0)
|
||||
{
|
||||
CV_ErrorNoReturn(Error::StsError, "Couldn't find any detections");
|
||||
return;
|
||||
}
|
||||
int outputShape[] = {1, 1, numKept, 7};
|
||||
int outputShape[] = {1, 1, (int)numKept, 7};
|
||||
outputs[0].create(4, outputShape, CV_32F);
|
||||
float* outputsData = outputs[0].ptr<float>();
|
||||
|
||||
int count = 0;
|
||||
size_t count = 0;
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
const std::vector<std::vector<float> >& confidenceScores =
|
||||
allConfidenceScores[i];
|
||||
const LabelBBox& decodeBBoxes = allDecodedBBoxes[i];
|
||||
for (std::map<int, std::vector<int> >::iterator it = allIndices[i].begin();
|
||||
it != allIndices[i].end(); ++it)
|
||||
count += outputDetections_(i, &outputsData[count * 7],
|
||||
allDecodedBBoxes[i], allConfidenceScores[i],
|
||||
allIndices[i]);
|
||||
}
|
||||
CV_Assert(count == numKept);
|
||||
}
|
||||
|
||||
size_t outputDetections_(
|
||||
const int i, float* outputsData,
|
||||
const LabelBBox& decodeBBoxes, const std::vector<std::vector<float> >& confidenceScores,
|
||||
const std::map<int, std::vector<int> >& indicesMap
|
||||
)
|
||||
{
|
||||
size_t count = 0;
|
||||
for (std::map<int, std::vector<int> >::const_iterator it = indicesMap.begin(); it != indicesMap.end(); ++it)
|
||||
{
|
||||
int label = it->first;
|
||||
if (confidenceScores.size() <= label)
|
||||
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find confidence predictions for label %d", label));
|
||||
const std::vector<float>& scores = confidenceScores[label];
|
||||
int locLabel = _shareLocation ? -1 : label;
|
||||
LabelBBox::const_iterator label_bboxes = decodeBBoxes.find(locLabel);
|
||||
if (label_bboxes == decodeBBoxes.end())
|
||||
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find location predictions for label %d", locLabel));
|
||||
const std::vector<int>& indices = it->second;
|
||||
|
||||
for (size_t j = 0; j < indices.size(); ++j, ++count)
|
||||
{
|
||||
int idx = indices[j];
|
||||
const caffe::NormalizedBBox& decode_bbox = label_bboxes->second[idx];
|
||||
outputsData[count * 7] = i;
|
||||
outputsData[count * 7 + 1] = label;
|
||||
outputsData[count * 7 + 2] = scores[idx];
|
||||
outputsData[count * 7 + 3] = decode_bbox.xmin();
|
||||
outputsData[count * 7 + 4] = decode_bbox.ymin();
|
||||
outputsData[count * 7 + 5] = decode_bbox.xmax();
|
||||
outputsData[count * 7 + 6] = decode_bbox.ymax();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t processDetections_(
|
||||
const LabelBBox& decodeBBoxes, const std::vector<std::vector<float> >& confidenceScores,
|
||||
std::vector<std::map<int, std::vector<int> > >& allIndices
|
||||
)
|
||||
{
|
||||
std::map<int, std::vector<int> > indices;
|
||||
size_t numDetections = 0;
|
||||
for (int c = 0; c < (int)_numClasses; ++c)
|
||||
{
|
||||
if (c == _backgroundLabelId)
|
||||
continue; // Ignore background class.
|
||||
if (c >= confidenceScores.size())
|
||||
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find confidence predictions for label %d", c));
|
||||
|
||||
const std::vector<float>& scores = confidenceScores[c];
|
||||
int label = _shareLocation ? -1 : c;
|
||||
|
||||
LabelBBox::const_iterator label_bboxes = decodeBBoxes.find(label);
|
||||
if (label_bboxes == decodeBBoxes.end())
|
||||
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find location predictions for label %d", label));
|
||||
ApplyNMSFast(label_bboxes->second, scores, _confidenceThreshold, _nmsThreshold, 1.0, _topK, indices[c]);
|
||||
numDetections += indices[c].size();
|
||||
}
|
||||
if (_keepTopK > -1 && numDetections > (size_t)_keepTopK)
|
||||
{
|
||||
std::vector<std::pair<float, std::pair<int, int> > > scoreIndexPairs;
|
||||
for (std::map<int, std::vector<int> >::iterator it = indices.begin();
|
||||
it != indices.end(); ++it)
|
||||
{
|
||||
int label = it->first;
|
||||
if (confidenceScores.size() <= label)
|
||||
{
|
||||
// Something bad happened if there are no predictions for current label.
|
||||
util::make_error<int>("Could not find confidence predictions for label ", label);
|
||||
continue;
|
||||
}
|
||||
const std::vector<int>& labelIndices = it->second;
|
||||
if (label >= confidenceScores.size())
|
||||
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find location predictions for label %d", label));
|
||||
const std::vector<float>& scores = confidenceScores[label];
|
||||
int locLabel = _shareLocation ? -1 : label;
|
||||
if (decodeBBoxes.find(locLabel) == decodeBBoxes.end())
|
||||
for (size_t j = 0; j < labelIndices.size(); ++j)
|
||||
{
|
||||
// Something bad happened if there are no predictions for current label.
|
||||
util::make_error<int>("Could not find location predictions for label ", locLabel);
|
||||
continue;
|
||||
}
|
||||
const std::vector<caffe::NormalizedBBox>& bboxes =
|
||||
decodeBBoxes.find(locLabel)->second;
|
||||
std::vector<int>& indices = it->second;
|
||||
|
||||
for (size_t j = 0; j < indices.size(); ++j)
|
||||
{
|
||||
int idx = indices[j];
|
||||
outputsData[count * 7] = i;
|
||||
outputsData[count * 7 + 1] = label;
|
||||
outputsData[count * 7 + 2] = scores[idx];
|
||||
caffe::NormalizedBBox clipBBox = bboxes[idx];
|
||||
outputsData[count * 7 + 3] = clipBBox.xmin();
|
||||
outputsData[count * 7 + 4] = clipBBox.ymin();
|
||||
outputsData[count * 7 + 5] = clipBBox.xmax();
|
||||
outputsData[count * 7 + 6] = clipBBox.ymax();
|
||||
|
||||
++count;
|
||||
size_t idx = labelIndices[j];
|
||||
CV_Assert(idx < scores.size());
|
||||
scoreIndexPairs.push_back(std::make_pair(scores[idx], std::make_pair(label, idx)));
|
||||
}
|
||||
}
|
||||
// Keep outputs k results per image.
|
||||
std::sort(scoreIndexPairs.begin(), scoreIndexPairs.end(),
|
||||
util::SortScorePairDescend<std::pair<int, int> >);
|
||||
scoreIndexPairs.resize(_keepTopK);
|
||||
|
||||
std::map<int, std::vector<int> > newIndices;
|
||||
for (size_t j = 0; j < scoreIndexPairs.size(); ++j)
|
||||
{
|
||||
int label = scoreIndexPairs[j].second.first;
|
||||
int idx = scoreIndexPairs[j].second.second;
|
||||
newIndices[label].push_back(idx);
|
||||
}
|
||||
allIndices.push_back(newIndices);
|
||||
return (size_t)_keepTopK;
|
||||
}
|
||||
else
|
||||
{
|
||||
allIndices.push_back(indices);
|
||||
return numDetections;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute bbox size.
|
||||
float BBoxSize(const caffe::NormalizedBBox& bbox,
|
||||
const bool normalized=true)
|
||||
|
||||
// **************************************************************
|
||||
// Utility functions
|
||||
// **************************************************************
|
||||
|
||||
// Compute bbox size
|
||||
template<bool normalized>
|
||||
static float BBoxSize(const caffe::NormalizedBBox& bbox)
|
||||
{
|
||||
if (bbox.xmax() < bbox.xmin() || bbox.ymax() < bbox.ymin())
|
||||
{
|
||||
// If bbox is invalid (e.g. xmax < xmin or ymax < ymin), return 0.
|
||||
return 0;
|
||||
return 0; // If bbox is invalid (e.g. xmax < xmin or ymax < ymin), return 0.
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -407,193 +384,155 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Clip the caffe::NormalizedBBox such that the range for each corner is [0, 1].
|
||||
void ClipBBox(const caffe::NormalizedBBox& bbox,
|
||||
caffe::NormalizedBBox* clipBBox)
|
||||
{
|
||||
clipBBox->set_xmin(std::max(std::min(bbox.xmin(), 1.f), 0.f));
|
||||
clipBBox->set_ymin(std::max(std::min(bbox.ymin(), 1.f), 0.f));
|
||||
clipBBox->set_xmax(std::max(std::min(bbox.xmax(), 1.f), 0.f));
|
||||
clipBBox->set_ymax(std::max(std::min(bbox.ymax(), 1.f), 0.f));
|
||||
clipBBox->clear_size();
|
||||
clipBBox->set_size(BBoxSize(*clipBBox));
|
||||
clipBBox->set_difficult(bbox.difficult());
|
||||
}
|
||||
|
||||
// Decode a bbox according to a prior bbox.
|
||||
void DecodeBBox(
|
||||
// Decode a bbox according to a prior bbox
|
||||
template<bool variance_encoded_in_target>
|
||||
static void DecodeBBox(
|
||||
const caffe::NormalizedBBox& prior_bbox, const std::vector<float>& prior_variance,
|
||||
const CodeType code_type, const bool variance_encoded_in_target,
|
||||
const CodeType code_type,
|
||||
const bool clip_bbox, const caffe::NormalizedBBox& bbox,
|
||||
caffe::NormalizedBBox* decode_bbox) {
|
||||
if (code_type == caffe::PriorBoxParameter_CodeType_CORNER) {
|
||||
if (variance_encoded_in_target) {
|
||||
// variance is encoded in target, we simply need to add the offset
|
||||
// predictions.
|
||||
decode_bbox->set_xmin(prior_bbox.xmin() + bbox.xmin());
|
||||
decode_bbox->set_ymin(prior_bbox.ymin() + bbox.ymin());
|
||||
decode_bbox->set_xmax(prior_bbox.xmax() + bbox.xmax());
|
||||
decode_bbox->set_ymax(prior_bbox.ymax() + bbox.ymax());
|
||||
} else {
|
||||
// variance is encoded in bbox, we need to scale the offset accordingly.
|
||||
decode_bbox->set_xmin(
|
||||
prior_bbox.xmin() + prior_variance[0] * bbox.xmin());
|
||||
decode_bbox->set_ymin(
|
||||
prior_bbox.ymin() + prior_variance[1] * bbox.ymin());
|
||||
decode_bbox->set_xmax(
|
||||
prior_bbox.xmax() + prior_variance[2] * bbox.xmax());
|
||||
decode_bbox->set_ymax(
|
||||
prior_bbox.ymax() + prior_variance[3] * bbox.ymax());
|
||||
}
|
||||
} else if (code_type == caffe::PriorBoxParameter_CodeType_CENTER_SIZE) {
|
||||
float prior_width = prior_bbox.xmax() - prior_bbox.xmin();
|
||||
CV_Assert(prior_width > 0);
|
||||
float prior_height = prior_bbox.ymax() - prior_bbox.ymin();
|
||||
CV_Assert(prior_height > 0);
|
||||
float prior_center_x = (prior_bbox.xmin() + prior_bbox.xmax()) / 2.;
|
||||
float prior_center_y = (prior_bbox.ymin() + prior_bbox.ymax()) / 2.;
|
||||
caffe::NormalizedBBox& decode_bbox)
|
||||
{
|
||||
float bbox_xmin = variance_encoded_in_target ? bbox.xmin() : prior_variance[0] * bbox.xmin();
|
||||
float bbox_ymin = variance_encoded_in_target ? bbox.ymin() : prior_variance[1] * bbox.ymin();
|
||||
float bbox_xmax = variance_encoded_in_target ? bbox.xmax() : prior_variance[2] * bbox.xmax();
|
||||
float bbox_ymax = variance_encoded_in_target ? bbox.ymax() : prior_variance[3] * bbox.ymax();
|
||||
switch(code_type)
|
||||
{
|
||||
case caffe::PriorBoxParameter_CodeType_CORNER:
|
||||
decode_bbox.set_xmin(prior_bbox.xmin() + bbox_xmin);
|
||||
decode_bbox.set_ymin(prior_bbox.ymin() + bbox_ymin);
|
||||
decode_bbox.set_xmax(prior_bbox.xmax() + bbox_xmax);
|
||||
decode_bbox.set_ymax(prior_bbox.ymax() + bbox_ymax);
|
||||
break;
|
||||
case caffe::PriorBoxParameter_CodeType_CENTER_SIZE:
|
||||
{
|
||||
float prior_width = prior_bbox.xmax() - prior_bbox.xmin();
|
||||
CV_Assert(prior_width > 0);
|
||||
float prior_height = prior_bbox.ymax() - prior_bbox.ymin();
|
||||
CV_Assert(prior_height > 0);
|
||||
float prior_center_x = (prior_bbox.xmin() + prior_bbox.xmax()) * .5;
|
||||
float prior_center_y = (prior_bbox.ymin() + prior_bbox.ymax()) * .5;
|
||||
|
||||
float decode_bbox_center_x, decode_bbox_center_y;
|
||||
float decode_bbox_width, decode_bbox_height;
|
||||
if (variance_encoded_in_target) {
|
||||
// variance is encoded in target, we simply need to retore the offset
|
||||
// predictions.
|
||||
decode_bbox_center_x = bbox.xmin() * prior_width + prior_center_x;
|
||||
decode_bbox_center_y = bbox.ymin() * prior_height + prior_center_y;
|
||||
decode_bbox_width = exp(bbox.xmax()) * prior_width;
|
||||
decode_bbox_height = exp(bbox.ymax()) * prior_height;
|
||||
} else {
|
||||
// variance is encoded in bbox, we need to scale the offset accordingly.
|
||||
decode_bbox_center_x =
|
||||
prior_variance[0] * bbox.xmin() * prior_width + prior_center_x;
|
||||
decode_bbox_center_y =
|
||||
prior_variance[1] * bbox.ymin() * prior_height + prior_center_y;
|
||||
decode_bbox_width =
|
||||
exp(prior_variance[2] * bbox.xmax()) * prior_width;
|
||||
decode_bbox_height =
|
||||
exp(prior_variance[3] * bbox.ymax()) * prior_height;
|
||||
float decode_bbox_center_x, decode_bbox_center_y;
|
||||
float decode_bbox_width, decode_bbox_height;
|
||||
decode_bbox_center_x = bbox_xmin * prior_width + prior_center_x;
|
||||
decode_bbox_center_y = bbox_ymin * prior_height + prior_center_y;
|
||||
decode_bbox_width = exp(bbox_xmax) * prior_width;
|
||||
decode_bbox_height = exp(bbox_ymax) * prior_height;
|
||||
decode_bbox.set_xmin(decode_bbox_center_x - decode_bbox_width * .5);
|
||||
decode_bbox.set_ymin(decode_bbox_center_y - decode_bbox_height * .5);
|
||||
decode_bbox.set_xmax(decode_bbox_center_x + decode_bbox_width * .5);
|
||||
decode_bbox.set_ymax(decode_bbox_center_y + decode_bbox_height * .5);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CV_ErrorNoReturn(Error::StsBadArg, "Unknown type.");
|
||||
};
|
||||
if (clip_bbox)
|
||||
{
|
||||
// Clip the caffe::NormalizedBBox such that the range for each corner is [0, 1]
|
||||
decode_bbox.set_xmin(std::max(std::min(decode_bbox.xmin(), 1.f), 0.f));
|
||||
decode_bbox.set_ymin(std::max(std::min(decode_bbox.ymin(), 1.f), 0.f));
|
||||
decode_bbox.set_xmax(std::max(std::min(decode_bbox.xmax(), 1.f), 0.f));
|
||||
decode_bbox.set_ymax(std::max(std::min(decode_bbox.ymax(), 1.f), 0.f));
|
||||
}
|
||||
|
||||
decode_bbox->set_xmin(decode_bbox_center_x - decode_bbox_width / 2.);
|
||||
decode_bbox->set_ymin(decode_bbox_center_y - decode_bbox_height / 2.);
|
||||
decode_bbox->set_xmax(decode_bbox_center_x + decode_bbox_width / 2.);
|
||||
decode_bbox->set_ymax(decode_bbox_center_y + decode_bbox_height / 2.);
|
||||
} else {
|
||||
CV_Error(Error::StsBadArg, "Unknown LocLossType.");
|
||||
}
|
||||
float bbox_size = BBoxSize(*decode_bbox);
|
||||
decode_bbox->set_size(bbox_size);
|
||||
if (clip_bbox) {
|
||||
ClipBBox(*decode_bbox, decode_bbox);
|
||||
}
|
||||
decode_bbox.clear_size();
|
||||
decode_bbox.set_size(BBoxSize<true>(decode_bbox));
|
||||
}
|
||||
|
||||
// Decode a set of bboxes according to a set of prior bboxes.
|
||||
void DecodeBBoxes(
|
||||
// Decode a set of bboxes according to a set of prior bboxes
|
||||
static void DecodeBBoxes(
|
||||
const std::vector<caffe::NormalizedBBox>& prior_bboxes,
|
||||
const std::vector<std::vector<float> >& prior_variances,
|
||||
const CodeType code_type, const bool variance_encoded_in_target,
|
||||
const bool clip_bbox, const std::vector<caffe::NormalizedBBox>& bboxes,
|
||||
std::vector<caffe::NormalizedBBox>* decode_bboxes) {
|
||||
CV_Assert(prior_bboxes.size() == prior_variances.size());
|
||||
CV_Assert(prior_bboxes.size() == bboxes.size());
|
||||
int num_bboxes = prior_bboxes.size();
|
||||
if (num_bboxes >= 1) {
|
||||
CV_Assert(prior_variances[0].size() == 4);
|
||||
}
|
||||
decode_bboxes->clear();
|
||||
for (int i = 0; i < num_bboxes; ++i) {
|
||||
caffe::NormalizedBBox decode_bbox;
|
||||
DecodeBBox(prior_bboxes[i], prior_variances[i], code_type,
|
||||
variance_encoded_in_target, clip_bbox, bboxes[i], &decode_bbox);
|
||||
decode_bboxes->push_back(decode_bbox);
|
||||
}
|
||||
std::vector<caffe::NormalizedBBox>& decode_bboxes)
|
||||
{
|
||||
CV_Assert(prior_bboxes.size() == prior_variances.size());
|
||||
CV_Assert(prior_bboxes.size() == bboxes.size());
|
||||
size_t num_bboxes = prior_bboxes.size();
|
||||
CV_Assert(num_bboxes == 0 || prior_variances[0].size() == 4);
|
||||
decode_bboxes.clear(); decode_bboxes.resize(num_bboxes);
|
||||
if(variance_encoded_in_target)
|
||||
{
|
||||
for (int i = 0; i < num_bboxes; ++i)
|
||||
DecodeBBox<true>(prior_bboxes[i], prior_variances[i], code_type,
|
||||
clip_bbox, bboxes[i], decode_bboxes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < num_bboxes; ++i)
|
||||
DecodeBBox<false>(prior_bboxes[i], prior_variances[i], code_type,
|
||||
clip_bbox, bboxes[i], decode_bboxes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Decode all bboxes in a batch.
|
||||
void DecodeBBoxesAll(const std::vector<LabelBBox>& all_loc_preds,
|
||||
// Decode all bboxes in a batch
|
||||
static void DecodeBBoxesAll(const std::vector<LabelBBox>& all_loc_preds,
|
||||
const std::vector<caffe::NormalizedBBox>& prior_bboxes,
|
||||
const std::vector<std::vector<float> >& prior_variances,
|
||||
const int num, const bool share_location,
|
||||
const int num_loc_classes, const int background_label_id,
|
||||
const CodeType code_type, const bool variance_encoded_in_target,
|
||||
const bool clip, std::vector<LabelBBox>* all_decode_bboxes) {
|
||||
CV_Assert(all_loc_preds.size() == num);
|
||||
all_decode_bboxes->clear();
|
||||
all_decode_bboxes->resize(num);
|
||||
for (int i = 0; i < num; ++i) {
|
||||
// Decode predictions into bboxes.
|
||||
LabelBBox& decode_bboxes = (*all_decode_bboxes)[i];
|
||||
for (int c = 0; c < num_loc_classes; ++c) {
|
||||
int label = share_location ? -1 : c;
|
||||
if (label == background_label_id) {
|
||||
// Ignore background class.
|
||||
continue;
|
||||
}
|
||||
if (all_loc_preds[i].find(label) == all_loc_preds[i].end()) {
|
||||
// Something bad happened if there are no predictions for current label.
|
||||
util::make_error<int>("Could not find location predictions for label ", label);
|
||||
}
|
||||
const std::vector<caffe::NormalizedBBox>& label_loc_preds =
|
||||
all_loc_preds[i].find(label)->second;
|
||||
DecodeBBoxes(prior_bboxes, prior_variances,
|
||||
code_type, variance_encoded_in_target, clip,
|
||||
label_loc_preds, &(decode_bboxes[label]));
|
||||
const bool clip, std::vector<LabelBBox>& all_decode_bboxes)
|
||||
{
|
||||
CV_Assert(all_loc_preds.size() == num);
|
||||
all_decode_bboxes.clear();
|
||||
all_decode_bboxes.resize(num);
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
// Decode predictions into bboxes.
|
||||
const LabelBBox& loc_preds = all_loc_preds[i];
|
||||
LabelBBox& decode_bboxes = all_decode_bboxes[i];
|
||||
for (int c = 0; c < num_loc_classes; ++c)
|
||||
{
|
||||
int label = share_location ? -1 : c;
|
||||
if (label == background_label_id)
|
||||
continue; // Ignore background class.
|
||||
LabelBBox::const_iterator label_loc_preds = loc_preds.find(label);
|
||||
if (label_loc_preds == loc_preds.end())
|
||||
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find location predictions for label %d", label));
|
||||
DecodeBBoxes(prior_bboxes, prior_variances,
|
||||
code_type, variance_encoded_in_target, clip,
|
||||
label_loc_preds->second, decode_bboxes[label]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get prior bounding boxes from prior_data.
|
||||
// Get prior bounding boxes from prior_data
|
||||
// prior_data: 1 x 2 x num_priors * 4 x 1 blob.
|
||||
// num_priors: number of priors.
|
||||
// prior_bboxes: stores all the prior bboxes in the format of caffe::NormalizedBBox.
|
||||
// prior_variances: stores all the variances needed by prior bboxes.
|
||||
void GetPriorBBoxes(const float* priorData, const int& numPriors,
|
||||
std::vector<caffe::NormalizedBBox>* priorBBoxes,
|
||||
std::vector<std::vector<float> >* priorVariances)
|
||||
static void GetPriorBBoxes(const float* priorData, const int& numPriors,
|
||||
std::vector<caffe::NormalizedBBox>& priorBBoxes,
|
||||
std::vector<std::vector<float> >& priorVariances)
|
||||
{
|
||||
priorBBoxes->clear();
|
||||
priorVariances->clear();
|
||||
priorBBoxes.clear(); priorBBoxes.resize(numPriors);
|
||||
priorVariances.clear(); priorVariances.resize(numPriors);
|
||||
for (int i = 0; i < numPriors; ++i)
|
||||
{
|
||||
int startIdx = i * 4;
|
||||
caffe::NormalizedBBox bbox;
|
||||
caffe::NormalizedBBox& bbox = priorBBoxes[i];
|
||||
bbox.set_xmin(priorData[startIdx]);
|
||||
bbox.set_ymin(priorData[startIdx + 1]);
|
||||
bbox.set_xmax(priorData[startIdx + 2]);
|
||||
bbox.set_ymax(priorData[startIdx + 3]);
|
||||
float bboxSize = BBoxSize(bbox);
|
||||
bbox.set_size(bboxSize);
|
||||
priorBBoxes->push_back(bbox);
|
||||
bbox.set_size(BBoxSize<true>(bbox));
|
||||
}
|
||||
|
||||
for (int i = 0; i < numPriors; ++i)
|
||||
{
|
||||
int startIdx = (numPriors + i) * 4;
|
||||
std::vector<float> var;
|
||||
// not needed here: priorVariances[i].clear();
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
var.push_back(priorData[startIdx + j]);
|
||||
priorVariances[i].push_back(priorData[startIdx + j]);
|
||||
}
|
||||
priorVariances->push_back(var);
|
||||
}
|
||||
}
|
||||
|
||||
// Scale the caffe::NormalizedBBox w.r.t. height and width.
|
||||
void ScaleBBox(const caffe::NormalizedBBox& bbox,
|
||||
const int height, const int width,
|
||||
caffe::NormalizedBBox* scaleBBox)
|
||||
{
|
||||
scaleBBox->set_xmin(bbox.xmin() * width);
|
||||
scaleBBox->set_ymin(bbox.ymin() * height);
|
||||
scaleBBox->set_xmax(bbox.xmax() * width);
|
||||
scaleBBox->set_ymax(bbox.ymax() * height);
|
||||
scaleBBox->clear_size();
|
||||
bool normalized = !(width > 1 || height > 1);
|
||||
scaleBBox->set_size(BBoxSize(*scaleBBox, normalized));
|
||||
scaleBBox->set_difficult(bbox.difficult());
|
||||
}
|
||||
|
||||
// Get location predictions from loc_data.
|
||||
// loc_data: num x num_preds_per_class * num_loc_classes * 4 blob.
|
||||
// num: the number of images.
|
||||
@@ -603,19 +542,19 @@ public:
|
||||
// share_location: if true, all classes share the same location prediction.
|
||||
// loc_preds: stores the location prediction, where each item contains
|
||||
// location prediction for an image.
|
||||
void GetLocPredictions(const float* locData, const int num,
|
||||
static void GetLocPredictions(const float* locData, const int num,
|
||||
const int numPredsPerClass, const int numLocClasses,
|
||||
const bool shareLocation, std::vector<LabelBBox>* locPreds)
|
||||
const bool shareLocation, std::vector<LabelBBox>& locPreds)
|
||||
{
|
||||
locPreds->clear();
|
||||
locPreds.clear();
|
||||
if (shareLocation)
|
||||
{
|
||||
CV_Assert(numLocClasses == 1);
|
||||
}
|
||||
locPreds->resize(num);
|
||||
for (int i = 0; i < num; ++i)
|
||||
locPreds.resize(num);
|
||||
for (int i = 0; i < num; ++i, locData += numPredsPerClass * numLocClasses * 4)
|
||||
{
|
||||
LabelBBox& labelBBox = (*locPreds)[i];
|
||||
LabelBBox& labelBBox = locPreds[i];
|
||||
for (int p = 0; p < numPredsPerClass; ++p)
|
||||
{
|
||||
int startIdx = p * numLocClasses * 4;
|
||||
@@ -626,13 +565,13 @@ public:
|
||||
{
|
||||
labelBBox[label].resize(numPredsPerClass);
|
||||
}
|
||||
labelBBox[label][p].set_xmin(locData[startIdx + c * 4]);
|
||||
labelBBox[label][p].set_ymin(locData[startIdx + c * 4 + 1]);
|
||||
labelBBox[label][p].set_xmax(locData[startIdx + c * 4 + 2]);
|
||||
labelBBox[label][p].set_ymax(locData[startIdx + c * 4 + 3]);
|
||||
caffe::NormalizedBBox& bbox = labelBBox[label][p];
|
||||
bbox.set_xmin(locData[startIdx + c * 4]);
|
||||
bbox.set_ymin(locData[startIdx + c * 4 + 1]);
|
||||
bbox.set_xmax(locData[startIdx + c * 4 + 2]);
|
||||
bbox.set_ymax(locData[startIdx + c * 4 + 3]);
|
||||
}
|
||||
}
|
||||
locData += numPredsPerClass * numLocClasses * 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -643,25 +582,24 @@ public:
|
||||
// num_classes: number of classes.
|
||||
// conf_preds: stores the confidence prediction, where each item contains
|
||||
// confidence prediction for an image.
|
||||
void GetConfidenceScores(const float* confData, const int num,
|
||||
static void GetConfidenceScores(const float* confData, const int num,
|
||||
const int numPredsPerClass, const int numClasses,
|
||||
std::vector<std::vector<std::vector<float> > >* confPreds)
|
||||
std::vector<std::vector<std::vector<float> > >& confPreds)
|
||||
{
|
||||
confPreds->clear();
|
||||
confPreds->resize(num);
|
||||
for (int i = 0; i < num; ++i)
|
||||
confPreds.clear(); confPreds.resize(num);
|
||||
for (int i = 0; i < num; ++i, confData += numPredsPerClass * numClasses)
|
||||
{
|
||||
std::vector<std::vector<float> >& labelScores = (*confPreds)[i];
|
||||
std::vector<std::vector<float> >& labelScores = confPreds[i];
|
||||
labelScores.resize(numClasses);
|
||||
for (int p = 0; p < numPredsPerClass; ++p)
|
||||
for (int c = 0; c < numClasses; ++c)
|
||||
{
|
||||
int startIdx = p * numClasses;
|
||||
for (int c = 0; c < numClasses; ++c)
|
||||
std::vector<float>& classLabelScores = labelScores[c];
|
||||
classLabelScores.resize(numPredsPerClass);
|
||||
for (int p = 0; p < numPredsPerClass; ++p)
|
||||
{
|
||||
labelScores[c].push_back(confData[startIdx + c]);
|
||||
classLabelScores[p] = confData[p * numClasses + c];
|
||||
}
|
||||
}
|
||||
confData += numPredsPerClass * numClasses;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,40 +612,35 @@ public:
|
||||
// nms_threshold: a threshold used in non maximum suppression.
|
||||
// top_k: if not -1, keep at most top_k picked indices.
|
||||
// indices: the kept indices of bboxes after nms.
|
||||
void ApplyNMSFast(const std::vector<caffe::NormalizedBBox>& bboxes,
|
||||
static void ApplyNMSFast(const std::vector<caffe::NormalizedBBox>& bboxes,
|
||||
const std::vector<float>& scores, const float score_threshold,
|
||||
const float nms_threshold, const float eta, const int top_k,
|
||||
std::vector<int>* indices) {
|
||||
// Sanity check.
|
||||
CV_Assert(bboxes.size() == scores.size());
|
||||
std::vector<int>& indices)
|
||||
{
|
||||
CV_Assert(bboxes.size() == scores.size());
|
||||
|
||||
// Get top_k scores (with corresponding indices).
|
||||
std::vector<std::pair<float, int> > score_index_vec;
|
||||
GetMaxScoreIndex(scores, score_threshold, top_k, &score_index_vec);
|
||||
// Get top_k scores (with corresponding indices).
|
||||
std::vector<std::pair<float, int> > score_index_vec;
|
||||
GetMaxScoreIndex(scores, score_threshold, top_k, score_index_vec);
|
||||
|
||||
// Do nms.
|
||||
float adaptive_threshold = nms_threshold;
|
||||
indices->clear();
|
||||
while (score_index_vec.size() != 0) {
|
||||
const int idx = score_index_vec.front().second;
|
||||
bool keep = true;
|
||||
for (int k = 0; k < indices->size(); ++k) {
|
||||
if (keep) {
|
||||
const int kept_idx = (*indices)[k];
|
||||
float overlap = JaccardOverlap(bboxes[idx], bboxes[kept_idx]);
|
||||
keep = overlap <= adaptive_threshold;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
// Do nms.
|
||||
float adaptive_threshold = nms_threshold;
|
||||
indices.clear();
|
||||
while (score_index_vec.size() != 0) {
|
||||
const int idx = score_index_vec.front().second;
|
||||
bool keep = true;
|
||||
for (int k = 0; k < (int)indices.size() && keep; ++k) {
|
||||
const int kept_idx = indices[k];
|
||||
float overlap = JaccardOverlap<true>(bboxes[idx], bboxes[kept_idx]);
|
||||
keep = overlap <= adaptive_threshold;
|
||||
}
|
||||
if (keep)
|
||||
indices.push_back(idx);
|
||||
score_index_vec.erase(score_index_vec.begin());
|
||||
if (keep && eta < 1 && adaptive_threshold > 0.5) {
|
||||
adaptive_threshold *= eta;
|
||||
}
|
||||
}
|
||||
if (keep) {
|
||||
indices->push_back(idx);
|
||||
}
|
||||
score_index_vec.erase(score_index_vec.begin());
|
||||
if (keep && eta < 1 && adaptive_threshold > 0.5) {
|
||||
adaptive_threshold *= eta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get max scores with corresponding indices.
|
||||
@@ -715,74 +648,66 @@ public:
|
||||
// threshold: only consider scores higher than the threshold.
|
||||
// top_k: if -1, keep all; otherwise, keep at most top_k.
|
||||
// score_index_vec: store the sorted (score, index) pair.
|
||||
void GetMaxScoreIndex(const std::vector<float>& scores, const float threshold,const int top_k,
|
||||
std::vector<std::pair<float, int> >* score_index_vec)
|
||||
static void GetMaxScoreIndex(const std::vector<float>& scores, const float threshold, const int top_k,
|
||||
std::vector<std::pair<float, int> >& score_index_vec)
|
||||
{
|
||||
CV_DbgAssert(score_index_vec.empty());
|
||||
// Generate index score pairs.
|
||||
for (size_t i = 0; i < scores.size(); ++i)
|
||||
{
|
||||
if (scores[i] > threshold)
|
||||
{
|
||||
score_index_vec->push_back(std::make_pair(scores[i], i));
|
||||
score_index_vec.push_back(std::make_pair(scores[i], i));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the score pair according to the scores in descending order
|
||||
std::stable_sort(score_index_vec->begin(), score_index_vec->end(),
|
||||
std::stable_sort(score_index_vec.begin(), score_index_vec.end(),
|
||||
util::SortScorePairDescend<int>);
|
||||
|
||||
// Keep top_k scores if needed.
|
||||
if (top_k > -1 && top_k < (int)score_index_vec->size())
|
||||
if (top_k > -1 && top_k < (int)score_index_vec.size())
|
||||
{
|
||||
score_index_vec->resize(top_k);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the intersection between two bboxes.
|
||||
void IntersectBBox(const caffe::NormalizedBBox& bbox1,
|
||||
const caffe::NormalizedBBox& bbox2,
|
||||
caffe::NormalizedBBox* intersect_bbox) {
|
||||
if (bbox2.xmin() > bbox1.xmax() || bbox2.xmax() < bbox1.xmin() ||
|
||||
bbox2.ymin() > bbox1.ymax() || bbox2.ymax() < bbox1.ymin())
|
||||
{
|
||||
// Return [0, 0, 0, 0] if there is no intersection.
|
||||
intersect_bbox->set_xmin(0);
|
||||
intersect_bbox->set_ymin(0);
|
||||
intersect_bbox->set_xmax(0);
|
||||
intersect_bbox->set_ymax(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect_bbox->set_xmin(std::max(bbox1.xmin(), bbox2.xmin()));
|
||||
intersect_bbox->set_ymin(std::max(bbox1.ymin(), bbox2.ymin()));
|
||||
intersect_bbox->set_xmax(std::min(bbox1.xmax(), bbox2.xmax()));
|
||||
intersect_bbox->set_ymax(std::min(bbox1.ymax(), bbox2.ymax()));
|
||||
score_index_vec.resize(top_k);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the jaccard (intersection over union IoU) overlap between two bboxes.
|
||||
float JaccardOverlap(const caffe::NormalizedBBox& bbox1,
|
||||
const caffe::NormalizedBBox& bbox2,
|
||||
const bool normalized=true)
|
||||
template<bool normalized>
|
||||
static float JaccardOverlap(const caffe::NormalizedBBox& bbox1,
|
||||
const caffe::NormalizedBBox& bbox2)
|
||||
{
|
||||
caffe::NormalizedBBox intersect_bbox;
|
||||
IntersectBBox(bbox1, bbox2, &intersect_bbox);
|
||||
float intersect_width, intersect_height;
|
||||
if (normalized)
|
||||
if (bbox2.xmin() > bbox1.xmax() || bbox2.xmax() < bbox1.xmin() ||
|
||||
bbox2.ymin() > bbox1.ymax() || bbox2.ymax() < bbox1.ymin())
|
||||
{
|
||||
intersect_width = intersect_bbox.xmax() - intersect_bbox.xmin();
|
||||
intersect_height = intersect_bbox.ymax() - intersect_bbox.ymin();
|
||||
// Return [0, 0, 0, 0] if there is no intersection.
|
||||
intersect_bbox.set_xmin(0);
|
||||
intersect_bbox.set_ymin(0);
|
||||
intersect_bbox.set_xmax(0);
|
||||
intersect_bbox.set_ymax(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect_width = intersect_bbox.xmax() - intersect_bbox.xmin() + 1;
|
||||
intersect_height = intersect_bbox.ymax() - intersect_bbox.ymin() + 1;
|
||||
intersect_bbox.set_xmin(std::max(bbox1.xmin(), bbox2.xmin()));
|
||||
intersect_bbox.set_ymin(std::max(bbox1.ymin(), bbox2.ymin()));
|
||||
intersect_bbox.set_xmax(std::min(bbox1.xmax(), bbox2.xmax()));
|
||||
intersect_bbox.set_ymax(std::min(bbox1.ymax(), bbox2.ymax()));
|
||||
}
|
||||
|
||||
float intersect_width, intersect_height;
|
||||
intersect_width = intersect_bbox.xmax() - intersect_bbox.xmin();
|
||||
intersect_height = intersect_bbox.ymax() - intersect_bbox.ymin();
|
||||
if (intersect_width > 0 && intersect_height > 0)
|
||||
{
|
||||
if (!normalized)
|
||||
{
|
||||
intersect_width++;
|
||||
intersect_height++;
|
||||
}
|
||||
float intersect_size = intersect_width * intersect_height;
|
||||
float bbox1_size = BBoxSize(bbox1);
|
||||
float bbox2_size = BBoxSize(bbox2);
|
||||
float bbox1_size = BBoxSize<true>(bbox1);
|
||||
float bbox2_size = BBoxSize<true>(bbox2);
|
||||
return intersect_size / (bbox1_size + bbox2_size - intersect_size);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
class FullyConnected : public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
FullyConnected() : srcMat(0), weights(0), biasMat(0), activ(0), dstMat(0), nstripes(0), useAVX2(false) {}
|
||||
FullyConnected() : srcMat(0), weights(0), biasMat(0), activ(0), dstMat(0), nstripes(0), useAVX(false), useAVX2(false) {}
|
||||
|
||||
static void run(const Mat& srcMat, const Mat& weights, const Mat& biasMat,
|
||||
Mat& dstMat, const ActivationLayer* activ, int nstripes)
|
||||
@@ -139,6 +139,7 @@ public:
|
||||
p.dstMat = &dstMat;
|
||||
p.nstripes = nstripes;
|
||||
p.activ = activ;
|
||||
p.useAVX = checkHardwareSupport(CPU_AVX);
|
||||
p.useAVX2 = checkHardwareSupport(CPU_AVX2);
|
||||
|
||||
parallel_for_(Range(0, nstripes), p, nstripes);
|
||||
@@ -176,7 +177,12 @@ public:
|
||||
|
||||
#if CV_TRY_AVX2
|
||||
if( useAVX2 )
|
||||
fastGEMM1T_avx2( sptr, wptr, wstep, biasptr, dptr, nw, vecsize);
|
||||
opt_AVX2::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize);
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_AVX
|
||||
if( useAVX )
|
||||
opt_AVX::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
@@ -185,19 +191,19 @@ public:
|
||||
#if CV_SIMD128
|
||||
for( ; i <= nw - 4; i += 4, wptr += 4*wstep )
|
||||
{
|
||||
vfloat32x4 vs0 = v_setall_f32(0.f), vs1 = v_setall_f32(0.f);
|
||||
vfloat32x4 vs2 = v_setall_f32(0.f), vs3 = v_setall_f32(0.f);
|
||||
v_float32x4 vs0 = v_setall_f32(0.f), vs1 = v_setall_f32(0.f);
|
||||
v_float32x4 vs2 = v_setall_f32(0.f), vs3 = v_setall_f32(0.f);
|
||||
|
||||
for( k = 0; k < vecsize; k += 4 )
|
||||
{
|
||||
vfloat32x4 v = v_load_aligned(sptr + k);
|
||||
v_float32x4 v = v_load_aligned(sptr + k);
|
||||
vs0 += v*v_load_aligned(wptr + k);
|
||||
vs1 += v*v_load_aligned(wptr + wstep + k);
|
||||
vs2 += v*v_load_aligned(wptr + wstep*2 + k);
|
||||
vs3 += v*v_load_aligned(wptr + wstep*3 + k);
|
||||
}
|
||||
|
||||
vfloat32x4 s = v_reduce_sum4(vs0, vs1, vs2, vs3);
|
||||
v_float32x4 s = v_reduce_sum4(vs0, vs1, vs2, vs3);
|
||||
s += v_load(biasptr + i);
|
||||
v_store(dptr + i, s);
|
||||
}
|
||||
@@ -228,6 +234,7 @@ public:
|
||||
const ActivationLayer* activ;
|
||||
Mat* dstMat;
|
||||
int nstripes;
|
||||
bool useAVX;
|
||||
bool useAVX2;
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,10 @@
|
||||
#include <opencv2/dnn.hpp>
|
||||
#include <opencv2/dnn/shape_utils.hpp>
|
||||
|
||||
// dispatched AVX/AVX2 optimizations
|
||||
#include "layers/layers_common.simd.hpp"
|
||||
#include "layers/layers_common.simd_declarations.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace dnn
|
||||
@@ -64,19 +68,6 @@ void getConvPoolPaddings(const Size& inp, const Size& out,
|
||||
const Size &kernel, const Size &stride,
|
||||
const String &padMode, Size &pad);
|
||||
|
||||
#if CV_TRY_AVX2
|
||||
void fastConv_avx2(const float* weights, size_t wstep, const float* bias,
|
||||
const float* rowbuf, float* output, const int* outShape,
|
||||
int blockSize, int vecsize, int vecsize_aligned,
|
||||
const float* relu, bool initOutput);
|
||||
void fastGEMM1T_avx2( const float* vec, const float* weights,
|
||||
size_t wstep, const float* bias,
|
||||
float* dst, int nvecs, int vecsize );
|
||||
void fastGEMM_avx2( const float* aptr, size_t astep, const float* bptr0,
|
||||
size_t bstep, float* cptr, size_t cstep,
|
||||
int ma, int na, int nb );
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+33
-14
@@ -40,17 +40,34 @@
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "layers_common.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace dnn {
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
|
||||
|
||||
void fastConv_avx2( const float* weights, size_t wstep, const float* bias,
|
||||
const float* rowbuf, float* output, const int* outShape,
|
||||
int blockSize, int vecsize, int vecsize_aligned,
|
||||
const float* relu, bool initOutput )
|
||||
void fastConv( const float* weights, size_t wstep, const float* bias,
|
||||
const float* rowbuf, float* output, const int* outShape,
|
||||
int blockSize, int vecsize, int vecsize_aligned,
|
||||
const float* relu, bool initOutput );
|
||||
void fastGEMM1T( const float* vec, const float* weights,
|
||||
size_t wstep, const float* bias,
|
||||
float* dst, int nvecs, int vecsize );
|
||||
void fastGEMM( const float* aptr, size_t astep, const float* bptr,
|
||||
size_t bstep, float* cptr, size_t cstep,
|
||||
int ma, int na, int nb );
|
||||
|
||||
#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) && CV_AVX
|
||||
|
||||
#if !CV_FMA // AVX workaround
|
||||
#undef _mm256_fmadd_ps
|
||||
#define _mm256_fmadd_ps(a, b, c) _mm256_add_ps(c, _mm256_mul_ps(a, b))
|
||||
#endif
|
||||
|
||||
void fastConv( const float* weights, size_t wstep, const float* bias,
|
||||
const float* rowbuf, float* output, const int* outShape,
|
||||
int blockSize, int vecsize, int vecsize_aligned,
|
||||
const float* relu, bool initOutput )
|
||||
{
|
||||
int outCn = outShape[1];
|
||||
size_t outPlaneSize = outShape[2]*outShape[3];
|
||||
@@ -215,9 +232,9 @@ void fastConv_avx2( const float* weights, size_t wstep, const float* bias,
|
||||
}
|
||||
|
||||
// dst = vec * weights^t + bias
|
||||
void fastGEMM1T_avx2( const float* vec, const float* weights,
|
||||
size_t wstep, const float* bias,
|
||||
float* dst, int nvecs, int vecsize )
|
||||
void fastGEMM1T( const float* vec, const float* weights,
|
||||
size_t wstep, const float* bias,
|
||||
float* dst, int nvecs, int vecsize )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -277,9 +294,9 @@ void fastGEMM1T_avx2( const float* vec, const float* weights,
|
||||
_mm256_zeroupper();
|
||||
}
|
||||
|
||||
void fastGEMM_avx2( const float* aptr, size_t astep, const float* bptr,
|
||||
size_t bstep, float* cptr, size_t cstep,
|
||||
int ma, int na, int nb )
|
||||
void fastGEMM( const float* aptr, size_t astep, const float* bptr,
|
||||
size_t bstep, float* cptr, size_t cstep,
|
||||
int ma, int na, int nb )
|
||||
{
|
||||
int n = 0;
|
||||
for( ; n <= nb - 16; n += 16 )
|
||||
@@ -347,5 +364,7 @@ void fastGEMM_avx2( const float* aptr, size_t astep, const float* bptr,
|
||||
_mm256_zeroupper();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif // CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_END
|
||||
}} // namespace
|
||||
@@ -11,14 +11,18 @@ else:
|
||||
|
||||
ignored_arg_types = ["RNG*"]
|
||||
|
||||
gen_template_check_self = Template(""" if(!PyObject_TypeCheck(self, &pyopencv_${name}_Type))
|
||||
gen_template_check_self = Template(""" $cname* _self_ = NULL;
|
||||
if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
|
||||
_self_ = ${amp}((pyopencv_${name}_t*)self)->v${get};
|
||||
if (_self_ == NULL)
|
||||
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
|
||||
$cname* _self_ = ${amp}((pyopencv_${name}_t*)self)->v${get};
|
||||
""")
|
||||
|
||||
gen_template_check_self_algo = Template(""" if(!PyObject_TypeCheck(self, &pyopencv_${name}_Type))
|
||||
gen_template_check_self_algo = Template(""" $cname* _self_ = NULL;
|
||||
if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
|
||||
_self_ = dynamic_cast<$cname*>(${amp}((pyopencv_${name}_t*)self)->v.get());
|
||||
if (_self_ == NULL)
|
||||
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
|
||||
$cname* _self_ = dynamic_cast<$cname*>(${amp}((pyopencv_${name}_t*)self)->v.get());
|
||||
""")
|
||||
|
||||
gen_template_call_constructor_prelude = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
|
||||
@@ -200,7 +204,10 @@ static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *clo
|
||||
gen_template_get_prop_algo = Template("""
|
||||
static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure)
|
||||
{
|
||||
return pyopencv_from(dynamic_cast<$cname*>(p->v.get())${access}${member});
|
||||
$cname* _self_ = dynamic_cast<$cname*>(p->v.get());
|
||||
if (_self_ == NULL)
|
||||
return failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
|
||||
return pyopencv_from(_self_${access}${member});
|
||||
}
|
||||
""")
|
||||
|
||||
@@ -224,7 +231,13 @@ static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value
|
||||
PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
|
||||
return -1;
|
||||
}
|
||||
return pyopencv_to(value, dynamic_cast<$cname*>(p->v.get())${access}${member}) ? 0 : -1;
|
||||
$cname* _self_ = dynamic_cast<$cname*>(p->v.get());
|
||||
if (_self_ == NULL)
|
||||
{
|
||||
failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
|
||||
return -1;
|
||||
}
|
||||
return pyopencv_to(value, _self_${access}${member}) ? 0 : -1;
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user