![]()
Real-time MiDaS Depth Estimation with ocvWrapper46
2025.10.13 14:20

program LiveMiDasDepthEstimation;
{$MODE Delphi} {$H+}
uses
SysUtils, StdCtrls,
Messages, Variants, Classes, Graphics,
Controls, Dialogs, Interfaces,
OPENCVWrapper; // Your installed OpenCV Wrapper unit
const
// MiDaS model file path (Adjust this path as needed)
MODEL_FILE_NAME = '../../Midas-v2.1-model-small.onnx';
// Window names
WIN_ORIGINAL = 'Original Feed';
WIN_DEPTH = 'MiDaS Depth Map';
// Define global variables for OpenCV objects
var
W_IN: integer = 256;
H_IN: Integer = 256;
SCALE: Single = 0.003922;
// Camera capture handle
capture: PCvVideoCapture_t;
// DNN network handle
net: PCvdnn_Net_t;
// Image Mat structures
frame: PCvMat_t; // Stores the raw camera frame (BGR)
outmat: PCvMat_t; // Stores the raw output blob from the DNN
heatMap: PCvMat_t; // Final processed depth heatmap
outgray: PCvMat_t; // Grayscale version of the depth map
outHeatmap: PCvMat_t;
outColor: PCvMat_t; // Blended output image
// Timing and utility variables
StartCount, StopCount, Freq: Int64;
TimingSeconds: Double;
vMin, vMax: Double;
matdims: array[0..1] of Integer;
outcvSize: PCvSize_t;
cvstr: PCVString_t;
c: Integer; // Key press value
modelBin: CvString_t;
winameOrig, winnameDepth : CvString_t;
// --- DNN Initialization ---
procedure InitializeMiDasNet;
begin
Writeln('Initializing MiDaS DNN...');
// 1. Read the network model from the ONNX file
modelBin.pstr := PAnsiChar(MODEL_FILE_NAME);
net := pCvdnn_readNetFromONNX(@modelBin);
if pCvdnn_NetEmpty(net) then
begin
Writeln('ERROR: Cannot load MiDaS model. Check file path: ', MODEL_FILE_NAME);
Halt(1);
end;
// 2. Set backend and target (use the default for simplicity, typically CPU)
pCvdnn_NetSetPreferableBackend(net, Ord(DNN_BACKEND_OPENCV));
pCvdnn_NetSetPreferableTarget(net, Ord(DNN_TARGET_CPU));
Writeln('MiDaS Network loaded successfully.');
end;
// --- CORE FRAME PROCESSING FUNCTION ---
// This takes a raw frame and generates a depth image
procedure GenerateDepthMap(const InputFrame: Pointer);
var
blob: PCvMat_t;
outptr: UInt64;
begin
// 1. Create Input Blob
// The MiDaS model requires a specific input size (384x384 or 256x256) and normalization.
// The DNN code snippet suggests 256x256 was used.
blob := pCvdnn_BlobFromImage(InputFrame, 1.0/255.0,
CvSize_(256, 256), // Input size for MiDaS-small
CvScalar_(123.675, 116.28, 103.53, 0), // Mean values for normalization
TRUE, // swapRB (MiDaS uses RGB, OpenCV reads BGR)
FALSE
);
// 2. Set the input and run the forward pass
pCvdnn_NetSetInput(net, blob);
// Start timing for performance check
// QueryPerformanceCounter(StartCount); // If using timing
outmat := pCvdnn_Netforward(net); // Get the raw depth output
// QueryPerformanceCounter(StopCount); // If using timing
// ... calculate and display TimingSeconds ...
// 3. Process the Output (Copied from frmMidasDNN.pas)
// The output 'outmat' is a 256x256 single-channel float map.
outptr := pCvMatGetDimPtr(outmat, 0, 0);
matdims[0] := 256;
matdims[1] := 256;
// Map the raw data into a Mat structure
heatMap := pCvMatCreate(2, @matdims[0], CV_32F, outptr);
// 4. Normalize and Convert to Grayscale
pCvminMaxLoc(heatMap, @vMin, @vMax );
outgray := pCvMatCreateEmpty;
// Scale the float depth values (vMin to vMax) to 8-bit image range (0-255)
pCvMatConvertTo(heatMap, outgray, CV_8UC1, (255.0/(vMax - vMin)));
// 5. Apply Colormap for Visualization
outColor := pCvMatCreateEmpty;
pCvapplyColorMap(outgray, outColor, Ord(COLORMAP_JET));
// 6. Resize the depth map to match the original frame size for display
outcvSize := CvSize_(pCvMatGetWidth(InputFrame), pCvMatGetHeight(InputFrame));
pCvresize(outColor, outColor, outcvSize);
// 7. Clean up intermediate blob
pCvMatDelete(blob);
end;
// --- Main Execution ---
begin
// A. Initialization
winameOrig.pstr:= PAnsiChar(AnsiString(WIN_ORIGINAL));
winnameDepth.pstr:= PAnsiChar(AnsiString(WIN_DEPTH));
//pCvNamedWindow(@WIN_ORIGINAL, Ord(WINDOW_AUTOSIZE));
//pCvNamedWindow(@WIN_DEPTH, Ord(WINDOW_AUTOSIZE));
// Initialize the DNN model
InitializeMiDasNet;
// 1. Open the camera stream (usually 0 for the default USB camera)
capture := pCvVideoCaptureCreate;
pCvVideoCaptureopenV3(capture, 0, Ord(CAP_ANY));
if not(pCvVideoCaptureisOpened(capture)) then
begin
Writeln('ERROR: Cannot open camera stream. Check camera ID or drivers.');
Halt(1);
end;
frame := pCvMatCreateEmpty; // Initialize Mat for storing the frame
// B. Main Loop
Writeln('Running... Press ESC or Q to exit.');
while True do
begin
// 2. Read Frame from Stream (The Video Capture part)
if not(pCvVideoCaptureread(capture, frame)) then Break;
{if pCvMatIsEmpty(frame) then
begin
// If the frame is empty, wait briefly before trying again
pCvwaitKey(10);
Continue;
end; }
// 3. Process Frame for Depth
GenerateDepthMap(frame); // Uses the frame to generate outColor (the depth image)
// 4. Display Results
pCvimshow(@winameOrig, frame);
pCvimshow(@winnameDepth, outColor);
// 5. Handle Exit (Press ESC or 'q')
c := pCvwaitKey(1); // Wait for 1 millisecond
if (c = 27) or (c = Ord('q')) then Break;
// 6. Clean up Mats used in the loop
// Note: frame is reused, but outColor and outmat need to be released
// if they were created inside the loop and not reused.
// Since pCvMatCreateEmpty is used inside GenerateDepthMap, the old pointer must be released.
// In this simplified example, we rely on the library's internal handling
// or manual release at the end, but for safety in large loops,
// ensure all temporary Mats are released after use.
end;
// C. Cleanup
Writeln('Cleaning up and exiting.');
pCvVideoCaptureRelease(capture);
pCvdnn_NetDelete(net);
pCvMatDelete(frame);
// Release any other dynamically allocated Mat objects (outColor, outgray, etc.)
end.