I have implemented Depth Measuring code to know depth between camera and sand container of a truck to see depth of sand inside the container. I was expecting all different depth in each pixel because it is essentially impossible to have flat depth all around sand content because sand was just dumped into the container without flattening. But When I checked the result of depth camera image, I can only see certain depth values (uniquely only about 13 values). If I make an example of depth array, It would be like this (suppose we got only 3 unique values instead of 13)

[33, 78, 9, 9
33, 78, 9, 9
78, 33, 78, 9
78, 78, 78, 33]

But when I check depth with depthAI viewer, it shows a lot more fine-grained depth values in each pixel. So it must be the code that is wrong in capturing depth in fine-grained manner.

We are using OAK-D S2 PoE camera, and distance between the camera and the container should be roughly 7m.

Here is full code taking out irrelevant parts leaving only depth camera part.
I wish to know where I should fix to get the fine-grained depth values throughout the depth array accurately.

import sys
print(sys.prefix)
import os
import io
import time
import json
import base64
import random
import socket
import datetime
from datetime import timedelta
from multiprocessing import Process, Queue
import threading
import traceback
import statistics
import logging.handlers
import matplotlib.pyplot as plt
from PIL import Image
import timm
import torch
import numpy as np
import pandas as pd
import cv2 
from torchvision import transforms


import subprocess


#### This is for depth camera
import depthai as dai
from datetime import timedelta

import pickle
sys.path.append("/home/sdt/Workspace/onvif/python-onvif-zeep/socket")
# sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


#### for MaskDINO #####

import multiprocessing as mp
# fmt: off
sys.path.insert(1, os.path.join(sys.path[0], '..'))
mp.set_start_method("spawn", force=True)


######################################################################
#                             Save Log                               #
######################################################################
logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
log_max_size = 1024000
log_file_count = 3
log_fileHandler = logging.handlers.RotatingFileHandler(
        filename=f"/home/sdt/Workspace/onvif/python-onvif-zeep/socket/sam2/logs/socket_data.log",
        maxBytes=log_max_size,
        backupCount=log_file_count,
        mode='a')

log_fileHandler.setFormatter(formatter)
logger.addHandler(log_fileHandler)




class depth_cam:
    def __init__(self):
        # Create pipeline
        self.pipeline = dai.Pipeline()
        self.device = dai.Device()
        self.fps = 30

        # The disparity is computed at this resolution, then upscaled to RGB resolution
        #monoResolution = dai.MonoCameraProperties.SensorResolution.THE_720_P
        self.monoResolution = dai.MonoCameraProperties.SensorResolution.THE_800_P
        # Define sources and outputs
        self.camRgb = self.pipeline.create(dai.node.ColorCamera)
        self.left = self.pipeline.create(dai.node.MonoCamera)
        self.right = self.pipeline.create(dai.node.MonoCamera)
        self.stereo = self.pipeline.create(dai.node.StereoDepth)

        try:
            calibData = self.device.readCalibration2()
            lensPosition = calibData.getLensPosition(dai.CameraBoardSocket.CAM_A)
            if lensPosition:
                self.camRgb.initialControl.setManualFocus(lensPosition)
        except:
            raise

        #Properties
        self.camRgb.setBoardSocket(dai.CameraBoardSocket.CAM_A)
        self.camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
        self.camRgb.setFps(self.fps)

        self.left.setResolution(self.monoResolution)
        self.left.setBoardSocket(dai.CameraBoardSocket.CAM_B)
        self.left.setFps(self.fps)
        self.right.setResolution(self.monoResolution)
        self.right.setBoardSocket(dai.CameraBoardSocket.CAM_C)
        self.right.setFps(self.fps)

        self.stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
        # LR-check is required for depth alignment
        self.stereo.setLeftRightCheck(True)
        self.stereo.setDepthAlign(dai.CameraBoardSocket.CAM_A)
        self.h, self.w = 1280, 720

        self.stereo.setOutputSize(self.h, self.w)


        ##################Use this when using Sync##################
        self.sync = self.pipeline.create(dai.node.Sync)
        self.sync.setSyncThreshold(timedelta(milliseconds=50))
        self.sync.inputs["rgb"].setQueueSize(1)
        self.sync.inputs["depth"].setQueueSize(1)
        self.sync.inputs["disparity"].setQueueSize(1)
        
        # Linking
        self.camRgb.isp.link(self.sync.inputs["rgb"])
        self.left.out.link(self.stereo.left)
        self.right.out.link(self.stereo.right)
        self.stereo.depth.link(self.sync.inputs["depth"])
        self.stereo.disparity.link(self.sync.inputs["disparity"])

        self.sync_out = self.pipeline.createXLinkOut()
        self.sync_out.setStreamName("rgbd")
        self.sync.out.link(self.sync_out.input)
        self.sync_out.input.setQueueSize(1)





