first commit
This commit is contained in:
108
camera_basler_capture_img/camera_main.py
Normal file
108
camera_basler_capture_img/camera_main.py
Normal file
@ -0,0 +1,108 @@
|
||||
import threading
|
||||
import queue
|
||||
import cv2
|
||||
from pypylon import pylon
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
# =================== 配置 ===================
|
||||
SAVE_DIR = "camera/continuous"
|
||||
SAVE_EVERY_N_FRAMES = 1 # 每N帧保存一张,None表示不保存
|
||||
SHOW = True
|
||||
QUEUE_MAXSIZE = 50
|
||||
|
||||
# =================== 相机搜索 ===================
|
||||
def search_get_device():
|
||||
"""搜索并返回 Basler GigE 相机对象"""
|
||||
tl_factory = pylon.TlFactory.GetInstance()
|
||||
for dev_info in tl_factory.EnumerateDevices():
|
||||
if dev_info.GetDeviceClass() == 'BaslerGigE':
|
||||
print(f"Found Basler GigE Camera: {dev_info.GetModelName()} IP: {dev_info.GetIpAddress()}")
|
||||
return pylon.InstantCamera(tl_factory.CreateDevice(dev_info))
|
||||
raise EnvironmentError("没有找到 Basler GigE 相机")
|
||||
|
||||
# =================== 异步处理线程 ===================
|
||||
frame_queue = queue.Queue(maxsize=QUEUE_MAXSIZE)
|
||||
exit_event = threading.Event()
|
||||
|
||||
def worker(save_dir, save_every_n_frames, show):
|
||||
frame_count = 0
|
||||
while not exit_event.is_set():
|
||||
try:
|
||||
item = frame_queue.get(timeout=0.1) # 队列空时短暂等待
|
||||
except queue.Empty:
|
||||
continue
|
||||
|
||||
if item is None:
|
||||
break
|
||||
|
||||
img, frame_num = item
|
||||
frame_count += 1
|
||||
|
||||
# 显示图像
|
||||
if show:
|
||||
cv2.imshow("Basler Live Feed", img)
|
||||
if cv2.waitKey(1) & 0xFF in (ord('q'), 27):
|
||||
exit_event.set()
|
||||
break
|
||||
|
||||
# 保存图像
|
||||
if save_every_n_frames and frame_num % save_every_n_frames == 0:
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S_%f')[:-3]
|
||||
filename = os.path.join(save_dir, f"frame_{frame_num:06d}_{timestamp}.png")
|
||||
cv2.imwrite(filename, img)
|
||||
print(f"[Saved] {filename}")
|
||||
|
||||
if show:
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
# =================== 主采集函数 ===================
|
||||
def continuous_grab(save_dir=SAVE_DIR, show=SHOW, save_every_n_frames=SAVE_EVERY_N_FRAMES):
|
||||
os.makedirs(save_dir, exist_ok=True)
|
||||
cam = search_get_device()
|
||||
cam.Open()
|
||||
# Load the User Set 1 user set
|
||||
cam.UserSetSelector.Value = "UserSet1"
|
||||
cam.UserSetLoad.Execute()
|
||||
cam.MaxNumBuffer = 30
|
||||
|
||||
converter = pylon.ImageFormatConverter()
|
||||
converter.OutputPixelFormat = pylon.PixelType_BGR8packed
|
||||
converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned
|
||||
|
||||
# 启动异步处理线程
|
||||
t = threading.Thread(target=worker, args=(save_dir, save_every_n_frames, show), daemon=True)
|
||||
t.start()
|
||||
|
||||
cam.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)
|
||||
frame_count = 0
|
||||
try:
|
||||
while cam.IsGrabbing() and not exit_event.is_set():
|
||||
grab_result = cam.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
|
||||
if grab_result.GrabSucceeded():
|
||||
image = converter.Convert(grab_result)
|
||||
img = image.GetArray()
|
||||
frame_count += 1
|
||||
|
||||
# 拷贝一份到队列
|
||||
if not frame_queue.full():
|
||||
frame_queue.put((img.copy(), frame_count))
|
||||
grab_result.Release()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("被 Ctrl+C 中断")
|
||||
cam.StopGrabbing()
|
||||
cam.Close()
|
||||
exit_event.set()
|
||||
|
||||
finally:
|
||||
cam.StopGrabbing()
|
||||
cam.Close()
|
||||
# 通知线程退出
|
||||
frame_queue.put(None)
|
||||
t.join()
|
||||
print(f"共采集 {frame_count} 帧")
|
||||
|
||||
# =================== 主入口 ===================
|
||||
if __name__ == "__main__":
|
||||
continuous_grab()
|
||||
Reference in New Issue
Block a user