Skip to content

Commit 24deeb6

Browse files
taxe10xiaoyachong
andauthored
Add slicing information to the message (#15)
* fix image open * read image from tiled and send real tiled url * Send slicing information --------- Co-authored-by: Xiaoya Chong <150726549+xiaoyachong@users.noreply.github.com>
1 parent b125a99 commit 24deeb6

1 file changed

Lines changed: 123 additions & 47 deletions

File tree

Lines changed: 123 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import asyncio
22
import os
3+
import logging
34
from datetime import datetime
4-
from glob import glob
5-
6-
# from arroyopy.schemas import NumpyArrayModel
7-
import msgpack
85
import typer
96
import zmq
107
import zmq.asyncio
11-
from PIL import Image
8+
import msgpack
9+
from tiled.client import from_uri
1210

1311
from ..config import settings
1412
from ..schemas import (
@@ -19,68 +17,146 @@
1917
)
2018

2119
"""
22-
Simulates however we are going to get images and sends them
23-
onto ZMQ, taking care of pydantic messages, serialization and msgpack
20+
Simulates image retrieval from Tiled and sends them onto ZMQ,
21+
taking care of pydantic messages, serialization and msgpack
2422
"""
2523

26-
FRAME_WIDTH = 1475
27-
FRAME_HEIGHT = 619
28-
DATA_TYPE = "float32"
24+
# Default Tiled configuration - use the exact URI format from data_simulator.py
25+
DATA_TILED_URI = (
26+
"https://tiled-demo.blueskyproject.io/api/v1/metadata/rsoxs/raw/"
27+
"468810ed-2ff9-4e92-8ca9-dcb376d01a56/primary/data/Small Angle CCD Detector_image"
28+
)
29+
TILED_API_KEY = os.getenv("DATA_TILED_KEY")
30+
if TILED_API_KEY == "":
31+
TILED_API_KEY = None
32+
33+
# Frame configuration
34+
FRAME_WIDTH = 1024
35+
FRAME_HEIGHT = 1026
36+
DATA_TYPE = "uint32"
37+
38+
# Setup logging
39+
logger = logging.getLogger(__name__)
40+
logging.basicConfig(level=logging.INFO)
2941

3042
app = typer.Typer()
3143

3244

33-
async def process_images(
34-
socket: zmq.asyncio.Socket, cycles: int, frames: int, pause: float
45+
def get_num_frames(tiled_uri, tiled_api_key=None):
46+
"""Get the number of available frames from Tiled, following data_simulator.py pattern"""
47+
client = from_uri(tiled_uri, api_key=tiled_api_key)
48+
return client.shape[0] if hasattr(client, 'shape') and len(client.shape) > 0 else 0
49+
50+
51+
async def process_images_from_tiled(
52+
socket: zmq.asyncio.Socket,
53+
cycles: int,
54+
frames: int,
55+
pause: float,
56+
tiled_uri: str,
57+
tiled_api_key: str = None
3558
):
36-
for cycle_num in range(cycles):
37-
# Get current time formatted as YYYY-MM-DD HH:MM:SS
38-
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
39-
start = SASStart(
40-
width=FRAME_WIDTH,
41-
height=FRAME_HEIGHT,
42-
data_type=DATA_TYPE,
43-
tiled_url="http://tiled:8000",
44-
run_name="test_run",
45-
run_id=str(current_time),
46-
)
47-
print("start")
48-
await socket.send(msgpack.packb(start.model_dump()))
49-
files = glob("/data/test_data/blade/*.tif")
50-
frame_num = 0
51-
for file in files:
52-
with os.read(file) as filebytes:
53-
image = Image.frombytes(filebytes)
54-
event = RawFrameEvent(
55-
image=SerializableNumpyArrayModel(array=image),
56-
frame_number=frame_num,
57-
tiled_url="tb://frame_url",
59+
"""
60+
Process images from Tiled and send them via ZMQ
61+
"""
62+
try:
63+
# Connect to Tiled server using the exact URI format
64+
logger.info(f"Connecting to Tiled server at {tiled_uri}")
65+
client = from_uri(tiled_uri, api_key=tiled_api_key)
66+
67+
# Get total number of available frames
68+
total_frames = get_num_frames(tiled_uri, tiled_api_key)
69+
logger.info(f"Total frames available in Tiled: {total_frames}")
70+
71+
for cycle_num in range(cycles):
72+
# Get current time formatted as YYYY-MM-DD HH:MM:SS
73+
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
74+
75+
# Send SAS Start event
76+
start = SASStart(
77+
width=FRAME_WIDTH,
78+
height=FRAME_HEIGHT,
79+
data_type=DATA_TYPE,
80+
tiled_url=tiled_uri,
81+
run_name=f"tiled_run_{cycle_num}",
82+
run_id=str(current_time),
5883
)
59-
print("event")
60-
await socket.send(msgpack.packb(event.model_dump()))
61-
stop = SASStop(num_frames=frames)
62-
print("stop")
63-
await socket.send(msgpack.packb(stop.model_dump()))
64-
await asyncio.sleep(pause)
65-
print(f"Cycle {cycle_num} complete sent {frames} frames")
84+
logger.info(f"Sending start event for cycle {cycle_num}")
85+
await socket.send(msgpack.packb(start.model_dump()))
86+
87+
# Determine number of frames to process in this cycle
88+
frame_count = min(frames, total_frames)
89+
if frame_count == 0:
90+
logger.warning("No frames available in Tiled")
91+
continue
92+
93+
# Process frames
94+
for frame_num in range(frame_count):
95+
try:
96+
# Get frame data directly from Tiled client
97+
# This is the correct way to read data from a Tiled array client
98+
# The read() method returns a numpy array with the image data
99+
image_array = client[frame_num]
100+
101+
# Create and send the frame event with the Tiled URI
102+
event = RawFrameEvent(
103+
image=SerializableNumpyArrayModel(array=image_array),
104+
frame_number=frame_num,
105+
tiled_url=f"{tiled_uri}?slice={frame_num}",
106+
)
107+
logger.info(f"Sending frame {frame_num} for cycle {cycle_num}")
108+
await socket.send(msgpack.packb(event.model_dump()))
109+
110+
except Exception as e:
111+
logger.error(f"Error processing frame {frame_num}: {e}")
112+
113+
# Send stop event
114+
stop = SASStop(num_frames=frame_count)
115+
logger.info(f"Sending stop event for cycle {cycle_num}")
116+
await socket.send(msgpack.packb(stop.model_dump()))
117+
118+
await asyncio.sleep(pause)
119+
logger.info(f"Cycle {cycle_num} complete - sent {frame_count} frames")
66120

67-
print("All cycles complete")
68-
return
121+
logger.info("All cycles complete")
122+
123+
except Exception as e:
124+
logger.error(f"Error in processing images: {e}")
69125

70126

71127
@app.command()
72-
def main(cycles: int = 10000, frames: int = 50, pause: float = 5):
128+
def main(
129+
cycles: int = 10000,
130+
frames: int = 50,
131+
pause: float = 5,
132+
tiled_uri: str = None,
133+
api_key: str = None
134+
):
135+
"""
136+
Run the image simulator that reads frames from Tiled and publishes them via ZMQ.
137+
138+
Args:
139+
cycles: Number of cycles to run
140+
frames: Maximum number of frames per cycle
141+
pause: Pause time between cycles in seconds
142+
tiled_uri: URI of the Tiled server (defaults to the predefined DATA_TILED_URI)
143+
api_key: API key for Tiled authentication (defaults to env var DATA_TILED_KEY)
144+
"""
145+
# Use provided values or fall back to defaults
146+
tiled_uri = tiled_uri or DATA_TILED_URI
147+
api_key = api_key or TILED_API_KEY
148+
73149
async def run():
74150
context = zmq.asyncio.Context()
75151
socket = context.socket(zmq.PUB)
76152
address = settings.tiled_poller.publish_address
77-
print(f"Connecting to {address}")
153+
logger.info(f"Binding to ZMQ address: {address}")
78154
socket.bind(address)
79-
await process_images(socket, cycles, frames, pause)
155+
await process_images_from_tiled(socket, cycles, frames, pause, tiled_uri, api_key)
80156
return
81157

82158
asyncio.run(run())
83159

84160

85161
if __name__ == "__main__":
86-
app()
162+
app()

0 commit comments

Comments
 (0)