Raspberry Pi로 실시간 영상 처리

카메라 모듈 사용법


OpenCV 설치

apt install libopencv-dev

OpenCV 코드

g++ hud0.cc -o hud.outpkg-config --cflags --libs opencv4`

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 카메라 열기
    cv::VideoCapture cap(0); // 0은 기본 카메라를 의미

    if (!cap.isOpened()) {
        std::cerr << "카메라를 열 수 없습니다." << std::endl;
        return -1;
    }

    while (true) {
        cv::Mat frame;
        // 카메라로부터 프레임 읽기
        cap >> frame;

        if (frame.empty()) {
            std::cerr << "프레임을 읽을 수 없습니다." << std::endl;
            break;
        }

        // "hello world" 텍스트 추가
        std::string text = "hello world";
        cv::Point position(50, 50); // 텍스트의 위치 (x, y)
        int font = cv::FONT_HERSHEY_SIMPLEX; // 글꼴
        double fontScale = 1.0; // 글꼴 크기
        cv::Scalar color(0, 255, 0); // 초록색 (B, G, R)
        int thickness = 2; // 텍스트 두께

        cv::putText(frame, text, position, font, fontScale, color, thickness);

        // 결과 영상 표시
        cv::imshow("Camera", frame);

        // 'q'를 누르면 종료
        if (cv::waitKey(1) == 'q') {
            break;
        }
    }

    // 자원 해제
    cap.release();
    cv::destroyAllWindows();

    return 0;
}

영상 데이터를 전송

#include <opencv2/opencv.hpp>
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 8080

int main() {
    // 카메라 열기
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        std::cerr << "카메라를 열 수 없습니다." << std::endl;
        return -1;
    }

    // 소켓 생성
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        std::cerr << "소켓 생성 실패" << std::endl;
        return -1;
    }

    // 서버 주소 설정
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.2"); // 수신 PC의 IP 주소로 변경

    // 서버에 연결
    if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "서버 연결 실패" << std::endl;
        return -1;
    }

    std::cout << "서버에 연결되었습니다." << std::endl;

    while (true) {
        cv::Mat frame;
        cap >> frame; // 프레임 캡처

        if (frame.empty()) {
            std::cerr << "프레임 캡처 실패" << std::endl;
            break;
        }

        // 프레임을 JPEG로 인코딩
        std::vector<uchar> buffer;
        cv::imencode(".jpg", frame, buffer);

        // 버퍼 크기 전송
        int buffer_size = buffer.size();
        send(sock, &buffer_size, sizeof(buffer_size), 0);

        // 프레임 데이터 전송
        send(sock, buffer.data(), buffer_size, 0);

        // 'q'를 누르면 종료
        if (cv::waitKey(1) == 'q') {
            break;
        }
    }

    // 자원 해제
    close(sock);
    cap.release();
    return 0;
}

영상 데이터를 수신

#include <opencv2/opencv.hpp>
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 8080

int main() {
    // 소켓 생성
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == 0) {
        std::cerr << "소켓 생성 실패" << std::endl;
        return -1;
    }

    // 서버 주소 설정
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY; // 모든 네트워크 인터페이스에서 수신
    address.sin_port = htons(PORT);

    // 소켓 바인딩
    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
        std::cerr << "바인딩 실패" << std::endl;
        return -1;
    }

    // 연결 대기
    if (listen(server_fd, 3) < 0) {
        std::cerr << "연결 대기 실패" << std::endl;
        return -1;
    }

    std::cout << "클라이언트 연결 대기 중..." << std::endl;

    int new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
    if (new_socket < 0) {
        std::cerr << "클라이언트 연결 실패" << std::endl;
        return -1;
    }

    std::cout << "클라이언트 연결됨!" << std::endl;

    while (true) {
        // 버퍼 크기 수신
        int buffer_size = 0;
        recv(new_socket, &buffer_size, sizeof(buffer_size), 0);

        // 데이터 수신
        std::vector<uchar> buffer(buffer_size);
        recv(new_socket, buffer.data(), buffer_size, 0);

        // JPEG 디코딩
        cv::Mat frame = cv::imdecode(buffer, cv::IMREAD_COLOR);

        if (frame.empty()) {
            std::cerr << "프레임 디코딩 실패" << std::endl;
            break;
        }

        // 화면에 출력
        cv::imshow("Received Frame", frame);

        // 'q'를 누르면 종료
        if (cv::waitKey(1) == 'q') {
            break;
        }
    }

    // 자원 해제
    close(new_socket);
    close(server_fd);
    return 0;
}

메모리 할당 실패하는 문제

module v4l2src0 reported failed to allocate required memory

libcamera 설치

  • 소스코드 다운로드&빌드
git clone https://git.libcamera.org/libcamera/libcamera.git && \
        cd libcamera && \
        meson setup build && \
        ninja -C build install

references