-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimelapse_capture.py
More file actions
145 lines (129 loc) · 6.07 KB
/
timelapse_capture.py
File metadata and controls
145 lines (129 loc) · 6.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import sys, time, os
import logging
from datetime import datetime
from pyueye import ueye
import numpy as np
from PIL import Image
# >>> Configurable parameters >>>
CAMERA_ID = 0 # Camera ID (0 = first camera)
IMAGE_WIDTH = 1280 # Image width in pixels
IMAGE_HEIGHT = 1024 # Image height in pixels
COLOR_CAMERA = True # True for color camera, False for mono
EXPOSURE_TIME_MS = 20.0 # Exposure time in milliseconds
CAPTURE_INTERVAL = 15 * 60 # Interval between captures in seconds (15 minutes)
OUTPUT_DIR = "captures" # Directory to save images (will be created if not exists)
# <<< End of configurable parameters <<<
# Setup logging to file and console
logging.basicConfig(filename="timelapse_capture.log", level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s")
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
logging.getLogger().addHandler(console)
# Ensure output directory exists
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
# Initialize camera and allocate memory (encapsulated in a function for reuse on reconnect)
def initialize_camera():
"""Open the camera, set it up for image capture, and return handles and parameters."""
hCam = ueye.HIDS(CAMERA_ID)
ret = ueye.is_InitCamera(hCam, None)
if ret != ueye.IS_SUCCESS:
logging.error(f"Camera initialization failed (error {ret}).")
return None, None, None, None # indicate failure
logging.info("Camera initialized.")
# Set color or mono mode
if COLOR_CAMERA:
ret = ueye.is_SetColorMode(hCam, ueye.IS_CM_BGR8_PACKED)
bits_per_pixel = 24
else:
ret = ueye.is_SetColorMode(hCam, ueye.IS_CM_MONO8)
bits_per_pixel = 8
if ret != ueye.IS_SUCCESS:
logging.error(f"Failed to set color mode (error {ret}).")
ueye.is_ExitCamera(hCam)
return None, None, None, None
# Set AOI (region of interest) to desired resolution
rect_aoi = ueye.IS_RECT()
rect_aoi.s32X = ueye.int(0); rect_aoi.s32Y = ueye.int(0)
rect_aoi.s32Width = ueye.int(IMAGE_WIDTH); rect_aoi.s32Height = ueye.int(IMAGE_HEIGHT)
ret = ueye.is_AOI(hCam, ueye.IS_AOI_IMAGE_SET_AOI, rect_aoi, ueye.sizeof(rect_aoi))
if ret != ueye.IS_SUCCESS:
logging.error(f"Failed to set AOI (error {ret}).")
ueye.is_ExitCamera(hCam)
return None, None, None, None
# Allocate and activate image memory
pcImageMemory = ueye.c_mem_p()
memID = ueye.int()
ret = ueye.is_AllocImageMem(hCam, IMAGE_WIDTH, IMAGE_HEIGHT, bits_per_pixel, pcImageMemory, memID)
if ret != ueye.IS_SUCCESS:
logging.error(f"Failed to allocate image memory (error {ret}).")
ueye.is_ExitCamera(hCam)
return None, None, None, None
ret = ueye.is_SetImageMem(hCam, pcImageMemory, memID)
if ret != ueye.IS_SUCCESS:
logging.error(f"Failed to set image memory (error {ret}).")
ueye.is_FreeImageMem(hCam, pcImageMemory, memID)
ueye.is_ExitCamera(hCam)
return None, None, None, None
# Set exposure time
exp_param = ueye.double(EXPOSURE_TIME_MS)
actual_exp = ueye.double()
ret = ueye.is_SetExposureTime(hCam, exp_param, actual_exp)
if ret == ueye.IS_SUCCESS:
logging.info(f"Exposure set to ~{actual_exp.value:.2f} ms")
else:
logging.warning(f"Could not set exposure (error {ret}). Using current camera setting.")
return hCam, pcImageMemory, memID, bits_per_pixel
# Open the camera and prepare for capture
hCam, pcImageMemory, memID, bits_per_pixel = initialize_camera()
if hCam is None:
sys.exit("Failed to initialize camera. Exiting.")
# Calculate line increment (stride) for image data
lineinc = IMAGE_WIDTH * int((bits_per_pixel + 7) / 8)
logging.info(f"Starting time-lapse: capturing an image every {CAPTURE_INTERVAL} seconds.")
try:
while True:
# Capture one frame (wait for image to be captured)
ret = ueye.is_FreezeVideo(hCam, ueye.IS_WAIT)
if ret != ueye.IS_SUCCESS:
logging.error(f"Frame capture failed (error {ret}). Attempting to reconnect...")
# Attempt to reinitialize the camera once if capture fails (e.g., camera disconnected)
ueye.is_FreeImageMem(hCam, pcImageMemory, memID)
ueye.is_ExitCamera(hCam)
time.sleep(2) # short delay before reconnect
hCam, pcImageMemory, memID, bits_per_pixel = initialize_camera()
if hCam is None:
logging.critical("Camera re-initialization failed. Stopping time-lapse.")
break
# If reinitialized successfully, continue to next iteration (retry capture)
lineinc = IMAGE_WIDTH * int((bits_per_pixel + 7) / 8)
continue
# If capture succeeded, copy image to array
data = ueye.get_data(pcImageMemory, IMAGE_WIDTH, IMAGE_HEIGHT, bits_per_pixel, lineinc, copy=True)
if bits_per_pixel == 24:
img_array = np.reshape(data, (IMAGE_HEIGHT, IMAGE_WIDTH, 3))
img_array = img_array[..., ::-1] # BGR to RGB
else:
img_array = np.reshape(data, (IMAGE_HEIGHT, IMAGE_WIDTH))
# Save the image with a timestamped filename
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"timelapse_{timestamp}.tiff"
filepath = os.path.join(OUTPUT_DIR, filename)
try:
Image.fromarray(img_array).save(filepath, format="TIFF")
logging.info(f"Captured image saved: {filepath}")
except Exception as e:
logging.error(f"Error saving image {filename}: {e}")
# Wait for the next capture time
time.sleep(CAPTURE_INTERVAL)
except KeyboardInterrupt:
logging.info("Time-lapse interrupted by user. Exiting...")
except Exception as e:
logging.exception(f"Unexpected error: {e}")
finally:
# Cleanup on exit
if 'hCam' in locals() and hCam is not None:
ueye.is_FreeImageMem(hCam, pcImageMemory, memID)
ueye.is_ExitCamera(hCam)
logging.info("Camera closed. Time-lapse stopped.")