Software Stack
DepthAI

ON THIS PAGE

  • Stereo Depth from host
  • Demo
  • Setup
  • Source code
  • Similar samples
  • Pipeline

Stereo Depth from host

This example runs stereo disparity matching on-device using stereo pair images from the host computer. Stereo pair images are pre-rectified, so device doesn't need to perform rectified.There are 3 depth modes which you can select inside the code:
  • lr_check: used for better occlusion handling. For more information click here
  • extended_disparity: suitable for short range objects. For more information click here
  • subpixel: suitable for long range. For more information click here
Example uses opencv's sliders which let user easily configure many stereo settings, and see live result in real time.

Demo

Setup

This example requires the DepthAI v3 API, see installation instructions.This example also requires dataset folder - you can download it from here

Source code

Python

Python

Python
GitHub
1#!/usr/bin/env python3
2
3import cv2
4import numpy as np
5import depthai as dai
6from time import sleep
7import datetime
8import argparse
9from pathlib import Path
10import math
11import os, re
12import csv
13import datetime
14
15datasetDefault = str((Path(__file__).parent / Path("../models/dataset")).resolve().absolute())
16parser = argparse.ArgumentParser()
17parser.add_argument("-p", "--dataset", nargs="?", help="Path to recorded frames", default=None)
18parser.add_argument("-d", "--debug", action="store_true", help="Enable debug outputs.")
19parser.add_argument("-e", "--evaluate", help="Evaluate the disparity calculation.", default=None)
20parser.add_argument("-dumpdispcost", "--dumpdisparitycostvalues", action="store_true", help="Dumps the disparity cost values for each disparity range. 96 byte for each pixel.")
21parser.add_argument("--download", action="store_true", help="Downloads the 2014 Middlebury dataset.")
22parser.add_argument("--calibration", help="Path to calibration file", default=None)
23parser.add_argument("--rectify", action="store_true", help="Enable rectified streams")
24parser.add_argument("--swapLR", action="store_true", help="Swap left and right cameras.")
25args = parser.parse_args()
26
27if args.evaluate is not None and args.dataset is not None:
28    import sys
29    raise ValueError("Cannot use both --dataset and --evaluate arguments at the same time.")
30
31evaluation_mode = args.evaluate is not None
32args.dataset = args.dataset or datasetDefault
33
34if args.download and args.evaluate is None:
35    import sys
36    raise ValueError("Cannot use --download without --evaluate argument.")
37
38if args.evaluate is None and not Path(args.dataset).exists():
39    import sys
40    raise FileNotFoundError(f"Required file/s not found, please run '{sys.executable} install_requirements.py'")
41
42if args.evaluate is not None and not args.download and not Path(args.evaluate).exists():
43    import sys
44    raise FileNotFoundError(f"Evaluation dataset path does not exist, use the --evaluate argument to specify the path.")
45
46if args.evaluate is not None and args.download and not Path(args.evaluate).exists():
47    os.makedirs(args.evaluate)
48
49def download_2014_middlebury(data_path):
50    import requests, zipfile, io
51    url = "https://vision.middlebury.edu/stereo/data/scenes2014/zip/"
52    r = requests.get(url)
53    c = r.content
54    reg = re.compile(r"href=('|\")(.+\.zip)('|\")")
55    matches = reg.findall(c.decode("utf-8"))
56    files = [m[1] for m in matches]
57
58    for f in files:
59        if os.path.isdir(os.path.join(data_path, f[:-4])):
60            print(f"Skipping {f}")
61        else:
62            print(f"Downloading {f} from {url + f}")
63            r = requests.get(url + f)
64            print(f"Extracting {f} to {data_path}")
65            z = zipfile.ZipFile(io.BytesIO(r.content))
66            z.extractall(data_path)
67
68if args.download:
69    download_2014_middlebury(args.evaluate)
70    if not evaluation_mode:
71        sys.exit(0)
72
73class StereoConfigHandlerRVC2:
74
75    class Trackbar:
76        def __init__(self, trackbarName, windowName, minValue, maxValue, defaultValue, handler):
77            self.min = minValue
78            self.max = maxValue
79            self.windowName = windowName
80            self.trackbarName = trackbarName
81            cv2.createTrackbar(trackbarName, windowName, minValue, maxValue, handler)
82            cv2.setTrackbarPos(trackbarName, windowName, defaultValue)
83
84        def set(self, value):
85            if value < self.min:
86                value = self.min
87                print(f"{self.trackbarName} min value is {self.min}")
88            if value > self.max:
89                value = self.max
90                print(f"{self.trackbarName} max value is {self.max}")
91            cv2.setTrackbarPos(self.trackbarName, self.windowName, value)
92
93    class CensusMaskHandler:
94
95        stateColor = [(0, 0, 0), (255, 255, 255)]
96        gridHeight = 50
97        gridWidth = 50
98
99        def fillRectangle(self, row, col):
100            src = self.gridList[row][col]["topLeft"]
101            dst = self.gridList[row][col]["bottomRight"]
102
103            stateColor = self.stateColor[1] if self.gridList[row][col]["state"] else self.stateColor[0]
104            self.changed = True
105
106            cv2.rectangle(self.gridImage, src, dst, stateColor, -1)
107            cv2.imshow(self.windowName, self.gridImage)
108
109
110        def clickCallback(self, event, x, y, flags, param):
111            if event == cv2.EVENT_LBUTTONDOWN:
112                col = x * (self.gridSize[1]) // self.width
113                row = y * (self.gridSize[0]) // self.height
114                self.gridList[row][col]["state"] = not self.gridList[row][col]["state"]
115                self.fillRectangle(row, col)
116
117
118        def __init__(self, windowName, gridSize):
119            self.gridSize = gridSize
120            self.windowName = windowName
121            self.changed = False
122
123            cv2.namedWindow(self.windowName)
124
125            self.width = StereoConfigHandlerRVC2.CensusMaskHandler.gridWidth * self.gridSize[1]
126            self.height = StereoConfigHandlerRVC2.CensusMaskHandler.gridHeight * self.gridSize[0]
127
128            self.gridImage = np.zeros((self.height + 50, self.width, 3), np.uint8)
129
130            cv2.putText(self.gridImage, "Click on grid to change mask!", (0, self.height+20), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255))
131            cv2.putText(self.gridImage, "White: ON   |   Black: OFF", (0, self.height+40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255))
132
133            self.gridList = [[dict() for _ in range(self.gridSize[1])] for _ in range(self.gridSize[0])]
134
135            for row in range(self.gridSize[0]):
136                rowFactor = self.height // self.gridSize[0]
137                srcY = row*rowFactor + 1
138                dstY = (row+1)*rowFactor - 1
139                for col in range(self.gridSize[1]):
140                    colFactor = self.width // self.gridSize[1]
141                    srcX = col*colFactor + 1
142                    dstX = (col+1)*colFactor - 1
143                    src = (srcX, srcY)
144                    dst = (dstX, dstY)
145                    self.gridList[row][col]["topLeft"] = src
146                    self.gridList[row][col]["bottomRight"] = dst
147                    self.gridList[row][col]["state"] = False
148                    self.fillRectangle(row, col)
149
150            cv2.setMouseCallback(self.windowName, self.clickCallback)
151            cv2.imshow(self.windowName, self.gridImage)
152
153        def getMask(self) -> np.uint64:
154            mask = np.uint64(0)
155            for row in range(self.gridSize[0]):
156                for col in range(self.gridSize[1]):
157                    if self.gridList[row][col]["state"]:
158                        pos = row*self.gridSize[1] + col
159                        mask = np.bitwise_or(mask, np.uint64(1) << np.uint64(pos))
160
161            return mask
162
163        def setMask(self, _mask: np.uint64):
164            mask = np.uint64(_mask)
165            for row in range(self.gridSize[0]):
166                for col in range(self.gridSize[1]):
167                    pos = row*self.gridSize[1] + col
168                    if np.bitwise_and(mask, np.uint64(1) << np.uint64(pos)):
169                        self.gridList[row][col]["state"] = True
170                    else:
171                        self.gridList[row][col]["state"] = False
172
173                    self.fillRectangle(row, col)
174
175        def isChanged(self):
176            changed = self.changed
177            self.changed = False
178            return changed
179
180        def destroyWindow(self):
181            cv2.destroyWindow(self.windowName)
182
183
184    censusMaskHandler = None
185    newConfig = False
186    config = None
187    trSigma = list()
188    trConfidence = list()
189    trLrCheck = list()
190    trFractionalBits = list()
191    trLineqAlpha = list()
192    trLineqBeta = list()
193    trLineqThreshold = list()
194    trCostAggregationP1 = list()
195    trCostAggregationP2 = list()
196    trTemporalAlpha = list()
197    trTemporalDelta = list()
198    trThresholdMinRange = list()
199    trThresholdMaxRange = list()
200    trSpeckleRange = list()
201    trSpatialAlpha = list()
202    trSpatialDelta = list()
203    trSpatialHoleFilling = list()
204    trSpatialNumIterations = list()
205    trDecimationFactor = list()
206    trDisparityShift = list()
207    trCenterAlignmentShift = list()
208    trInvalidateEdgePixels = list()
209
210    def trackbarSigma(value):
211        StereoConfigHandlerRVC2.config.postProcessing.bilateralSigmaValue = value
212        StereoConfigHandlerRVC2.newConfig = True
213        for tr in StereoConfigHandlerRVC2.trSigma:
214            tr.set(value)
215
216    def trackbarConfidence(value):
217        StereoConfigHandlerRVC2.config.costMatching.confidenceThreshold = value
218        StereoConfigHandlerRVC2.newConfig = True
219        for tr in StereoConfigHandlerRVC2.trConfidence:
220            tr.set(value)
221
222    def trackbarLrCheckThreshold(value):
223        StereoConfigHandlerRVC2.config.algorithmControl.leftRightCheckThreshold = value
224        StereoConfigHandlerRVC2.newConfig = True
225        for tr in StereoConfigHandlerRVC2.trLrCheck:
226            tr.set(value)
227
228    def trackbarFractionalBits(value):
229        StereoConfigHandlerRVC2.config.algorithmControl.subpixelFractionalBits = value
230        StereoConfigHandlerRVC2.newConfig = True
231        for tr in StereoConfigHandlerRVC2.trFractionalBits:
232            tr.set(value)
233
234    def trackbarLineqAlpha(value):
235        StereoConfigHandlerRVC2.config.costMatching.linearEquationParameters.alpha = value
236        StereoConfigHandlerRVC2.newConfig = True
237        for tr in StereoConfigHandlerRVC2.trLineqAlpha:
238            tr.set(value)
239
240    def trackbarLineqBeta(value):
241        StereoConfigHandlerRVC2.config.costMatching.linearEquationParameters.beta = value
242        StereoConfigHandlerRVC2.newConfig = True
243        for tr in StereoConfigHandlerRVC2.trLineqBeta:
244            tr.set(value)
245
246    def trackbarLineqThreshold(value):
247        StereoConfigHandlerRVC2.config.costMatching.linearEquationParameters.threshold = value
248        StereoConfigHandlerRVC2.newConfig = True
249        for tr in StereoConfigHandlerRVC2.trLineqThreshold:
250            tr.set(value)
251
252    def trackbarCostAggregationP1(value):
253        StereoConfigHandlerRVC2.config.costAggregation.horizontalPenaltyCostP1 = value
254        StereoConfigHandlerRVC2.config.costAggregation.verticalPenaltyCostP1 = value
255        StereoConfigHandlerRVC2.newConfig = True
256        for tr in StereoConfigHandlerRVC2.trCostAggregationP1:
257            tr.set(value)
258
259    def trackbarCostAggregationP2(value):
260        StereoConfigHandlerRVC2.config.costAggregation.horizontalPenaltyCostP2 = value
261        StereoConfigHandlerRVC2.config.costAggregation.verticalPenaltyCostP2 = value
262        StereoConfigHandlerRVC2.newConfig = True
263        for tr in StereoConfigHandlerRVC2.trCostAggregationP2:
264            tr.set(value)
265
266    def trackbarTemporalFilterAlpha(value):
267        StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.alpha = value / 100.
268        StereoConfigHandlerRVC2.newConfig = True
269        for tr in StereoConfigHandlerRVC2.trTemporalAlpha:
270            tr.set(value)
271
272    def trackbarTemporalFilterDelta(value):
273        StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.delta = value
274        StereoConfigHandlerRVC2.newConfig = True
275        for tr in StereoConfigHandlerRVC2.trTemporalDelta:
276            tr.set(value)
277
278    def trackbarSpatialFilterAlpha(value):
279        StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.alpha = value / 100.
280        StereoConfigHandlerRVC2.newConfig = True
281        for tr in StereoConfigHandlerRVC2.trSpatialAlpha:
282            tr.set(value)
283
284    def trackbarSpatialFilterDelta(value):
285        StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.delta = value
286        StereoConfigHandlerRVC2.newConfig = True
287        for tr in StereoConfigHandlerRVC2.trSpatialDelta:
288            tr.set(value)
289
290    def trackbarSpatialFilterHoleFillingRadius(value):
291        StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.holeFillingRadius = value
292        StereoConfigHandlerRVC2.newConfig = True
293        for tr in StereoConfigHandlerRVC2.trSpatialHoleFilling:
294            tr.set(value)
295
296    def trackbarSpatialFilterNumIterations(value):
297        StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.numIterations = value
298        StereoConfigHandlerRVC2.newConfig = True
299        for tr in StereoConfigHandlerRVC2.trSpatialNumIterations:
300            tr.set(value)
301
302    def trackbarThresholdMinRange(value):
303        StereoConfigHandlerRVC2.config.postProcessing.thresholdFilter.minRange = value * 1000
304        StereoConfigHandlerRVC2.newConfig = True
305        for tr in StereoConfigHandlerRVC2.trThresholdMinRange:
306            tr.set(value)
307
308    def trackbarThresholdMaxRange(value):
309        StereoConfigHandlerRVC2.config.postProcessing.thresholdFilter.maxRange = value * 1000
310        StereoConfigHandlerRVC2.newConfig = True
311        for tr in StereoConfigHandlerRVC2.trThresholdMaxRange:
312            tr.set(value)
313
314    def trackbarSpeckleRange(value):
315        StereoConfigHandlerRVC2.config.postProcessing.speckleFilter.speckleRange = value
316        StereoConfigHandlerRVC2.newConfig = True
317        for tr in StereoConfigHandlerRVC2.trSpeckleRange:
318            tr.set(value)
319
320    def trackbarDecimationFactor(value):
321        StereoConfigHandlerRVC2.config.postProcessing.decimationFilter.decimationFactor = value
322        StereoConfigHandlerRVC2.newConfig = True
323        for tr in StereoConfigHandlerRVC2.trDecimationFactor:
324            tr.set(value)
325
326    def trackbarDisparityShift(value):
327        StereoConfigHandlerRVC2.config.algorithmControl.disparityShift = value
328        StereoConfigHandlerRVC2.newConfig = True
329        for tr in StereoConfigHandlerRVC2.trDisparityShift:
330            tr.set(value)
331
332    def trackbarCenterAlignmentShift(value):
333        if StereoConfigHandlerRVC2.config.algorithmControl.depthAlign != dai.StereoDepthConfig.AlgorithmControl.DepthAlign.CENTER:
334            print("Center alignment shift factor requires CENTER alignment enabled!")
335            return
336        StereoConfigHandlerRVC2.config.algorithmControl.centerAlignmentShiftFactor = value / 100.
337        print(f"centerAlignmentShiftFactor: {StereoConfigHandlerRVC2.config.algorithmControl.centerAlignmentShiftFactor:.2f}")
338        StereoConfigHandlerRVC2.newConfig = True
339        for tr in StereoConfigHandlerRVC2.trCenterAlignmentShift:
340            tr.set(value)
341
342    def trackbarInvalidateEdgePixels(value):
343        StereoConfigHandlerRVC2.config.algorithmControl.numInvalidateEdgePixels = value
344        print(f"numInvalidateEdgePixels: {StereoConfigHandlerRVC2.config.algorithmControl.numInvalidateEdgePixels:.2f}")
345        StereoConfigHandlerRVC2.newConfig = True
346        for tr in StereoConfigHandlerRVC2.trInvalidateEdgePixels:
347            tr.set(value)
348
349    def handleKeypress(key, stereoDepthConfigInQueue):
350        if key == ord("m"):
351            StereoConfigHandlerRVC2.newConfig = True
352            medianSettings = [dai.MedianFilter.MEDIAN_OFF, dai.MedianFilter.KERNEL_3x3, dai.MedianFilter.KERNEL_5x5, dai.MedianFilter.KERNEL_7x7]
353            currentMedian = StereoConfigHandlerRVC2.config.postProcessing.median
354            nextMedian = medianSettings[(medianSettings.index(currentMedian)+1) % len(medianSettings)]
355            print(f"Changing median to {nextMedian.name} from {currentMedian.name}")
356            StereoConfigHandlerRVC2.config.postProcessing.median = nextMedian
357        if key == ord("w"):
358            StereoConfigHandlerRVC2.newConfig = True
359            StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.enable = not StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.enable
360            state = "on" if StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.enable else "off"
361            print(f"Spatial filter {state}")
362        if key == ord("t"):
363            StereoConfigHandlerRVC2.newConfig = True
364            StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.enable = not StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.enable
365            state = "on" if StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.enable else "off"
366            print(f"Temporal filter {state}")
367        if key == ord("s"):
368            StereoConfigHandlerRVC2.newConfig = True
369            StereoConfigHandlerRVC2.config.postProcessing.speckleFilter.enable = not StereoConfigHandlerRVC2.config.postProcessing.speckleFilter.enable
370            state = "on" if StereoConfigHandlerRVC2.config.postProcessing.speckleFilter.enable else "off"
371            print(f"Speckle filter {state}")
372        if key == ord("r"):
373            StereoConfigHandlerRVC2.newConfig = True
374            temporalSettings = [dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.PERSISTENCY_OFF,
375            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_8_OUT_OF_8,
376            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_2_IN_LAST_3,
377            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_2_IN_LAST_4,
378            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_2_OUT_OF_8,
379            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_1_IN_LAST_2,
380            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_1_IN_LAST_5,
381            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_1_IN_LAST_8,
382            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.PERSISTENCY_INDEFINITELY,
383            ]
384            currentTemporal = StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.persistencyMode
385            nextTemporal = temporalSettings[(temporalSettings.index(currentTemporal)+1) % len(temporalSettings)]
386            print(f"Changing temporal persistency to {nextTemporal.name} from {currentTemporal.name}")
387            StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.persistencyMode = nextTemporal
388        if key == ord("n"):
389            StereoConfigHandlerRVC2.newConfig = True
390            decimationSettings = [dai.StereoDepthConfig.PostProcessing.DecimationFilter.DecimationMode.PIXEL_SKIPPING,
391            dai.StereoDepthConfig.PostProcessing.DecimationFilter.DecimationMode.NON_ZERO_MEDIAN,
392            dai.StereoDepthConfig.PostProcessing.DecimationFilter.DecimationMode.NON_ZERO_MEAN,
393            ]
394            currentDecimation = StereoConfigHandlerRVC2.config.postProcessing.decimationFilter.decimationMode
395            nextDecimation = decimationSettings[(decimationSettings.index(currentDecimation)+1) % len(decimationSettings)]
396            print(f"Changing decimation mode to {nextDecimation.name} from {currentDecimation.name}")
397            StereoConfigHandlerRVC2.config.postProcessing.decimationFilter.decimationMode = nextDecimation
398        if key == ord("a"):
399            StereoConfigHandlerRVC2.newConfig = True
400            alignmentSettings = [dai.StereoDepthConfig.AlgorithmControl.DepthAlign.RECTIFIED_RIGHT,
401            dai.StereoDepthConfig.AlgorithmControl.DepthAlign.RECTIFIED_LEFT,
402            dai.StereoDepthConfig.AlgorithmControl.DepthAlign.CENTER,
403            ]
404            currentAlignment = StereoConfigHandlerRVC2.config.algorithmControl.depthAlign
405            nextAlignment = alignmentSettings[(alignmentSettings.index(currentAlignment)+1) % len(alignmentSettings)]
406            print(f"Changing alignment mode to {nextAlignment.name} from {currentAlignment.name}")
407            StereoConfigHandlerRVC2.config.algorithmControl.depthAlign = nextAlignment
408        elif key == ord("c"):
409            StereoConfigHandlerRVC2.newConfig = True
410            censusSettings = [dai.StereoDepthConfig.CensusTransform.KernelSize.AUTO, dai.StereoDepthConfig.CensusTransform.KernelSize.KERNEL_5x5, dai.StereoDepthConfig.CensusTransform.KernelSize.KERNEL_7x7, dai.StereoDepthConfig.CensusTransform.KernelSize.KERNEL_7x9]
411            currentCensus = StereoConfigHandlerRVC2.config.censusTransform.kernelSize
412            nextCensus = censusSettings[(censusSettings.index(currentCensus)+1) % len(censusSettings)]
413            if nextCensus != dai.StereoDepthConfig.CensusTransform.KernelSize.AUTO:
414                censusGridSize = [(5,5), (7,7), (7,9)]
415                censusDefaultMask = [np.uint64(0XA82415), np.uint64(0XAA02A8154055), np.uint64(0X2AA00AA805540155)]
416                censusGrid = censusGridSize[nextCensus]
417                censusMask = censusDefaultMask[nextCensus]
418                StereoConfigHandlerRVC2.censusMaskHandler = StereoConfigHandlerRVC2.CensusMaskHandler("Census mask", censusGrid)
419                StereoConfigHandlerRVC2.censusMaskHandler.setMask(censusMask)
420            else:
421                print("Census mask config is not available in AUTO census kernel mode. Change using the 'c' key")
422                StereoConfigHandlerRVC2.config.censusTransform.kernelMask = 0
423                StereoConfigHandlerRVC2.censusMaskHandler.destroyWindow()
424            print(f"Changing census transform to {nextCensus.name} from {currentCensus.name}")
425            StereoConfigHandlerRVC2.config.censusTransform.kernelSize = nextCensus
426        elif key == ord("d"):
427            StereoConfigHandlerRVC2.newConfig = True
428            dispRangeSettings = [dai.StereoDepthConfig.CostMatching.DisparityWidth.DISPARITY_64, dai.StereoDepthConfig.CostMatching.DisparityWidth.DISPARITY_96]
429            currentDispRange = StereoConfigHandlerRVC2.config.costMatching.disparityWidth
430            nextDispRange = dispRangeSettings[(dispRangeSettings.index(currentDispRange)+1) % len(dispRangeSettings)]
431            print(f"Changing disparity range to {nextDispRange.name} from {currentDispRange.name}")
432            StereoConfigHandlerRVC2.config.costMatching.disparityWidth = nextDispRange
433        elif key == ord("f"):
434            StereoConfigHandlerRVC2.newConfig = True
435            StereoConfigHandlerRVC2.config.costMatching.enableCompanding = not StereoConfigHandlerRVC2.config.costMatching.enableCompanding
436            state = "on" if StereoConfigHandlerRVC2.config.costMatching.enableCompanding else "off"
437            print(f"Companding {state}")
438        elif key == ord("v"):
439            StereoConfigHandlerRVC2.newConfig = True
440            StereoConfigHandlerRVC2.config.censusTransform.enableMeanMode = not StereoConfigHandlerRVC2.config.censusTransform.enableMeanMode
441            state = "on" if StereoConfigHandlerRVC2.config.censusTransform.enableMeanMode else "off"
442            print(f"Census transform mean mode {state}")
443        elif key == ord("1"):
444            StereoConfigHandlerRVC2.newConfig = True
445            StereoConfigHandlerRVC2.config.algorithmControl.enableLeftRightCheck = not StereoConfigHandlerRVC2.config.algorithmControl.enableLeftRightCheck
446            state = "on" if StereoConfigHandlerRVC2.config.algorithmControl.enableLeftRightCheck else "off"
447            print(f"LR-check {state}")
448        elif key == ord("2"):
449            StereoConfigHandlerRVC2.newConfig = True
450            StereoConfigHandlerRVC2.config.algorithmControl.enableSubpixel = not StereoConfigHandlerRVC2.config.algorithmControl.enableSubpixel
451            state = "on" if StereoConfigHandlerRVC2.config.algorithmControl.enableSubpixel else "off"
452            print(f"Subpixel {state}")
453        elif key == ord("3"):
454            StereoConfigHandlerRVC2.newConfig = True
455            StereoConfigHandlerRVC2.config.algorithmControl.enableExtended = not StereoConfigHandlerRVC2.config.algorithmControl.enableExtended
456            state = "on" if StereoConfigHandlerRVC2.config.algorithmControl.enableExtended else "off"
457            print(f"Extended {state}")
458
459        censusMaskChanged = False
460        if StereoConfigHandlerRVC2.censusMaskHandler is not None:
461            censusMaskChanged = StereoConfigHandlerRVC2.censusMaskHandler.isChanged()
462        if censusMaskChanged:
463            StereoConfigHandlerRVC2.config.censusTransform.kernelMask = StereoConfigHandlerRVC2.censusMaskHandler.getMask()
464            StereoConfigHandlerRVC2.newConfig = True
465
466        StereoConfigHandlerRVC2.sendConfig(stereoDepthConfigInQueue)
467
468    def sendConfig(stereoDepthConfigInQueue):
469        if StereoConfigHandlerRVC2.newConfig:
470            StereoConfigHandlerRVC2.newConfig = False
471            # configMessage = dai.StereoDepthConfig()
472            configMessage = StereoConfigHandlerRVC2.config
473            stereoDepthConfigInQueue.send(configMessage)
474
475    def updateDefaultConfig(config):
476        StereoConfigHandlerRVC2.config = config
477
478    def registerWindow(stream):
479        cv2.namedWindow(stream, cv2.WINDOW_NORMAL)
480
481        StereoConfigHandlerRVC2.trConfidence.append(StereoConfigHandlerRVC2.Trackbar("Disparity confidence", stream, 0, 255, StereoConfigHandlerRVC2.config.costMatching.confidenceThreshold, StereoConfigHandlerRVC2.trackbarConfidence))
482        StereoConfigHandlerRVC2.trSigma.append(StereoConfigHandlerRVC2.Trackbar("Bilateral sigma", stream, 0, 100, StereoConfigHandlerRVC2.config.postProcessing.bilateralSigmaValue, StereoConfigHandlerRVC2.trackbarSigma))
483        StereoConfigHandlerRVC2.trLrCheck.append(StereoConfigHandlerRVC2.Trackbar("LR-check threshold", stream, 0, 16, StereoConfigHandlerRVC2.config.algorithmControl.leftRightCheckThreshold, StereoConfigHandlerRVC2.trackbarLrCheckThreshold))
484        StereoConfigHandlerRVC2.trFractionalBits.append(StereoConfigHandlerRVC2.Trackbar("Subpixel fractional bits", stream, 3, 5, StereoConfigHandlerRVC2.config.algorithmControl.subpixelFractionalBits, StereoConfigHandlerRVC2.trackbarFractionalBits))
485        StereoConfigHandlerRVC2.trDisparityShift.append(StereoConfigHandlerRVC2.Trackbar("Disparity shift", stream, 0, 100, StereoConfigHandlerRVC2.config.algorithmControl.disparityShift, StereoConfigHandlerRVC2.trackbarDisparityShift))
486        StereoConfigHandlerRVC2.trCenterAlignmentShift.append(StereoConfigHandlerRVC2.Trackbar("Center alignment shift factor", stream, 0, 100, StereoConfigHandlerRVC2.config.algorithmControl.centerAlignmentShiftFactor, StereoConfigHandlerRVC2.trackbarCenterAlignmentShift))
487        StereoConfigHandlerRVC2.trInvalidateEdgePixels.append(StereoConfigHandlerRVC2.Trackbar("Invalidate edge pixels", stream, 0, 100, StereoConfigHandlerRVC2.config.algorithmControl.numInvalidateEdgePixels, StereoConfigHandlerRVC2.trackbarInvalidateEdgePixels))
488        StereoConfigHandlerRVC2.trLineqAlpha.append(StereoConfigHandlerRVC2.Trackbar("Linear equation alpha", stream, 0, 15, StereoConfigHandlerRVC2.config.costMatching.linearEquationParameters.alpha, StereoConfigHandlerRVC2.trackbarLineqAlpha))
489        StereoConfigHandlerRVC2.trLineqBeta.append(StereoConfigHandlerRVC2.Trackbar("Linear equation beta", stream, 0, 15, StereoConfigHandlerRVC2.config.costMatching.linearEquationParameters.beta, StereoConfigHandlerRVC2.trackbarLineqBeta))
490        StereoConfigHandlerRVC2.trLineqThreshold.append(StereoConfigHandlerRVC2.Trackbar("Linear equation threshold", stream, 0, 255, StereoConfigHandlerRVC2.config.costMatching.linearEquationParameters.threshold, StereoConfigHandlerRVC2.trackbarLineqThreshold))
491        StereoConfigHandlerRVC2.trCostAggregationP1.append(StereoConfigHandlerRVC2.Trackbar("Cost aggregation P1", stream, 0, 500, StereoConfigHandlerRVC2.config.costAggregation.horizontalPenaltyCostP1, StereoConfigHandlerRVC2.trackbarCostAggregationP1))
492        StereoConfigHandlerRVC2.trCostAggregationP2.append(StereoConfigHandlerRVC2.Trackbar("Cost aggregation P2", stream, 0, 500, StereoConfigHandlerRVC2.config.costAggregation.horizontalPenaltyCostP2, StereoConfigHandlerRVC2.trackbarCostAggregationP2))
493        StereoConfigHandlerRVC2.trTemporalAlpha.append(StereoConfigHandlerRVC2.Trackbar("Temporal filter alpha", stream, 0, 100, int(StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.alpha*100), StereoConfigHandlerRVC2.trackbarTemporalFilterAlpha))
494        StereoConfigHandlerRVC2.trTemporalDelta.append(StereoConfigHandlerRVC2.Trackbar("Temporal filter delta", stream, 0, 100, StereoConfigHandlerRVC2.config.postProcessing.temporalFilter.delta, StereoConfigHandlerRVC2.trackbarTemporalFilterDelta))
495        StereoConfigHandlerRVC2.trSpatialAlpha.append(StereoConfigHandlerRVC2.Trackbar("Spatial filter alpha", stream, 0, 100, int(StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.alpha*100), StereoConfigHandlerRVC2.trackbarSpatialFilterAlpha))
496        StereoConfigHandlerRVC2.trSpatialDelta.append(StereoConfigHandlerRVC2.Trackbar("Spatial filter delta", stream, 0, 100, StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.delta, StereoConfigHandlerRVC2.trackbarSpatialFilterDelta))
497        StereoConfigHandlerRVC2.trSpatialHoleFilling.append(StereoConfigHandlerRVC2.Trackbar("Spatial filter hole filling radius", stream, 0, 16, StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.holeFillingRadius, StereoConfigHandlerRVC2.trackbarSpatialFilterHoleFillingRadius))
498        StereoConfigHandlerRVC2.trSpatialNumIterations.append(StereoConfigHandlerRVC2.Trackbar("Spatial filter number of iterations", stream, 0, 4, StereoConfigHandlerRVC2.config.postProcessing.spatialFilter.numIterations, StereoConfigHandlerRVC2.trackbarSpatialFilterNumIterations))
499        StereoConfigHandlerRVC2.trThresholdMinRange.append(StereoConfigHandlerRVC2.Trackbar("Threshold filter min range", stream, 0, 65, StereoConfigHandlerRVC2.config.postProcessing.thresholdFilter.minRange, StereoConfigHandlerRVC2.trackbarThresholdMinRange))
500        StereoConfigHandlerRVC2.trThresholdMaxRange.append(StereoConfigHandlerRVC2.Trackbar("Threshold filter max range", stream, 0, 65, StereoConfigHandlerRVC2.config.postProcessing.thresholdFilter.maxRange, StereoConfigHandlerRVC2.trackbarThresholdMaxRange))
501        StereoConfigHandlerRVC2.trSpeckleRange.append(StereoConfigHandlerRVC2.Trackbar("Speckle filter range", stream, 0, 240, StereoConfigHandlerRVC2.config.postProcessing.speckleFilter.speckleRange, StereoConfigHandlerRVC2.trackbarSpeckleRange))
502        StereoConfigHandlerRVC2.trDecimationFactor.append(StereoConfigHandlerRVC2.Trackbar("Decimation factor", stream, 1, 4, StereoConfigHandlerRVC2.config.postProcessing.decimationFilter.decimationFactor, StereoConfigHandlerRVC2.trackbarDecimationFactor))
503
504    def __init__(self, config):
505        print("Control median filter using the 'm' key.")
506        print("Control census transform kernel size using the 'c' key.")
507        print("Control disparity search range using the 'd' key.")
508        print("Control disparity companding using the 'f' key.")
509        print("Control census transform mean mode using the 'v' key.")
510        print("Control depth alignment using the 'a' key.")
511        print("Control decimation algorithm using the 'a' key.")
512        print("Control temporal persistency mode using the 'r' key.")
513        print("Control spatial filter using the 'w' key.")
514        print("Control temporal filter using the 't' key.")
515        print("Control speckle filter using the 's' key.")
516        print("Control left-right check mode using the '1' key.")
517        print("Control subpixel mode using the '2' key.")
518        print("Control extended mode using the '3' key.")
519        if evaluation_mode:
520            print("Switch between images using '[' and ']' keys.")
521
522        StereoConfigHandlerRVC2.config = config
523
524        if StereoConfigHandlerRVC2.config.censusTransform.kernelSize != dai.StereoDepthConfig.CensusTransform.KernelSize.AUTO:
525            censusMask = StereoConfigHandlerRVC2.config.censusTransform.kernelMask
526            censusGridSize = [(5,5), (7,7), (7,9)]
527            censusGrid = censusGridSize[StereoConfigHandlerRVC2.config.censusTransform.kernelSize]
528            if StereoConfigHandlerRVC2.config.censusTransform.kernelMask == 0:
529                censusDefaultMask = [np.uint64(0xA82415), np.uint64(0xAA02A8154055), np.uint64(0x2AA00AA805540155)]
530                censusMask = censusDefaultMask[StereoConfigHandlerRVC2.config.censusTransform.kernelSize]
531            StereoConfigHandlerRVC2.censusMaskHandler = StereoConfigHandlerRVC2.CensusMaskHandler("Census mask", censusGrid)
532            StereoConfigHandlerRVC2.censusMaskHandler.setMask(censusMask)
533        else:
534            print("Census mask config is not available in AUTO Census kernel mode. Change using the 'c' key")
535class StereoConfigHandlerRVC4:
536
537    class Trackbar:
538        def __init__(self, trackbarName, windowName, minValue, maxValue, defaultValue, handler):
539            self.min = minValue
540            self.max = maxValue
541            self.windowName = windowName
542            self.trackbarName = trackbarName
543            cv2.createTrackbar(trackbarName, windowName, minValue, maxValue, handler)
544            cv2.setTrackbarPos(trackbarName, windowName, defaultValue)
545
546        def set(self, value):
547            if value < self.min:
548                value = self.min
549                print(f"{self.trackbarName} min value is {self.min}")
550            if value > self.max:
551                value = self.max
552                print(f"{self.trackbarName} max value is {self.max}")
553            cv2.setTrackbarPos(self.trackbarName, self.windowName, value)
554
555    newConfig = False
556    config = None
557    trConfidence = list()
558    trLrCheck = list()
559    trTemporalAlpha = list()
560    trTemporalDelta = list()
561    trThresholdMinRange = list()
562    trThresholdMaxRange = list()
563    trSpeckleRange = list()
564    trSpatialAlpha = list()
565    trSpatialDelta = list()
566    trSpatialHoleFilling = list()
567    trSpatialNumIterations = list()
568    trDecimationFactor = list()
569    trDisparityShift = list()
570    trCenterAlignmentShift = list()
571    trInvalidateEdgePixels = list()
572
573    def trackbarConfidence(value):
574        StereoConfigHandlerRVC4.config.costMatching.confidenceThreshold = value
575        StereoConfigHandlerRVC4.newConfig = True
576        for tr in StereoConfigHandlerRVC4.trConfidence:
577            tr.set(value)
578
579    def trackbarLrCheckThreshold(value):
580        StereoConfigHandlerRVC4.config.algorithmControl.leftRightCheckThreshold = value
581        StereoConfigHandlerRVC4.newConfig = True
582        for tr in StereoConfigHandlerRVC4.trLrCheck:
583            tr.set(value)
584
585    def trackbarTemporalFilterAlpha(value):
586        StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.alpha = value / 100.
587        StereoConfigHandlerRVC4.newConfig = True
588        for tr in StereoConfigHandlerRVC4.trTemporalAlpha:
589            tr.set(value)
590
591    def trackbarTemporalFilterDelta(value):
592        StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.delta = value
593        StereoConfigHandlerRVC4.newConfig = True
594        for tr in StereoConfigHandlerRVC4.trTemporalDelta:
595            tr.set(value)
596
597    def trackbarSpatialFilterAlpha(value):
598        StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.alpha = value / 100.
599        StereoConfigHandlerRVC4.newConfig = True
600        for tr in StereoConfigHandlerRVC4.trSpatialAlpha:
601            tr.set(value)
602
603    def trackbarSpatialFilterDelta(value):
604        StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.delta = value
605        StereoConfigHandlerRVC4.newConfig = True
606        for tr in StereoConfigHandlerRVC4.trSpatialDelta:
607            tr.set(value)
608
609    def trackbarSpatialFilterHoleFillingRadius(value):
610        StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.holeFillingRadius = value
611        StereoConfigHandlerRVC4.newConfig = True
612        for tr in StereoConfigHandlerRVC4.trSpatialHoleFilling:
613            tr.set(value)
614
615    def trackbarSpatialFilterNumIterations(value):
616        StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.numIterations = value
617        StereoConfigHandlerRVC4.newConfig = True
618        for tr in StereoConfigHandlerRVC4.trSpatialNumIterations:
619            tr.set(value)
620
621    def trackbarThresholdMinRange(value):
622        StereoConfigHandlerRVC4.config.postProcessing.thresholdFilter.minRange = value * 1000
623        StereoConfigHandlerRVC4.newConfig = True
624        for tr in StereoConfigHandlerRVC4.trThresholdMinRange:
625            tr.set(value)
626
627    def trackbarThresholdMaxRange(value):
628        StereoConfigHandlerRVC4.config.postProcessing.thresholdFilter.maxRange = value * 1000
629        StereoConfigHandlerRVC4.newConfig = True
630        for tr in StereoConfigHandlerRVC4.trThresholdMaxRange:
631            tr.set(value)
632
633    def trackbarSpeckleRange(value):
634        StereoConfigHandlerRVC4.config.postProcessing.speckleFilter.speckleRange = value
635        StereoConfigHandlerRVC4.newConfig = True
636        for tr in StereoConfigHandlerRVC4.trSpeckleRange:
637            tr.set(value)
638
639    def trackbarDecimationFactor(value):
640        StereoConfigHandlerRVC4.config.postProcessing.decimationFilter.decimationFactor = value
641        StereoConfigHandlerRVC4.newConfig = True
642        for tr in StereoConfigHandlerRVC4.trDecimationFactor:
643            tr.set(value)
644
645    def trackbarDisparityShift(value):
646        StereoConfigHandlerRVC4.config.algorithmControl.disparityShift = value
647        StereoConfigHandlerRVC4.newConfig = True
648        for tr in StereoConfigHandlerRVC4.trDisparityShift:
649            tr.set(value)
650
651    def trackbarCenterAlignmentShift(value):
652        if StereoConfigHandlerRVC4.config.algorithmControl.depthAlign != dai.StereoDepthConfig.AlgorithmControl.DepthAlign.CENTER:
653            print("Center alignment shift factor requires CENTER alignment enabled!")
654            return
655        StereoConfigHandlerRVC4.config.algorithmControl.centerAlignmentShiftFactor = value / 100.
656        print(f"centerAlignmentShiftFactor: {StereoConfigHandlerRVC4.config.algorithmControl.centerAlignmentShiftFactor:.2f}")
657        StereoConfigHandlerRVC4.newConfig = True
658        for tr in StereoConfigHandlerRVC4.trCenterAlignmentShift:
659            tr.set(value)
660
661    def trackbarInvalidateEdgePixels(value):
662        StereoConfigHandlerRVC4.config.algorithmControl.numInvalidateEdgePixels = value
663        print(f"numInvalidateEdgePixels: {StereoConfigHandlerRVC4.config.algorithmControl.numInvalidateEdgePixels:.2f}")
664        StereoConfigHandlerRVC4.newConfig = True
665        for tr in StereoConfigHandlerRVC4.trInvalidateEdgePixels:
666            tr.set(value)
667
668    tr_occlusionConfidenceWeight = list()
669    def trackbar_occlusionConfidenceWeight(value):
670        StereoConfigHandlerRVC4.config.confidenceMetrics.occlusionConfidenceWeight = value
671        print(f"occlusionConfidenceWeight: {StereoConfigHandlerRVC4.config.confidenceMetrics.occlusionConfidenceWeight:.2f}")
672        StereoConfigHandlerRVC4.newConfig = True
673        for tr in StereoConfigHandlerRVC4.tr_occlusionConfidenceWeight:
674            tr.set(value)
675
676    tr_motionVectorConfidenceWeight = list()
677    def trackbar_motionVectorConfidenceWeight(value):
678        StereoConfigHandlerRVC4.config.confidenceMetrics.motionVectorConfidenceWeight = value
679        print(f"motionVectorConfidenceWeight: {StereoConfigHandlerRVC4.config.confidenceMetrics.motionVectorConfidenceWeight:.2f}")
680        StereoConfigHandlerRVC4.newConfig = True
681        for tr in StereoConfigHandlerRVC4.tr_motionVectorConfidenceWeight:
682            tr.set(value)
683
684    tr_motionVectorConfidenceThreshold = list()
685    def trackbar_motionVectorConfidenceThreshold(value):
686        StereoConfigHandlerRVC4.config.confidenceMetrics.motionVectorConfidenceThreshold = value
687        print(f"motionVectorConfidenceThreshold: {StereoConfigHandlerRVC4.config.confidenceMetrics.motionVectorConfidenceThreshold:.2f}")
688        StereoConfigHandlerRVC4.newConfig = True
689        for tr in StereoConfigHandlerRVC4.tr_motionVectorConfidenceThreshold:
690            tr.set(value)
691
692    tr_flatnessConfidenceWeight = list()
693    def trackbar_flatnessConfidenceWeight(value):
694        StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessConfidenceWeight = value
695        print(f"flatnessConfidenceWeight: {StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessConfidenceWeight:.2f}")
696        StereoConfigHandlerRVC4.newConfig = True
697        for tr in StereoConfigHandlerRVC4.tr_flatnessConfidenceWeight:
698            tr.set(value)
699
700    tr_flatnessConfidenceThreshold = list()
701    def trackbar_flatnessConfidenceThreshold(value):
702        StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessConfidenceThreshold = value
703        print(f"flatnessConfidenceThreshold: {StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessConfidenceThreshold:.2f}")
704        StereoConfigHandlerRVC4.newConfig = True
705        for tr in StereoConfigHandlerRVC4.tr_flatnessConfidenceThreshold:
706            tr.set(value)
707
708    tr_flatnessOverride = list()
709    def trackbar_flatnessOverride(value):
710        StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessOverride = bool(value)
711        print(f"flatnessOverride: {StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessOverride:.2f}")
712        StereoConfigHandlerRVC4.newConfig = True
713        for tr in StereoConfigHandlerRVC4.tr_flatnessOverride:
714            tr.set(value)
715
716    tr_adaptiveMedianFilter_enable = list()
717    def trackbar_adaptiveMedianFilter_enable(value):
718        StereoConfigHandlerRVC4.config.postProcessing.adaptiveMedianFilter.enable = bool(value)
719        print(f"adaptiveMedianFilter.enable: {StereoConfigHandlerRVC4.config.postProcessing.adaptiveMedianFilter.enable:.2f}")
720        StereoConfigHandlerRVC4.newConfig = True
721        for tr in StereoConfigHandlerRVC4.tr_adaptiveMedianFilter_enable:
722            tr.set(value)
723
724    tr_adaptiveMedianFilter_threshold = list()
725    def trackbar_adaptiveMedianFilter_threshold(value):
726        StereoConfigHandlerRVC4.config.postProcessing.adaptiveMedianFilter.confidenceThreshold = value
727        print(f"adaptiveMedianFilter_threshold: {StereoConfigHandlerRVC4.config.postProcessing.adaptiveMedianFilter.confidenceThreshold:.2f}")
728        StereoConfigHandlerRVC4.newConfig = True
729        for tr in StereoConfigHandlerRVC4.tr_adaptiveMedianFilter_threshold:
730            tr.set(value)
731
732    tr_noiseThresholdOffset = list()
733    def trackbar_noiseThresholdOffset(value):
734        StereoConfigHandlerRVC4.config.censusTransform.noiseThresholdOffset = value
735        print(f"noiseThresholdOffset: {StereoConfigHandlerRVC4.config.censusTransform.noiseThresholdOffset:.2f}")
736        StereoConfigHandlerRVC4.newConfig = True
737        for tr in StereoConfigHandlerRVC4.tr_noiseThresholdOffset:
738            tr.set(value)
739
740    tr_noiseThresholdScale = list()
741    def trackbar_noiseThresholdScale(value):
742        StereoConfigHandlerRVC4.config.censusTransform.noiseThresholdScale = value - 128
743        print(f"noiseThresholdScale: {StereoConfigHandlerRVC4.config.censusTransform.noiseThresholdScale:.2f}")
744        StereoConfigHandlerRVC4.newConfig = True
745        for tr in StereoConfigHandlerRVC4.tr_noiseThresholdScale:
746            tr.set(value)
747
748    tr_p1_enableAdaptive = list()
749    def trackbar_p1_enableAdaptive(value):
750        StereoConfigHandlerRVC4.config.costAggregation.p1Config.enableAdaptive = bool(value)
751        print(f"p1Config.enableAdaptive: {StereoConfigHandlerRVC4.config.costAggregation.p1Config.enableAdaptive:.2f}")
752        StereoConfigHandlerRVC4.newConfig = True
753        for tr in StereoConfigHandlerRVC4.tr_p1_enableAdaptive:
754            tr.set(value)
755
756    tr_p1_defaultValue = list()
757    def trackbar_p1_defaultValue(value):
758        StereoConfigHandlerRVC4.config.costAggregation.p1Config.defaultValue = value
759        print(f"p1Config.defaultValue: {StereoConfigHandlerRVC4.config.costAggregation.p1Config.defaultValue:.2f}")
760        StereoConfigHandlerRVC4.newConfig = True
761        for tr in StereoConfigHandlerRVC4.tr_p1_defaultValue:
762            tr.set(value)
763
764    tr_p1_edgeValue = list()
765    def trackbar_p1_edgeValue(value):
766        StereoConfigHandlerRVC4.config.costAggregation.p1Config.edgeValue = value
767        print(f"p1Config.edgeValue: {StereoConfigHandlerRVC4.config.costAggregation.p1Config.edgeValue:.2f}")
768        StereoConfigHandlerRVC4.newConfig = True
769        for tr in StereoConfigHandlerRVC4.tr_p1_edgeValue:
770            tr.set(value)
771
772    tr_p1_smoothValue = list()
773    def trackbar_p1_smoothValue(value):
774        StereoConfigHandlerRVC4.config.costAggregation.p1Config.smoothValue = value
775        print(f"p1Config.smoothValue: {StereoConfigHandlerRVC4.config.costAggregation.p1Config.smoothValue:.2f}")
776        StereoConfigHandlerRVC4.newConfig = True
777        for tr in StereoConfigHandlerRVC4.tr_p1_smoothValue:
778            tr.set(value)
779
780    tr_p1_edgeThreshold = list()
781    def trackbar_p1_edgeThreshold(value):
782        StereoConfigHandlerRVC4.config.costAggregation.p1Config.edgeThreshold = value
783        print(f"p1Config.edgeThreshold: {StereoConfigHandlerRVC4.config.costAggregation.p1Config.edgeThreshold:.2f}")
784        StereoConfigHandlerRVC4.newConfig = True
785        for tr in StereoConfigHandlerRVC4.tr_p1_edgeThreshold:
786            tr.set(value)
787
788    tr_p1_smoothThreshold = list()
789    def trackbar_p1_smoothThreshold(value):
790        StereoConfigHandlerRVC4.config.costAggregation.p1Config.smoothThreshold = value
791        print(f"p1Config.smoothThreshold: {StereoConfigHandlerRVC4.config.costAggregation.p1Config.smoothThreshold:.2f}")
792        StereoConfigHandlerRVC4.newConfig = True
793        for tr in StereoConfigHandlerRVC4.tr_p1_smoothThreshold:
794            tr.set(value)
795
796    tr_p2_enableAdaptive = list()
797    def trackbar_p2_enableAdaptive(value):
798        StereoConfigHandlerRVC4.config.costAggregation.p2Config.enableAdaptive = bool(value)
799        print(f"p2Config.enableAdaptive: {StereoConfigHandlerRVC4.config.costAggregation.p2Config.enableAdaptive:.2f}")
800        StereoConfigHandlerRVC4.newConfig = True
801        for tr in StereoConfigHandlerRVC4.tr_p2_enableAdaptive:
802            tr.set(value)
803
804    tr_p2_defaultValue = list()
805    def trackbar_p2_defaultValue(value):
806        StereoConfigHandlerRVC4.config.costAggregation.p2Config.defaultValue = value
807        print(f"p2Config.defaultValue: {StereoConfigHandlerRVC4.config.costAggregation.p2Config.defaultValue:.2f}")
808        StereoConfigHandlerRVC4.newConfig = True
809        for tr in StereoConfigHandlerRVC4.tr_p2_defaultValue:
810            tr.set(value)
811
812    tr_p2_edgeValue = list()
813    def trackbar_p2_edgeValue(value):
814        StereoConfigHandlerRVC4.config.costAggregation.p2Config.edgeValue = value
815        print(f"p2Config.edgeValue: {StereoConfigHandlerRVC4.config.costAggregation.p2Config.edgeValue:.2f}")
816        StereoConfigHandlerRVC4.newConfig = True
817        for tr in StereoConfigHandlerRVC4.tr_p2_edgeValue:
818            tr.set(value)
819
820    tr_p2_smoothValue = list()
821    def trackbar_p2_smoothValue(value):
822        StereoConfigHandlerRVC4.config.costAggregation.p2Config.smoothValue = value
823        print(f"p2Config.smoothValue: {StereoConfigHandlerRVC4.config.costAggregation.p2Config.smoothValue:.2f}")
824        StereoConfigHandlerRVC4.newConfig = True
825        for tr in StereoConfigHandlerRVC4.tr_p2_smoothValue:
826            tr.set(value)
827
828    tr_holefilling_enable = list()
829    def trackbar_holefilling_enable(value):
830        StereoConfigHandlerRVC4.config.postProcessing.holeFilling.enable = bool(value)
831        print(f"holeFilling.enable: {StereoConfigHandlerRVC4.config.postProcessing.holeFilling.enable:.2f}")
832        StereoConfigHandlerRVC4.newConfig = True
833        for tr in StereoConfigHandlerRVC4.tr_holefilling_enable:
834            tr.set(value)
835
836    tr_holefilling_highConfidenceThreshold = list()
837    def trackbar_holefilling_highConfidenceThreshold(value):
838        StereoConfigHandlerRVC4.config.postProcessing.holeFilling.highConfidenceThreshold = value
839        print(f"holeFilling.highConfidenceThreshold: {StereoConfigHandlerRVC4.config.postProcessing.holeFilling.highConfidenceThreshold:.2f}")
840        StereoConfigHandlerRVC4.newConfig = True
841        for tr in StereoConfigHandlerRVC4.tr_holefilling_highConfidenceThreshold:
842            tr.set(value)
843
844    tr_holefilling_fillConfidenceThreshold = list()
845    def trackbar_holefilling_fillConfidenceThreshold(value):
846        StereoConfigHandlerRVC4.config.postProcessing.holeFilling.fillConfidenceThreshold = value
847        print(f"holeFilling.fillConfidenceThreshold: {StereoConfigHandlerRVC4.config.postProcessing.holeFilling.fillConfidenceThreshold:.2f}")
848        StereoConfigHandlerRVC4.newConfig = True
849        for tr in StereoConfigHandlerRVC4.tr_holefilling_fillConfidenceThreshold:
850            tr.set(value)
851
852    tr_holefilling_minValidDisparity = list()
853    def trackbar_holefilling_minValidDisparity(value):
854        StereoConfigHandlerRVC4.config.postProcessing.holeFilling.minValidDisparity = value
855        print(f"holeFilling.minValidDisparity: {StereoConfigHandlerRVC4.config.postProcessing.holeFilling.minValidDisparity:.2f}")
856        StereoConfigHandlerRVC4.newConfig = True
857        for tr in StereoConfigHandlerRVC4.tr_holefilling_minValidDisparity:
858            tr.set(value)
859
860    tr_holefilling_invalidateDisparities = list()
861    def trackbar_holefilling_invalidateDisparities(value):
862        StereoConfigHandlerRVC4.config.postProcessing.holeFilling.invalidateDisparities = bool(value)
863        print(f"holeFilling.invalidateDisparities: {StereoConfigHandlerRVC4.config.postProcessing.holeFilling.invalidateDisparities:.2f}")
864        StereoConfigHandlerRVC4.newConfig = True
865        for tr in StereoConfigHandlerRVC4.tr_holefilling_invalidateDisparities:
866            tr.set(value)
867
868    def handleKeypress(key, stereoDepthConfigInQueue):
869        if key == ord("m"):
870            StereoConfigHandlerRVC4.newConfig = True
871            medianSettings = [dai.MedianFilter.MEDIAN_OFF, dai.MedianFilter.KERNEL_3x3, dai.MedianFilter.KERNEL_5x5]
872            currentMedian = StereoConfigHandlerRVC4.config.postProcessing.median
873            nextMedian = medianSettings[(medianSettings.index(currentMedian)+1) % len(medianSettings)]
874            print(f"Changing median to {nextMedian.name} from {currentMedian.name}")
875            StereoConfigHandlerRVC4.config.postProcessing.median = nextMedian
876        if key == ord("w"):
877            StereoConfigHandlerRVC4.newConfig = True
878            StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.enable = not StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.enable
879            state = "on" if StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.enable else "off"
880            print(f"Spatial filter {state}")
881        if key == ord("t"):
882            StereoConfigHandlerRVC4.newConfig = True
883            StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.enable = not StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.enable
884            state = "on" if StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.enable else "off"
885            print(f"Temporal filter {state}")
886        if key == ord("s"):
887            StereoConfigHandlerRVC4.newConfig = True
888            StereoConfigHandlerRVC4.config.postProcessing.speckleFilter.enable = not StereoConfigHandlerRVC4.config.postProcessing.speckleFilter.enable
889            state = "on" if StereoConfigHandlerRVC4.config.postProcessing.speckleFilter.enable else "off"
890            print(f"Speckle filter {state}")
891        if key == ord("r"):
892            StereoConfigHandlerRVC4.newConfig = True
893            temporalSettings = [dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.PERSISTENCY_OFF,
894            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_8_OUT_OF_8,
895            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_2_IN_LAST_3,
896            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_2_IN_LAST_4,
897            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_2_OUT_OF_8,
898            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_1_IN_LAST_2,
899            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_1_IN_LAST_5,
900            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.VALID_1_IN_LAST_8,
901            dai.StereoDepthConfig.PostProcessing.TemporalFilter.PersistencyMode.PERSISTENCY_INDEFINITELY,
902            ]
903            currentTemporal = StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.persistencyMode
904            nextTemporal = temporalSettings[(temporalSettings.index(currentTemporal)+1) % len(temporalSettings)]
905            print(f"Changing temporal persistency to {nextTemporal.name} from {currentTemporal.name}")
906            StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.persistencyMode = nextTemporal
907        if key == ord("n"):
908            StereoConfigHandlerRVC4.newConfig = True
909            decimationSettings = [dai.StereoDepthConfig.PostProcessing.DecimationFilter.DecimationMode.PIXEL_SKIPPING,
910            dai.StereoDepthConfig.PostProcessing.DecimationFilter.DecimationMode.NON_ZERO_MEDIAN,
911            dai.StereoDepthConfig.PostProcessing.DecimationFilter.DecimationMode.NON_ZERO_MEAN,
912            ]
913            currentDecimation = StereoConfigHandlerRVC4.config.postProcessing.decimationFilter.decimationMode
914            nextDecimation = decimationSettings[(decimationSettings.index(currentDecimation)+1) % len(decimationSettings)]
915            print(f"Changing decimation mode to {nextDecimation.name} from {currentDecimation.name}")
916            StereoConfigHandlerRVC4.config.postProcessing.decimationFilter.decimationMode = nextDecimation
917        if key == ord("a"):
918            StereoConfigHandlerRVC4.newConfig = True
919            alignmentSettings = [dai.StereoDepthConfig.AlgorithmControl.DepthAlign.RECTIFIED_RIGHT,
920            dai.StereoDepthConfig.AlgorithmControl.DepthAlign.RECTIFIED_LEFT,
921            dai.StereoDepthConfig.AlgorithmControl.DepthAlign.CENTER,
922            ]
923            currentAlignment = StereoConfigHandlerRVC4.config.algorithmControl.depthAlign
924            nextAlignment = alignmentSettings[(alignmentSettings.index(currentAlignment)+1) % len(alignmentSettings)]
925            print(f"Changing alignment mode to {nextAlignment.name} from {currentAlignment.name}")
926            StereoConfigHandlerRVC4.config.algorithmControl.depthAlign = nextAlignment
927        elif key == ord("1"):
928            StereoConfigHandlerRVC4.newConfig = True
929            StereoConfigHandlerRVC4.config.algorithmControl.enableSwLeftRightCheck = not StereoConfigHandlerRVC4.config.algorithmControl.enableSwLeftRightCheck
930            state = "on" if StereoConfigHandlerRVC4.config.algorithmControl.enableSwLeftRightCheck else "off"
931            print(f"LR-check {state}")
932        elif key == ord("4"):
933            StereoConfigHandlerRVC4.newConfig = True
934            StereoConfigHandlerRVC4.config.costMatching.enableSwConfidenceThresholding = not StereoConfigHandlerRVC4.config.costMatching.enableSwConfidenceThresholding
935            state = "on" if StereoConfigHandlerRVC4.config.costMatching.enableSwConfidenceThresholding else "off"
936            print(f"SW confidence thresholding {state}")
937        elif key == ord("3"):
938            StereoConfigHandlerRVC4.newConfig = True
939            StereoConfigHandlerRVC4.config.algorithmControl.enableExtended = not StereoConfigHandlerRVC4.config.algorithmControl.enableExtended
940            state = "on" if StereoConfigHandlerRVC4.config.algorithmControl.enableExtended else "off"
941            print(f"Extended {state}")
942
943        StereoConfigHandlerRVC4.sendConfig(stereoDepthConfigInQueue)
944
945    def sendConfig(stereoDepthConfigInQueue):
946        if StereoConfigHandlerRVC4.newConfig:
947            StereoConfigHandlerRVC4.newConfig = False
948
949            # configMessage = dai.StereoDepthConfig()
950            configMessage = StereoConfigHandlerRVC4.config
951            if configMessage.confidenceMetrics.occlusionConfidenceWeight + StereoConfigHandlerRVC4.config.confidenceMetrics.motionVectorConfidenceWeight + StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessConfidenceWeight != 32:
952                print("Sum of occlusion, motion vector and flatness confidence weights must be 32")
953
954            stereoDepthConfigInQueue.send(configMessage)
955
956    def updateDefaultConfig(config):
957        StereoConfigHandlerRVC4.config = config
958
959    def registerWindow(stream):
960        cv2.namedWindow(stream, cv2.WINDOW_NORMAL)
961
962        StereoConfigHandlerRVC4.trConfidence.append(StereoConfigHandlerRVC4.Trackbar("Disparity confidence", stream, 0, 255, StereoConfigHandlerRVC4.config.costMatching.confidenceThreshold, StereoConfigHandlerRVC4.trackbarConfidence))
963        StereoConfigHandlerRVC4.trLrCheck.append(StereoConfigHandlerRVC4.Trackbar("LR-check threshold", stream, 0, 16, StereoConfigHandlerRVC4.config.algorithmControl.leftRightCheckThreshold, StereoConfigHandlerRVC4.trackbarLrCheckThreshold))
964        StereoConfigHandlerRVC4.trDisparityShift.append(StereoConfigHandlerRVC4.Trackbar("Disparity shift", stream, 0, 100, StereoConfigHandlerRVC4.config.algorithmControl.disparityShift, StereoConfigHandlerRVC4.trackbarDisparityShift))
965        StereoConfigHandlerRVC4.trCenterAlignmentShift.append(StereoConfigHandlerRVC4.Trackbar("Center alignment shift factor", stream, 0, 100, StereoConfigHandlerRVC4.config.algorithmControl.centerAlignmentShiftFactor, StereoConfigHandlerRVC4.trackbarCenterAlignmentShift))
966        StereoConfigHandlerRVC4.trInvalidateEdgePixels.append(StereoConfigHandlerRVC4.Trackbar("Invalidate edge pixels", stream, 0, 100, StereoConfigHandlerRVC4.config.algorithmControl.numInvalidateEdgePixels, StereoConfigHandlerRVC4.trackbarInvalidateEdgePixels))
967        StereoConfigHandlerRVC4.trTemporalAlpha.append(StereoConfigHandlerRVC4.Trackbar("Temporal filter alpha", stream, 0, 100, int(StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.alpha*100), StereoConfigHandlerRVC4.trackbarTemporalFilterAlpha))
968        StereoConfigHandlerRVC4.trTemporalDelta.append(StereoConfigHandlerRVC4.Trackbar("Temporal filter delta", stream, 0, 100, StereoConfigHandlerRVC4.config.postProcessing.temporalFilter.delta, StereoConfigHandlerRVC4.trackbarTemporalFilterDelta))
969        StereoConfigHandlerRVC4.trSpatialAlpha.append(StereoConfigHandlerRVC4.Trackbar("Spatial filter alpha", stream, 0, 100, int(StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.alpha*100), StereoConfigHandlerRVC4.trackbarSpatialFilterAlpha))
970        StereoConfigHandlerRVC4.trSpatialDelta.append(StereoConfigHandlerRVC4.Trackbar("Spatial filter delta", stream, 0, 100, StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.delta, StereoConfigHandlerRVC4.trackbarSpatialFilterDelta))
971        StereoConfigHandlerRVC4.trSpatialHoleFilling.append(StereoConfigHandlerRVC4.Trackbar("Spatial filter hole filling radius", stream, 0, 16, StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.holeFillingRadius, StereoConfigHandlerRVC4.trackbarSpatialFilterHoleFillingRadius))
972        StereoConfigHandlerRVC4.trSpatialNumIterations.append(StereoConfigHandlerRVC4.Trackbar("Spatial filter number of iterations", stream, 0, 4, StereoConfigHandlerRVC4.config.postProcessing.spatialFilter.numIterations, StereoConfigHandlerRVC4.trackbarSpatialFilterNumIterations))
973        StereoConfigHandlerRVC4.trThresholdMinRange.append(StereoConfigHandlerRVC4.Trackbar("Threshold filter min range", stream, 0, 65, StereoConfigHandlerRVC4.config.postProcessing.thresholdFilter.minRange, StereoConfigHandlerRVC4.trackbarThresholdMinRange))
974        StereoConfigHandlerRVC4.trThresholdMaxRange.append(StereoConfigHandlerRVC4.Trackbar("Threshold filter max range", stream, 0, 65, StereoConfigHandlerRVC4.config.postProcessing.thresholdFilter.maxRange, StereoConfigHandlerRVC4.trackbarThresholdMaxRange))
975        StereoConfigHandlerRVC4.trSpeckleRange.append(StereoConfigHandlerRVC4.Trackbar("Speckle filter range", stream, 0, 240, StereoConfigHandlerRVC4.config.postProcessing.speckleFilter.speckleRange, StereoConfigHandlerRVC4.trackbarSpeckleRange))
976        StereoConfigHandlerRVC4.trDecimationFactor.append(StereoConfigHandlerRVC4.Trackbar("Decimation factor", stream, 1, 4, StereoConfigHandlerRVC4.config.postProcessing.decimationFilter.decimationFactor, StereoConfigHandlerRVC4.trackbarDecimationFactor))
977        StereoConfigHandlerRVC4.tr_occlusionConfidenceWeight.append(StereoConfigHandlerRVC4.Trackbar("Occlusion confidence weight", stream, 0, 32, StereoConfigHandlerRVC4.config.confidenceMetrics.occlusionConfidenceWeight, StereoConfigHandlerRVC4.trackbar_occlusionConfidenceWeight))
978        StereoConfigHandlerRVC4.tr_motionVectorConfidenceWeight.append(StereoConfigHandlerRVC4.Trackbar("Motion vector confidence weight", stream, 0, 32, StereoConfigHandlerRVC4.config.confidenceMetrics.motionVectorConfidenceWeight, StereoConfigHandlerRVC4.trackbar_motionVectorConfidenceWeight))
979        StereoConfigHandlerRVC4.tr_motionVectorConfidenceThreshold.append(StereoConfigHandlerRVC4.Trackbar("Motion vector confidence threshold", stream, 0, 3, StereoConfigHandlerRVC4.config.confidenceMetrics.motionVectorConfidenceThreshold, StereoConfigHandlerRVC4.trackbar_motionVectorConfidenceThreshold))
980        StereoConfigHandlerRVC4.tr_flatnessConfidenceWeight.append(StereoConfigHandlerRVC4.Trackbar("Flatness confidence weight", stream, 0, 32, StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessConfidenceWeight, StereoConfigHandlerRVC4.trackbar_flatnessConfidenceWeight))
981        StereoConfigHandlerRVC4.tr_flatnessConfidenceThreshold.append(StereoConfigHandlerRVC4.Trackbar("Flatness confidence threshold", stream, 1, 7, StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessConfidenceThreshold, StereoConfigHandlerRVC4.trackbar_flatnessConfidenceThreshold))
982        StereoConfigHandlerRVC4.tr_flatnessOverride.append(StereoConfigHandlerRVC4.Trackbar("Flatness override enable", stream, 0, 1, int(StereoConfigHandlerRVC4.config.confidenceMetrics.flatnessOverride), StereoConfigHandlerRVC4.trackbar_flatnessOverride))
983        StereoConfigHandlerRVC4.tr_adaptiveMedianFilter_enable.append(StereoConfigHandlerRVC4.Trackbar("Adaptive median filter enable", stream, 0, 1, int(StereoConfigHandlerRVC4.config.postProcessing.adaptiveMedianFilter.enable), StereoConfigHandlerRVC4.trackbar_adaptiveMedianFilter_enable))
984        StereoConfigHandlerRVC4.tr_adaptiveMedianFilter_threshold.append(StereoConfigHandlerRVC4.Trackbar("Adaptive median filter threshold", stream, 0, 255, StereoConfigHandlerRVC4.config.postProcessing.adaptiveMedianFilter.confidenceThreshold, StereoConfigHandlerRVC4.trackbar_adaptiveMedianFilter_threshold))
985        StereoConfigHandlerRVC4.tr_noiseThresholdOffset.append(StereoConfigHandlerRVC4.Trackbar("Noise threshold offset", stream, 0, 127, StereoConfigHandlerRVC4.config.censusTransform.noiseThresholdOffset, StereoConfigHandlerRVC4.trackbar_noiseThresholdOffset))
986        StereoConfigHandlerRVC4.tr_noiseThresholdScale.append(StereoConfigHandlerRVC4.Trackbar("Noise threshold scale (value - 128)", stream, 0, 255, StereoConfigHandlerRVC4.config.censusTransform.noiseThresholdScale + 128, StereoConfigHandlerRVC4.trackbar_noiseThresholdScale))
987        StereoConfigHandlerRVC4.tr_p1_enableAdaptive.append(StereoConfigHandlerRVC4.Trackbar("P1 enable adaptive", stream, 0, 1, int(StereoConfigHandlerRVC4.config.costAggregation.p1Config.enableAdaptive), StereoConfigHandlerRVC4.trackbar_p1_enableAdaptive))
988        StereoConfigHandlerRVC4.tr_p1_defaultValue.append(StereoConfigHandlerRVC4.Trackbar("P1 default value", stream, 10, 50, StereoConfigHandlerRVC4.config.costAggregation.p1Config.defaultValue, StereoConfigHandlerRVC4.trackbar_p1_defaultValue))
989        StereoConfigHandlerRVC4.tr_p1_edgeValue.append(StereoConfigHandlerRVC4.Trackbar("P1 edge value", stream, 10, 50, StereoConfigHandlerRVC4.config.costAggregation.p1Config.edgeValue, StereoConfigHandlerRVC4.trackbar_p1_edgeValue))
990        StereoConfigHandlerRVC4.tr_p1_smoothValue.append(StereoConfigHandlerRVC4.Trackbar("P1 smooth value", stream, 10, 50, StereoConfigHandlerRVC4.config.costAggregation.p1Config.smoothValue, StereoConfigHandlerRVC4.trackbar_p1_smoothValue))
991        StereoConfigHandlerRVC4.tr_p1_edgeThreshold.append(StereoConfigHandlerRVC4.Trackbar("P1 edge threshold", stream, 8, 16, StereoConfigHandlerRVC4.config.costAggregation.p1Config.edgeThreshold, StereoConfigHandlerRVC4.trackbar_p1_edgeThreshold))
992        StereoConfigHandlerRVC4.tr_p1_smoothThreshold.append(StereoConfigHandlerRVC4.Trackbar("P1 smooth threshold", stream, 2, 12, StereoConfigHandlerRVC4.config.costAggregation.p1Config.smoothThreshold, StereoConfigHandlerRVC4.trackbar_p1_smoothThreshold))
993        StereoConfigHandlerRVC4.tr_p2_enableAdaptive.append(StereoConfigHandlerRVC4.Trackbar("P2 enable adaptive", stream, 0, 1, int(StereoConfigHandlerRVC4.config.costAggregation.p2Config.enableAdaptive), StereoConfigHandlerRVC4.trackbar_p2_enableAdaptive))
994        StereoConfigHandlerRVC4.tr_p2_defaultValue.append(StereoConfigHandlerRVC4.Trackbar("P2 default value", stream, 20, 100, StereoConfigHandlerRVC4.config.costAggregation.p2Config.defaultValue, StereoConfigHandlerRVC4.trackbar_p2_defaultValue))
995        StereoConfigHandlerRVC4.tr_p2_edgeValue.append(StereoConfigHandlerRVC4.Trackbar("P2 edge value", stream, 20, 100, StereoConfigHandlerRVC4.config.costAggregation.p2Config.edgeValue, StereoConfigHandlerRVC4.trackbar_p2_edgeValue))
996        StereoConfigHandlerRVC4.tr_p2_smoothValue.append(StereoConfigHandlerRVC4.Trackbar("P2 smooth value", stream, 20, 100, StereoConfigHandlerRVC4.config.costAggregation.p2Config.smoothValue, StereoConfigHandlerRVC4.trackbar_p2_smoothValue))
997        StereoConfigHandlerRVC4.tr_holefilling_enable.append(StereoConfigHandlerRVC4.Trackbar("Hole filling enable", stream, 0, 1, int(StereoConfigHandlerRVC4.config.postProcessing.holeFilling.enable), StereoConfigHandlerRVC4.trackbar_holefilling_enable))
998        StereoConfigHandlerRVC4.tr_holefilling_highConfidenceThreshold.append(StereoConfigHandlerRVC4.Trackbar("Hole filling high confidence threshold", stream, 0, 255, StereoConfigHandlerRVC4.config.postProcessing.holeFilling.highConfidenceThreshold, StereoConfigHandlerRVC4.trackbar_holefilling_highConfidenceThreshold))
999        StereoConfigHandlerRVC4.tr_holefilling_fillConfidenceThreshold.append(StereoConfigHandlerRVC4.Trackbar("Hole filling fill confidence threshold", stream, 0, 255, StereoConfigHandlerRVC4.config.postProcessing.holeFilling.fillConfidenceThreshold, StereoConfigHandlerRVC4.trackbar_holefilling_fillConfidenceThreshold))
1000        StereoConfigHandlerRVC4.tr_holefilling_minValidDisparity.append(StereoConfigHandlerRVC4.Trackbar("Hole filling min valid disparity", stream, 1, 3, StereoConfigHandlerRVC4.config.postProcessing.holeFilling.minValidDisparity, StereoConfigHandlerRVC4.trackbar_holefilling_minValidDisparity))
1001        StereoConfigHandlerRVC4.tr_holefilling_invalidateDisparities.append(StereoConfigHandlerRVC4.Trackbar("Hole filling invalidate disparities", stream, 0, 1, int(StereoConfigHandlerRVC4.config.postProcessing.holeFilling.invalidateDisparities), StereoConfigHandlerRVC4.trackbar_holefilling_invalidateDisparities))
1002
1003    def __init__(self, config):
1004        print("Control median filter using the 'm' key.")
1005        print("Control depth alignment using the 'a' key.")
1006        print("Control decimation algorithm using the 'a' key.")
1007        print("Control temporal persistency mode using the 'r' key.")
1008        print("Control spatial filter using the 'w' key.")
1009        print("Control temporal filter using the 't' key.")
1010        print("Control speckle filter using the 's' key.")
1011        print("Control left-right check mode using the '1' key.")
1012        print("Control extended mode using the '3' key.")
1013        print("Control SW confidence thresholding using the '4' key.")
1014        if evaluation_mode:
1015            print("Switch between images using '[' and ']' keys.")
1016
1017        StereoConfigHandlerRVC4.config = config
1018
1019
1020# StereoDepth initial config options.
1021outDepth = True  # Disparity by default
1022outConfidenceMap = False  # Output disparity confidence map
1023outRectified = True   # Output and display rectified streams
1024lrcheck = True   # Better handling for occlusions
1025extended = True  # Closer-in minimum depth, disparity range is doubled. Unsupported for now.
1026subpixel = True   # Better accuracy for longer distance, fractional disparity 32-levels
1027
1028width = 1280
1029height = 800
1030
1031xoutStereoCfg = None
1032
1033# Create pipeline
1034pipeline = dai.Pipeline()
1035
1036# Define sources and outputs
1037stereo = pipeline.create(dai.node.StereoDepth)
1038
1039monoLeft = stereo.left.createInputQueue()
1040monoRight = stereo.right.createInputQueue()
1041xinStereoDepthConfig = stereo.inputConfig.createInputQueue()
1042
1043xoutDisparity = stereo.disparity.createOutputQueue()
1044xoutDisparity.setName("disparity")
1045xoutStereoCfg = stereo.outConfig.createOutputQueue()
1046xoutStereoCfg.setName("stereoCfg")
1047xoutLeft = stereo.syncedLeft.createOutputQueue()
1048xoutLeft.setName("left")
1049xoutRight = stereo.syncedRight.createOutputQueue()
1050xoutRight.setName("right")
1051if outDepth:
1052    xoutDepth = stereo.depth.createOutputQueue()
1053    xoutDepth.setName("depth")
1054if outConfidenceMap:
1055    xoutConfMap = stereo.confidenceMap.createOutputQueue()
1056    xoutConfMap.setName("confidenceMap")
1057if outRectified:
1058    xoutRectifLeft = stereo.rectifiedLeft.createOutputQueue()
1059    xoutRectifRight = stereo.rectifiedRight.createOutputQueue()
1060    xoutRectifLeft.setName("rectifiedLeft")
1061    xoutRectifRight.setName("rectifiedRight")
1062
1063if args.debug:
1064    xoutDebugLrCheckIt1 = stereo.debugDispLrCheckIt1.createOutputQueue()
1065    xoutDebugLrCheckIt2 = stereo.debugDispLrCheckIt1.createOutputQueue()
1066    xoutDebugExtLrCheckIt1 = stereo.debugDispLrCheckIt1.createOutputQueue()
1067    xoutDebugExtLrCheckIt2 = stereo.debugDispLrCheckIt1.createOutputQueue()
1068
1069    xoutDebugLrCheckIt1.setName("debugLrCheckIt1")
1070    xoutDebugLrCheckIt2.setName("debugLrCheckIt2")
1071    xoutDebugExtLrCheckIt1.setName("debugExtLrCheckIt1")
1072    xoutDebugExtLrCheckIt2.setName("debugExtLrCheckIt2")
1073
1074if args.dumpdisparitycostvalues:
1075    xoutDebugCostDump = stereo.debugDispCostDump.createOutputQueue()
1076    xoutDebugCostDump.setName("debugCostDump")
1077
1078# Properties
1079stereo.initialConfig.setMedianFilter(dai.MedianFilter.MEDIAN_OFF)  # KERNEL_7x7 default
1080stereo.setLeftRightCheck(lrcheck)
1081stereo.setExtendedDisparity(extended)
1082stereo.setSubpixel(subpixel)
1083stereo.initialConfig.setSubpixelFractionalBits(4)
1084
1085stereo.initialConfig.costMatching.disparityWidth = dai.StereoDepthConfig.CostMatching.DisparityWidth.DISPARITY_64
1086
1087stereo.initialConfig.setConfidenceThreshold(127)
1088stereo.initialConfig.setLeftRightCheckThreshold(4)
1089
1090# Switching depthAlign mode at runtime is not supported while aligning to a specific camera is enabled
1091stereo.setDepthAlign(dai.StereoDepthConfig.AlgorithmControl.DepthAlign.RECTIFIED_LEFT)
1092
1093# allocates resources for worst case scenario
1094# allowing runtime switch of stereo modes
1095stereo.setRuntimeModeSwitch(True)
1096
1097currentConfig = stereo.initialConfig
1098
1099platform = pipeline.getDefaultDevice().getPlatform()
1100
1101if platform == dai.Platform.RVC2:
1102    StereoConfigHandler = StereoConfigHandlerRVC2
1103elif platform == dai.Platform.RVC4:
1104    StereoConfigHandler = StereoConfigHandlerRVC4
1105    currentConfig.confidenceMetrics = stereo.initialConfig.confidenceMetrics
1106else:
1107    StereoConfigHandler = StereoConfigHandlerRVC2
1108
1109StereoConfigHandler(currentConfig)
1110StereoConfigHandler.registerWindow("Stereo control panel")
1111
1112if(args.calibration):
1113    calibrationHandler = dai.CalibrationHandler(args.calibration)
1114    pipeline.setCalibrationData(calibrationHandler)
1115stereo.setInputResolution(width, height)
1116stereo.setRectification(args.rectify)
1117baseline = 75
1118fov = 71.86
1119focal = width / (2 * math.tan(fov / 2 / 180 * math.pi))
1120
1121stereo.setBaseline(baseline/10)
1122stereo.setFocalLength(focal)
1123
1124
1125def convertToCv2Frame(name, image, config):
1126
1127    maxDisp = config.getMaxDisparity()
1128    subpixelLevels = pow(2, config.algorithmControl.subpixelFractionalBits)
1129    subpixel = config.algorithmControl.enableSubpixel
1130    dispIntegerLevels = maxDisp if not subpixel else maxDisp / subpixelLevels
1131
1132    frame = image.getFrame()
1133
1134    # frame.tofile(name+".raw")
1135
1136    if name == "depth":
1137        dispScaleFactor = baseline * focal
1138        with np.errstate(divide="ignore"):
1139            frame = dispScaleFactor / frame
1140            if np.isnan(frame).any() or np.isinf(frame).any():
1141                frame = np.nan_to_num(frame, nan=0, posinf=0, neginf=0)
1142
1143        frame = np.clip(frame * 255. / dispIntegerLevels, 0, 255).astype(np.uint8)
1144        frame = cv2.applyColorMap(frame, cv2.COLORMAP_HOT)
1145    elif "confidence_map" in name:
1146        pass
1147    elif name == "disparity_cost_dump":
1148        # frame.tofile(name+".raw")
1149        pass
1150    elif "disparity" in name:
1151        if 1: # Optionally, extend disparity range to better visualize it
1152            frame = (frame * 255. / maxDisp).astype(np.uint8)
1153        return frame
1154        # if 1: # Optionally, apply a color map
1155        #     frame = cv2.applyColorMap(frame, cv2.COLORMAP_HOT)
1156
1157    return frame
1158
1159class DatasetManager:
1160    def __init__(self, path):
1161        self.path = path
1162        self.index = 0
1163        self.names = [d for d in os.listdir(path) if os.path.isdir(os.path.join(path, d))]
1164        if len(self.names) == 0:
1165            raise RuntimeError("No dataset found at {}".format(path))
1166
1167    def get(self):
1168        return os.path.join(self.path, self.names[self.index])
1169
1170    def get_name(self):
1171        return self.names[self.index]
1172
1173    def next(self):
1174        self.index = (self.index + 1) % len(self.names)
1175        return self.get()
1176
1177    def prev(self):
1178        self.index = (self.index - 1) % len(self.names)
1179        return self.get()
1180
1181
1182def read_pfm(file):
1183    file = open(file, "rb")
1184
1185    color = None
1186    width = None
1187    height = None
1188    scale = None
1189    endian = None
1190
1191    header = file.readline().rstrip()
1192    if header.decode("ascii") == "PF":
1193        color = True
1194    elif header.decode("ascii") == "Pf":
1195        color = False
1196    else:
1197        raise Exception("Not a PFM file.")
1198
1199    dim_match = re.search(r"(\d+)\s(\d+)", file.readline().decode("ascii"))
1200    if dim_match:
1201        width, height = map(int, dim_match.groups())
1202    else:
1203        raise Exception("Malformed PFM header.")
1204
1205    scale = float(file.readline().rstrip())
1206    if scale < 0: # little-endian
1207        endian = "<"
1208        scale = -scale
1209    else:
1210        endian = ">" # big-endian
1211
1212    data = np.fromfile(file, endian + "f")
1213    shape = (height, width, 3) if color else (height, width)
1214    return np.flip(np.reshape(data, shape), axis=0), scale
1215
1216def calculate_err_measures(gt_img, oak_img):
1217    assert gt_img.shape == oak_img.shape
1218
1219    gt_mask = gt_img != 0
1220    oak_mask = oak_img != 0
1221    mask = gt_mask & oak_mask
1222
1223    gt_img[~gt_mask] = 0.
1224    oak_img[~mask] = 0.
1225    err = np.abs(gt_img - oak_img)
1226
1227    n = np.sum(gt_mask)
1228    invalid = np.sum(gt_mask & ~oak_mask)
1229
1230    bad05 = np.sum(mask & (err > 0.5))
1231    bad1 = np.sum(mask & (err > 1.))
1232    bad2 = np.sum(mask & (err > 2.))
1233    bad4 = np.sum(mask & (err > 4.))
1234    sum_err = np.sum(err[mask])
1235    sum_sq_err = np.sum(err[mask] ** 2)
1236    errs = err[mask]
1237
1238    bad05_p = 100. * bad05 / n
1239    total_bad05_p = 100. * (bad05 + invalid) / n
1240    bad1_p = 100. * bad1 / n
1241    total_bad1_p = 100. * (bad1 + invalid) / n
1242    bad2_p = 100. * bad2 / n
1243    total_bad2_p = 100. * (bad2 + invalid) / n
1244    bad4_p = 100. * bad4 / n
1245    total_bad4_p = 100. * (bad4 + invalid) / n
1246    invalid_p = 100. * invalid / n
1247    if n == invalid:
1248        avg_err = 0.
1249        mse = 0.
1250    else:
1251        avg_err = sum_err / (n - invalid)
1252        mse = sum_sq_err / (n - invalid)
1253    if len(errs) == 0:
1254        a50 = 0.
1255        a90 = 0.
1256        a95 = 0.
1257        a99 = 0.
1258    else:
1259        a50 = np.percentile(errs, 50)
1260        a90 = np.percentile(errs, 90)
1261        a95 = np.percentile(errs, 95)
1262        a99 = np.percentile(errs, 99)
1263
1264    return {
1265        "bad0.5": bad05_p,
1266        "total_bad0.5": total_bad05_p,
1267        "bad1": bad1_p,
1268        "total_bad1": total_bad1_p,
1269        "bad2": bad2_p,
1270        "total_bad2": total_bad2_p,
1271        "bad4": bad4_p,
1272        "total_bad4": total_bad4_p,
1273        "invalid": invalid_p,
1274        "avg_err": avg_err,
1275        "mse": mse,
1276        "a50": a50,
1277        "a90": a90,
1278        "a95": a95,
1279        "a99": a99
1280    }
1281
1282def show_evaluation(img_name, evals):
1283    cv2.namedWindow("Evaluation", cv2.WINDOW_NORMAL)
1284    font = cv2.FONT_HERSHEY_SIMPLEX
1285    font_scale = 2
1286    thickness = 3
1287    color = (0, 0, 0)
1288    lines = [
1289        f"Name: {img_name}",
1290        f"Bad0.5: {evals['bad0.5']:.2f}%",
1291        f"Total Bad0.5: {evals['total_bad0.5']:.2f}%",
1292        f"Bad1: {evals['bad1']:.2f}%",
1293        f"Total Bad1: {evals['total_bad1']:.2f}%",
1294        f"Bad2: {evals['bad2']:.2f}%",
1295        f"Total Bad2: {evals['total_bad2']:.2f}%",
1296        f"Bad4: {evals['bad4']:.2f}%",
1297        f"Total Bad4: {evals['total_bad4']:.2f}%",
1298        f"Invalid: {evals['invalid']:.2f}%",
1299        f"Avg Err: {evals['avg_err']:.2f}",
1300        f"MSE: {evals['mse']:.2f}",
1301        f"A50: {evals['a50']:.2f}",
1302        f"A90: {evals['a90']:.2f}",
1303        f"A95: {evals['a95']:.2f}",
1304        f"A99: {evals['a99']:.2f}"
1305    ]
1306    sizes = [cv2.getTextSize(line, font, font_scale, thickness) for line in lines]
1307    sizes = [(size[0][0], size[0][1] + size[1], size[1]) for size in sizes]
1308    max_width = max([size[0] for size in sizes])
1309    total_height = sum([size[1] for size in sizes]) + (len(lines) - 1) * thickness
1310    img = np.ones((total_height + thickness, max_width, 3), dtype=np.uint8) * 255
1311    y = 0
1312    for line, size in zip(lines, sizes):
1313        cv2.putText(img, line, (0, y + size[1] - size[2]), font, font_scale, color, thickness)
1314        y += size[1] + thickness
1315    cv2.imshow("Evaluation", img)
1316
1317def show_debug_disparity(gt_img, oak_img):
1318    def rescale_img(img):
1319        img[img == np.inf] = 0.
1320        img = cv2.resize(img, (1280, 800), interpolation=cv2.INTER_AREA)
1321        return img.astype(np.uint16)
1322
1323    gt_img = rescale_img(gt_img)
1324    oak_img = rescale_img(oak_img)
1325    maxv = max(gt_img.max(), oak_img.max())
1326    gt_img = (gt_img * 255. / maxv).astype(np.uint8)
1327    oak_img = (oak_img * 255. / maxv).astype(np.uint8)
1328    cv2.imshow("GT", gt_img)
1329    cv2.imshow("OAK", oak_img)
1330
1331if evaluation_mode:
1332    dataset = DatasetManager(args.evaluate)
1333
1334    # Get the current timestamp
1335    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
1336    # Create the filename with the timestamp
1337    filename = f"stereo_middleburry_{'RVC2' if platform == dai.Platform.RVC2 else 'RVC4'}_{timestamp}.csv"
1338    # Write the dictionary to a CSV file (append mode)
1339    file_exists = False
1340
1341    try:
1342        with open(filename, 'r'):
1343            file_exists = True
1344    except FileNotFoundError:
1345        pass
1346
1347print("Connecting and starting the pipeline")
1348# Connect to device and start pipeline
1349with pipeline:
1350    pipeline.start()
1351
1352    stereoDepthConfigInQueue = xinStereoDepthConfig
1353
1354    inStreamsCameraID = [dai.CameraBoardSocket.CAM_B, dai.CameraBoardSocket.CAM_C]
1355    in_q_list = []
1356    in_q_list.append(monoLeft)
1357    in_q_list.append(monoRight)
1358
1359    # Create a receive queue for each stream
1360    q_list = []
1361    q_list.append(xoutLeft)
1362    q_list.append(xoutRight)
1363    if outDepth:
1364        q_list.append(xoutDepth)
1365    if outConfidenceMap:
1366        q_list.append(xoutConfMap)
1367    q_list.append(xoutDisparity)
1368    if outRectified:
1369        q_list.append(xoutRectifLeft)
1370        q_list.append(xoutRectifRight)
1371
1372    inCfg = xoutStereoCfg
1373
1374    # Need to set a timestamp for input frames, for the sync stage in Stereo node
1375    timestamp_ms = 0
1376    index = 0
1377    prevQueues = q_list.copy()
1378    while pipeline.isRunning():
1379        # Handle input streams, if any
1380        if in_q_list:
1381            dataset_size = 1  # Number of image pairs
1382            frame_interval_ms = 50
1383            q_names = ["in_left", "in_right"]
1384            for i, q in enumerate(in_q_list):
1385                path = os.path.join(dataset.get(), f"im{i}.png") if evaluation_mode else args.dataset + "/" + str(index) + "/" + q_names[i] + ".png"
1386                data = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
1387                data = cv2.resize(data, (width, height), interpolation = cv2.INTER_AREA)
1388                data = data.reshape(height*width)
1389                tstamp = datetime.timedelta(seconds = timestamp_ms // 1000,
1390                                            milliseconds = timestamp_ms % 1000)
1391                img = dai.ImgFrame()
1392                img.setData(data)
1393                img.setTimestamp(tstamp)
1394                img.setInstanceNum(inStreamsCameraID[i])
1395                img.setType(dai.ImgFrame.Type.RAW8)
1396                img.setWidth(width)
1397                img.setStride(width)
1398                img.setHeight(height)
1399                q.send(img)
1400                # print("Sent frame: {:25s}".format(path), "timestamp_ms:", timestamp_ms)
1401            timestamp_ms += frame_interval_ms
1402            index = (index + 1) % dataset_size
1403            sleep(frame_interval_ms / 1000)
1404
1405        gt_disparity = None
1406        if evaluation_mode:
1407            # Load GT disparity
1408            if currentConfig.algorithmControl.depthAlign == dai.StereoDepthConfig.AlgorithmControl.DepthAlign.RECTIFIED_LEFT:
1409                gt_disparity = read_pfm(os.path.join(dataset.get(), f"disp0.pfm"))[0]
1410            else:
1411                gt_disparity = read_pfm(os.path.join(dataset.get(), f"disp1.pfm"))[0]
1412
1413        # Handle output streams
1414        currentConfig = inCfg.get()
1415
1416        lrCheckEnabled = currentConfig.algorithmControl.enableLeftRightCheck
1417        extendedEnabled = currentConfig.algorithmControl.enableExtended
1418        queues = q_list.copy()
1419
1420        if args.dumpdisparitycostvalues:
1421            queues.append(xoutDebugCostDump)
1422
1423        if args.debug:
1424            q_list_debug = []
1425
1426            activeDebugStreams = []
1427            if lrCheckEnabled:
1428                q_list_debug.append(xoutDebugLrCheckIt1)
1429                q_list_debug.append(xoutDebugLrCheckIt2)
1430            if extendedEnabled:
1431                q_list_debug.append(xoutDebugExtLrCheckIt1)
1432                if lrCheckEnabled:
1433                    q_list_debug.append(xoutDebugExtLrCheckIt2)
1434
1435            queues.extend(q_list_debug)
1436
1437        def ListDiff(li1, li2):
1438            return list(set(li1) - set(li2)) + list(set(li2) - set(li1))
1439
1440        diff = ListDiff(prevQueues, queues)
1441        for s in diff:
1442            name = s.getName()
1443            cv2.destroyWindow(name)
1444        prevQueues = queues.copy()
1445
1446        disparity = None
1447        for q in queues:
1448            if q.getName() in ["left", "right"]: continue
1449            data = q.get()
1450            if q.getName() == "disparity":
1451                disparity = data.getFrame()
1452            frame = convertToCv2Frame(q.getName(), data, currentConfig)
1453            cv2.imshow(q.getName(), frame)
1454
1455        if disparity is not None and gt_disparity is not None:
1456            subpixel_bits = 1 << currentConfig.algorithmControl.subpixelFractionalBits
1457            subpixel_enabled = currentConfig.algorithmControl.enableSubpixel
1458            width_scale = float(gt_disparity.shape[1]) / float(disparity.shape[1])
1459
1460            disparity = disparity.astype(np.float32)
1461            if subpixel_enabled:
1462                disparity = disparity / subpixel_bits
1463            disparity = disparity * width_scale
1464            disparity = cv2.resize(disparity, (gt_disparity.shape[1], gt_disparity.shape[0]), interpolation = cv2.INTER_LINEAR)
1465
1466            gt_disparity[gt_disparity == np.inf] = 0
1467            # disparity[disparity == 0.] = np.inf
1468
1469            show_debug_disparity(gt_disparity, disparity)
1470            err_vals = calculate_err_measures(gt_disparity, disparity)
1471            show_evaluation(dataset.get_name(), err_vals)
1472            err_vals["name"] = dataset.get_name()
1473
1474        saveToCsvFile = False
1475        key = cv2.waitKey(1)
1476        if key == ord("q"):
1477            break
1478        elif evaluation_mode and key == ord("["):
1479            dataset.next()
1480            saveToCsvFile = True
1481        elif evaluation_mode and key == ord("]"):
1482            dataset.prev()
1483            saveToCsvFile = True
1484
1485        if saveToCsvFile:
1486            with open(filename, 'a', newline='') as csvfile:
1487                writer = csv.writer(csvfile)
1488                # Write the header only if the file doesn't exist
1489                if not file_exists:
1490                    writer.writerow(err_vals.keys())
1491                    file_exists = True
1492                # Write the err_vals
1493                writer.writerow(err_vals.values())
1494
1495        StereoConfigHandler.handleKeypress(key, stereoDepthConfigInQueue)

Similar samples

Pipeline

Need assistance?

Head over to Discussion Forum for technical support or any other questions you might have.