diff --git a/include/aidge/backend/opencv/data/TensorImpl.hpp b/include/aidge/backend/opencv/data/TensorImpl.hpp
index d1a4daa99f6ad47fbe1534006724d333571f5bc4..1fe5ed12852d06482eef46f6ce7eaa8d60227fa8 100644
--- a/include/aidge/backend/opencv/data/TensorImpl.hpp
+++ b/include/aidge/backend/opencv/data/TensorImpl.hpp
@@ -7,12 +7,15 @@
 #include "aidge/data/Tensor.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
+#include "aidge/utils/ErrorHandling.hpp"
+#include "aidge/utils/future_std/span.hpp"
 
 #include <iostream>
 
 namespace {
 template <typename T> struct OpenCvType { static const int type; };
 template <> const int OpenCvType<char>::type = CV_8SC1;
+template <> const int OpenCvType<signed char>::type = CV_8SC1;
 template <> const int OpenCvType<short>::type = CV_16SC1;
 template <> const int OpenCvType<int>::type = CV_32SC1;
 template <> const int OpenCvType<unsigned char>::type = CV_8UC1;
@@ -24,34 +27,36 @@ template <> const int OpenCvType<double>::type = CV_64FC1;
 namespace Aidge {
   
 class TensorImpl_opencv_ {
-protected:
-  cv::Mat mData;
-public :
-  virtual const cv::Mat getCvMat() const { return mData; }
-  virtual void setCvMat(cv::Mat mat) {mData=mat;}
+public:
+    virtual const cv::Mat& getCvMat() const = 0;
+    virtual void setCvMat(const cv::Mat& mat ) = 0;
 };
 
 template <class T> class TensorImpl_opencv : public TensorImpl, public TensorImpl_opencv_ {
 private:
     const Tensor &mTensor; // Impl needs to access Tensor information, but is not
                            // supposed to change it!
-    cv::Mat mData;
 
+    future_std::span<cv::Mat> mData;
+
+    std::unique_ptr<cv::Mat> mDataOwner = std::unique_ptr<cv::Mat>(new cv::Mat(0,0,OpenCvType<T>::type));
+    
 public:
     static constexpr const char *Backend = "opencv";
 
-  TensorImpl_opencv(const Tensor &tensor)
+    TensorImpl_opencv(const Tensor &tensor)
       : TensorImpl(Backend), mTensor(tensor) {}
 
     bool operator==(const TensorImpl &otherImpl) const override final {
         // Create iterators for both matrices
-        cv::MatConstIterator_<T> it1 = mData.begin<T>();
-        const cv::Mat otherData =
-            reinterpret_cast<const TensorImpl_opencv<T> &>(otherImpl).data();
+        cv::MatConstIterator_<T> it1 = mDataOwner->begin<T>();
+        const future_std::span<cv::Mat> tmp = reinterpret_cast<const TensorImpl_opencv<T> &>(otherImpl).data();
+        
+        const cv::Mat otherData = *(tmp.data());
         cv::MatConstIterator_<T> it2 = otherData.begin<T>();
 
         // Iterate over the elements and compare them
-        for (; it1 != mData.end<T>(); ++it1, ++it2) {
+        for (; it1 != mDataOwner->end<T>(); ++it1, ++it2) {
             if (*it1 != *it2) {
                 return false;
             }
@@ -59,111 +64,175 @@ public:
         return true;
     }
 
-    static std::unique_ptr<TensorImpl_opencv<T>> create(const Tensor &tensor) {
+    static std::unique_ptr<TensorImpl_opencv> create(const Tensor &tensor) {
         return std::make_unique<TensorImpl_opencv<T>>(tensor);
     }
 
     // native interface
-    const cv::Mat &data() const { return mData; }
-
-    // void setData(cv::Mat mat){mData=mat;}
+    const future_std::span<cv::Mat> data() const { return mData; }
 
     std::size_t scalarSize() const override { return sizeof(T); }
 
-    void copy(const void *src, NbElts_t length, std::size_t /*offset = 0*/) override {
-      std::copy(static_cast<const T*>(src), static_cast<const T*>(src) + length, static_cast<T*>(rawPtr()));
+    std::size_t size() const override { return mData.size(); }
+
+    void setDevice(DeviceIdx_t device) override {
+        AIDGE_ASSERT(device == 0, "device cannot be != 0 for Opencv backend");
+    }
+
+    void copy(const void *src, NbElts_t length, NbElts_t offset = 0) override {
+        AIDGE_ASSERT(length <= mData.size() || length <= mTensor.size(), "copy length is above capacity");
+        std::copy(static_cast<const T *>(src), static_cast<const T *>(src) + length,
+                  static_cast<T *>(rawPtr()) + offset);
     }
 
-    void *rawPtr() override {
-      if (mData.ptr() == nullptr) {
-        lazyInit(mData);
-      }
-      return mData.ptr<T>();
+    void copyCast(const void *src, NbElts_t length, const DataType srcDt) override {
+        if (length == 0) {
+            return;
+        }
+
+        AIDGE_ASSERT(length <= mData.size() || length <= mTensor.size(), "copy length is above capacity");
+        if (srcDt == DataType::Float64) {
+            std::copy(static_cast<const double*>(src), static_cast<const double*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::Float32) {
+            std::copy(static_cast<const float*>(src), static_cast<const float*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::Float16) {
+            std::copy(static_cast<const half_float::half*>(src), static_cast<const half_float::half*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::Int64) {
+            std::copy(static_cast<const int64_t*>(src), static_cast<const int64_t*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::UInt64) {
+            std::copy(static_cast<const uint64_t*>(src), static_cast<const uint64_t*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::Int32) {
+            std::copy(static_cast<const int32_t*>(src), static_cast<const int32_t*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::UInt32) {
+            std::copy(static_cast<const uint32_t*>(src), static_cast<const uint32_t*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::Int16) {
+            std::copy(static_cast<const int16_t*>(src), static_cast<const int16_t*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::UInt16) {
+            std::copy(static_cast<const uint16_t*>(src), static_cast<const uint16_t*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::Int8) {
+            std::copy(static_cast<const int8_t*>(src), static_cast<const int8_t*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else if (srcDt == DataType::UInt8) {
+            std::copy(static_cast<const uint8_t*>(src), static_cast<const uint8_t*>(src) + length,
+                    static_cast<T *>(rawPtr()));
+        }
+        else {
+            AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsupported data type.");
+        }
+    }
+
+    
+    void copyFromDevice(const void *src, NbElts_t length, const std::pair<std::string, DeviceIdx_t>& device) override {
+        AIDGE_ASSERT(device.first == Backend, "backend must match");
+        AIDGE_ASSERT(device.second == 0, "device cannot be != 0 for CPU backend");
+        copy(src, length);
+    }
+
+    void copyFromHost(const void *src, NbElts_t length) override {
+        copy(src, length);
+    }
+
+    void copyToHost(void *dst, NbElts_t length) const override {
+        AIDGE_ASSERT(length <= mData.size() || length <= mTensor.size(), "copy length is above capacity");
+        const T* src = static_cast<const T*>(rawPtr());
+        std::copy(static_cast<const T *>(src), static_cast<const T *>(src) + length,
+                  static_cast<T *>(dst));
+    }
+
+    void *rawPtr(NbElts_t offset = 0) override {
+        lazyInit();
+        return (mData.data()->ptr() + offset*sizeof(T));
     };
 
-  void setRawPtr(void */*ptr*/) override final {
-    printf("Not implemented yet.\n");
-    // assert(mTensor.nbDims()<=3 && "nbDims > 3 is not supported for opencv backends.");
+    const void *rawPtr(NbElts_t offset = 0) const override {
+        AIDGE_ASSERT(mData.size() >= mTensor.size(), "accessing uninitialized const rawPtr");
+        return (mData.data()->ptr() + offset*sizeof(T));
+    };
 
-    // std::vector<cv::Mat> channels;
-    // for (std::size_t k = 0; k < mTensor.dims()[2]; ++k) {
-    //   channels.push_back(cv::Mat(static_cast<int>(mTensor.dims()[1]),
-    //                               static_cast<int>(mTensor.dims()[0]),
-    //                               OpenCvType<T>::type,
-    //                               static_cast<T*>(ptr) + k*mTensor.dims()[1]*mTensor.dims()[0]*sizeof(T)));
-    // }
-    // cv::merge(channels, mData);
-  };
+    void *hostPtr(NbElts_t offset = 0) override {
+        lazyInit();
+        std::cout << *reinterpret_cast<T *>(mData.data()->ptr()) + offset << std::endl;
+        return (mData.data()->ptr() + offset*sizeof(T));
+    };
 
-  void* getRaw(std::size_t idx) override {
-    return  static_cast<void*>(&mData.at<T>(static_cast<int>(idx)));
-   };
+    const void *hostPtr(NbElts_t offset = 0) const override {
+        AIDGE_ASSERT(mData.size() >= mTensor.size(), "accessing uninitialized const hostPtr");
+        return (mData.data()->ptr() + offset*sizeof(T));
+    };
+
+    const cv::Mat& getCvMat() const override { return *mDataOwner.get(); }
+    void setCvMat(const cv::Mat& mat) override {mDataOwner.reset(new cv::Mat(std::move(mat)));}
+    
 
   virtual ~TensorImpl_opencv() = default;
 
 private:
-  void lazyInit(cv::Mat &mat) {
-    std::cout << "call lazy init tensorimpl_opencv : " << std::endl;
-    assert(mTensor.nbDims() <= 3 && "OpenCV implementation does not support "
-                                    "tensor with more than 3 dimensions");
-
-    if (mat.cols == static_cast<int>(mTensor.dims()[0]) && mat.rows == static_cast<int>(mTensor.dims()[1]) &&
-        mat.channels() == static_cast<int>(mTensor.dims()[2])) {
-      // Correct size, not change
-      return;
-    }
 
-    if (mat.rows * mat.cols * mat.channels() == static_cast<int>(mTensor.size())) {
-      // Shape has changed, data will not be invalided
-      mat = mat.reshape(mTensor.dims()[2], mTensor.dims()[1]);
-      return;
-    }
+  void lazyInit() {
+    if (mData.size() < mTensor.size()) {
+        // Need more data, a re-allocation will occur
+        AIDGE_ASSERT(mData.empty() || mDataOwner != nullptr, "trying to enlarge non-owned data");
+
+        cv::Mat myNewMatrix;
+        if (mTensor.nbDims() < 3) {
+            myNewMatrix = cv::Mat(((mTensor.nbDims() > 1) ? static_cast<int>(mTensor.dims()[1])
+                                                    : (mTensor.nbDims() > 0) ? 1
+                                                                            : 0),
+                            (mTensor.nbDims() > 0) ? static_cast<int>(mTensor.dims()[0]) : 0,
+                            OpenCvType<T>::type);
+        } else {
+            std::vector<cv::Mat> channels;
+
+            for (std::size_t k = 0; k < mTensor.dims()[2]; ++k) {
+                channels.push_back(cv::Mat(static_cast<int>(mTensor.dims()[1]),
+                                        static_cast<int>(mTensor.dims()[0]),
+                                        OpenCvType<T>::type));
+            }
+
+            cv::merge(channels, myNewMatrix);
+        }
 
-    // Number of element has changed, daya WILL BE invalided
-    if (mTensor.nbDims() < 3) {
-      mat = cv::Mat(((mTensor.nbDims() > 1) ? static_cast<int>(mTensor.dims()[1])
-                                            : (mTensor.nbDims() > 0) ? 1
-                                                                      : 0),
-                    (mTensor.nbDims() > 0) ? static_cast<int>(mTensor.dims()[0]) : 0,
-                    OpenCvType<T>::type);
-    } else {
-      std::vector<cv::Mat> channels;
-
-      for (std::size_t k = 0; k < mTensor.dims()[2]; ++k) {
-        channels.push_back(cv::Mat(static_cast<int>(mTensor.dims()[1]),
-                                   static_cast<int>(mTensor.dims()[0]),
-                                   OpenCvType<T>::type));
-      }
-
-      cv::merge(channels, mat);
+        mDataOwner.reset(new cv::Mat(std::forward<cv::Mat>(myNewMatrix)));
+        mData = future_std::span<cv::Mat>(mDataOwner.get(), mTensor.size());
+      
     }
   }
 };
 
 namespace {
-static Registrar<Tensor>
-    registrarTensorImpl_opencv_Float64({"opencv", DataType::Float64},
-                                       Aidge::TensorImpl_opencv<double>::create);   
-static Registrar<Tensor>
-    registrarTensorImpl_opencv_Float32({"opencv", DataType::Float32},
-                                       Aidge::TensorImpl_opencv<float>::create);
-static Registrar<Tensor>
-    registrarTensorImpl_opencv_Int32({"opencv", DataType::Int32},
-                                     Aidge::TensorImpl_opencv<int>::create);
-static Registrar<Tensor>
-    registrarTensorImpl_opencv_Int16({"opencv", DataType::Int16},
-                                     Aidge::TensorImpl_opencv<int16_t>::create);    
-static Registrar<Tensor>
-    registrarTensorImpl_opencv_UInt16({"opencv", DataType::UInt16},
-                                     Aidge::TensorImpl_opencv<uint16_t>::create); 
-// static Registrar<Tensor>
-//     registrarTensorImpl_opencv_Int8({"opencv", DataType::Int8},
-//                                      Aidge::TensorImpl_opencv<int8_t>::create); 
-static Registrar<Tensor>
-    registrarTensorImpl_opencv_UInt8({"opencv", DataType::UInt8},
-                                     Aidge::TensorImpl_opencv<uint8_t>::create); 
-                                                                        
-                                
+static Registrar<Tensor> registrarTensorImpl_opencv_Float64(
+        {"opencv", DataType::Float64}, Aidge::TensorImpl_opencv<double>::create);
+static Registrar<Tensor> registrarTensorImpl_opencv_Float32(
+        {"opencv", DataType::Float32}, Aidge::TensorImpl_opencv<float>::create);
+static Registrar<Tensor> registrarTensorImpl_opencv_Int32(
+        {"opencv", DataType::Int32}, Aidge::TensorImpl_opencv<int>::create);
+static Registrar<Tensor> registrarTensorImpl_opencv_Int16(
+        {"opencv", DataType::Int16}, Aidge::TensorImpl_opencv<int16_t>::create);
+static Registrar<Tensor> registrarTensorImpl_opencv_UInt16(
+        {"opencv", DataType::UInt16}, Aidge::TensorImpl_opencv<uint16_t>::create);
+static Registrar<Tensor> registrarTensorImpl_opencv_Int8(
+        {"opencv", DataType::Int8}, Aidge::TensorImpl_opencv<int8_t>::create);
+static Registrar<Tensor> registrarTensorImpl_opencv_UInt8(
+        {"opencv", DataType::UInt8}, Aidge::TensorImpl_opencv<uint8_t>::create);                              
 } // namespace
 } // namespace Aidge