EDSDK Python:如何将相机图像加载至系统内存而非磁盘?
直接将EDSDK拍摄的图像存入Python数据结构的可行方案
可以实现直接将图像存入Python数据结构,核心问题在于内存流的生命周期管理和跨线程数据安全传递,以下是修复后的实现方案:
关键问题分析
- 你当前的代码中,内存流
out在回调内创建但未完成数据提取,回调结束后EDSDK会回收相关资源,外部访问会导致崩溃 time.sleep(4)是不可靠的等待方式,无法确保回调执行完成- 未正确释放EDSDK资源(如相机列表、会话等),可能导致相机无响应
修复后的完整代码
首先导入必要模块:
import edsdk from edsdk import ObjectEvent, PropID, SaveTo, CameraCommand import pythoncom import os from queue import Queue import numpy as np from PIL import Image
定义线程安全队列用于传递图像数据,以及回调函数:
# 线程安全队列,用于从回调传递图像数据到主程序 image_queue = Queue() def callback_object(event: ObjectEvent, object_handle: edsdk.EdObject) -> int: if event == ObjectEvent.DirItemCreated: dir_item_info = edsdk.GetDirectoryItemInfo(object_handle) # 创建内存流并下载图像 out_stream = edsdk.CreateMemoryStream(dir_item_info["size"]) edsdk.Download(object_handle, dir_item_info["size"], out_stream) edsdk.DownloadComplete(object_handle) # 从内存流读取原始数据 raw_data = edsdk.ReadStream(out_stream, 0, dir_item_info["size"]) # 获取图像信息,转换为Python可处理的格式 image_info = edsdk.GetImageInfo(object_handle) # JPEG格式直接转PIL Image if image_info["imageType"] == edsdk.ImageType.JPEG: img = Image.frombytes("RGB", (image_info["width"], image_info["height"]), raw_data) image_queue.put(img) # RAW格式需额外处理(需安装rawpy库) # elif image_info["imageType"] == edsdk.ImageType.RAW: # import rawpy # with rawpy.imread(raw_data) as raw: # img_np = raw.postprocess() # image_queue.put(img_np) # 必须释放EDSDK资源 edsdk.Release(out_stream) edsdk.Release(object_handle) return 0
主程序逻辑:
def main(): edsdk.InitializeSDK() try: cam_list = edsdk.GetCameraList() cam_count = edsdk.GetChildCount(cam_list) if cam_count == 0: print("未检测到相机") return cam = edsdk.GetChildAtIndex(cam_list, 0) edsdk.OpenSession(cam) # 设置保存到主机 edsdk.SetPropertyData(cam, PropID.SaveTo, 0, SaveTo.Host) # 设置对象事件回调 edsdk.SetObjectEventHandler(cam, ObjectEvent.DirItemCreated, callback_object) # 发送拍照命令 edsdk.SendCommand(cam, CameraCommand.TakePicture, 0) # 等待回调完成并获取图像,超时10秒 print("等待图像数据...") try: img = image_queue.get(timeout=10) print("成功获取图像,尺寸:", img.size) # 此处可直接使用img进行后续处理(如分析、显示) # img.show() except: print("获取图像超时") # 清理资源 edsdk.CloseSession(cam) edsdk.Release(cam) edsdk.Release(cam_list) finally: edsdk.TerminateSDK() if __name__ == "__main__": if os.name == "nt": pythoncom.CoInitialize() main() if os.name == "nt": pythoncom.CoUninitialize()
核心注意事项
- 资源释放:所有通过EDSDK创建/获取的对象(内存流、目录项、相机、相机列表)必须调用
edsdk.Release()释放,否则会导致内存泄漏或相机锁死 - 回调内完成数据提取:必须在回调函数内部完成内存流的数据读取,回调结束后EDSDK会回收相关资源,外部访问会崩溃
- 线程安全传递:使用
queue.Queue实现回调(EDSDK线程)和主程序线程之间的安全数据传递 - 避免硬等待:不要用
time.sleep(),改用队列的get(timeout)或事件通知来等待回调完成 - 图像格式处理:根据相机设置的图像格式(JPEG/RAW)选择对应的转换方式,RAW格式需要额外依赖库(如
rawpy)
内容的提问来源于stack exchange,提问作者maycookie
相关产品推荐
相关产品推荐

