# UVC & Disparity

This example demonstrates how to use your OAK device as a UVC webcam. The UVC feature allows you to use your OAK device as a
regular webcam in applications like OpenCV's `cv2.VideoCapture()`, native camera apps, and more.

### How It Works:

The [StereoDepth](https://docs.luxonis.com/software/depthai-components/nodes/stereo_depth.md) node outputs image data in the UINT8
format. However, the [UVC](https://docs.luxonis.com/software/depthai-components/nodes/uvc.md) node expects the data in NV12
format. To bridge this gap, an intermediary
[ImageManip](https://docs.luxonis.com/software/depthai-components/nodes/image_manip.md) node is used to convert the GRAY8 output
from the MonoCamera node to NV12 format, which is then passed to the UVC node for streaming. This doesn't work with stereo depth
output, since depth is UINT16 which we cannot convert to NV12.

This example won't work if we enable the subpixel disparity feature, since that outputs UINT16 as well.

### Similar samples:

 * [UVC & Color Camera](https://docs.luxonis.com/software/depthai/examples/uvc_rgb.md)
 * [UVC & Mono Camera](https://docs.luxonis.com/software/depthai/examples/uvc_mono.md)

## Setup

Please run the [install script](https://github.com/luxonis/depthai-python/blob/main/examples/install_requirements.py) to download
all required dependencies. Please note that this script must be ran from git context, so you have to download the
[depthai-python](https://github.com/luxonis/depthai-python) repository first and then run the script

```bash
git clone https://github.com/luxonis/depthai-python.git
cd depthai-python/examples
python3 install_requirements.py
```

For additional information, please follow the [installation guide](https://docs.luxonis.com/software/depthai/manual-install.md).

## Code used for testing

```python
import cv2

# Initialize the VideoCapture object to use the default camera (camera index 0 is webcam)
cap = cv2.VideoCapture(1)

# Check if the camera opened successfully
if not cap.isOpened():
    print("Error: Could not open camera.")
    exit()

# Loop to continuously get frames from the camera
while True:
    ret, frame = cap.read()

    if not ret:
        print("Error: Could not read frame.")
        break

    cv2.imshow('Video Feed', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
```

## Source code

#### Python

```python
#!/usr/bin/env python3

import time

import depthai as dai

pipeline = dai.Pipeline()

# Define a source - two mono (grayscale) cameras
mono_left = pipeline.createMonoCamera()
mono_right = pipeline.createMonoCamera()

mono_left.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P)
mono_left.setBoardSocket(dai.CameraBoardSocket.CAM_B)

mono_right.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P)
mono_right.setBoardSocket(dai.CameraBoardSocket.CAM_C)

# Create stereo depth
stereo = pipeline.createStereoDepth()
stereo.initialConfig.setConfidenceThreshold(255)
stereo.setLeftRightCheck(True)
# 0.190 values, better for visualization
stereo.setExtendedDisparity(True)

# Create an UVC (USB Video Class) output node
uvc = pipeline.createUVC()

# Manip for frame type conversion
manip = pipeline.createImageManip()
manip.initialConfig.setResize(1280, 720)
manip.initialConfig.setFrameType(dai.RawImgFrame.Type.NV12)
manip.initialConfig.setColormap(dai.Colormap.STEREO_TURBO, stereo.initialConfig.getMaxDisparity())
manip.setMaxOutputFrameSize(int(1280*720*1.5))

# Linking
mono_left.out.link(stereo.left)
mono_right.out.link(stereo.right)
stereo.disparity.link(manip.inputImage)
manip.out.link(uvc.input)

# Note: if the pipeline is sent later to device (using startPipeline()),
# it is important to pass the device config separately when creating the device
config = dai.Device.Config()
config.board.uvc = dai.BoardConfig.UVC(1280, 720)
config.board.uvc.frameType = dai.ImgFrame.Type.NV12
# config.board.uvc.cameraName = "My Custom Cam"
pipeline.setBoardConfig(config.board)

# Standard UVC load with depthai
with dai.Device(pipeline) as device:
    # Dot projector
    device.setIrLaserDotProjectorBrightness(765)
    print("\nDevice started, please keep this process running")
    print("and open an UVC viewer to check the camera stream.")
    print("\nTo close: Ctrl+C")

    # Doing nothing here, just keeping the host feeding the watchdog
    while True:
        try:
            time.sleep(0.1)
        except KeyboardInterrupt:
            break
```

## Pipeline

### Need assistance?

Head over to [Discussion Forum](https://discuss.luxonis.com/) for technical support or any other questions you might have.
