From 2b68a1b0c0e2d5711e2b4b7ae364f73abfcda7f9 Mon Sep 17 00:00:00 2001 From: edgar Date: Sat, 7 Jan 2023 17:49:28 +0400 Subject: [PATCH 1/2] update readme before release 0.0.6 --- .github/workflows/release.yml | 2 ++ README.md | 58 ++++++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d6655ec..a094f78c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,8 @@ name: Release on: + release: + types: [published] workflow_dispatch: env: diff --git a/README.md b/README.md index d5e542a4..df14ab1a 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,75 @@ # kornia-rs: Low level implementations for Computer Vision in Rust. -## (🚨 Warning: Unstable Prototype 🚨) - [![Continuous integration](https://github.com/kornia/kornia-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/kornia/kornia-rs/actions/workflows/ci.yml) [![PyPI version](https://badge.fury.io/py/kornia-rs.svg)](https://badge.fury.io/py/kornia-rs) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENCE) [![Slack](https://img.shields.io/badge/Slack-4A154B?logo=slack&logoColor=white)](https://join.slack.com/t/kornia/shared_invite/zt-csobk21g-CnydWe5fmvkcktIeRFGCEQ) -The expectation of this project is to provide low level functionality -for Computer Vision written in [Rust](https://www.rust-lang.org/) to be consumed by deep learning frameworks, specially those working with images. We mainly provide I/O for images (future: video, cameras) and visualisation. +This project provides low level functionality for Computer Vision written in [Rust](https://www.rust-lang.org/) to be consumed by machine learning and data-science frameworks, specially those working with images. We mainly aim to provide I/O functionality for images (future: video, cameras), and visualisation in future. -The library is written in [Rust](https://www.rust-lang.org/) and wrapped to Python (potentially later to C/C++) using [PyO3/Maturin](https://github.com/PyO3/maturin). The library can also be used as a standalone Rust crate. +- The library is written in [Rust](https://www.rust-lang.org/). +- Python bindings are created with [PyO3/Maturin](https://github.com/PyO3/maturin). +- We package with support for Linux [amd64/arm64], Macos and WIndows. +- Supported Python versions are 3.7/3.8/3.9/3.10/3.11 ## Basic Usage -Load an image, that is converted to `cv::Tensor` wich is designed centric -to the DLPack protocol to share tensor data across deep learning frameworks with a zero-copy cost. - -The visualisation API is based on `vviz`: https://github.com/strasdat/vviz +Load an image, that is converted to `cv::Tensor` wich is a centric structure to the DLPack protocol to share tensor data across frameworks with a zero-copy cost. ```python import kornia_rs as K from kornia_rs import Tensor as cvTensor + # load an image with Rust `image-rs` as backend library cv_tensor: cvTensor = K.read_image_rs("dog.jpeg") assert cv_tensor.shape == [195, 258, 3] - # convert to dlpack to import to torch and numpy - # NOTE: later we will support to jax and mxnet. + # convert to dlpack to import to torch th_tensor = torch.utils.dlpack.from_dlpack(cv_tensor) - np_tensor = np.from_dlpack(cv_tensor) assert th_tensor.shape == (195, 258, 3) assert np_tensor.shape == (195, 258, 3) + + # or to numpy with same interface + np_tensor = np.from_dlpack(cv_tensor) +``` + +## Advanced usage + +Encode or decoda image streams using the `turbojpeg` backend + +```python +# load image using turbojpeg +cv_tensor = K.read_image_jpeg("dog.jpeg") +image: np.ndarray = np.from_dlpack(cv_tensor) # HxWx3 + +# encode the image with jpeg +image_encoder = K.ImageEncoder() +image_encoder.set_quality(95) # set the encoding quality + +# get the encoded stream +image_encoded: List[int] = image_encoder.encode(image.tobytes(), image.shape) + +# write to disk the encoded stream +K.write_image_jpeg("dog_encoded.jpeg", image_encoded) + +# decode back the image +image_decoder = K.ImageDecoder() + +decoded_tensor = image_decoder.decode(bytes(image_encoded)) +decoded_image: np.ndarray = np.from_dlpack(decoded_tensor) # HxWx3 ``` -## TODO +## TODO: short/mid-terrm - [x] [infra] Automate packaging for manywheels. - [x] [kornia] integrate with the new `Image` API - [x] [dlpack] move dlpack implementation to dlpack-rs. -- [ ] [dlpack] implement test for numpy, jax and mxnet. +- [x] [dlpack] implement test for torch and numpy. +- [ ] [dlpack] update dlpack version >=0.8 - [ ] [dlpack] implement `DLPack` to `cv::Tensor`. + +## TODO: not priority for now + - [ ] [io] Implement image encoding and explore video. - [ ] [viz] Fix minor issues and implement a full `VizManager` to work on the browser. - [ ] [tensor] implement basic functionality to test: add, sub, mul, etc. @@ -91,7 +120,6 @@ maturin develop --extras dev pytest test/ ``` - ## Contributing This is a child project of [Kornia](https://github.com/kornia/kornia). Join the community to get in touch with us, or just sponsor the project: https://opencollective.com/kornia From fec19ff171599cca9bac2981babe9aa82b14c48c Mon Sep 17 00:00:00 2001 From: edgarriba Date: Sat, 7 Jan 2023 20:13:01 +0000 Subject: [PATCH 2/2] fix memory issue --- pyproject.toml | 1 + src/dlpack_py.rs | 5 ++--- src/tensor.rs | 7 +++---- test/test_io.py | 22 ++++++++++++++++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 56bdfcaf..5a9cd607 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ classifiers = [ [project.optional-dependencies] dev = [ "pytest", + "pytest-asyncio", "kornia==0.6.3", "numpy==1.23.0", "jax[cpu]", diff --git a/src/dlpack_py.rs b/src/dlpack_py.rs index 6f451e2e..d62044f6 100644 --- a/src/dlpack_py.rs +++ b/src/dlpack_py.rs @@ -92,14 +92,13 @@ pub fn cvtensor_to_dlpack(x: &cv::Tensor, py: Python) -> PyResult { let dlm_tensor_bx = Box::new(dlm_tensor); // create python capsule - let capsule: PyObject = unsafe { + let capsule = unsafe { let ptr = pyo3::ffi::PyCapsule_New( - &*dlm_tensor_bx as *const dlpack::DLManagedTensor as *mut c_void, + Box::into_raw(dlm_tensor_bx) as *mut c_void, DLPACK_CAPSULE_NAME.as_ptr() as *const c_char, Some(dlpack_capsule_destructor as pyo3::ffi::PyCapsule_Destructor), ); PyObject::from_owned_ptr(py, ptr) }; - Box::leak(dlm_tensor_bx); // to hold reference until program exits Ok(capsule) } diff --git a/src/tensor.rs b/src/tensor.rs index c7dec03b..079f6241 100644 --- a/src/tensor.rs +++ b/src/tensor.rs @@ -40,14 +40,13 @@ pub mod cv { } #[pyo3(name = "__dlpack__")] - pub fn to_dlpack_py(&self, py: Python) -> PyResult { + pub fn dlpack_py(&self, py: Python) -> PyResult { cvtensor_to_dlpack(self, py) } #[pyo3(name = "__dlpack_device__")] - pub fn to_dlpack_device_py(&self) -> (i32, i32) { - let tensor_bx = Box::new(self); - let dl_tensor = cvtensor_to_dltensor(&tensor_bx); + pub fn dlpack_device_py(&self) -> (i32, i32) { + let dl_tensor = cvtensor_to_dltensor(self); ( dl_tensor.device.device_type as i32, dl_tensor.device.device_id, diff --git a/test/test_io.py b/test/test_io.py index c6d5aa20..83ba2d38 100644 --- a/test/test_io.py +++ b/test/test_io.py @@ -1,4 +1,7 @@ from pathlib import Path +import pytest +import random +import asyncio import kornia_rs as K from kornia_rs import Tensor as cvTensor @@ -84,3 +87,22 @@ def test_write_read_jpeg(): read_image = np.from_dlpack(read_tensor) np.testing.assert_allclose(decoded_image, read_image) + +async def encode_frame(i: int) -> bytes: + img = (np.random.rand(480, 640, 3) * 255).astype(np.uint8) + frame = K.ImageEncoder().encode(img.tobytes(), img.shape) + await asyncio.sleep(random.random()) + img_decoded = K.ImageDecoder().decode(bytes(frame)) + await asyncio.sleep(random.random()) + img = np.from_dlpack(img_decoded) + await asyncio.sleep(random.random()) + print(f"End: {i}") + return img.mean() + + +@pytest.mark.asyncio +async def test_receive_stream_task(): + tasks = [asyncio.create_task(encode_frame(i)) for i in range(3)] + results = await asyncio.gather(*tasks) + mean = sum(results) / len(results) + print(mean)