# Undistort camera stream

This example shows how to undistort a wide FOV camera stream using the
[Camera](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/camera.md) node. Undistortion is not automatic; it
is enabled per output with `requestOutput(..., enableUndistortion=True)` (or `requestFullResolutionOutput`). Any requested output
can be undistorted this way.

Notes:

 * Undistortion does not change the stored camera intrinsics, and there is no exposed "alpha" or equivalent to tune the
   undistortion crop.
 * Undistortion does change the effective FOV; depending on your requested output size and resize mode, you may see less FOV after
   undistortion.

## Demo

This example requires the DepthAI v3 API, see [installation instructions](https://docs.luxonis.com/software-v3/depthai.md).

## Pipeline

## Source code

#### Python

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

import cv2
import depthai as dai

# Create pipeline
with dai.Pipeline() as pipeline:
    # Define source and output
    cam = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B)
    croppedQueue = cam.requestOutput((300,300), resizeMode=dai.ImgResizeMode.CROP, enableUndistortion=True).createOutputQueue()
    stretchedQueue = cam.requestOutput((300,300), resizeMode=dai.ImgResizeMode.STRETCH, enableUndistortion=True).createOutputQueue()
    letterBoxedQueue = cam.requestOutput((300,300), resizeMode=dai.ImgResizeMode.LETTERBOX, enableUndistortion=True).createOutputQueue()

    # Connect to device and start pipeline
    pipeline.start()
    while pipeline.isRunning():
        croppedIn = croppedQueue.get()
        assert isinstance(croppedIn, dai.ImgFrame)
        cv2.imshow("cropped undistorted", croppedIn.getCvFrame())

        stretchedIn = stretchedQueue.get()
        assert isinstance(stretchedIn, dai.ImgFrame)
        cv2.imshow("stretched undistorted", stretchedIn.getCvFrame())

        letterBoxedIn = letterBoxedQueue.get()
        assert isinstance(letterBoxedIn, dai.ImgFrame)
        cv2.imshow("letterboxed undistorted", letterBoxedIn.getCvFrame())

        if cv2.waitKey(1) == ord("q"):
            break
```

#### C++

```cpp
#include <atomic>
#include <csignal>
#include <iostream>
#include <memory>
#include <opencv2/opencv.hpp>
#include <optional>

#include "depthai/depthai.hpp"

// Global flag for graceful shutdown
std::atomic<bool> quitEvent(false);

// Signal handler
void signalHandler(int signum) {
    quitEvent = true;
}

int main() {
    // Set up signal handlers
    signal(SIGTERM, signalHandler);
    signal(SIGINT, signalHandler);

    try {
        // Create pipeline
        dai::Pipeline pipeline;

        // Define source and outputs
        auto cam = pipeline.create<dai::node::Camera>();
        cam->build(dai::CameraBoardSocket::CAM_B, std::nullopt, 30);

        // Create output queues with different resize modes
        auto croppedQueue = cam->requestOutput(std::make_pair(300, 300), dai::ImgFrame::Type::NV12, dai::ImgResizeMode::CROP, 20, 20)->createOutputQueue();

        auto stretchedQueue = cam->requestOutput(std::make_pair(300, 300), dai::ImgFrame::Type::NV12, dai::ImgResizeMode::STRETCH, 20, 20)->createOutputQueue();

        auto letterBoxedQueue =
            cam->requestOutput(std::make_pair(300, 300), dai::ImgFrame::Type::NV12, dai::ImgResizeMode::LETTERBOX, 20, 20)->createOutputQueue();

        // Start pipeline
        pipeline.start();

        // Main loop
        while(pipeline.isRunning() && !quitEvent) {
            // Get and show cropped undistorted frame
            auto croppedIn = croppedQueue->get<dai::ImgFrame>();
            cv::imshow("cropped undistorted", croppedIn->getCvFrame());

            // Get and show stretched undistorted frame
            auto stretchedIn = stretchedQueue->get<dai::ImgFrame>();
            cv::imshow("stretched undistorted", stretchedIn->getCvFrame());

            // Get and show letterboxed undistorted frame
            auto letterBoxedIn = letterBoxedQueue->get<dai::ImgFrame>();
            cv::imshow("letterboxed undistorted", letterBoxedIn->getCvFrame());

            // Check for quit key
            if(cv::waitKey(1) == 'q') {
                break;
            }
        }

        // Cleanup
        pipeline.stop();
        pipeline.wait();

    } catch(const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}
```

### Need assistance?

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