Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions deapi/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ def connect(self, host: str = "127.0.0.1", port: int = 13240, read_only=False):

version = [int(part) for part in server_version[:4]]
temp = version[2] + version[1] * 1000 + version[0] * 1000000
if temp >= 2008000 and version[3] >= 11901:
## version 2.8.0 build 11901+ — virtual image buffer support (SDK 5.3.0)
if temp >= 2008000 and version[3] >= 12073:
## version 2.8.0 build 12073+ — virtual image buffer support (SDK 5.3.0)
self.commandVersion = 16
elif (temp >= 2007005 and version[3] < 11274) or temp >= 2008000:
## version after 2.8.0 (older builds)
Expand Down Expand Up @@ -1717,6 +1717,8 @@ def get_result(
"autoStretchGamma",
]
)
if self.commandVersion >= 16:
attributes_order.append("current_scan_pattern_idx")

# special casting rules
field_casts = {
Expand Down Expand Up @@ -2063,6 +2065,8 @@ def get_virtual_image_buffer(
- Other values indicate timeout, failure, or finished state.
frame_index : int
The acquisition frame index associated with this virtual image.
pattern_index : int
The scan pattern index associated with this virtual image.
image : numpy.ndarray or None
2-D array of shape ``(height, width)`` on success, ``None`` otherwise.
"""
Expand All @@ -2076,14 +2080,16 @@ def get_virtual_image_buffer(

status = MovieBufferStatus.UNKNOWN
frame_index = 0
pattern_index = 0
image = None

if response:
values = self.__getParameters(response.acknowledge[0])
if isinstance(values, list) and len(values) >= 3:
if isinstance(values, list) and len(values) >= 4:
status_int = values[0]
total_bytes = values[1]
frame_index = values[2]
pattern_index = values[3]
try:
status = MovieBufferStatus(status_int)
except ValueError:
Expand All @@ -2100,7 +2106,7 @@ def get_virtual_image_buffer(
else:
status = MovieBufferStatus.FAILED

return status, frame_index, image
return status, frame_index, pattern_index, image

def save_image(self, image, fileName, textSize=0):
t0 = self.GetTime()
Expand Down
4 changes: 4 additions & 0 deletions deapi/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ class Attributes:
output_binning_method : int, optional
Method used for binning the output image. Defaults to BinningMethod.AVERAGE,
other options are BinningMethod.NONE, BinningMethod.SUM, and BinningMethod.FOURIERCROP.
current_scan_pattern_idx : int, optional
Index of the current scan pattern.
"""

def __init__(
Expand Down Expand Up @@ -332,6 +334,7 @@ def __init__(
output_binning_x: int = 1,
output_binning_y: int = 1,
output_binning_method: int = 1, # BinningMethod.AVERAGE
current_scan_pattern_idx: int = 0,
):

self.centerX = center_x
Expand Down Expand Up @@ -381,6 +384,7 @@ def __init__(
self.output_binning_x = output_binning_x
self.output_binning_y = output_binning_y
self.output_binning_method = output_binning_method
self.current_scan_pattern_idx = current_scan_pattern_idx

def __repr__(self):
return (
Expand Down
7 changes: 4 additions & 3 deletions deapi/simulated_server/fake_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -757,9 +757,10 @@ def _fake_get_result(self, command):
float(np.min(image)), # autoStretchMin 26
float(np.max(image)), # autoStretchMax 27
float(1.0), # autoStretchGamma 28
float(np.min(image)), # histogram min 29
float(np.max(image)), # histogram max 30
float(np.max(image)), # histogram upper local max 31
int(0), # current_scan_pattern_idx 29
float(np.min(image)), # histogram min 30
float(np.max(image)), # histogram max 31
float(np.max(image)), # histogram upper local max 32
]

# Then histogram...
Expand Down
52 changes: 26 additions & 26 deletions deapi/tests/test_scanning/test_virtual_image_buffers.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,45 +83,45 @@ def test_streaming_all_virtual_buffers(self, client):
queue_virtual_buffers=True,
)

received_frames: list[tuple[int, int, np.ndarray]] = []
received_frames: list[tuple[int, int, int, np.ndarray]] = []
# UNKNOWN = 0, FAILED = 1, TIMEOUT = 3, FINISHED = 4, OK = 5
# OK --> Still more frames to access

finshed = False
finished = False

while not finshed:
while not finished:
for buf_id in range(NUM_VIRTUAL_BUFFERS):
status, frame_index, image = client.get_virtual_image_buffer(
status, frame_index, pattern_index, image = client.get_virtual_image_buffer(
buf_id, virtual_image_info=info
)
print(
f"buf_id={buf_id} frame={frame_index} status={status} image shape: {image.shape if image is not None else None}"
f"buf_id={buf_id} frame={frame_index} pattern={pattern_index} status={status} image shape: {image.shape if image is not None else None}"
)

if status == MovieBufferStatus.OK:
assert (
image is not None
), f"buf_id={buf_id} frame={frame_index}: status OK but image is None"
), f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: status OK but image is None"
assert image.shape == (
info.height,
info.width,
), f"buf_id={buf_id} frame={frame_index}: unexpected shape {image.shape}"
received_frames.append((buf_id, frame_index, image))
), f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: unexpected shape {image.shape}"
received_frames.append((buf_id, frame_index, pattern_index, image))

elif status == MovieBufferStatus.FINISHED:
finshed = True
finished = True
# This channel is done — mark finished.

elif status == MovieBufferStatus.TIMEOUT:
print(
f"buf_id={buf_id} frame={frame_index}: timeout waiting for frame"
f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: timeout waiting for frame"
)
# This can happen if we check a channel before its first frame is ready.
# Just ignore and check again in the next loop iteration.

elif status == MovieBufferStatus.FAILED:
print(
f"buf_id={buf_id} frame={frame_index}: failed to retrieve frame-- Likely this"
f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: failed to retrieve frame-- Likely this"
f"virtual image is not initialized."
)

Expand Down Expand Up @@ -156,47 +156,47 @@ def test_streaming_all_virtual_buffers_one_off(self, client):
queue_virtual_buffers=True,
)

received_frames: list[tuple[int, int, np.ndarray]] = []
received_frames: list[tuple[int, int, int, np.ndarray]] = []
# UNKNOWN = 0, FAILED = 1, TIMEOUT = 3, FINISHED = 4, OK = 5
# OK --> Still more frames to access

finshed = False
finished = False

while not finshed:
while not finished:
for buf_id in range(NUM_VIRTUAL_BUFFERS):
status, frame_index, image = client.get_virtual_image_buffer(
status, frame_index, pattern_index, image = client.get_virtual_image_buffer(
buf_id, virtual_image_info=info
)
print(
f"buf_id={buf_id} frame={frame_index} status={status} image shape: {image.shape if image is not None else None}"
f"buf_id={buf_id} frame={frame_index} pattern={pattern_index} status={status} image shape: {image.shape if image is not None else None}"
)

if buf_id == 4:
assert status == MovieBufferStatus.FAILED
if status == MovieBufferStatus.OK:
assert (
image is not None
), f"buf_id={buf_id} frame={frame_index}: status OK but image is None"
), f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: status OK but image is None"
assert image.shape == (
info.height,
info.width,
), f"buf_id={buf_id} frame={frame_index}: unexpected shape {image.shape}"
received_frames.append((buf_id, frame_index, image))
), f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: unexpected shape {image.shape}"
received_frames.append((buf_id, frame_index, pattern_index, image))

