Merge remote-tracking branch 'upstream/3.4' into merge-3.4
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Mon, 25 Jan 2021 22:34:41 +0000 (22:34 +0000)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Mon, 25 Jan 2021 22:42:13 +0000 (22:42 +0000)
1  2 
modules/core/src/ocl.cpp
modules/dnn/misc/python/test/test_dnn.py
modules/dnn/src/onnx/onnx_importer.cpp
modules/dnn/src/tensorflow/tf_importer.cpp
modules/dnn/test/test_onnx_importer.cpp
modules/highgui/src/window_w32.cpp
modules/python/src2/cv2.cpp
modules/python/test/test_misc.py

@@@ -833,324 -829,9 +833,326 @@@ public
  #endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
  
  
 +
 +struct OpenCLExecutionContext::Impl
 +{
 +    ocl::Context context_;
 +    int device_;  // device index in context
 +    ocl::Queue queue_;
 +    int useOpenCL_;
 +
 +protected:
 +    Impl() = delete;
 +
 +    void _init_device(cl_device_id deviceID)
 +    {
 +        CV_Assert(deviceID);
 +        int ndevices = (int)context_.ndevices();
 +        CV_Assert(ndevices > 0);
 +        bool found = false;
 +        for (int i = 0; i < ndevices; i++)
 +        {
 +            ocl::Device d = context_.device(i);
 +            cl_device_id dhandle = (cl_device_id)d.ptr();
 +            if (dhandle == deviceID)
 +            {
 +                device_ = i;
 +                found = true;
 +                break;
 +            }
 +        }
 +        CV_Assert(found && "OpenCL device can't work with passed OpenCL context");
 +    }
 +
 +    void _init_device(const ocl::Device& device)
 +    {
 +        CV_Assert(device.ptr());
 +        int ndevices = (int)context_.ndevices();
 +        CV_Assert(ndevices > 0);
 +        bool found = false;
 +        for (int i = 0; i < ndevices; i++)
 +        {
 +            ocl::Device d = context_.device(i);
 +            if (d.getImpl() == device.getImpl())
 +            {
 +                device_ = i;
 +                found = true;
 +                break;
 +            }
 +        }
 +        CV_Assert(found && "OpenCL device can't work with passed OpenCL context");
 +    }
 +
 +public:
 +    Impl(cl_platform_id platformID, cl_context context, cl_device_id deviceID)
 +        : device_(0), useOpenCL_(-1)
 +    {
 +        CV_UNUSED(platformID);
 +        CV_Assert(context);
 +        CV_Assert(deviceID);
 +
 +        context_ = Context::fromHandle(context);
 +        _init_device(deviceID);
 +        queue_ = Queue(context_, context_.device(device_));
 +    }
 +
 +    Impl(const ocl::Context& context, const ocl::Device& device, const ocl::Queue& queue)
 +        : device_(0), useOpenCL_(-1)
 +    {
 +        CV_Assert(context.ptr());
 +        CV_Assert(device.ptr());
 +
 +        context_ = context;
 +        _init_device(device);
 +        queue_ = queue;
 +    }
 +
 +    Impl(const ocl::Context& context, const ocl::Device& device)
 +        : device_(0), useOpenCL_(-1)
 +    {
 +        CV_Assert(context.ptr());
 +        CV_Assert(device.ptr());
 +
 +        context_ = context;
 +        _init_device(device);
 +        queue_ = Queue(context_, context_.device(device_));
 +    }
 +
 +    Impl(const ocl::Context& context, const int device, const ocl::Queue& queue)
 +        : context_(context)
 +        , device_(device)
 +        , queue_(queue)
 +        , useOpenCL_(-1)
 +    {
 +        // nothing
 +    }
 +    Impl(const Impl& other)
 +        : context_(other.context_)
 +        , device_(other.device_)
 +        , queue_(other.queue_)
 +        , useOpenCL_(-1)
 +    {
 +        // nothing
 +    }
 +
 +    inline bool useOpenCL() const { return const_cast<Impl*>(this)->useOpenCL(); }
 +    bool useOpenCL()
 +    {
 +        if (useOpenCL_ < 0)
 +        {
 +            try
 +            {
 +                useOpenCL_ = 0;
 +                if (!context_.empty() && context_.ndevices() > 0)
 +                {
 +                    const Device& d = context_.device(device_);
 +                    useOpenCL_ = d.available();
 +                }
 +            }
 +            catch (const cv::Exception&)
 +            {
 +                // nothing
 +            }
 +            if (!useOpenCL_)
 +                CV_LOG_INFO(NULL, "OpenCL: can't use OpenCL execution context");
 +        }
 +        return useOpenCL_ > 0;
 +    }
 +
 +    void setUseOpenCL(bool flag)
 +    {
 +        if (!flag)
 +            useOpenCL_ = 0;
 +        else
 +            useOpenCL_ = -1;
 +    }
 +
 +    static const std::shared_ptr<Impl>& getInitializedExecutionContext()
 +    {
 +        CV_TRACE_FUNCTION();
 +
 +        CV_LOG_INFO(NULL, "OpenCL: initializing thread execution context");
 +
 +        static bool initialized = false;
 +        static std::shared_ptr<Impl> g_primaryExecutionContext;
 +
 +        if (!initialized)
 +        {
 +            cv::AutoLock lock(getInitializationMutex());
 +            if (!initialized)
 +            {
 +                CV_LOG_INFO(NULL, "OpenCL: creating new execution context...");
 +                try
 +                {
 +                    Context c = ocl::Context::create(std::string());
 +                    if (c.ndevices())
 +                    {
 +                        int deviceId = 0;
 +                        auto& d = c.device(deviceId);
 +                        if (d.available())
 +                        {
 +                            auto q = ocl::Queue(c, d);
 +                            if (!q.ptr())
 +                            {
 +                                CV_LOG_ERROR(NULL, "OpenCL: Can't create default OpenCL queue");
 +                            }
 +                            else
 +                            {
 +                                g_primaryExecutionContext = std::make_shared<Impl>(c, deviceId, q);
 +                                CV_LOG_INFO(NULL, "OpenCL: device=" << d.name());
 +                            }
 +                        }
 +                        else
 +                        {
 +                            CV_LOG_ERROR(NULL, "OpenCL: OpenCL device is not available (CL_DEVICE_AVAILABLE returns false)");
 +                        }
 +                    }
 +                    else
 +                    {
 +                        CV_LOG_INFO(NULL, "OpenCL: context is not available/disabled");
 +                    }
 +                }
 +                catch (const std::exception& e)
 +                {
 +                    CV_LOG_INFO(NULL, "OpenCL: Can't initialize OpenCL context/device/queue: " << e.what());
 +                }
 +                catch (...)
 +                {
 +                    CV_LOG_WARNING(NULL, "OpenCL: Can't initialize OpenCL context/device/queue: unknown C++ exception");
 +                }
 +                initialized = true;
 +            }
 +        }
 +        return g_primaryExecutionContext;
 +    }
 +};
 +
 +Context& OpenCLExecutionContext::getContext() const
 +{
 +    CV_Assert(p);
 +    return p->context_;
 +}
 +Device& OpenCLExecutionContext::getDevice() const
 +{
 +    CV_Assert(p);
 +    return p->context_.device(p->device_);
 +}
 +Queue& OpenCLExecutionContext::getQueue() const
 +{
 +    CV_Assert(p);
 +    return p->queue_;
 +}
 +
 +bool OpenCLExecutionContext::useOpenCL() const
 +{
 +    if (p)
 +        return p->useOpenCL();
 +    return false;
 +}
 +void OpenCLExecutionContext::setUseOpenCL(bool flag)
 +{
 +    CV_Assert(p);
 +    p->setUseOpenCL(flag);
 +}
 +
 +/* static */
 +OpenCLExecutionContext& OpenCLExecutionContext::getCurrent()
 +{
 +    CV_TRACE_FUNCTION();
 +    CoreTLSData& data = getCoreTlsData();
 +    OpenCLExecutionContext& c = data.oclExecutionContext;
 +    if (!data.oclExecutionContextInitialized)
 +    {
 +        data.oclExecutionContextInitialized = true;
 +        if (c.empty() && haveOpenCL())
 +            c.p = Impl::getInitializedExecutionContext();
 +    }
 +    return c;
 +}
 +
 +/* static */
 +OpenCLExecutionContext& OpenCLExecutionContext::getCurrentRef()
 +{
 +    CV_TRACE_FUNCTION();
 +    CoreTLSData& data = getCoreTlsData();
 +    OpenCLExecutionContext& c = data.oclExecutionContext;
 +    return c;
 +}
 +
 +void OpenCLExecutionContext::bind() const
 +{
 +    CV_TRACE_FUNCTION();
 +    CV_Assert(p);
 +    CoreTLSData& data = getCoreTlsData();
 +    data.oclExecutionContext = *this;
 +    data.oclExecutionContextInitialized = true;
 +    data.useOpenCL = p->useOpenCL_;  // propagate "-1", avoid call useOpenCL()
 +}
 +
 +
 +OpenCLExecutionContext OpenCLExecutionContext::cloneWithNewQueue() const
 +{
 +    CV_TRACE_FUNCTION();
 +    CV_Assert(p);
 +    const Queue q(getContext(), getDevice());
 +    return cloneWithNewQueue(q);
 +}
 +
 +OpenCLExecutionContext OpenCLExecutionContext::cloneWithNewQueue(const ocl::Queue& q) const
 +{
 +    CV_TRACE_FUNCTION();
 +    CV_Assert(p);
 +    CV_Assert(q.ptr() != NULL);
 +    OpenCLExecutionContext c;
 +    c.p = std::make_shared<Impl>(p->context_, p->device_, q);
 +    return c;
 +}
 +
 +/* static */
 +OpenCLExecutionContext OpenCLExecutionContext::create(const Context& context, const Device& device, const ocl::Queue& queue)
 +{
 +    CV_TRACE_FUNCTION();
 +    if (!haveOpenCL())
 +        CV_Error(cv::Error::OpenCLApiCallError, "OpenCL runtime is not available!");
 +
 +    CV_Assert(!context.empty());
 +    CV_Assert(context.ptr());
 +    CV_Assert(!device.empty());
 +    CV_Assert(device.ptr());
 +    OpenCLExecutionContext ctx;
 +    ctx.p = std::make_shared<OpenCLExecutionContext::Impl>(context, device, queue);
 +    return ctx;
 +
 +}
 +
 +/* static */
 +OpenCLExecutionContext OpenCLExecutionContext::create(const Context& context, const Device& device)
 +{
 +    CV_TRACE_FUNCTION();
 +    if (!haveOpenCL())
 +        CV_Error(cv::Error::OpenCLApiCallError, "OpenCL runtime is not available!");
 +
 +    CV_Assert(!context.empty());
 +    CV_Assert(context.ptr());
 +    CV_Assert(!device.empty());
 +    CV_Assert(device.ptr());
 +    OpenCLExecutionContext ctx;
 +    ctx.p = std::make_shared<OpenCLExecutionContext::Impl>(context, device);
 +    return ctx;
 +
 +}
 +
 +void OpenCLExecutionContext::release()
 +{
 +    CV_TRACE_FUNCTION();
 +    p.reset();
 +}
 +
 +
