Skip to content

Commit fa19359

Browse files
committed
fix: path issues tests, rename cslcamera
1 parent ef93365 commit fa19359

9 files changed

Lines changed: 49 additions & 40 deletions

File tree

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def __init__(self, config_file, cam_param, downscale=3, mm_dir = "C:/Program Fil
109109
if key not in ["name", "MMconfig"]:
110110
try:
111111
self.mmc.setProperty(self.name, key, config[key])
112-
logger.info(key, self.get_param(key))
112+
logger.info("Set config parameter %s=%s", key, self.get_param(key))
113113
except Exception as e:
114114
logger.error(f"Failed to update parameter '{key}' with value '{config[key]}': {e}")
115115

@@ -119,7 +119,7 @@ def __init__(self, config_file, cam_param, downscale=3, mm_dir = "C:/Program Fil
119119
for key in cam_param:
120120
try:
121121
self.mmc.setProperty(self.name, key, cam_param[key])
122-
logger.info(key, self.get_param(key))
122+
logger.info("Set local parameter %s=%s", key, self.get_param(key))
123123

124124
except Exception as e:
125125
logger.error(f"Failed to update parameter '{key}' with value '{cam_param[key]}': {e}")
@@ -136,7 +136,7 @@ def update_param(self, key, val):
136136
"""
137137
try:
138138
self.mmc.setProperty(self.name, key, val)
139-
logger.info(key, self.get_param(key))
139+
logger.info("Updated parameter %s=%s", key, self.get_param(key))
140140

141141
except Exception as e:
142142
logger.error(f"Failed to update parameter '{key}' with value '{val}': {e}")
@@ -161,27 +161,42 @@ def get_param(self, key):
161161
def continuous_stream(self, transform=None):
162162
"""
163163
Perform continuous streaming of the camera frames and display them in a window.
164+
165+
The window is shown at a reduced size so that large sensor
166+
images still fit on screen. Press 'q' to close.
164167
"""
165-
cv2.namedWindow('live',cv2.WINDOW_AUTOSIZE)
168+
cv2.namedWindow('live', cv2.WINDOW_NORMAL)
166169
self.mmc.startContinuousSequenceAcquisition(1)
167170
while True:
168171
if self.mmc.getRemainingImageCount() > 0:
169172
self.frame = self.mmc.popNextImage()
170-
self.image = np.mean(self.frame[:,:,:3], axis =2)
171-
#self.image = np.array(Image.fromarray(np.uint8(self.frame)))
172-
#self.image[self.image<np.quantile(self.image, 0.99)] = 0
173+
# Average RGB channels to get a grayscale image (like original code)
174+
self.image = np.mean(self.frame[:, :, :3], axis=2)
175+
# self.image = np.array(Image.fromarray(np.uint8(self.frame)))
176+
# self.image[self.image<np.quantile(self.image, 0.99)] = 0
177+
173178
if transform is not None:
174-
# Apply the transform function here
175-
transformed_image = self.image.copy()
176-
transformed_image = transform(transformed_image)
177-
image = resize(self.image, transformed_image.shape)
178-
# Create a combined image by stacking the original and transformed images horizontally
179-
combined_image = np.hstack((image, transformed_image))
180-
# Display the combined image
181-
182-
cv2.imshow('live', cv2.normalize(combined_image, None, 255, 0, cv2.NORM_MINMAX, cv2.CV_8UC1))
179+
# Apply the transform function here
180+
transformed_image = self.image.copy()
181+
transformed_image = transform(transformed_image)
182+
image = resize(self.image, transformed_image.shape)
183+
# Create a combined image by stacking the original and transformed images horizontally
184+
combined_image = np.hstack((image, transformed_image))
185+
# Display the combined image (downscaled for the screen)
186+
disp = cv2.normalize(combined_image, None, 255, 0, cv2.NORM_MINMAX, cv2.CV_8UC1)
183187
else:
184-
cv2.imshow('live', cv2.normalize(self.image, None, 255,0, cv2.NORM_MINMAX, cv2.CV_8UC1))
188+
disp = cv2.normalize(self.image, None, 255, 0, cv2.NORM_MINMAX, cv2.CV_8UC1)
189+
190+
# Downscale display image if it is larger than a typical window
191+
max_h, max_w = 600, 800
192+
h, w = disp.shape[:2]
193+
scale = min(max_h / h, max_w / w, 1.0)
194+
if scale < 1.0:
195+
new_size = (int(w * scale), int(h * scale))
196+
disp = cv2.resize(disp, new_size, interpolation=cv2.INTER_AREA)
197+
198+
cv2.imshow('live', disp)
199+
185200
if cv2.waitKey(1) & 0xFF == ord('q'):
186201
break
187202

@@ -293,4 +308,3 @@ def save_video(self, save_folder, _run=None):
293308
_run.add_artifact(fname, "video.tiff")
294309
_run.add_artifact(fname, "video_timing.csv")
295310
return result, timing
296-

ControlCamera/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .CSLcamera import ControlCamera
1+
from .ControlCamera import ControlCamera

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![Python Version](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/downloads/)
66
[![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-blue.svg)](LICENSE)
77
[![DOI](https://img.shields.io/badge/DOI-pending%20Zenodo-orange.svg)](https://zenodo.org)
8-
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)](https://github.com/Alienor134/UC2_Fluorescence_microscope)
8+
[![Platform](https://img.shields.io/badge/platform-Windows-lightgrey.svg)](https://github.com/Alienor134/UC2_Fluorescence_microscope)
99
[![Arduino Compatible](https://img.shields.io/badge/Arduino-Compatible-00979D?logo=Arduino&logoColor=white)](https://www.arduino.cc/)
1010

1111
---
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import unittest
22
from unittest.mock import patch
33
from pathlib import Path
4+
import importlib
45

56
from ControlCamera import ControlCamera
7+
cc_module = importlib.import_module("ControlCamera.ControlCamera")
68

79

8-
TESTS_DIR = Path(__file__).resolve().parent
910
# MMconfig directory lives alongside Tests/, not inside unit/
10-
MMCONFIG_DIR = TESTS_DIR.parent / "MMconfig"
11-
CONFIG_FILE = MMCONFIG_DIR / "Daheng.json"
11+
MMCONFIG_DIR = "MMconfig"
12+
CONFIG_FILE = MMCONFIG_DIR + "/Daheng.json"
1213

1314

1415
class FakeCore:
@@ -36,24 +37,24 @@ class TestControlCameraParams(unittest.TestCase):
3637
"""Hardware‑free tests focusing on camera parameter handling."""
3738

3839
def setUp(self):
39-
# Patch CMMCorePlus.instance() used inside CSLcamera to return our fake core
40-
patch_target = "ControlCamera.CSLcamera.CMMCorePlus"
41-
self._patcher = patch(patch_target)
40+
# Patch CMMCorePlus.instance() as used in the ControlCamera implementation
41+
# module so that it returns our FakeCore instead of real hardware.
42+
self._patcher = patch.object(cc_module, "CMMCorePlus")
4243
MockCoreClass = self._patcher.start()
4344

4445
self.fake_core = FakeCore()
4546
MockCoreClass.instance.return_value = self.fake_core
4647

47-
cam_params = {"Exposure": "10"}
48+
cam_params = {"Exposure(us)": "10"}
4849
self.camera = ControlCamera(str(CONFIG_FILE), cam_params)
4950

5051
def tearDown(self):
5152
self._patcher.stop()
5253

5354
def test_update_and_get_param_roundtrip(self):
5455
# Changing a parameter should be visible via get_param
55-
self.camera.update_param("Exposure", "20")
56-
value = self.camera.get_param("Exposure")
56+
self.camera.update_param("Exposure(us)", "20")
57+
value = self.camera.get_param("Exposure(us)")
5758
self.assertEqual(value, "20")
5859

5960
def test_initial_config_applies_some_properties(self):

Tests/test_daheng.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
# Define test configuration file and parameters
77

88
CAM_PARAMS = {"TriggerMode": "On", #off
9-
"TriggerSource": "Line0"} #Software
9+
"TriggerSource": "Line0",
10+
"SensorHeight":2048,
11+
"SensorWidth":2448} #Software
1012
CONFIG_FILE = "MMconfig/Daheng.json"
1113

1214
# Initialize the camera controller

Tests/test_output/video.tiff

-8.45 KB
Binary file not shown.

Tests/test_output/video_timing.csv

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
11
,0
2-
0,1768221226.2650905
3-
1,1768221226.328556
4-
2,1768221226.390074
5-
3,1768221226.4594235
6-
4,1768221226.5228765
7-
5,1768221226.583436
8-
6,1768221226.6459248
9-
7,1768221226.7025583
10-
8,1768221226.7591913
11-
9,1768221226.8148563
2+
0,1769184539.625449
3+
1,1769184539.973073

Tests/unit/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)