# project joee 开发日志 09.25
# 需求
将原本采集卡连接单个摄像头的方案修改为:采集卡连接两个摄像头,并且将两个摄像头采集到的图像信息合并成一张图像。
# -part1 - 需求分析
# 1. 驱动调用
首先要修改采集卡调用部分的代码,使得采集卡 Devices::Grabber 部分能够接收和区分不同摄像头的句柄,并且调用相关 API 时加以区分这部分应该不难实现。
# 2. 回调处理
其次当采集卡产生回调时,应根据不同摄像头相同序号的帧进行帧同步,标识出两个相同时刻的帧,问题在于,两个摄像头产生的缓冲区图像能否保证是在同一时刻产生的,以及采集卡缓冲区应该设置为多大。
查阅开发手册:
# 2.1. 图像缓冲区的三种状态:
Empty 空状态,意味着当前缓冲区没有相机采集到的图像数据
Full 满状态,意味着当前缓冲区已经被相机采集到的图像数据填满
Transfer 传输状态,意味着相机正在向该缓冲区内传输数据
用户可以通过 IKapGetBufferStatus 来获取指定传输缓冲区的状态。
# 2.2. 图像缓冲区的状态切换
图像缓冲区的状态会在如下时刻切换:
图像采集 启动 时,所有图像缓冲区被设置为 Empty
当一帧完整的数据被传输到该图像缓冲区后,设置该图像缓冲区状态为 Full
当图像数据正在向该图像缓冲区传输时,设置该图像缓冲区状态为 Transfer , 对于 线扫描相机 ,可以在 Transfer 状态获取图像缓冲区已经传输的有效行数
当 IKEvent_FrameReady 的回调函数执行完成后(无论是否设置),都会自动设置图像缓冲区状态为 Empty



1 2 3 4
| int transfer_mode = (int)FrameTransferMode.IKP_FRAME_TRAANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT; CheckIKapBoard(IKapBoard.IKapSetInfo(m_hBoard,(uint)INFO_ID.IKP_FRAME_TRANSFER_MODE,transfer_mode));
|
配置参数的相关代码
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
| private void Configure(IntPtr m_hBoard) {
CheckIKapBoard(IKapBoard.IKapLoadConfigurationFromFile(m_hBoard, Application.StartupPath + "\\parameter\\" + configFileName + ".vlcf"));
CheckIKapBoard(IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_COUNT, m_nTotalFrameCount));
int timeout = -1; CheckIKapBoard(IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_TIME_OUT, timeout));
int grab_mode = (int)GrabMode.IKP_GRAB_NON_BLOCK; CheckIKapBoard(IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_GRAB_MODE, grab_mode));
int transfer_mode = (int)FrameTransferMode.IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT; CheckIKapBoard(IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, transfer_mode));
int ret; ret = IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_IMAGE_WIDTH, ref nWidth); CheckIKapBoard(ret); ret = IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_IMAGE_HEIGHT, ref nHeight); CheckIKapBoard(ret);
}
|
当前使用的传输模式为
IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT
也就是第三种模式: 同步保护模式,
在这种模式下,需要建立一定的图像缓冲区,但是需要及时取出图像帧,如果要保证不会出现帧丢失,就要适当增加缓冲区大小。除此之外,还需要手动对图像进行编号,特别是当图像采集设备多于一个时,要对原有的图像编号逻辑进行更换,以保证图像帧同步。
# 3. 图像后处理
在确保帧同步之后,就需要对图像进行合并。
由于之前确定的方案为从内存中提取 bitmap 数据直接处理,但是官方源码给的方案是保存成位图文件,所以这部分需要进行额外一些操作。
1 2 3 4 5 6
| public System.Drawing.Imaging.BitmapData LockBits (System.Drawing.Rectangle rect, System.Drawing.Imaging.ImageLockMode flags, System.Drawing.Imaging.PixelFormat format);
|
对获取到的图像帧 A B 分别进行 LockBits 操作,使得能够直接对位图内存进行操作,然后通过逐行合并两个位图行得到新行,最后生成新的位图。
# -part2 - 处理过程
使用 API IKapBoard.IKapGetBoardCount 确定当前连接到的设备数量
1 2 3
| uint nPCIeDevCount = IKapBoard.IKapGetBoardCount( (int)BoardType.IKBoardPCIE, ref nPCIeDevCount);
|
之后部分就跟之前的差不多了,添加 for 循环语句,并在 pParam 参数字段中传入该设备的标识号,这样就能在回调中识别该帧是由哪个设备产生的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| for (uint i = 0; i < nPCIeDevCount; i++) { IntPtr m_hBoard = IKapBoard.IKapOpen((int)BoardType.IKBoardPCIE, i); if (m_hBoard.Equals(new IntPtr(-1))) { log._.Info("Opening Camera ..."); OpenDevice(m_hBoard); log._.Info("Configuring Camera ..."); Configure(m_hBoard); RegisterCallback(m_hBoard,(IntPtr) i); } }
|
现在应该能识别到多个采集设备了,后续要到能够进行远程设备连接才能进行测试了。
图像后处理部分,根据需求更改再决定是否添加。