Opencv возвращается к более высокому разрешению, чем то, что я установил

У меня проблема с сохранением изображений. Я хочу начать с того, что не хочу изменять размер изображения после его получения, я хочу, чтобы веб-камера работала с собственным более низким разрешением, которое поддерживает моя камера. Я использую ОС Raspberry Pi. Поддерживаемые разрешения поддерживаются.

pi@raspberrypi:~/Desktop $ v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture

[0]: 'YUYV' (YUYV 4:2:2)
    Size: Discrete 640x480
        Interval: Discrete 0.033s (30.000 fps)
    Size: Discrete 352x288
        Interval: Discrete 0.033s (30.000 fps)
    Size: Discrete 320x240
        Interval: Discrete 0.033s (30.000 fps)
    Size: Discrete 176x144
        Interval: Discrete 0.033s (30.000 fps)
    Size: Discrete 160x120
        Interval: Discrete 0.033s (30.000 fps)

Я попытался изменить разрешение через терминал и через свой код на C++ следующим образом.

в C++

stream.set(cv::CAP_PROP_FRAME_WIDTH, 320);
stream.set(cv::CAP_PROP_FRAME_HEIGHT, 240);

в терминале поменял и проверил разрешение

pi@raspberrypi:~/Desktop $ v4l2-ctl -d0 --set-fmt-video=width=320,height=240
pi@raspberrypi:~/Desktop $ v4l2-ctl -d0 --get-fmt-video | egrep 'Pixel Format|Width/Height'
Width/Height      : 320/240
Pixel Format      : 'YUYV' (YUYV 4:2:2)
pi@raspberrypi:~/Desktop $ v4l2-ctl -d2 --set-fmt-video=width=320,height=240
pi@raspberrypi:~/Desktop $ v4l2-ctl -d2 --get-fmt-video | egrep 'Pixel Format|Width/Height'
Width/Height      : 320/240
Pixel Format      : 'YUYV' (YUYV 4:2:2)
pi@raspberrypi:~/Desktop $ v4l2-ctl -d4 --set-fmt-video=width=320,height=240
pi@raspberrypi:~/Desktop $ v4l2-ctl -d4 --get-fmt-video | egrep 'Pixel Format|Width/Height'
Width/Height      : 320/240
Pixel Format      : 'YUYV' (YUYV 4:2:2)

Когда я запускаю свой код, он всегда сохраняется с более высоким разрешением 640x480. Я использую 3 потока для каждого потока. В коде нет ничего принципиально неправильного, он сохраняет, но в более высоком разрешении. Но когда я запускаю что-то вроде streamer -f jpeg -o image.jpeg, он сохраняет правильно

Простой пример кода на C++, который не сохраняется в разрешении 320/240, но сохраняет в разрешении 640x480. Выполнение приведенного выше кода egrep также показывает, что ширина / высота возвращаются к 640/480. Поэтому я уверен, что OpenCV не очень хорошо играет, когда я меняю эти значения.

#include <stdio.h>
#include <stdlib.h>
#include <thread>
#include <iostream>
#include <fstream>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <string>
#include <boost/date_time/posix_time/posix_time.hpp>


int main(){
int i = 0;
    cv::VideoCapture stream(0);
    stream.set(cv::CAP_PROP_FRAME_WIDTH, 320);
    stream.set(cv::CAP_PROP_FRAME_HEIGHT, 240);
    cv::Mat3b Frame;
    if(!stream.isOpened())
{
    std::cout << "Cannot Open Camera: " + 0 + '\n';
}
else
{
    std::cout << "Camera Open: " << 0 + '\n';
}

    while (true)
    {
        stream.open(0);
        const boost::posix_time::ptime now = 
            boost::posix_time::microsec_clock::local_time();
        const boost::posix_time::time_duration td = now.time_of_day();
        const long year         = now.date().year();
        const long month        = now.date().month();
        const long day          = now.date().day();
        const long hours        = td.hours();
        const long minutes      = td.minutes();
        const long seconds      = td.seconds();
        const long milliseconds = td.total_milliseconds() -
                                  ((hours * 3600 + minutes * 60 + seconds) * 1000);

        char buf[80];
        sprintf(buf, "%02ld%02ld%02ld_%02ld%02ld%02ld__%03ld", 
            year, month, day, hours, minutes, seconds, milliseconds);
            std::string sBuf = buf;
            std::string PATH = std::string("/home/pi/Desktop/") +
                            "camA" + 
                                '/' +
                                "camA" +
                                '_' +
                                sBuf +
                                ".jpeg";
        stream.grab();
        stream.retrieve(Frame);
        cv::imwrite(PATH, Frame);
        i++;
        if (i == 1){
            stream.release();
            break;
        }
    }
}

Есть идеи, что я могу сделать, чтобы это исправить? Может быть, изменить / dev / video* только на чтение, если это разрешено с OpenCV?

1 ответ

Я думаю, что лучше, если вы используете api библиотеки v4l2 напрямую. См. Полный пример здесь: https://gist.github.com/maxlapshin/1253534

Для установки ширины и высоты они используют этот код:

if (force_format) {
fprintf(stderr, "Set H264\r\n");
            fmt.fmt.pix.width       = 640; //replace
            fmt.fmt.pix.height      = 480; //replace
            fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_H264; //replace
            fmt.fmt.pix.field       = V4L2_FIELD_ANY;

            if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
                    errno_exit("VIDIOC_S_FMT");

            /* Note VIDIOC_S_FMT may change width and height. */
    }

Вы можете установить здесь свои собственные значения. Я предлагаю вам дать себе время проанализировать и протестировать пример.

Другие вопросы по тегам