Skip to content

perf(python): efficient data convesion between numpy to raw - #40

Open
ktro2828 wants to merge 4 commits into
mainfrom
perf/python/image-data-conversion
Open

perf(python): efficient data convesion between numpy to raw#40
ktro2828 wants to merge 4 commits into
mainfrom
perf/python/image-data-conversion

Conversation

@ktro2828

@ktro2828 ktro2828 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

PR Type

  • Improvement

Related Links

Description

Image now implements Python's read-only buffer protocol and provides Image.to_numpy().
to_numpy() returns a zero-copy NumPy view by default, while copy=True produces independent
mutable storage. Image.from_numpy() now passes a contiguous NumPy buffer directly to C++, where
one bulk memcpy replaces millions of Python-integer conversions. The existing Image.data
list getter and iterable setter remain available for compatibility.

Because a zero-copy view references the C++ vector, callers must not reassign Image.data while a
view is alive. The view retains the Image object itself, so deleting the original Python variable
does not invalidate the view.

Benchmark

Image now implements Python's read-only buffer protocol and provides Image.to_numpy().
to_numpy() returns a zero-copy NumPy view by default, while copy=True produces independent
mutable storage. Image.from_numpy() now passes a contiguous NumPy buffer directly to C++, where
one bulk memcpy replaces millions of Python-integer conversions. The existing Image.data
list getter and iterable setter remain available for compatibility.

Because a zero-copy view references the C++ vector, callers must not reassign Image.data while a
view is alive. The view retains the Image object itself, so deleting the original Python variable
does not invalidate the view.

Direction Before After Speedup
NumPy input into Image 184.090 ms/frame (list -> vector) 0.168 ms/frame (buffer -> vector) 1,096.35×
Decoded Image into NumPy 51.053 ms/frame (vector -> list) 0.002 ms/frame (zero-copy view) 24,396.76×

Review Procedure

Remarks

Pre-Review Checklist for the PR Author

PR Author should check the checkboxes below when creating the PR.

  • Assign PR to reviewer

Checklist for the PR Reviewer

Reviewers should check the checkboxes below before approval.

  • Commits are properly organized and messages are according to the guideline
  • (Optional) Unit tests have been written for new behavior
  • PR title describes the changes

Post-Review Checklist for the PR Author

PR Author should check the checkboxes below before merging.

  • All open points are addressed and tracked via issues or tickets

CI Checks

  • Build and test for PR: Required to pass before the merge.

Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp>
Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp>
Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp>
@ktro2828
ktro2828 marked this pull request as ready for review September 3, 2026 06:43
@ktro2828
ktro2828 requested a review from manato September 3, 2026 06:43
@ktro2828

ktro2828 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

cc @zusizusi

@manato manato left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ktro2828
Thank you very much for improving the performance of python binding! The speed up is quite impressive!
I left a few comments to the places where I noticed. Though they may miss the point, your consideration is appreciated!

image.format = ImageFormat.RAW

data_u8 = data.astype(np.uint8)
data_u8 = np.ascontiguousarray(data, dtype=np.uint8)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data_u8 = np.ascontiguousarray(data, dtype=np.uint8)
data_u8 = np.array(data, dtype=np.uint8, copy=True, order='C')

According to my search, np.ascontiguousarray behaves differently according if the input data is already contiguous or not:

  • if the data is already contiguous: returns data as it is
  • if the data is NOT contiguous: returns contiguous copy

If we would prefer to secure that from_numpy method returns a new instance (i.e., independent memory region from input), like which is tested test_common.py::test_image_buffer_input_is_independent_and_numpy_output_can_copy(), using always making copy might be better.
Checikg if this aligns your intention is appreciated 🙏

np.testing.assert_array_equal(array, np.arange(7, dtype=np.uint8))


def test_image_to_numpy():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ask] For me, this function tests nothing (just filling the object members). Is it intended?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants