Skip to content

Commit b30eb79

Browse files
committed
handle 16 and 32 bps output
1 parent b240694 commit b30eb79

File tree

8 files changed

+124
-12
lines changed

8 files changed

+124
-12
lines changed

CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ Added
88
~~~~~
99

1010
- camera mode for baking 360 degree panoramic views
11+
- support 16 bit per channel and hdr (32 bit fp per channel) output to image files and ndarray
12+
13+
Fixed
14+
~~~~~
15+
16+
- correct light emission in volumes
17+
- fix restoring scene global variables from json
1118

1219
`v0.8.0`_ - 2020-06-04
1320
----------------------

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ Features
5757
- post-processing: tonal correction curves, levels adjustment, apply mask/overlay, AI denoiser
5858
- GPU acceleration using RT Cores and everything else what comes with `OptiX 7 <https://developer.nvidia.com/optix>`__
5959
- callbacks at the scene initialization, start and end of each frame raytracing, end of progressive accumulation
60-
- image output to `numpy <http://www.numpy.org>`__ array, or save to popular image file formats
60+
- 8/16/32bps image output to `numpy <http://www.numpy.org>`__ array, or save to popular image file formats
6161
- hardware accelerated video output to MP4 file format using `NVENC 9.0 <https://developer.nvidia.com/nvidia-video-codec-sdk>`__
62-
- configurable multi-GPU support
6362
- Tkinter based simple GUI window or headless raytracer
63+
- configurable multi-GPU support
6464

6565
System Requirements
6666
-------------------

docs/enums.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ Other
6666
:members:
6767
.. autoclass:: plotoptix.enums.ChannelOrder
6868
:members:
69+
.. autoclass:: plotoptix.enums.ChannelDepth
70+
:members:
6971

7072
.. toctree::
7173
:caption: API Reference

plotoptix/_load_lib.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ def _load_optix_win():
6060
optix.save_image_to_file.argtypes = [c_wchar_p]
6161
optix.save_image_to_file.restype = c_bool
6262

63+
optix.save_image_to_file_16bps.argtypes = [c_wchar_p]
64+
optix.save_image_to_file_16bps.restype = c_bool
65+
66+
optix.save_image_to_file_32bps.argtypes = [c_wchar_p]
67+
optix.save_image_to_file_32bps.restype = c_bool
68+
69+
optix.get_output.argtypes = [c_void_p, c_int, c_int]
70+
optix.get_output.restype = c_bool
71+
6372
optix.get_fps.restype = c_float
6473

6574
optix.start_rt.restype = c_bool
@@ -552,6 +561,14 @@ def save_scene_to_file(self, fname): return self._optix.save_scene_to_file(fname
552561

553562
def save_image_to_file(self, fname): return self._optix.save_image_to_file(fname)
554563

564+
def save_image_to_file_16bps(self, fname): return self._optix.save_image_to_file_16bps(fname)
565+
566+
def save_image_to_file_32bps(self, fname): return self._optix.save_image_to_file_32bps(fname)
567+
568+
def get_output(self, buf_ptr, buf_size, depth):
569+
return self._optix.get_output_ptr(IntPtr.__overloads__[Int64](buf_ptr), buf_size, depth)
570+
571+
555572
def get_fps(self): return self._optix.get_fps()
556573

557574
def start_rt(self): return self._optix.start_rt()

plotoptix/bin/RnD.SharpOptiX.dll

3.5 KB
Binary file not shown.

plotoptix/bin/rndSharpOptiX7.dll

3 KB
Binary file not shown.

plotoptix/enums.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,22 @@ class ChannelOrder(Enum):
357357
"""
358358
"""
359359

360+
class ChannelDepth(Enum):
361+
"""Color channel depth: 8, 16 or 32 bits per sample.
362+
"""
363+
364+
Bps8 = 1
365+
"""
366+
"""
367+
368+
Bps16 = 2
369+
"""
370+
"""
371+
372+
Bps32 = 3
373+
"""
374+
"""
375+
360376
class Postprocessing(Enum):
361377
"""2D postprocessing stages.
362378

plotoptix/npoptix.py

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -329,21 +329,68 @@ def close(self) -> None:
329329
def is_started(self) -> bool: return self._is_started
330330
def is_closed(self) -> bool: return self._is_closed
331331

332-
def get_rt_output(self) -> np.ndarray:
332+
def get_rt_output(self, bps: Union[ChannelDepth, str] = ChannelDepth.Bps8) -> np.ndarray:
333333
"""Return a copy of the output image.
334+
335+
The image data type is specified with the ``bps`` argument. 8 bit per channel data,
336+
``numpy.uint8``, is returned by default. Use ``Bps16`` value to read the image in
337+
16 bit per channel depth, ``numpy.uint16``. Use ``Bps32`` value to read the HDR image
338+
in 32 bit per channel format, ``numpy.float32``.
339+
340+
Channels ordering is RGBA, with constant values in the alpha channel (100% opaque,
341+
to be used in the future releases).
334342
335343
Safe to call at any time, from any thread.
336344
345+
Parameters
346+
----------
347+
bps : ChannelDepth enum or string, optional
348+
Color depth.
349+
337350
Returns
338351
-------
339352
out : ndarray
340-
RGBA array of shape (height, width, 4) and type ``numpy.uint8``.
353+
RGBA array of shape (height, width, 4) and type corresponding to ``bps`` argument.
354+
355+
See Also
356+
--------
357+
:class:`plotoptix.enums.ChannelDepth`
341358
"""
342359
assert self._is_started, "Raytracing output not running."
343-
with self._padlock:
344-
a = self._img_rgba.copy()
360+
361+
if isinstance(bps, str): bps = ChannelDepth[bps]
362+
363+
a = None
364+
365+
try:
366+
self._padlock.acquire()
367+
368+
ok = True
369+
370+
if bps == ChannelDepth.Bps8:
371+
a = self._img_rgba.copy()
372+
elif bps == ChannelDepth.Bps16:
373+
a = np.ascontiguousarray(np.zeros((self._height, self._width, 4), dtype=np.uint16))
374+
ok = self._optix.get_output(a.ctypes.data, a.nbytes, bps.value)
375+
elif bps == ChannelDepth.Bps32:
376+
a = np.ascontiguousarray(np.zeros((self._height, self._width, 4), dtype=np.float32))
377+
ok = self._optix.get_output(a.ctypes.data, a.nbytes, bps.value)
378+
379+
if not ok:
380+
msg = "Image not saveed."
381+
self._logger.error(msg)
382+
if self._raise_on_error: raise ValueError(msg)
383+
384+
except Exception as e:
385+
self._logger.error(str(e))
386+
if self._raise_on_error: raise
387+
388+
finally:
389+
self._padlock.release()
390+
345391
return a
346392

393+
347394
def resize(self, width: Optional[int] = None, height: Optional[int] = None) -> None:
348395
"""Change dimensions of the raytracing output.
349396
@@ -1642,7 +1689,7 @@ def save_scene(self, file_name: str) -> None:
16421689
self._padlock.acquire()
16431690

16441691
if not self._optix.save_scene_to_file(file_name):
1645-
msg = "Scene not saveed."
1692+
msg = "Scene not saved."
16461693
self._logger.error(msg)
16471694
if self._raise_on_error: raise ValueError(msg)
16481695

@@ -1654,22 +1701,45 @@ def save_scene(self, file_name: str) -> None:
16541701
self._padlock.release()
16551702

16561703

1657-
def save_image(self, file_name: str) -> None:
1704+
def save_image(self, file_name: str,
1705+
bps: Union[ChannelDepth, str] = ChannelDepth.Bps8) -> None:
16581706
"""Save current image to file.
16591707
1660-
Save current content of the image buffer to file. Accepted formats,
1661-
recognized by the extension used in the ``file_name``, are bmp, gif,
1662-
png, jpg, and tif. Existing files are overwritten.
1708+
Save current content of the image buffer to a file. Accepted formats,
1709+
recognized by the extension used in the ``file_name``, are:
1710+
1711+
- bmp, gif, png, jpg, and tif for 8bps color depth,
1712+
- png, and tif for 16bps color depth,
1713+
- tif for 32bps hdr images.
1714+
1715+
Existing files are overwritten.
16631716
16641717
Parameters
16651718
----------
16661719
file_name : str
16671720
Output file name.
1721+
bps : ChannelDepth enum or string, optional
1722+
Color depth.
1723+
1724+
See Also
1725+
--------
1726+
:class:`plotoptix.enums.ChannelDepth`
16681727
"""
1728+
if isinstance(bps, str): bps = ChannelDepth[bps]
1729+
16691730
try:
16701731
self._padlock.acquire()
16711732

1672-
if not self._optix.save_image_to_file(file_name):
1733+
if bps == ChannelDepth.Bps8:
1734+
ok = self._optix.save_image_to_file(file_name)
1735+
elif bps == ChannelDepth.Bps16:
1736+
ok = self._optix.save_image_to_file_16bps(file_name)
1737+
elif bps == ChannelDepth.Bps32:
1738+
ok = self._optix.save_image_to_file_32bps(file_name)
1739+
else:
1740+
ok = False
1741+
1742+
if not ok:
16731743
msg = "Image not saveed."
16741744
self._logger.error(msg)
16751745
if self._raise_on_error: raise ValueError(msg)

0 commit comments

Comments
 (0)