Последнее обновление:
August 28, 2017

Есть мысль... Жми, напиши!
Что имеем: Постов : 167 Авторов: 1 Категорий: 37

Конвертация QVideoFrame to OpenCV Mat в Qt5.6 и OpenCV3.1

Потребовалось на днях обрабатывать кадры с камеры (Использовалась QCamera) через OpenCV.

Да,  OpenCV может сам захватывать фреймы, но в случае с Qt QCamera работает лучше и есть больше параметров (например выбо р формата YUV или MJPG).

Вот так выглядит конвертация:

 QVideoFrame copy(frame);
    if (frame.isValid() && copy.map(QAbstractVideoBuffer::ReadOnly)) {
        Mat frameYUV=Mat(copy.height() + copy.height()/2, copy.width(), CV_8UC1, (void*)copy.bits() );
        
        Mat frameRGB;
        cvtColor(frameYUV, frameRGB, CV_YUV2BGRA_I420);

        imshow("Video", frameRGB);

    }

C камеры приходит QVideoFrame frame в формате YUV.

Вот и всё =)

 

 

Views :

157

OpenCV warpPerspective, warpAffine без обрезки (whole image) и размер результата (destination result image size)

В общем потребовалось восстановить перспективу картинки,
на примере этой:

sheet

Как обычно — нашли 4 точки на картинке, в данном случае — углы листа, по часовой стрелке, начиная с верхнего левого:

[20, 340] [860,110] [1160, 650] [200, 950]

Хотим, что бы лист располагался прямо, а для этого мы знаем, что ширина и высота листа 870 на 620 пикселей, аналогично координаты по часовой стрелке, начиная с верхнего левого:

[0, 0] [870, 0] [870, 620] [0, 620]

в данном случае левый верхний угол располагается в нуле (где ещё то), а правый нижний строго по горизонтали и вертикали (мы ведь хотим расположить прямо)

ладно, пора покодить (доки нам в помощь):

/*
* Пока что всё как обычно
* открываем картинку,
* задаём найденные и целевые точки,
*/
Mat input;
input = imread("/home/pavelk/Projects/OpenCVwrapPerspective/sheet.jpg");

Point2f inputQuad[4];
inputQuad[0] = Point2f( 20, 340 );
inputQuad[1] = Point2f( 860,110 );
inputQuad[2] = Point2f( 1160, 650 );
inputQuad[3] = Point2f( 200, 950 );

Point2f outputQuad[4];
outputQuad[0] = Point2f( 0, 0 );
outputQuad[1] = Point2f( 870, 0 );
outputQuad[2] = Point2f( 870, 620 );
outputQuad[3] = Point2f( 0, 620 );

/*
* Находим матрицу трансформации
*/
Mat M = getPerspectiveTransform( inputQuad, outputQuad );

/*
* Теперь применяем трансформацию на картинке с помощью warpPerspective
*/

Mat output;
warpPerspective(input, output, M, Size(2000, 2000));

Но тут сталкиваемся с первой засадой — нужно задать итоговый размер, а его мы до трансформации не знаем =(   Ну ладно, попробуем пока что подгадать.

Посмотрим на вывод:

output1

Как видим, перспективу то мы исправили,
но что если нам так же нужна вся плоскость картинки, а не только сам лист (например потому, что точки  мы можем найти только с помощью этого объекта, а нам нужен абсолютно другой)?
Да и с определением итогового размера можно не угадать, а заранее задавать слишком большой — тормоза для последующих обработок.

Почему так происходит?

Потому, что когда мы задали целевую точку верхнего левого угла [0, 0], то при трансформации получается (см. формулу warpPerspective), что нужно взять позицию с отрицательными координатами с картинки оригинала, а откуда на ней взяться отрицательному-то значению…  Вот и получается обрезка.  Можно, конечно, заранее подгадать смещение целевых точек, что бы не было отрицательных позиций, но мы не знаем, как может повернуться исходная картинка, да и проблему с размером результата мы не решим да и вообще гадать — не мой метод.

Что будем делать?

Как следует из написанного выше — нам нужно сместить целевые точки, поэтому будем выяснять насколько их смещать, а для этого нам нужно выяснить, где окажется левый верхний угол после трансформации. Но! Не забываем, что исходная картинка может быть как угодно повёрнута, и левый нижний окажется дальше в минусе, чем верхний левый. Поэтому выясняем положение после трансформации всех четырёх углов исходной картинки, а что бы не геммороиться с определением где какой угол — найдём их ограничительную рамку, благо для этого в OpenCV есть метод boundingRect и сместим целевые точки в обратную сторону от её позиции, а бонусом по её размеру мы знаем размер итоговой картинки=)

