傳感器同步
目前主要有兩種方法來(lái)同步不同傳感器的信息(幀、IMU數(shù)據(jù)包、ToF等):
- 硬件同步(基于硬件信號(hào)觸發(fā),同步精度較高,需要硬件支持)
- 軟件同步(基于時(shí)間戳或序列號(hào)同步,同步精度較低,無(wú)需硬件支持)
此博客重點(diǎn)介紹硬件同步,它允許在多個(gè)相機(jī)傳感器之間精確同步,并可能與其他硬件同步,如閃光燈LED、外部IMU或其他相機(jī)。
硬件同步信號(hào)
FSYNC信號(hào)
FSYNC/FSIN(幀同步)信號(hào)是一個(gè)脈沖,在開(kāi)始捕獲每個(gè)幀時(shí)被驅(qū)動(dòng)為高電平。它的長(zhǎng)度與曝光時(shí)間不成正比,可以是輸入或輸出,工作電壓是1.8V。
在雙目立體相機(jī)(OAK-D*)上,我們希望雙目黑白相機(jī)是完全同步的,所以一個(gè)相機(jī)傳感器(如左相機(jī))的FSYNC設(shè)置為INPUT(輸入),而另一個(gè)相機(jī)傳感器(如右相機(jī))的FSYNC設(shè)置為OUTPUT(輸出)。在這樣的配置中,右相機(jī)驅(qū)動(dòng)左相機(jī)。
注意:目前,只有OV9282/OV9782可以輸出FSYNC信號(hào),而IMX378/477/577/等應(yīng)該也有這個(gè)能力,但還不支持(所以這些信號(hào)不能驅(qū)動(dòng)FSYNC信號(hào),只能被它驅(qū)動(dòng))。AR0234只支持輸入FSYNC信號(hào)。
如果我們想用外部信號(hào)驅(qū)動(dòng)相機(jī),我們需要將FSIN設(shè)置為相機(jī)傳感器的INPUT。將一個(gè)信號(hào)發(fā)生器連接到所有的FSIN引腳上,這樣相機(jī)將根據(jù)信號(hào)發(fā)生器的觸發(fā)信號(hào)捕獲每一幀圖像。
STROBE信號(hào)
STROBE信號(hào)是圖像傳感器的輸出,在圖像傳感器的曝光期間是有效的(高電平)。它可以用來(lái)驅(qū)動(dòng)外部的LED照明,所以照明只在曝光時(shí)間內(nèi)激活,而不是持續(xù)開(kāi)啟,這將減少功耗和發(fā)熱。
在OAK-D-Pro系列相機(jī)上使用STROBE信號(hào)(它有板載照明紅外LED和紅外激光點(diǎn)陣發(fā)射器)來(lái)驅(qū)動(dòng)激光/LED。
硬件接線
硬件設(shè)備
我們使用的硬件設(shè)備如下:
OV9782廣角相機(jī) × 4
OAK-FFC-4P攝像頭模組 × 1
OV9782廣角相機(jī)產(chǎn)品特點(diǎn):
- CMOS感光
- 全局快門(mén)
- 最大幀率:120 FPS
- 最大分辨率: 1MP(1280×800)
- DFOV:89.5°
- HFOV:80°
- VFOV:55°
- 對(duì)焦范圍:固定焦點(diǎn):19.6 cm – ∞
OAK-FFC-4P攝像頭模組屬于分體式OAK,可以通過(guò)軟排線接入4個(gè)獨(dú)立的MIPI相機(jī)模塊,其產(chǎn)品特點(diǎn)有:
- 4T算力;
- 4K H.265推流;
- 厘米級(jí)測(cè)量精度;
- 支持的平臺(tái)和語(yǔ)言:Windows10、Ubuntu、樹(shù)莓派、linux、macOS、Jetson、Python、C++、ROS、Android(需depthai≥2.16.0)。
接線步驟
1、首先,使用跳線將每根電纜上的 FSIN 測(cè)試點(diǎn)連接到相應(yīng)相機(jī)板上的 FSIN 引腳(也可以直接將相機(jī)板上的所有FSIN引腳直接相連):
2、然后,將4個(gè)OV9782廣角相機(jī)通過(guò)排線連接到OAK-FFC-4P攝像頭模組:
3、最后,給攝像頭模組供電,并通過(guò)USB接入電腦PC中。
軟件驅(qū)動(dòng)
編寫(xiě)測(cè)試代碼和打印設(shè)備時(shí)間戳,camera_driver.py
文件如下:
import depthai as dai
import time
import cv2
import collections
set_fps = 30
class FPS:
def __init__(self, window_size=30):
self.dq = collections.deque(maxlen=window_size)
self.fps = 0
def update(self, timestamp=None):
if timestamp == None: timestamp = time.monotonic()
count = len(self.dq)
if count > 0: self.fps = count / (timestamp - self.dq[0])
self.dq.append(timestamp)
def get(self):
return self.fps
cam_list = ['rgb', 'left', 'right', 'camd']
cam_socket_opts = {
'rgb' : dai.CameraBoardSocket.RGB, # Or CAM_A
'left' : dai.CameraBoardSocket.LEFT, # Or CAM_B
'right': dai.CameraBoardSocket.RIGHT, # Or CAM_C
'camd' : dai.CameraBoardSocket.CAM_D,
}
pipeline = dai.Pipeline()
cam = {}
xout = {}
for c in cam_list:
cam[c] = pipeline.create(dai.node.MonoCamera)
cam[c].setResolution(dai.MonoCameraProperties.SensorResolution.THE_800_P)
if c == 'rgb':
cam[c].initialControl.setFrameSyncMode(dai.CameraControl.FrameSyncMode.OUTPUT)
else:
cam[c].initialControl.setFrameSyncMode(dai.CameraControl.FrameSyncMode.INPUT)
cam[c].setBoardSocket(cam_socket_opts[c])
xout[c] = pipeline.create(dai.node.XLinkOut)
xout[c].setStreamName(c)
cam[c].out.link(xout[c].input)
config = dai.Device.Config()
config.board.gpio[6] = dai.BoardConfig.GPIO(dai.BoardConfig.GPIO.OUTPUT,
dai.BoardConfig.GPIO.Level.HIGH)
with dai.Device(config) as device:
device.startPipeline(pipeline)
q = {}
fps_host = {} # FPS computed based on the time we receive frames in app
fps_capt = {} # FPS computed based on capture timestamps from device
for c in cam_list:
q[c] = device.getOutputQueue(name=c, maxSize=1, blocking=False)
cv2.namedWindow(c, cv2.WINDOW_NORMAL)
cv2.resizeWindow(c, (640, 480))
fps_host[c] = FPS()
fps_capt[c] = FPS()
while True:
frame_list = []
for c in cam_list:
pkt = q[c].tryGet()
if pkt is not None:
fps_host[c].update()
fps_capt[c].update(pkt.getTimestamp().total_seconds())
print(c+":",pkt.getTimestampDevice())
frame = pkt.getCvFrame()
cv2.imshow(c, frame)
print("-------------------------------")
# print("\rFPS:",
# *["{:6.2f}|{:6.2f}".format(fps_host[c].get(), fps_capt[c].get()) for c in cam_list],
# end='', flush=True)
key = cv2.waitKey(1)
if key == ord('q'):
break
運(yùn)行文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-698993.html
python camera_driver.py
參考文獻(xiàn)
1、通過(guò)硬件觸發(fā)信號(hào)實(shí)現(xiàn)OAK多相機(jī)之間的同步拍攝
2、官方文檔:硬件同步
3、官方文檔:oak-ffc-4p
4、原理圖
5、oak_deptahi_external_trigger_fsync.py文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-698993.html
#!/usr/bin/env python3
import depthai as dai
import cv2
import time
pipeline = dai.Pipeline()
camRgb = pipeline.create(dai.node.ColorCamera)
camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.RGB)
camRgb.setIspScale(2,3)
camRgb.initialControl.setFrameSyncMode(dai.CameraControl.FrameSyncMode.INPUT)
camRgb.initialControl.setExternalTrigger(4,3)
xoutRgb = pipeline.create(dai.node.XLinkOut)
xoutRgb.setStreamName("color")
camRgb.isp.link(xoutRgb.input)
monoLeft = pipeline.create(dai.node.MonoCamera)
monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P)
monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
monoLeft.initialControl.setFrameSyncMode(dai.CameraControl.FrameSyncMode.INPUT)
monoLeft.initialControl.setExternalTrigger(4,3)
xoutLeft = pipeline.create(dai.node.XLinkOut)
xoutLeft.setStreamName("left")
monoLeft.out.link(xoutLeft.input)
monoRight = pipeline.createMonoCamera()
monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P)
monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)
monoRight.initialControl.setFrameSyncMode(dai.CameraControl.FrameSyncMode.INPUT)
monoRight.initialControl.setExternalTrigger(4,3)
xoutRight = pipeline.create(dai.node.XLinkOut)
xoutRight.setStreamName("right")
monoRight.out.link(xoutRight.input)
# Connect to device with pipeline
with dai.Device(pipeline) as device:
arr = ['left', 'right', 'color']
queues = {}
frames = {}
for name in arr:
queues[name] = device.getOutputQueue(name)
print("Starting...")
while True:
for name in arr:
if queues[name].has():
frames[name]=queues[name].get().getCvFrame()
for name, frame in frames.items():
cv2.imshow(name, frame)
key = cv2.waitKey(1)
if key == ord('q'):
break
到了這里,關(guān)于計(jì)算機(jī)視覺(jué):OAK多相機(jī)硬件同步拍攝的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!