elif status == MovieBufferStatus.FINISHED:
finshed = True
finished = True
# This channel is done — mark finished.

elif status == MovieBufferStatus.TIMEOUT:
print(
f"buf_id={buf_id} frame={frame_index}: timeout waiting for frame"
f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: timeout waiting for frame"
)
# This can happen if we check a channel before its first frame is ready.
# Just ignore and check again in the next loop iteration.

elif status == MovieBufferStatus.FAILED:
print(
f"buf_id={buf_id} frame={frame_index}: failed to retrieve frame-- Likely this"
f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: failed to retrieve frame-- Likely this"
f"virtual image is not initialized."
)

Expand Down Expand Up @@ -242,7 +242,7 @@ def test_streaming_multiple_xy_arrays(self, client):
queue_virtual_buffers=True,
)

received_frames: list[tuple[int, int, np.ndarray]] = []
received_frames: list[tuple[int, int, int, np.ndarray]] = []
# UNKNOWN = 0, FAILED = 1, TIMEOUT = 3, FINISHED = 4, OK = 5
# OK --> Still more frames to access

Expand All @@ -253,12 +253,12 @@ def test_streaming_multiple_xy_arrays(self, client):
for buf_id in range(NUM_VIRTUAL_BUFFERS):
got_frame = False
while not got_frame:
status, frame_index, image = client.get_virtual_image_buffer(
status, frame_index, pattern_index, image = client.get_virtual_image_buffer(
buf_id, virtual_image_info=info, timeout_msec=1000 # 1 sec
)
if status == MovieBufferStatus.OK:
received_frames.append(
(buf_id, frame_index, image)
(buf_id, frame_index, pattern_index, image)
) # Do whatever with the frame.
got_frame = True

Expand All @@ -271,7 +271,7 @@ def test_streaming_multiple_xy_arrays(self, client):
got_frame = False
elif status == MovieBufferStatus.FAILED:
print(
f"buf_id={buf_id} frame={frame_index}: failed to retrieve frame-- Likely this"
f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: failed to retrieve frame-- Likely this"
f" virtual image is not initialized."
)
got_frame = True
4 changes: 2 additions & 2 deletions deapi/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Used by FakeServer so its reported "Server Software Version" always matches
# the commandVersion used for dispatch, making tests version-agnostic.
_command_version_to_server_version = {
16: "2.8.0.11901",
16: "2.8.0.12073",
15: "2.7.5.1000",
13: "2.7.4.10590",
12: "2.7.4.1000",
Expand All @@ -18,5 +18,5 @@

# The server version string that corresponds to the current commandVersion.
fake_server_software_version = _command_version_to_server_version.get(
commandVersion, "2.8.0.11901"
commandVersion, "2.8.0.12073"
)
23 changes: 12 additions & 11 deletions doc/reference/scan_design.rst
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,8 @@ frame is captured.
)

# ── Collect streamed virtual image frames ─────────────────────────────────
# Each entry is (buf_id, frame_index, image_array).
received_frames: list[tuple[int, int, np.ndarray]] = []
# Each entry is (buf_id, frame_index, pattern_index, image_array).
received_frames: list[tuple[int, int, int, np.ndarray]] = []

# MovieBufferStatus meanings:
# UNKNOWN = 0 — status not yet determined
Expand All @@ -489,15 +489,15 @@ frame is captured.
for buf_id in range(NUM_VIRTUAL_BUFFERS):
got_frame = False
while not got_frame:
status, frame_index, image = client.get_virtual_image_buffer(
status, frame_index, pattern_index, image = client.get_virtual_image_buffer(
buf_id,
virtual_image_info=info,
timeout_msec=1000, # Wait up to 1 s for a frame
)

if status == MovieBufferStatus.OK:
# Frame retrieved — store it for downstream processing
received_frames.append((buf_id, frame_index, image))
received_frames.append((buf_id, frame_index, pattern_index, image))
got_frame = True

elif status == MovieBufferStatus.FINISHED:
Expand All @@ -511,7 +511,7 @@ frame is captured.

elif status == MovieBufferStatus.FAILED:
print(
f"buf_id={buf_id} frame={frame_index}: failed to retrieve frame — "
f"buf_id={buf_id} frame={frame_index} pattern={pattern_index}: failed to retrieve frame — "
f"likely this virtual image channel is not initialized."
)
got_frame = True # Skip this frame and continue
Expand Down Expand Up @@ -595,12 +595,12 @@ frame is captured.
bool gotFrame = false;
while (!gotFrame)
{
var (status, frameIndex, image) =
var (status, frameIndex, patternIndex, image) =
client.GetVirtualImageBuffer(bufId, info, timeoutMsec: 1000);

if (status == MovieBufferStatus.OK)
{
receivedFrames.Add((bufId, frameIndex, image));
receivedFrames.Add((bufId, frameIndex, patternIndex, image));
gotFrame = true;
}
else if (status == MovieBufferStatus.Finished)
Expand All @@ -616,7 +616,7 @@ frame is captured.
else // FAILED or UNKNOWN
{
Console.WriteLine(
$"bufId={bufId} frame={frameIndex}: failed to retrieve frame — " +
$"bufId={bufId} frame={frameIndex} pattern={patternIndex}: failed to retrieve frame — " +
$"likely this virtual image channel is not initialized.");
gotFrame = true;
}
Expand Down Expand Up @@ -684,7 +684,7 @@ frame is captured.

// ── Collect streamed virtual image frames ─────────────────────────────
// Each entry stores the detector channel, frame index, and pixel data.
using Frame = std::tuple<int, int, std::vector<float>>;
using Frame = std::tuple<int, int, int, std::vector<float>>;
std::vector<Frame> receivedFrames;

// deapi::MovieBufferStatus values:
Expand All @@ -699,11 +699,11 @@ frame is captured.
for (int bufId = 0; bufId < NUM_VIRTUAL_BUFFERS; ++bufId) {
bool gotFrame = false;
while (!gotFrame) {
auto [status, frameIndex, image] =
auto [status, frameIndex, patternIndex, image] =
client.getVirtualImageBuffer(bufId, info, /*timeoutMsec=*/1000);

if (status == deapi::MovieBufferStatus::OK) {
receivedFrames.emplace_back(bufId, frameIndex, image);
receivedFrames.emplace_back(bufId, frameIndex, patternIndex, image);
gotFrame = true;
} else if (status == deapi::MovieBufferStatus::FINISHED) {
finished = true;
Expand All @@ -714,6 +714,7 @@ frame is captured.
} else { // FAILED or UNKNOWN
std::cerr << "bufId=" << bufId
<< " frame=" << frameIndex
<< " pattern=" << patternIndex
<< ": failed to retrieve frame — "
"likely this virtual image channel is not initialized.\n";
gotFrame = true;
Expand Down
Loading