Покодим:

/**
* Выясняем положение углов исходной картинке,
* по ширине и высоте
*/
vector<Point2f> inputCorners(4);
inputCorners[0]=Point2f(0, 0);
inputCorners[1]=Point2f(input.cols, 0);
inputCorners[2]=Point2f(0, input.rows);
inputCorners[3]=Point2f(input.cols, input.rows);

/*
* Выясняем, где они будут - применяем трансформацию
*/
vector<Point2f> outputCorners(4);
perspectiveTransform(inputCorners, outputCorners, M);

/*
* Находим ограничительную рамку
*/
Rect br= boundingRect(outputCorners);

/*
* Сдвигаем все целевые точки в противоположное направление, 
* от того, куда ушла ограничительная рамка
*/
for(int i=0; i<4; i++) {
   outputQuad[i]+=Point2f(-br.x,-br.y);
}

/*
* Ну и заново вычисляем матрицу трансформацию
* с новыми целевыми точками
*/
 M = getPerspectiveTransform( inputQuad, outputQuad );

/*
* Применяем трансформацию к картинке
* размер - как ограничительная рамка
*/
warpPerspective(input, output, M, br.size());

/*
* Ну и показываем итоговую картинку
*/
imshow("Output2", output);

Посмотрим на результат:
output2

По-моему, получилось идеально? =)

Ок, полный листинг на Qt 5.6 console application:

#include <QApplication>
#include <QDebug>
#include <iostream>

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

using namespace std;
using namespace cv;


int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    Mat input = imread("/home/pavelk/Projects/OpenCVwrapPerspective/sheet.jpg");

    Point2f inputQuad[4];
    inputQuad[0] = Point2f( 20, 340 );
    inputQuad[1] = Point2f( 860,110 );
    inputQuad[2] = Point2f( 1160, 650 );
    inputQuad[3] = Point2f( 200, 950 );

    Point2f outputQuad[4];
    outputQuad[0] = Point2f( 0, 0 );
    outputQuad[1] = Point2f( 870, 0 );
    outputQuad[2] = Point2f( 870, 620 );
    outputQuad[3] = Point2f( 0, 620 );

    Mat M = getPerspectiveTransform( inputQuad, outputQuad );

    vector<Point2f> inputCorners(4);
    inputCorners[0]=Point2f(0, 0);
    inputCorners[1]=Point2f(input.cols, 0);
    inputCorners[2]=Point2f(0, input.rows);
    inputCorners[3]=Point2f(input.cols, input.rows);

    vector<Point2f> outputCorners(4);
    perspectiveTransform(inputCorners, outputCorners, M);

    Rect br= boundingRect(outputCorners);

    for(int i=0; i<4; i++) {
        outputQuad[i]+=Point2f(-br.x,-br.y);
    }

    M = getPerspectiveTransform( inputQuad, outputQuad );

    warpPerspective(input, output, M, br.size());

    resize(input, input, Size(1000,1000));
    imshow("Input", input);
    resize(output, output, Size(1000,1000));
    imshow("Output2", output);

    waitKey(5000);

    return app.exec();
}

Вот как-то так =)

Views :

530

OpenCV 3.1 захват видео с камеры в Qt 5.6

Надеюсь, компиляция прошла успешно =)

Обновил на новый лад с использованием Mat

Создаём новый консольный проект, в .pro файле дописываем:

INCLUDEPATH += "/usr/local/opencv/3.1/include/"
LIBS += -L"/usr/local/opencv/3.1/lib/"
LIBS += -lopencv_core \
        -lopencv_features2d \
        -lopencv_highgui \
        -lopencv_imgcodecs \
        -lopencv_imgproc \
        -lopencv_video \
        -lopencv_videoio \
        -lopencv_videostab

Теперь основное main.cpp:

