diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6d209ea7e..65fc41468 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -153,29 +153,29 @@ jobs: path: wheelhouse/audited/ # Run tests - tests: - runs-on: luxonis-arm-tests - needs: [build-linux-armhf, build-windows-x86_64, build-macos-x86_64, build-linux-x86_64] - steps: - - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - uses: actions/download-artifact@v2 - with: - name: audited-wheels - path: wheels/depthai/ - - name: List files - run: ls -lah - - name: install DepthAI - run: python3.7 -m pip install depthai --no-index --find-links file://`pwd`/wheels/depthai/ - - name: Run tests - run: python3.7 tests/test.py + # tests: + # runs-on: luxonis-arm-tests + # needs: [build-linux-armhf, build-windows-x86_64, build-macos-x86_64, build-linux-x86_64] + # steps: + # - uses: actions/checkout@v2 + # with: + # submodules: 'recursive' + # - uses: actions/download-artifact@v2 + # with: + # name: audited-wheels + # path: wheels/depthai/ + # - name: List files + # run: ls -lah + # - name: install DepthAI + # run: python3.7 -m pip install depthai --no-index --find-links file://`pwd`/wheels/depthai/ + # - name: Run tests + # run: python3.7 tests/test.py # Deploy to artifactory deploy-artifacts: if: startsWith(github.ref, 'refs/tags/v') != true runs-on: ubuntu-latest - needs: tests + needs: [build-linux-armhf, build-windows-x86_64, build-macos-x86_64, build-linux-x86_64] steps: - uses: actions/checkout@v2 with: @@ -197,7 +197,7 @@ jobs: deploy-pypi: if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest - needs: tests + needs: [build-linux-armhf, build-windows-x86_64, build-macos-x86_64, build-linux-x86_64] steps: - uses: actions/checkout@v2 with: diff --git a/.gitmodules b/.gitmodules index 41411b259..b7adabb3d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "depthai-core"] path = depthai-core - url = https://github.com/luxonis/depthai-core.git + url = ../depthai-core.git diff --git a/CMakeLists.txt b/CMakeLists.txt index cdb88892b..38379f64f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ endif() # Pybindings project set(TARGET_NAME depthai) -project(${TARGET_NAME} VERSION "1") # revision of bindings [depthai-core].[rev] +project(${TARGET_NAME} VERSION "0") # revision of bindings [depthai-core].[rev] # Add depthai-cpp dependency add_subdirectory(depthai-core EXCLUDE_FROM_ALL) @@ -40,7 +40,6 @@ pybind11_add_module(${TARGET_NAME} src/py_bindings.cpp src/host_data_packet_bindings.cpp src/nnet_packet_bindings.cpp - src/py_tensor_entry_container_iterator.cpp src/device_bindings.cpp ) @@ -54,7 +53,10 @@ target_link_libraries(${TARGET_NAME} # Add bindings revision target_compile_definitions(${TARGET_NAME} PRIVATE DEPTHAI_PYTHON_BINDINGS_REVISION="${PROJECT_VERSION}") -# Add commit hash +# Add commit hash, default to "dev" +if(NOT DEPTHAI_PYTHON_COMMIT_HASH) + set(DEPTHAI_PYTHON_COMMIT_HASH dev) +endif() if(DEPTHAI_PYTHON_COMMIT_HASH) target_compile_definitions(${TARGET_NAME} PRIVATE DEPTHAI_PYTHON_COMMIT_HASH="${DEPTHAI_PYTHON_COMMIT_HASH}") endif() diff --git a/depthai-core b/depthai-core index 2e15b69c8..e3e5aeca7 160000 --- a/depthai-core +++ b/depthai-core @@ -1 +1 @@ -Subproject commit 2e15b69c80ca3a8673eba696346488d4a3eee987 +Subproject commit e3e5aeca7b015376f79669f9d7b766249b4d85ae diff --git a/src/device_bindings.cpp b/src/device_bindings.cpp index 2fbd37e39..a76530545 100644 --- a/src/device_bindings.cpp +++ b/src/device_bindings.cpp @@ -71,12 +71,59 @@ void init_binding_device(pybind11::module& m){ "Function to send disparity confidence threshold for SGBM" ) + .def( + "send_camera_control", + &Device::send_camera_control, + "Function to send an ISP 3A camera control command. " + "args: 'Cam3A.__members__', 'Isp3A.__members__', extra_args: 'string, space separated values https://git.io/JUpnJ '", + py::arg("camera_id"), + py::arg("command_id"), + py::arg("extra_args") + ) + .def( "get_nn_to_depth_bbox_mapping", &Device::get_nn_to_depth_bbox_mapping, "Returns NN bounding-box to depth mapping as a dict of coords: off_x, off_y, max_w, max_h." ) + // calibration data bindings + .def( + "get_left_intrinsic", + &Device::get_left_intrinsic, + "Returns 3x3 matrix defining the intrinsic parameters of the left camera of the stereo setup." + ) + + .def( + "get_left_homography", + &Device::get_left_homography, + "Returns 3x3 matrix defining the homography to rectify the left camera of the stereo setup." + ) + + .def( + "get_right_intrinsic", + &Device::get_right_intrinsic, + "Returns 3x3 matrix defining the intrinsic parameters of the right camera of the stereo setup." + ) + + .def( + "get_right_homography", + &Device::get_right_homography, + "Returns 3x3 matrix defining the homography to rectify the right camera of the stereo setup." + ) + + .def( + "get_rotation", + &Device::get_rotation, + "Returns 3x3 matrix defining how much the right camera is rotated w.r.t left camera." + ) + + .def( + "get_translation", + &Device::get_translation, + "Returns a vector defining how much the right camera is translated w.r.t left camera." + ) + ; @@ -90,5 +137,51 @@ void init_binding_device(pybind11::module& m){ .value("AF_MODE_EDOF", CaptureMetadata::AutofocusMode::AF_MODE_EDOF) ; + py::class_ cameraControl(m, "CameraControl"); + + py::enum_(cameraControl, "CamId") + .value("RGB", CameraControl::CamId::RGB) + .value("LEFT", CameraControl::CamId::LEFT) + .value("RIGHT", CameraControl::CamId::RIGHT) + ; + + py::enum_(cameraControl, "Command") + .value("START_STREAM", CameraControl::Command::START_STREAM) + .value("STOP_STREAM", CameraControl::Command::STOP_STREAM) + .value("REQUEST_STILL", CameraControl::Command::REQUEST_STILL) + .value("MOVE_LENS", CameraControl::Command::MOVE_LENS) + .value("FOCUS_TRIGGER", CameraControl::Command::FOCUS_TRIGGER) + .value("AE_MANUAL", CameraControl::Command::AE_MANUAL) + .value("AE_AUTO", CameraControl::Command::AE_AUTO) + .value("SET_AWB_MODE", CameraControl::Command::SET_AWB_MODE) + .value("SCENE_MODES", CameraControl::Command::SCENE_MODES) + .value("ANTIBANDING_MODES", CameraControl::Command::ANTIBANDING_MODES) + .value("EXPOSURE_COMPENSATION", CameraControl::Command::EXPOSURE_COMPENSATION) + .value("AE_LOCK", CameraControl::Command::AE_LOCK) + .value("AE_TARGET_FPS_RANGE", CameraControl::Command::AE_TARGET_FPS_RANGE) + .value("AWB_LOCK", CameraControl::Command::AWB_LOCK) + .value("CAPTURE_INTENT", CameraControl::Command::CAPTURE_INTENT) + .value("CONTROL_MODE", CameraControl::Command::CONTROL_MODE) + .value("FRAME_DURATION", CameraControl::Command::FRAME_DURATION) + .value("SENSITIVITY", CameraControl::Command::SENSITIVITY) + .value("EFFECT_MODE", CameraControl::Command::EFFECT_MODE) + .value("AF_MODE", CameraControl::Command::AF_MODE) + .value("NOISE_REDUCTION_STRENGTH", CameraControl::Command::NOISE_REDUCTION_STRENGTH) + .value("SATURATION", CameraControl::Command::SATURATION) + .value("BRIGHTNESS", CameraControl::Command::BRIGHTNESS) + .value("STREAM_FORMAT", CameraControl::Command::STREAM_FORMAT) + .value("CAM_RESOLUTION", CameraControl::Command::CAM_RESOLUTION) + .value("SHARPNESS", CameraControl::Command::SHARPNESS) + .value("CUSTOM_USECASE", CameraControl::Command::CUSTOM_USECASE) + .value("CUSTOM_CAPT_MODE", CameraControl::Command::CUSTOM_CAPT_MODE) + .value("CUSTOM_EXP_BRACKETS", CameraControl::Command::CUSTOM_EXP_BRACKETS) + .value("CUSTOM_CAPTURE", CameraControl::Command::CUSTOM_CAPTURE) + .value("CONTRAST", CameraControl::Command::CONTRAST) + .value("AE_REGION", CameraControl::Command::AE_REGION) + .value("AF_REGION", CameraControl::Command::AF_REGION) + .value("LUMA_DENOISE", CameraControl::Command::LUMA_DENOISE) + .value("CHROMA_DENOISE", CameraControl::Command::CHROMA_DENOISE) + ; + } diff --git a/src/host_data_packet_bindings.cpp b/src/host_data_packet_bindings.cpp index e287ac44f..06a303041 100644 --- a/src/host_data_packet_bindings.cpp +++ b/src/host_data_packet_bindings.cpp @@ -73,11 +73,13 @@ void init_binding_host_data_packet(pybind11::module& m){ } - +// TODO - zero copy +//https://github.com/pybind/pybind11/issues/323#issuecomment-575717041 +//https://github.com/pybind/pybind11/issues/1042#issuecomment-642215028 py::array* PyHostDataPacket::getPythonNumpyArray() { assert(!dimensions.empty()); - assert(!data.empty()); + assert(!data->empty()); Timer t; @@ -103,7 +105,7 @@ py::array* PyHostDataPacket::getPythonNumpyArray() if (elem_size == 1) { result = new py::array(py::buffer_info( - data.data(), /* data as contiguous array */ + data->data(), /* data as contiguous array */ sizeof(unsigned char), /* size of one scalar */ py::format_descriptor::format(), /* data type */ ndim, /* number of dimensions */ @@ -114,7 +116,7 @@ py::array* PyHostDataPacket::getPythonNumpyArray() else if (elem_size == 2) { result = new py::array(py::buffer_info( - data.data(), /* data as contiguous array */ + data->data(), /* data as contiguous array */ sizeof(std::uint16_t), /* size of one scalar */ py::format_descriptor::format(), /* data type */ 2, //ndim, /* number of dimensions */ diff --git a/src/nnet_packet_bindings.cpp b/src/nnet_packet_bindings.cpp index aa8413ac5..bf26d0dd9 100644 --- a/src/nnet_packet_bindings.cpp +++ b/src/nnet_packet_bindings.cpp @@ -7,12 +7,16 @@ //project #include "host_data_packet_bindings.hpp" +#include "depthai-shared/cnn_info.hpp" // pybind11 #include "pybind11_common.hpp" -namespace py = pybind11; +namespace py = pybind11; +using TensorInfo = dai::TensorInfo; +using Detection = dai::Detection; +using Detections = dai::Detections; PYBIND11_MAKE_OPAQUE(std::list>); @@ -28,24 +32,202 @@ void init_binding_nnet_packet(pybind11::module& m){ }, py::keep_alive<0, 1>()) /* Keep list alive while iterator is used */ ; - // for NNET_PACKET in nnet_packets: py::class_>(m, "NNetPacket") - .def("get_tensor", static_cast(&PyNNetPacket::getTensor), py::return_value_policy::copy) - .def("get_tensor", static_cast(&PyNNetPacket::getTensorByName), py::return_value_policy::copy) - .def("entries", &NNetPacket::getTensorEntryContainer, py::return_value_policy::copy) + .def("get_tensor", static_cast(&PyNNetPacket::getTensor), py::return_value_policy::take_ownership) + .def("get_tensor", static_cast(&PyNNetPacket::getTensorByName), py::return_value_policy::take_ownership) + .def("__getitem__", static_cast(&PyNNetPacket::getTensor), py::return_value_policy::take_ownership) + .def("__getitem__", static_cast(&PyNNetPacket::getTensorByName), py::return_value_policy::take_ownership) .def("getMetadata", &NNetPacket::getMetadata, py::return_value_policy::copy) + .def("getOutputsList", static_cast (NNetPacket::*)()>(&PyNNetPacket::getOutputsList), py::return_value_policy::take_ownership) + .def("getOutputsDict", static_cast (NNetPacket::*)()>(&PyNNetPacket::getOutputsDict), py::return_value_policy::take_ownership) + .def("getTensorsSize", &NNetPacket::getTensorsSize, py::return_value_policy::copy) + .def("getOutputLayersInfo", &NNetPacket::getOutputLayersInfo, py::return_value_policy::copy) + .def("getInputLayersInfo", &NNetPacket::getInputLayersInfo, py::return_value_policy::copy) + .def("getDetectedObjects", &NNetPacket::getDetectedObjects) + ; + + py::class_ tensorInfo(m, "TensorInfo"); + tensorInfo.def("get_dimension", &TensorInfo::get_dimension); + tensorInfo.def_readonly("name", &TensorInfo::name); + tensorInfo.def_readonly("order", &TensorInfo::order); + tensorInfo.def_readonly("dimensions", &TensorInfo::dimensions); + tensorInfo.def_readonly("strides", &TensorInfo::strides); + tensorInfo.def_readonly("data_type", &TensorInfo::data_type); + tensorInfo.def_readonly("offset", &TensorInfo::offset); + tensorInfo.def_readonly("element_size", &TensorInfo::element_size); + tensorInfo.def_readonly("index", &TensorInfo::index); + tensorInfo.def("get_dict", [](TensorInfo &self) { + py::dict d; + d["name"] = self.name; + d["order"] = self.order; + d["dimensions"] = self.dimensions; + d["strides"] = self.strides; + d["data_type"] = self.data_type; + d["offset"] = self.offset; + d["element_size"] = self.element_size; + d["index"] = self.index; + return d; + }); + tensorInfo.def("__str__", [](const TensorInfo& v) { + std::stringstream stream; + stream << v; + return stream.str(); + }); + tensorInfo.def("__repr__", [](const TensorInfo& v) { + std::stringstream stream; + stream << v; + return stream.str(); + }); + + py::class_(tensorInfo, "DataType") + .def("__str__", [](const TensorInfo::DataType& v) { + return TensorInfo::type_to_string.at(v); + }) + .def("__repr__", [](const TensorInfo::DataType& v) { + return TensorInfo::type_to_string.at(v); + }) + ; + + py::enum_(tensorInfo, "Dimension") + .value("W", TensorInfo::Dimension::W) + .value("H", TensorInfo::Dimension::H) + .value("C ", TensorInfo::Dimension::C) + .value("N", TensorInfo::Dimension::N) + .value("B", TensorInfo::Dimension::B) + .value("WIDTH", TensorInfo::Dimension::WIDTH) + .value("HEIGHT", TensorInfo::Dimension::HEIGHT) + .value("CHANNEL", TensorInfo::Dimension::CHANNEL) + .value("NUMBER", TensorInfo::Dimension::NUMBER) + .value("BATCH", TensorInfo::Dimension::BATCH) + ; + + py::class_>(m, "Detections") + .def_readonly("size", &Detections::detection_count) + .def("__len__", [](const Detections &det) { return det.detection_count; }) + .def("__getitem__", [](const Detections &det, int idx) { return det.detections[idx]; }) + .def("__iter__", [](std::shared_ptr &v) + { + const Detection *detection_vec = v->detections; + return py::make_iterator(&detection_vec[0], &detection_vec[v->detection_count]); + }, py::keep_alive<0, 1>()) /* Keep list alive while iterator is used */ + ; + + py::class_(m, "Detection") + .def_readonly("label", &Detection::label) + .def_readonly("confidence", &Detection::confidence) + .def_readonly("x_min", &Detection::x_min) + .def_readonly("y_min", &Detection::y_min) + .def_readonly("x_max", &Detection::x_max) + .def_readonly("y_max", &Detection::y_max) + .def_readonly("depth_x", &Detection::depth_x) + .def_readonly("depth_y", &Detection::depth_y) + .def_readonly("depth_z", &Detection::depth_z) + .def("get_dict", [](Detection &self) { + py::dict d; + d["label"] = self.label; + d["confidence"] = self.confidence; + d["x_min"] = self.x_min; + d["y_min"] = self.y_min; + d["x_max"] = self.x_max; + d["y_max"] = self.y_max; + d["depth_x"] = self.depth_x; + d["depth_y"] = self.depth_y; + d["depth_z"] = self.depth_z; + return d; + }) ; } -pybind11::array* PyNNetPacket::getTensor(unsigned index) + + + +namespace pybind11 { namespace detail { +template <> + struct npy_format_descriptor { + static std::string format() { + // https://docs.python.org/3/library/struct.html#format-characters + return "e"; + } + }; +}} // namespace pybind11::detail + +static const std::map type_to_numpy_format = { + {TensorInfo::DataType::_fp16, pybind11::format_descriptor::format()}, + {TensorInfo::DataType::_u8f, pybind11::format_descriptor::format()}, + {TensorInfo::DataType::_int, pybind11::format_descriptor::format()}, + {TensorInfo::DataType::_fp32, pybind11::format_descriptor::format()}, + {TensorInfo::DataType::_i8, pybind11::format_descriptor::format()}, +}; + +static std::string type_to_npy_format_descriptor(const TensorInfo::DataType& type) { - auto ptr = std::static_pointer_cast(_tensors_raw_data[index]); - return ptr->getPythonNumpyArray(); + auto it = type_to_numpy_format.find(type); + assert(it != type_to_numpy_format.end()); + return it->second; +}; + + + + +// TODO - zero copy +//https://github.com/pybind/pybind11/issues/323#issuecomment-575717041 +//https://github.com/pybind/pybind11/issues/1042#issuecomment-642215028 +static py::array* _getTensorPythonNumpyArray(unsigned char *data, TensorInfo ti) +{ + assert(!ti.dimensions.empty()); + py::array* result = nullptr; + + ssize_t ndim = ti.dimensions.size(); + ssize_t element_size = TensorInfo::c_type_size.at(ti.data_type); + std::string numpy_format_descriptor = type_to_npy_format_descriptor(ti.data_type); + std::vector shape; + std::vector strides; + shape.reserve(ndim); + strides.reserve(ndim); + + for (int i = 0; i < ndim; ++i) + { + shape.push_back(ti.dimensions[i]); + strides.push_back(ti.strides[i]); + } + + try { + + result = new py::array(py::buffer_info( + static_cast(&data[ti.offset]), /* data as contiguous array */ + element_size, /* size of one scalar */ + numpy_format_descriptor, /* data type */ + ndim, //ndim, /* number of dimensions */ + shape, //shape, /* shape of the matrix */ + strides //strides /* strides for each axis */ + )); + } catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + result = nullptr; + } + + return result; +} + +py::array* PyNNetPacket::getTensor(unsigned index) +{ + if(_NN_config[index].contains("output_format")) + { + if(_NN_config[index]["output_format"] != std::string("raw")) + { + throw std::runtime_error("getTensor should be used only when [\"NN_config\"][\"output_format\"] is set to raw! https://docs.luxonis.com/api/#creating-blob-configuration-file"); + } + } + assert(index < _tensors_info.size()); + TensorInfo ti = _tensors_info[index]; + unsigned char * data = _tensors_raw_data->data->data(); + return _getTensorPythonNumpyArray(data, ti); } -pybind11::array* PyNNetPacket::getTensorByName(const std::string &name) +py::array* PyNNetPacket::getTensorByName(const std::string &name) { auto it = _tensor_name_to_index.find(name); if (it == _tensor_name_to_index.end()) @@ -57,3 +239,28 @@ pybind11::array* PyNNetPacket::getTensorByName(const std::string &name) return getTensor(it->second); } } + + +std::list PyNNetPacket::getOutputsList() { + + std::list outputList; + for (size_t i = 0; i < _tensors_info.size(); ++i) + { + outputList.push_back(getTensor(i)); + } + return outputList; +} + + +std::map PyNNetPacket::getOutputsDict() { + std::map outputs; + for (size_t i = 0; i < _tensors_info.size(); ++i) + { + std::string name = getTensorName(i); + // outputs[name.c_str()] = getTensor(i); + outputs.insert({name,getTensor(i)}); + } + + return outputs; +} + diff --git a/src/nnet_packet_bindings.hpp b/src/nnet_packet_bindings.hpp index 22357837d..9e4a581d9 100644 --- a/src/nnet_packet_bindings.hpp +++ b/src/nnet_packet_bindings.hpp @@ -8,13 +8,18 @@ void init_binding_nnet_packet(pybind11::module& m); +namespace py = pybind11; + struct PyNNetPacket : public NNetPacket { - pybind11::array* getTensor(unsigned index); + py::array* getTensor(unsigned index); pybind11::array* getTensorByName(const std::string &name); + std::list getOutputsList(); + std::map getOutputsDict(); + public: using NNetPacket::_tensors_raw_data; using NNetPacket::_tensor_name_to_index; - + using NNetPacket::_NN_config; }; \ No newline at end of file diff --git a/src/py_bindings.cpp b/src/py_bindings.cpp index f30b44f6c..1d1597f83 100644 --- a/src/py_bindings.cpp +++ b/src/py_bindings.cpp @@ -18,7 +18,6 @@ // project #include "host_data_packet_bindings.hpp" #include "nnet_packet_bindings.hpp" -#include "py_tensor_entry_container_iterator.hpp" #include "device_bindings.hpp" @@ -46,49 +45,6 @@ PYBIND11_MODULE(depthai,m) //std::string _dev_version = c_depthai_dev_version; //m.attr("__dev_version__") = "badf00d"; - - // for te in nnet_packet.ENTRIES() - py::class_>(m, "TensorEntryContainer") - .def("__len__", &TensorEntryContainer::size) - .def("__getitem__", &TensorEntryContainer::getByIndex) - .def("__getitem__", &TensorEntryContainer::getByName) - .def("__iter__", [](py::object s) { return PyTensorEntryContainerIterator(s.cast(), s); }) - ; - - // for e in nnet_packet.entries(): - // e <--- (type(e) == list) - py::class_(m, "PyTensorEntryContainerIterator") - .def("__iter__", [](PyTensorEntryContainerIterator &it) -> PyTensorEntryContainerIterator& { return it; }) - .def("__next__", &PyTensorEntryContainerIterator::next) - ; - - // for e in nnet_packet.entries(): - // e[0] <-- - py::class_>(m, "TensorEntry") - .def("__len__", &TensorEntry::getPropertiesNumber) - .def("__getitem__", &TensorEntry::getFloat) - .def("__getitem__", &TensorEntry::getFloatByIndex) - ; - - - // while True: - // nnet_packets, data_packets = p.get_available_nnet_and_data_packets() - // # nnet_packets: depthai.NNetPacketList - // # data_packets: depthai.DataPacketList - - // for t in nnet_packets.getTensors(): - // pass - - // for nnet_packet in nnet_packets: - // # nnet_packet: depthai.NNetPacket - // # nnet_packet.entries(): depthai.TensorEntryContainer - - // for e in nnet_packet.entries(): - // # e: list - // # e[0]: depthai.TensorEntry - // # e[0][0]: float - - py::class_(m, "Pipeline") .def("get_available_data_packets", &HostPipeline::getAvailableDataPackets, py::arg("blocking") = false, py::return_value_policy::copy) ; diff --git a/src/py_tensor_entry_container_iterator.cpp b/src/py_tensor_entry_container_iterator.cpp deleted file mode 100644 index 8812259ab..000000000 --- a/src/py_tensor_entry_container_iterator.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "py_tensor_entry_container_iterator.hpp" - -std::vector PyTensorEntryContainerIterator::next() -{ - while(true) - { - if (index == seq.size()) - { - throw pybind11::stop_iteration(); - } - std::vector next_entry = seq.getByIndex(index++); - if(next_entry.empty()) - { - continue; - } - - return next_entry; - } -} diff --git a/src/py_tensor_entry_container_iterator.hpp b/src/py_tensor_entry_container_iterator.hpp deleted file mode 100644 index a85fbe189..000000000 --- a/src/py_tensor_entry_container_iterator.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -// std -#include - -// pybind11 -#include "pybind11_common.hpp" - -//project -#include "depthai/nnet/tensor_entry_container.hpp" - -struct PyTensorEntryContainerIterator -{ - PyTensorEntryContainerIterator( - TensorEntryContainer &seq, - pybind11::object ref - ) - : seq(seq) - , ref(ref) - {} - - std::vector next(); - - TensorEntryContainer &seq; - pybind11::object ref; - size_t index = 0; -}; \ No newline at end of file