Skip to content

Commit 6b831f2

Browse files
committed
Created a utils module
- Added settings util - Added recorder util - Added DS_Store to gitignore
1 parent 83e70ec commit 6b831f2

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,4 @@ cython_debug/
159159
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
160160
#.idea/
161161
.vscode/
162+
.DS_Store

microscope/utils/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .settings import *
2+
from .recorder import *

microscope/utils/recorder.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import cv2
2+
import requests
3+
import numpy as np
4+
import threading
5+
import time
6+
from epics import PV
7+
8+
9+
class VideoWriter:
10+
def __init__(self, url, fps, output_path, epics_pv_name=None):
11+
self.url = url
12+
self.fps = fps
13+
self.output_path = output_path
14+
self.epics_pv_name = epics_pv_name
15+
if epics_pv_name:
16+
self.epics_pv = PV(epics_pv_name)
17+
self.epics_pv.add_callback(self._watch_pv)
18+
self.fourcc = cv2.VideoWriter_fourcc(*"mp4v")
19+
self.current_image = None
20+
self.is_recording = False
21+
self.writer_thread = None
22+
self.reader_thread = None
23+
24+
def get_image_from_url(self):
25+
try:
26+
response = requests.get(self.url, stream=True)
27+
response.raise_for_status()
28+
image = np.asarray(bytearray(response.content), dtype="uint8")
29+
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
30+
return image
31+
except requests.HTTPError:
32+
print(f"HTTP GET request to url {self.url} failed.")
33+
except Exception as e:
34+
print(
35+
f"An error occurred while trying to retrieve an image from the url {self.url}: {str(e)}"
36+
)
37+
return None
38+
39+
def start_recording(self):
40+
self.is_recording = True
41+
self.writer_thread = threading.Thread(target=self._writer_loop)
42+
self.writer_thread.start()
43+
self.reader_thread = threading.Thread(target=self._reader_loop)
44+
self.reader_thread.start()
45+
46+
def stop_recording(self):
47+
self.is_recording = False
48+
if self.writer_thread:
49+
self.writer_thread.join()
50+
if self.reader_thread:
51+
self.reader_thread.join()
52+
53+
def _watch_pv(self, **kwargs):
54+
if kwargs["pvname"] != self.epics_pv_name:
55+
return
56+
if kwargs["value"] == 1 and not self.is_recording:
57+
print(f"{self.epics_pv_name} : {kwargs['value']}. START record action")
58+
self.start_recording()
59+
elif kwargs["value"] == 0 and self.is_recording:
60+
print(f"{self.epics_pv_name} : {kwargs['value']}. STOP record action")
61+
self.stop_recording()
62+
63+
def _reader_loop(self):
64+
while self.is_recording:
65+
image = self.get_image_from_url()
66+
if image is not None:
67+
self.current_image = image
68+
time.sleep(1.0 / self.fps)
69+
70+
def _writer_loop(self):
71+
out = None
72+
frame_size = None
73+
frame_period = 1.0 / self.fps
74+
while self.is_recording:
75+
if self.current_image is not None:
76+
if out is None:
77+
frame_size = (
78+
self.current_image.shape[1],
79+
self.current_image.shape[0],
80+
)
81+
out = cv2.VideoWriter(
82+
self.output_path, self.fourcc, self.fps, frame_size
83+
)
84+
out.write(self.current_image)
85+
time.sleep(frame_period)
86+
if out is not None:
87+
out.release()
88+
89+
90+
if __name__ == "__main__":
91+
# Usage
92+
url = "http://localhost:8080/output.jpg"
93+
fps = 10
94+
output_file_path = "output.mp4"
95+
pv_name = "XF:17IDB-ES:AMX{Stills}-Stat"
96+
video_writer = VideoWriter(url, fps, output_file_path, epics_pv_name=pv_name)
97+
98+
# PV Name is optional. If not using PV name you can start or stop recording like so
99+
"""
100+
video_writer.start_recording()
101+
time.sleep(10) # Let it record for 10 seconds
102+
video_writer.stop_recording()
103+
"""
104+
105+
# Otherwise you would run your script and as long as the program is alive the PV will
106+
# start and stop the recording. In this example, the program is kept alive using
107+
# an infinite loop
108+
while True:
109+
pass

0 commit comments

Comments
 (0)