++
  // true if we have initialized OpenCL subsystem with available platforms
- static bool g_isOpenCLActivated = false;
+ static bool g_isOpenCLInitialized = false;
+ static bool g_isOpenCLAvailable = false;
  
  bool haveOpenCL()
  {
          {
              cl_uint n = 0;
              g_isOpenCLAvailable = ::clGetPlatformIDs(0, NULL, &n) == CL_SUCCESS;
-             g_isOpenCLActivated = n > 0;
+             g_isOpenCLAvailable &= n > 0;
 +            CV_LOG_INFO(NULL, "OpenCL: found " << n << " platforms");
          }
          catch (...)
          {
@@@ -148,55 -148,6 +148,55 @@@ class dnn_test(NewOpenCVTests)
          normAssert(self, blob, target)
  
  
-             # FIXIT never properly work: cv.rectangle(frame, list(box), (0, 255, 0))
 +    def test_model(self):
 +        img_path = self.find_dnn_file("dnn/street.png")
 +        weights = self.find_dnn_file("dnn/MobileNetSSD_deploy.caffemodel", required=False)
 +        config = self.find_dnn_file("dnn/MobileNetSSD_deploy.prototxt", required=False)
 +        if weights is None or config is None:
 +            raise unittest.SkipTest("Missing DNN test files (dnn/MobileNetSSD_deploy.{prototxt/caffemodel}). Verify OPENCV_DNN_TEST_DATA_PATH configuration parameter.")
 +
 +        frame = cv.imread(img_path)
 +        model = cv.dnn_DetectionModel(weights, config)
 +        model.setInputParams(size=(300, 300), mean=(127.5, 127.5, 127.5), scale=1.0/127.5)
 +
 +        iouDiff = 0.05
 +        confThreshold = 0.0001
 +        nmsThreshold = 0
 +        scoreDiff = 1e-3
 +
 +        classIds, confidences, boxes = model.detect(frame, confThreshold, nmsThreshold)
 +
 +        refClassIds = (7, 15)
 +        refConfidences = (0.9998, 0.8793)
 +        refBoxes = ((328, 238, 85, 102), (101, 188, 34, 138))
 +
 +        normAssertDetections(self, refClassIds, refConfidences, refBoxes,
 +                             classIds, confidences, boxes,confThreshold, scoreDiff, iouDiff)
 +
 +        for box in boxes:
 +            cv.rectangle(frame, box, (0, 255, 0))
 +            cv.rectangle(frame, np.array(box), (0, 255, 0))
 +            cv.rectangle(frame, tuple(box), (0, 255, 0))
++            cv.rectangle(frame, list(box), (0, 255, 0))
 +
 +
 +    def test_classification_model(self):
 +        img_path = self.find_dnn_file("dnn/googlenet_0.png")
 +        weights = self.find_dnn_file("dnn/squeezenet_v1.1.caffemodel", required=False)
 +        config = self.find_dnn_file("dnn/squeezenet_v1.1.prototxt")
 +        ref = np.load(self.find_dnn_file("dnn/squeezenet_v1.1_prob.npy"))
 +        if weights is None or config is None:
 +            raise unittest.SkipTest("Missing DNN test files (dnn/squeezenet_v1.1.{prototxt/caffemodel}). Verify OPENCV_DNN_TEST_DATA_PATH configuration parameter.")
 +
 +        frame = cv.imread(img_path)
 +        model = cv.dnn_ClassificationModel(config, weights)
 +        model.setInputSize(227, 227)
 +        model.setInputCrop(True)
 +
 +        out = model.predict(frame)
 +        normAssert(self, out, ref)
 +
 +
      def test_face_detection(self):
          proto = self.find_dnn_file('dnn/opencv_face_detector.prototxt')
          model = self.find_dnn_file('dnn/opencv_face_detector.caffemodel', required=False)
Simple merge
Simple merge
Simple merge