#include <QApplication>
#include <QDebug>

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

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    qDebug()<<"Hello world";

    //-- Выбираем первую попавшуюся камеру
    VideoCapture cap(0);

    //-- Проверяем, удалось ли подключиться
    if (!cap.isOpened()) {
        qDebug()<<"Camera not opened!";
        return 0;
    }

    //-- Выставляем параметры камеры ширину и высоту кадра в пикселях
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 1280);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 960);

    Mat frame;

    while (true) {
        cap >> frame; //-- захватываем очередной кадр

        imshow("Video", frame); //-- показываем его

        char c = cvWaitKey(33); //-- если была нажата клавиша, узнаём её код

        if (c==27) { //-- нажата ESC, прерываем цикл
            break;
        }

    }


    return app.exec();
}

Впринципе, ничего сложного.

Views :

3867

Правильный способ конвертирования cv::Mat в QImage

Некогда рассказывать почему так, но это реально работает =)

QImage Camera::mat2Qimg(const Mat &src) {
    cv::Mat temp;
    cvtColor(src, temp,CV_BGR2RGB);
    QImage dest((uchar*) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
    QImage dest2(dest);
    dest2.detach();
    return dest2;
}
Views :

1062

Компиляция и установка OpenCV на Ubuntu для Qt 5.6 c поддержкой ffmpeg

Обновил для OpenCV 3.1

А началось всё с того что не работает CvCapture* capture = cvCreateFileCapture( filename );

capture возрашает ноль. Сука. Т.е. OpenCV отказывается воспроизводить mp4 видео.

У меня основной путь будет такой  cd /home/pavelk/Projects/OpenCV

Ставим нужные пакеты

sudo apt-get update
sudo apt-get install build-essential checkinstall git cmake libfaac-dev libjack-jackd2-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libsdl1.2-dev libtheora-dev libva-dev libvdpau-dev libvorbis-dev libx11-dev libxfixes-dev libxvidcore-dev texi2html yasm zlib1g-dev

sudo apt-get install libgstreamer0.10-0 libgstreamer0.10-dev gstreamer0.10-tools gstreamer0.10-plugins-base libgstreamer-plugins-base0.10-dev gstreamer0.10-plugins-good gstreamer0.10-plugins-ugly gstreamer0.10-plugins-bad gstreamer0.10-ffmpeg

Добавим x264 и ffmpeg по вкусу.

git clone git://git.videolan.org/x264.git
cd x264
./configure --enable-shared --enable-pic
make
sudo make install
cd ..

git clone git://git.videolan.org/ffmpeg.git 
cd ffmpeg

./configure --enable-gpl --enable-libfaac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libtheora --enable-libvorbis --enable-libx264 --enable-nonfree --enable-postproc --enable-version3 --enable-x11grab --enable-shared

Чёто жопой чую половину тут нафиг не надо… Пофиг пляшем.

make
sudo make install
cd ..
sudo apt-get install libgtk2.0-0 libgtk2.0-dev
sudo apt-get install libjpeg62 libjpeg62-dev
sudo apt-get install cmake-gui

Ну и теперь клонируем наш OpenCV, собираем, ставим:

git clone https://github.com/Itseez/opencv.git OpenCV3.0
cd OpenCV3.0
export PATH=/opt/Qt/5.6/gcc_64/bin:$PATH
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/opencv/3.1/  -DWITH_QT=ON
make -j5
sudo make install

Если нужны дополнительные модули, например xfeatures2d для работы со SURF, то нужно их скачать отдельно и в параметрах компиляции указать папку с модулями:

git clone https://github.com/opencv/opencv_contrib

в параметры cmake добавить:

-DOPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules

Все библиотеки будут в папке /usr/local/opencv/3.0/

 

Простенький пример:

В *.pro файл проекта добавляем:

INCLUDEPATH +="/usr/local/opencv/3.1/include/"
LIBS += -L"/usr/local/opencv/3.1/lib/"
LIBS += -lopencv_core \
        -lopencv_features2d \
        -lopencv_highgui \
        -lopencv_imgcodecs \
        -lopencv_imgproc \
        -lopencv_video \
        -lopencv_videoio \
        -lopencv_videostab

Здесь мы подключаем все библиотеки OpenCV

main.cpp

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
   namedWindow("My Image");
   Mat image = imread("K:/Projects/OpenCV HelloWorld/img.jpg");

   imshow("My Image", image);
   waitKey(5000);

    return 0;
}

Всё должно получиться =)

 

Views :

2900