def main_depth(q, sdt_msdb):
    try:
        packets = q.get()
        logger.info(f"Depth queue got data")

        str_data = packets[0]
        logger.info(f"Depth str_data: {str_data}")
        depth_frame = packets[1]
        logger.info(f"depth_frame shape: {depth_frame.shape}")
        rgb_frame = packets[2]
        logger.info(f"rgb_frame shape: {rgb_frame.shape}")


    except:
            logger.error(traceback.format_exc())
    



if __name__ == "__main__":
    # Fix Seed

    # Load Camera
    depth_camera = depth_cam()
    print("Depth cam initialized")
    logger.info(f"Depth camera initialized: {depth_camera}")

    queue_depth = Queue()

    with depth_camera.device:
        depth_camera.device.startPipeline(depth_camera.pipeline)
        for _ in range(20):
            depth_camera.device.getOutputQueue("rgbd", maxSize=1, blocking=False).getAll()
            logger.info("Left queue for depth camera flushed")

        while True:
            try:

            # Connect to device and start pipeline
                while True:
                    logger.info('Waiting for client......')
                
                    data = client_socket.recv(1024)  # type: bytes
                    if not data:
                        break

                    #############DEPTH CAMERA START########################
                    time.sleep(0.6)
                    depth_camera.messages = depth_camera.device.getOutputQueue("rgbd", maxSize=1, blocking=False).getAll()


                    for message_group in depth_camera.messages:
                        for name, frame in message_group:
                            if name == 'depth':
                                # If the packet from RGB camera is present, we're retrieving the frame in OpenCV format using getCvFrame
                                depth_frame = frame.getCvFrame()##.astype(np.uint16)
                                depth_time = datetime.datetime.now()
                                logger.info(f"Depth depth img saved at : {depth_time}")
                                logger.info(f"Depth depth array saved at : {depth_time}")
                                with open(f"/home/sdt/Workspace/onvif/python-onvif-zeep/hojun/image_test/depth_depth_array/depthFrameArray_{depth_time}_{item_code}_{type_code}_{from_code}.pickle", 'wb') as f:
                                    pickle.dump(depth_frame, f)


                    #=======================================
                    qdata_depth = [depth_frame]
                    queue_depth.put(qdata_depth)

                    sampyo_processes = [
                        Process(target=main_depth, args=(queue_depth))
                    ]
                    
                    for process in sampyo_processes:
                        process.start()


                logger.info(f"[*] Disconnected connection from {client_address[0]}:{client_address[1]}")
                client_socket.close()
                
            except KeyboardInterrupt:
                server_socket.close()
                cv2.destroyAllWindows()

                exit()

            except ConnectionResetError:
                logger.info(f"[*] Client Disconnected.")

            except Exception as e:
                logger.error(traceback.format_exc())
                server_socket.close()
                exit()

Thank you in advance.

Hi,
Looks like the issue is not with the camera, but more how the depth data is used in your code.

  • You use depth.getCvFrame() but maybe not handling the data type correctly, so if you don’t normalize it, it looks weird.
  • The Sync node and how you read from it might not be right — not clear if you really get depth or disparity frames.
  • You don’t turn on things like extendedDisparity, which help a lot when camera is far (like 7m).

I suggest you look at these:

    5 days later

    lovro
    Thank you. I will check on those and get back!