Skip to content

Commit 9d644aa

Browse files
committed
WIP
1 parent 67635fd commit 9d644aa

File tree

6 files changed

+282
-78
lines changed

6 files changed

+282
-78
lines changed

Cargo.lock

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ crate-type = ["cdylib"]
1212

1313
[dependencies]
1414
pyo3 = { version = "0.24.2", features = ["extension-module"] }
15+
bitvec = { version = "1.0.1" }

README.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
## pylibjpeg-rle
1010

11-
A fast DICOM ([PackBits](https://en.wikipedia.org/wiki/PackBits)) RLE plugin for [pylibjpeg](https://github.com/pydicom/pylibjpeg), written in Rust with a Python 3.7+ wrapper.
11+
A fast DICOM ([PackBits](https://en.wikipedia.org/wiki/PackBits)) RLE plugin for [pylibjpeg](https://github.com/pydicom/pylibjpeg), written in Rust with a Python wrapper.
1212

1313
Linux, MacOS and Windows are all supported.
1414

@@ -85,32 +85,32 @@ ds.save_as('as_rle.dcm')
8585
### Benchmarks
8686
#### Decoding
8787

88-
Time per 1000 decodes, pydicom's default RLE handler vs. pylibjpeg-rle
88+
Time per 1000 decodes, pydicom's default RLE decoder vs. pylibjpeg-rle:
8989

9090
| Dataset | Pixels | Bytes | pydicom | pylibjpeg-rle |
9191
| --- | --- | --- | --- | --- |
92-
| OBXXXX1A_rle.dcm | 480,000 | 480,000 | 4.89 s | 0.79 s |
93-
| OBXXXX1A_rle_2frame.dcm | 960,000 | 960,000 | 9.89 s | 1.65 s |
94-
| SC_rgb_rle.dcm | 10,000 | 30,000 | 0.20 s | 0.15 s |
95-
| SC_rgb_rle_2frame.dcm | 20,000 | 60,000 | 0.32 s | 0.18 s |
96-
| MR_small_RLE.dcm | 4,096 | 8,192 | 0.35 s | 0.13 s |
97-
| emri_small_RLE.dcm | 40,960 | 81,920 | 1.13 s | 0.28 s |
98-
| SC_rgb_rle_16bit.dcm | 10,000 | 60,000 | 0.33 s | 0.17 s |
99-
| SC_rgb_rle_16bit_2frame.dcm | 20,000 | 120,000 | 0.56 s | 0.21 s |
100-
| rtdose_rle_1frame.dcm | 100 | 400 | 0.12 s | 0.13 s |
101-
| rtdose_rle.dcm | 1,500 | 6,000 | 0.53 s | 0.26 s |
102-
| SC_rgb_rle_32bit.dcm | 10,000 | 120,000 | 0.56 s | 0.19 s |
103-
| SC_rgb_rle_32bit_2frame.dcm | 20,000 | 240,000 | 1.03 s | 0.28 s |
92+
| OBXXXX1A_rle.dcm | 480,000 | 480,000 | 5.7 s | 1.1 s |
93+
| OBXXXX1A_rle_2frame.dcm | 960,000 | 960,000 | 11.5 s | 2.1 s |
94+
| SC_rgb_rle.dcm | 10,000 | 30,000 | 0.28 s | 0.19 s |
95+
| SC_rgb_rle_2frame.dcm | 20,000 | 60,000 | 0.45 s | 0.28 s |
96+
| MR_small_RLE.dcm | 4,096 | 8,192 | 0.46 s | 0.15 s |
97+
| emri_small_RLE.dcm | 40,960 | 81,920 | 1.8 s | 0.67 s |
98+
| SC_rgb_rle_16bit.dcm | 10,000 | 60,000 | 0.48 s | 0.25 s |
99+
| SC_rgb_rle_16bit_2frame.dcm | 20,000 | 120,000 | 0.86 s | 0.39 s |
100+
| rtdose_rle_1frame.dcm | 100 | 400 | 0.16 s | 0.13 s |
101+
| rtdose_rle.dcm | 1,500 | 6,000 | 1.0 s | 0.64 s |
102+
| SC_rgb_rle_32bit.dcm | 10,000 | 120,000 | 0.82 s | 0.35 s |
103+
| SC_rgb_rle_32bit_2frame.dcm | 20,000 | 240,000 | 1.5 s | 0.60 s |
104104

105105
#### Encoding
106106

107-
Time per 1000 encodes, pydicom's default RLE handler vs. pylibjpeg-rle
107+
Time per 1000 encodes, pydicom's default RLE encoder vs. pylibjpeg-rle and [python-gdcm](https://github.com/tfmoraes/python-gdcm):
108108

109-
| Dataset | Pixels | Bytes | pydicom | pylibjpeg-rle |
110-
| --- | --- | --- | --- | --- |
111-
| OBXXXX1A.dcm | 480,000 | 480,000 | 30.7 s | 1.36 s |
112-
| SC_rgb.dcm | 10,000 | 30,000 | 1.80 s | 0.09 s |
113-
| MR_small.dcm | 4,096 | 8,192 | 2.29 s | 0.04 s |
114-
| SC_rgb_16bit.dcm | 10,000 | 60,000 | 3.57 s | 0.17 s |
115-
| rtdose_1frame.dcm | 100 | 400 | 0.19 s | 0.003 s |
116-
| SC_rgb_32bit.dcm | 10,000 | 120,000 | 7.20 s | 0.33 s |
109+
| Dataset | Pixels | Bytes | pydicom | pylibjpeg-rle | python-gdcm |
110+
| --- | --- | --- | --- | --- | --- |
111+
| OBXXXX1A.dcm | 480,000 | 480,000 | 30.6 s | 1.4 s | 1.5 s |
112+
| SC_rgb.dcm | 10,000 | 30,000 | 1.9 s | 0.11 s | 0.21 s |
113+
| MR_small.dcm | 4,096 | 8,192 | 3.0 s | 0.11 s | 0.29 s |
114+
| SC_rgb_16bit.dcm | 10,000 | 60,000 | 3.6 s | 0.18 s | 0.28 s |
115+
| rtdose_1frame.dcm | 100 | 400 | 0.28 s | 0.04 s | 0.14 s |
116+
| SC_rgb_32bit.dcm | 10,000 | 120,000 | 7.1 s | 0.32 s | 0.43 s |

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ keywords = ["dicom pydicom python rle pylibjpeg rust"]
3232
license = "MIT"
3333
name = "pylibjpeg-rle"
3434
readme = "README.md"
35-
version = "2.1.0"
35+
version = "2.2.0.dev0"
3636
requires-python = ">=3.10"
3737
dependencies = [
3838
"numpy>=2.0",

rle/utils.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ def encode_array(
106106
107107
.. versionadded:: 1.1
108108
109+
.. versionchanged:: 2.2
110+
111+
Added support for 'bits_allocated' 1.
112+
109113
Parameters
110114
----------
111115
arr : numpy.ndarray
@@ -124,7 +128,7 @@ def encode_array(
124128
* ``samples_per_px': int`` the number of samples per pixel, either
125129
1 for monochrome or 3 for RGB or similar data.
126130
* ``'bits_per_px': int`` the number of bits needed to contain each
127-
pixel, either 8, 16, 32 or 64.
131+
pixel, either 1, 8, 16, 32 or 64.
128132
* ``'nr_frames': int`` the number of frames in `arr`, required if
129133
more than one frame is present.
130134
@@ -169,6 +173,10 @@ def encode_pixel_data(
169173
to 15 in order to meet the requirements of the *RLE Lossless*
170174
transfer syntax.
171175
176+
.. versionchanged:: 2.2
177+
178+
Added support for 'bits_allocated' 1.
179+
172180
Parameters
173181
----------
174182
src : bytes
@@ -189,7 +197,7 @@ def encode_pixel_data(
189197
* ``samples_per_pixel': int`` the number of samples per pixel, either
190198
1 for monochrome or 3 for RGB or similar data.
191199
* ``'bits_allocated': int`` the number of bits needed to contain each
192-
pixel, either 8, 16, 32 or 64.
200+
pixel, either 1, 8, 16, 32 or 64.
193201
194202
Returns
195203
-------
@@ -212,9 +220,9 @@ def encode_pixel_data(
212220
msg = "(0028,0002) 'Samples per Pixel'" if ds else "'samples_per_pixel'"
213221
raise ValueError(f"{msg} must be 1 or 3")
214222

215-
if bpp not in [8, 16, 32, 64]:
223+
if bpp not in [1, 8, 16, 32, 64]:
216224
msg = "(0028,0100) 'Bits Allocated'" if ds else "'bits_allocated'"
217-
raise ValueError(f"{msg} must be 8, 16, 32 or 64")
225+
raise ValueError(f"{msg} must be 1, 8, 16, 32 or 64")
218226

219227
if bpp / 8 * spp > 15:
220228
raise ValueError(
@@ -235,6 +243,7 @@ def encode_pixel_data(
235243
return cast(bytes, encode_frame(src, r, c, spp, bpp, byteorder))
236244

237245

246+
# TODO: unpack Bits Stored 1
238247
def generate_frames(ds: "Dataset", reshape: bool = True) -> Iterator[np.ndarray]:
239248
"""Yield a *Pixel Data* frame from `ds` as an :class:`~numpy.ndarray`.
240249
@@ -310,6 +319,7 @@ def generate_frames(ds: "Dataset", reshape: bool = True) -> Iterator[np.ndarray]
310319
yield arr.transpose(1, 2, 0)
311320

312321

322+
# TODO: unpack Bits Stored 1
313323
def pixel_array(ds: "Dataset") -> "np.ndarray":
314324
"""Return the entire *Pixel Data* as an :class:`~numpy.ndarray`.
315325

0 commit comments

Comments
 (0)