您好!我理解您需要完整的 `.py` 文件来操作海康双目相机。由于直接提供完整的代码需要考虑您的具体环境(如相机型号、SDK版本、系统平台),我将为您提供一个**通用且完整的 Python 脚本模板**,它包含了:
1. **SDK 加载**(Windows/Linux 兼容写法)
2. **设备发现与连接**
3. **图像采集与显示**(使用 OpenCV)
4. **资源释放与错误处理**
您可以根据自己的实际情况调整以下部分:
- `SDK 路径`
- `相机 IP 地址/序列号`
- `图像分辨率、帧率等参数`
---
### **完整代码文件:`hik_stereo_camera.py`**
```python
#!/usr/bin/env python3
"""
海康威视(Hikvision)双目相机采集示例
环境要求:
1. 安装海康官方 SDK(MVViewer 或 MVS 开发包)
2. 将 SDK 的 `MvCameraControl.h` 和动态库文件放入指定路径
3. 安装 Python 包:pip install opencv-python numpy
"""
import sys
import os
import ctypes
import numpy as np
import cv2
# ==================== 1. 加载海康 SDK ====================
# 请根据您的 SDK 安装路径修改以下路径
if sys.platform == "win32":
SDK_PATH = r"C:\Program Files\MVS\Development\Samples\Python\MvImport"
DLL_PATH = os.path.join(SDK_PATH, "MvCameraControl.dll")
else: # Linux
SDK_PATH = "/opt/MVS/Samples/64/Python/MvImport"
DLL_PATH = os.path.join(SDK_PATH, "libMvCameraControl.so")
# 添加 SDK 路径到系统路径
sys.path.append(SDK_PATH)
try:
from MvCameraControl_class import *
except ImportError as e:
print(f"错误:无法导入海康 SDK 模块,请检查路径:{SDK_PATH}")
print(f"详细错误:{e}")
sys.exit(1)
# 加载动态库
if not os.path.exists(DLL_PATH):
print(f"错误:未找到海康 SDK 动态库,请检查路径:{DLL_PATH}")
sys.exit(1)
# ==================== 2. 相机操作类 ====================
class HikStereoCamera:
def __init__(self):
self.cam_handle = None
self.is_connected = False
def discover_cameras(self):
"""发现局域网内的海康相机设备"""
device_list = MV_CC_DEVICE_INFO_LIST()
ret = MvCamera.MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, device_list)
if ret != 0:
print("错误:枚举设备失败,错误码:", ret)
return []
cameras = []
for i in range(device_list.nDeviceNum):
device_info = device_list.pDeviceInfo[i]
if device_info.nTLayerType == MV_GIGE_DEVICE:
# 千兆网相机
chUserDefinedName = ""
for j in range(device_info.SpecialInfo.stGigEInfo.chUserDefinedName):
chUserDefinedName += chr(device_info.SpecialInfo.stGigEInfo.chUserDefinedName[j])
ip_addr = ".".join(map(str, device_info.SpecialInfo.stGigEInfo.nCurrentIp))
cameras.append({
'index': i,
'type': 'GigE',
'name': chUserDefinedName,
'ip': ip_addr,
'serial': device_info.SpecialInfo.stGigEInfo.chSerialNumber.decode('ascii')
})
elif device_info.nTLayerType == MV_USB_DEVICE:
# USB相机
cameras.append({
'index': i,
'type': 'USB',
'name': device_info.SpecialInfo.stUsb3VInfo.chUserDefinedName.decode('utf-8'),
'serial': device_info.SpecialInfo.stUsb3VInfo.chSerialNumber.decode('ascii')
})
return cameras
def connect(self, camera_index=0):
"""连接指定索引的相机"""
device_list = MV_CC_DEVICE_INFO_LIST()
ret = MvCamera.MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, device_list)
if ret != 0 or device_list.nDeviceNum == 0:
print("错误:未找到可用相机设备")
return False
if camera_index >= device_list.nDeviceNum:
print(f"错误:相机索引 {camera_index} 超出范围,共 {device_list.nDeviceNum} 个设备")
return False
# 创建相机实例
self.cam_handle = MvCamera()
device_info = device_list.pDeviceInfo[camera_index]
# 连接设备
ret = self.cam_handle.MV_CC_CreateHandle(device_info)
if ret != 0:
print("错误:创建设备句柄失败,错误码:", ret)
return False
ret = self.cam_handle.MV_CC_OpenDevice()
if ret != 0:
print("错误:打开设备失败,错误码:", ret)
return False
self.is_connected = True
print("相机连接成功!")
return True
def set_parameters(self):
"""设置相机参数(可根据需要修改)"""
if not self.is_connected:
return False
# 设置触发模式为连续采集(非触发模式)
ret = self.cam_handle.MV_CC_SetEnumValue("TriggerMode", 0)
if ret != 0:
print("警告:设置触发模式失败")
# 设置曝光时间(单位:微秒)
ret = self.cam_handle.MV_CC_SetFloatValue("ExposureTime", 10000.0)
if ret != 0:
print("警告:设置曝光时间失败")
# 设置增益
ret = self.cam_handle.MV_CC_SetFloatValue("Gain", 0.0)
if ret != 0:
print("警告:设置增益失败")
return True
def start_streaming(self):
"""开始采集图像流"""
if not self.is_connected:
return False
ret = self.cam_handle.MV_CC_StartGrabbing()
if ret != 0:
print("错误:开始采集失败,错误码:", ret)
return False
print("开始采集图像...")
return True
def get_frame(self, timeout=1000):
"""
获取一帧图像
返回: (ret, frame_left, frame_right)
"""
if not self.is_connected:
return False, None, None
stFrame = MV_FRAME_OUT()
ret = self.cam_handle.MV_CC_GetImageBuffer(stFrame, timeout)
if ret != 0:
return False, None, None
# 将原始数据转换为 numpy 数组
data = (ctypes.c_ubyte * stFrame.stFrameInfo.nFrameLen).from_address(stFrame.pBufAddr)
img_data = np.frombuffer(data, dtype=np.uint8)
# 根据图像格式转换(这里假设为 Mono8 或 BayerRG8)
if stFrame.stFrameInfo.enPixelType == PixelType_Gvsp_Mono8:
# 单目灰度图像
height = stFrame.stFrameInfo.nHeight
width = stFrame.stFrameInfo.nWidth
frame = img_data.reshape(height, width)
return True, frame, None
elif stFrame.stFrameInfo.enPixelType == PixelType_Gvsp_BayerRG8:
# Bayer 格式需要去马赛克
height = stFrame.stFrameInfo.nHeight
width = stFrame.stFrameInfo.nWidth
bayer_img = img_data.reshape(height, width)
frame = cv2.cvtColor(bayer_img, cv2.COLOR_BayerRG2RGB)
return True, frame, None
# 注意:双目相机可能需要特殊处理左右图像分离
# 具体取决于相机输出模式(左右拼接、独立流等)
# 释放缓冲区
self.cam_handle.MV_CC_FreeImageBuffer(stFrame)
return False, None, None
def stop_streaming(self):
"""停止采集"""
if not self.is_connected:
return
self.cam_handle.MV_CC_StopGrabbing()
print("停止采集")
def disconnect(self):
"""断开相机连接"""
if self.cam_handle:
self.stop_streaming()
self.cam_handle.MV_CC_CloseDevice()
self.cam_handle.MV_CC_DestroyHandle()
self.cam_handle = None
self.is_connected = False
print("相机已断开连接")
# ==================== 3. 主程序入口 ====================
def main():
print("=" * 50)
print("海康双目相机采集程序")
print("=" * 50)
# 创建相机实例
camera = HikStereoCamera()
# 发现设备
print("\n正在搜索相机设备...")
cameras = camera.discover_cameras()
if len(cameras) == 0:
print("未找到任何相机设备,请检查:")
print("1. 相机是否通电并连接网络/USB")
print("2. 防火墙是否允许相机通信")
print("3. 网卡是否在同一网段(对于网口相机)")
return
print(f"找到 {len(cameras)} 个相机设备:")
for i, cam in enumerate(cameras):
if cam['type'] == 'GigE':
print(f" [{i}] {cam['name']} (IP: {cam['ip']}, SN: {cam['serial']})")
else:
print(f" [{i}] {cam['name']} (USB, SN: {cam['serial']})")
# 连接第一个相机(可修改为选择特定相机)
camera_index = 0
print(f"\n正在连接相机 [{camera_index}]...")
if not camera.connect(camera_index):
print("连接失败,程序退出")
return
# 设置参数
camera.set_parameters()
# 开始采集
if not camera.start_streaming():
camera.disconnect()
return
# 创建显示窗口
cv2.namedWindow("Hikvision Stereo Camera", cv2.WINDOW_NORMAL)
print("\n操作说明:")
print(" - 按 'S' 键保存当前帧")
print(" - 按 'Q' 或 ESC 键退出程序")
print("开始显示图像...")
frame_count = 0
save_count = 0
try:
while True:
# 获取一帧
ret, frame_left, frame_right = camera.get_frame(timeout=500)
if ret and frame_left is not None:
frame_count += 1
# 显示帧率
if frame_count % 30 == 0:
print(f"已采集 {frame_count} 帧", end='\r')
# 显示图像
display_frame = frame_left
if len(frame_left.shape) == 2: # 灰度图转彩色显示
display_frame = cv2.cvtColor(frame_left, cv2.COLOR_GRAY2BGR)
# 添加文字信息
cv2.putText(display_frame, f"Frame: {frame_count}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow("Hikvision Stereo Camera", display_frame)
# 键盘控制
key = cv2.waitKey(1) & 0xFF
if key == ord('q') or key == 27: # Q 或 ESC
break
elif key == ord('s'): # 保存图像
if ret and frame_left is not None:
filename = f"capture_{save_count:04d}.png"
cv2.imwrite(filename, frame_left)
print(f"图像已保存: {filename}")
save_count += 1
except KeyboardInterrupt:
print("\n用户中断程序")
except Exception as e:
print(f"程序运行出错: {e}")
finally:
# 清理资源
cv2.destroyAllWindows()
camera.disconnect()
print("\n程序正常退出")
# ==================== 4. 脚本执行 ====================
if __name__ == "__main__":
main()
```
---
### **使用说明:**
1. **环境准备**:
```bash
pip install opencv-python numpy
```
2. **SDK配置**:
- 从海康官网下载并安装 MVS(机器视觉软件包)
- 修改代码中的 `SDK_PATH` 指向您的 SDK 安装路径
- 确保 `MvCameraControl_class.py` 在 SDK_PATH 中
3. **运行程序**:
```bash
python hik_stereo_camera.py
```
4. **关键调整点**:
- 如果是**双目相机**,可能需要修改 `get_frame()` 方法中的图像分离逻辑
- 如需**左右图像分离**,请参考相机 SDK 文档中的多流采集示例
- 可调整曝光、增益等参数在 `set_parameters()` 中
---
### **下一步建议**:
1. 先运行此脚本测试基础连接
2. 如果遇到错误,请提供:
- 错误信息截图
- 您的相机具体型号
- 操作系统版本(Windows/Linux)
3. 根据您的具体需求,我可以帮您:
- 修改为双目分离采集
- 添加深度计算功能
- 实现录制视频功能
您可以直接将此代码保存为 `.py` 文件并在 PyCharm 中运行。需要我针对某个部分进一步解释吗? 😊