import numpy as np
import struct
import json
import os
import sys
import time
from datetime import datetime
def save_dark_cal_with_header(calibration_data, filename, camera_model="ICX285"):
"""
保存工业相机暗场校准文件(含可读文本头)
参数:
calibration_data: 字典列表,每个字典包含:
'exposure_ms': 曝光时间(毫秒)
'dark_frame': 暗场图像(numpy uint16数组)
'sensor_temp': 传感器温度(℃)
'timestamp': 采集时间戳(可选)
filename: 输出文件名
camera_model: 相机型号标识
"""
# 验证输入数据
if not calibration_data:
raise ValueError("校准数据不能为空")
# 创建文本头信息
text_header = create_text_header(calibration_data, camera_model)
# 创建二进制数据块
binary_data = create_binary_data(calibration_data)
# 原子写入文件
temp_filename = f"{filename}.tmp"
try:
with open(temp_filename, 'wb') as f:
# 写入文本头(UTF-8编码)
f.write(text_header.encode('ANSI'))
# 写入分隔符(标记文本头结束)
f.write(b'\n\nBINARY_DATA_START\n\n')
# 写入二进制数据
f.write(binary_data)
# 原子操作重命名
os.replace(temp_filename, filename)
return True
except Exception as e:
print(f"保存失败: {str(e)}")
if os.path.exists(temp_filename):
os.remove(temp_filename)
return False
def create_text_header(calibration_data, camera_model):
"""创建可读文本头文件"""
# 基础信息
header = f"Industrial Dark Calibration File\n"
header += f"Camera Model: {camera_model}\n"
header += f"Creation Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
header += f"Frame Count: {len(calibration_data)}\n"
# 图像尺寸信息
width = calibration_data[0]['dark_frame'].shape[1]
height = calibration_data[0]['dark_frame'].shape[0]
header += f"Image Size: {width}x{height} pixels\n"
header += f"Data Type: uint16\n"
header += f"Byte Order: {sys.byteorder}-endian\n\n"
# 校准帧详细信息
header += "Calibration Frames:\n"
header += "Index | Exposure(ms) | Temperature(℃) | Timestamp\n"
header += "------|-------------|----------------|-----------------------\n"
for i, data in enumerate(calibration_data):
timestamp = datetime.fromtimestamp(
data.get('timestamp', time.time())
).strftime('%Y-%m-%d %H:%M:%S')
header += (
f"{i + 1:5} | "
f"{data['exposure_ms']:11.2f} | "
f"{data['sensor_temp']:14.1f} | "
f"{timestamp}\n"
)
# 添加注释和元数据
header += "\nNotes:\n"
header += "1. Binary data starts after 'BINARY_DATA_START' marker\n"
header += "2. Each frame is stored as: [exposure(4B)][width(4B)][height(4B)][data]\n"
header += "3. Exposure time stored as float32 (milliseconds)\n"
return header
def create_binary_data(calibration_data):
"""创建二进制数据块"""
binary_data = bytearray()
endian = '<' if sys.byteorder == 'little' else '>'
frame_format = f'{endian}fII' # 曝光(ms), 宽度, 高度
for data in calibration_data:
frame = data['dark_frame']
width, height = frame.shape[1], frame.shape[0]
# 打包帧头
frame_header = struct.pack(
frame_format,
data['exposure_ms'],
width,
height
)
# 添加帧头和图像数据
binary_data.extend(frame_header)
binary_data.extend(frame.tobytes())
return binary_data
# 使用示例
if __name__ == "__main__":
# 创建不同曝光的暗场数据
calibration_data = [
{
'exposure_ms': 2.0,
'dark_frame': np.random.randint(0, 100, (768, 1024), dtype=np.uint16),
'sensor_temp': 25.0
},
{
'exposure_ms': 50.0,
'dark_frame': np.random.randint(0, 500, (768, 1024), dtype=np.uint16),
'sensor_temp': 25.3
},
{
'exposure_ms': 200.0,
'dark_frame': np.random.randint(0, 2000, (768, 1024), dtype=np.uint16),
'sensor_temp': 26.1
}
]
# 保存带文本头的校准文件
success = save_dark_cal_with_header(
calibration_data,
"industrial_dark_calibration.dcl",
camera_model="IMX342"
)
if success:
print("带文本头的暗场校准文件保存成功!")
print("可用文本编辑器查看文件头部信息")
读取以上程序生成的暗场校准文件,用于图像暗场校准
最新发布