博主QQ:1356438802
QQ群:473383394——UVC&OpenCV47
本文实验平台:win7_64bits + OpenCV 2.4.10 + QT Creator 3.4.1 + QT 5.4.2(MSVC 2013, 32bit)
一、先讲一个题外的东西,但是跟QT和video相关的。
QT5开始有QCamera类,可以很方便的实现camera的预览、拍照、录像。
示例下载:http://download.csdn.net/detail/luoyouren/9570139
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent)
{
this->resize(1280, 720);
camera = NULL;
view_finder = NULL;
camera_image_capture = NULL;
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
if(cameras.count() < 1)
{
qDebug() << "There's not camera available!";
return;
}
camera = new QCamera();
camera_image_capture = new QCameraImageCapture(camera);
//用于实时预览
view_finder = new QCameraViewfinder();
capture_button = new QPushButton();
save_button = new QPushButton();
exit_button = new QPushButton();
QHBoxLayout *main_layout = new QHBoxLayout();
QVBoxLayout *v_layout = new QVBoxLayout();
//用于显示拍照截图, 初始大小为320x240
display_label = new QLabel();
display_label->setFixedSize(320, 240);
//label自适应其内容的大小进行缩放
display_label->setScaledContents(true);
//垂直布局,容纳窗口右边的控件
v_layout->addWidget(display_label);
v_layout->addStretch();
v_layout->addWidget(capture_button);
v_layout->addWidget(save_button);
v_layout->addWidget(exit_button);
//水平布局,主窗口: 左边是预览区域
main_layout->addWidget(view_finder);
main_layout->addLayout(v_layout);
//连接信号和槽函数
connect(capture_button, &QPushButton::clicked, this, &Dialog::captureImage);
connect(save_button, &QPushButton::clicked, this, &Dialog::saveImage);
connect(exit_button, &QPushButton::clicked, this, &Dialog::close);
connect(camera_image_capture, &QCameraImageCapture::imageCaptured, this, &Dialog::displayImage);
/*
* 我的阶段性理解:
* QCameraImageCapture::CaptureToFile
* capture时,可以指定文件名路径,在SIGNAL(imageCaptured)后会自动保存图片文件;
* 如果空的文件名路径,将按照默认规则和默认路径保存图片——"库\图片"
*
* QCameraImageCapture::CaptureToBuffer
* capture时,图像保存在buffer里面,用户在SIGNAL(imageCaptured)后自行手动保存图片
*
*/
camera_image_capture->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);
camera->setCaptureMode(QCamera::CaptureStillImage);
camera->setViewfinder(view_finder);
camera->start(); //启动摄像头
this->setLayout(main_layout);
//设置控件名称
this->translateLanguage();
mPixelFmt = camera_image_capture->bufferFormat();
qDebug() << "bufferFormat is " << mPixelFmt;
//
QList<QVideoFrame::PixelFormat> pFList = camera_image_capture->supportedBufferFormats();
qDebug() << "supported bufferFormat = " << pFList.count();
foreach (QVideoFrame::PixelFormat pf, pFList) {
qDebug() << "supported bufferFormat is " << pf;
}
QImageEncoderSettings imageSettings;
qDebug() << "1 current codec is " << camera_image_capture->encodingSettings().codec();
//暂时没有效果
imageSettings.setCodec("image/png");
imageSettings.setResolution(640, 480);
camera_image_capture->setEncodingSettings(imageSettings);
}
Dialog::~Dialog()
{
close_camera();
}
void Dialog::translateLanguage()
{
this->setWindowTitle("testCapture");
capture_button->setText(tr("capture"));
save_button->setText(tr("save"));
exit_button->setText(tr("exit"));
}
void Dialog::displayImage(int id, QImage image)
{
mPixelFmt = camera_image_capture->bufferFormat();
qDebug() << "image id = " << id << "; bufferFormat is " << mPixelFmt;
qDebug() << "2 current codec is " << camera_image_capture->encodingSettings().codec();
display_label->setPixmap(QPixmap::fromImage(image));
}
void Dialog::captureImage()
{
//截图
camera_image_capture->capture();
}
void Dialog::saveImage()
{
const QPixmap *pixmap = display_label->pixmap();
if(pixmap)
{
pixmap->save("F:\\a.jpg");
}
}
void Dialog::close_camera()
{
if((NULL != camera) && (QCamera::ActiveState == camera->state()))
{
camera->stop();
delete camera;
delete view_finder;
delete camera_image_capture;
}
}
二、在前面一篇文章中,我利用opencv 2.4.10已经初步达到了usb camera的预览功能。
现在我对这个示例进行一些优化,并且对cvtColor这个格式转换函数做测试,看看它参数变化对图像产生什么影响。具体效果需要大家自己去实验体会!
之所以做这个事情,是因为我要把这个程序移植到Android平台——《我的Opencv4Android添加V4L2支持的移植记录(1)》,Android上的ImageView只支持ARGB8888格式,opencv出来的frame是RGB888格式,要想办法转换格式。
示例下载:http://download.csdn.net/detail/luoyouren/9570162
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
mCapture = NULL;
mTimer = NULL;
mFrame = NULL;
mIsOpen = false;
mTimer = new QTimer(this);
if(NULL != mTimer)
{
qDebug() << "4545454545454\n";
//50ms超时,就去取图片帧
connect(mTimer, SIGNAL(timeout()), this, SLOT(getFrame()));
}
qDebug() << "3333333333333333\n";
//:/pic/pic/desktop.jpg
// QImage image = QImage(":/pic/pic/desktop.jpg");
// ui->label->setPixmap(QPixmap::fromImage(image));
qDebug() << "444444444444444\n";
}
Dialog::~Dialog()
{
uninit();
if(NULL != mTimer)
{
delete mTimer;
mTimer = NULL;
}
qDebug() << "--------------- ~Dialog\n";
delete ui;
}
void Dialog::init()
{
if(mIsOpen == false)
{
mCapture = NULL;
mCapture = cvCaptureFromCAM(0);
if(NULL == mCapture)
{
qDebug() << "init camera failed!\n";
return;
}
ui->BtnOpen->setText(QString::fromLocal8Bit("关闭"));
if(NULL != mTimer)
{
mTimer->start(50); //50毫秒取一帧图片
}
mIsOpen = true;
}
else
{
uninit();
}
}
void Dialog::uninit()
{
qDebug() << "uninit camera!\n";
if(mIsOpen == true)
{
if(NULL != mTimer)
{
mTimer->stop();
}
if(NULL != mCapture)
{
cvReleaseCapture(&mCapture);
}
ui->BtnOpen->setText(QString::fromLocal8Bit("打开"));
mIsOpen = false;
qDebug() << "uninit camera done!\n";
}
}
void Dialog::on_BtnOpen_clicked()
{
init();
}
void Dialog::getFrame()
{
if(NULL == mCapture)
{
qDebug() << "mCapture has been released!";
return;
}
mFrame = NULL;
mFrame = cvQueryFrame(mCapture); //取图片帧
if(NULL == mFrame)
{
qDebug() << "cvQueryFrame failed";
return;
}
int w = mFrame->width;
int h = mFrame->height;
// int imgSize = frame->imageSize;
#if 1
qDebug() << "RGBA w= " << w << " h= " << h;
Mat imgData(h, w, CV_8UC3, mFrame->imageData);
Mat imgBGRA;
// cvtColor(imgData, imgBGRA, CV_RGB2BGRA); //颜色反相
// cvtColor(imgData, imgBGRA, CV_BGR2BGRA); //颜色正常
cvtColor(imgData, imgBGRA, CV_RGB2RGBA); //颜色正常
// cvtColor(imgData, imgBGRA, CV_BGR2RGBA); //颜色反相
qDebug() << "imgData.elemsize= " << imgData.elemSize() << " imgBGRA.elemsize= " << imgBGRA.elemSize();
//注意rgbSwapped也会影响图像
QImage image = QImage((const uchar*)imgBGRA.data, w, h, QImage::Format_ARGB32);
#else
qDebug() << "RGB888\n";
//usb camera取出来的数据就是RGB888
//将图片转换为Image对象,rgbSwapped是为了显示效果色彩好一些。
QImage image = QImage((const uchar*)frame->imageData, w, h, QImage::Format_RGB888).rgbSwapped();
#endif
ui->label->setPixmap(QPixmap::fromImage(image));
}
三、前面用的都是opencv1的C函数调用
下面我要使用opencv2中的C++API进行usb camera预览、录像,主要是VideoCapture和VideoWriter两个类的使用。
示例下载:http://download.csdn.net/detail/luoyouren/9570171
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->label->setScaledContents(true); //fit video to label area
rate = 30;
timer = NULL;
timer = new QTimer(this);
if(NULL != timer)
{
connect(timer, SIGNAL(timeout()), this, SLOT(nextFrame()));
}
}
MainWindow::~MainWindow()
{
if (capture.isOpened())
{
//decide if capture is already opened; if so,close it
capture.release();
}
if (writer.isOpened())
{
writer.release();
}
if(NULL != timer)
{
if(timer->isActive())
{
timer->stop();
}
delete timer;
}
delete ui;
}
QImage MainWindow::Mat2QImage(cv::Mat cvImg)
{
QImage qImg;
//3 channels color image
if(cvImg.channels() == 3)
{
cv::cvtColor(cvImg, cvImg,CV_BGR2RGB);
qImg =QImage((const unsigned char*)(cvImg.data),
cvImg.cols, cvImg.rows,
cvImg.cols*cvImg.channels(),
QImage::Format_RGB888);
}
else if(cvImg.channels() == 1)
{
//grayscale image
qImg =QImage((const unsigned char*)(cvImg.data),
cvImg.cols,cvImg.rows,
cvImg.cols*cvImg.channels(),
QImage::Format_Indexed8);
}
else
{
qImg =QImage((const unsigned char*)(cvImg.data),
cvImg.cols,cvImg.rows,
cvImg.cols*cvImg.channels(),
QImage::Format_RGB888);
}
return qImg;
}
///auto get next frame
void MainWindow::nextFrame()
{
capture >> frame;
if (!frame.empty())
{
image = Mat2QImage(frame);
ui->label->setPixmap(QPixmap::fromImage(image));
}
}
void MainWindow::on_btnOpenFile_clicked()
{
if (capture.isOpened())
{
//decide if capture is already opened; if so,close it
capture.release();
}
//get video file
QString filename =QFileDialog::getOpenFileName(this,tr("Open Video File"),".",tr("Video Files(*.avi *.mp4 *.flv *.mkv)"));
capture.open(filename.toLocal8Bit().data());
if (capture.isOpened())
{
rate= capture.get(CV_CAP_PROP_FPS);
qDebug() << "rate = " << rate;
if(NULL != timer)
{
//set timer match with FPS
timer->setInterval(1000/rate);
timer->start();
}
}
}
void MainWindow::on_btnOpenCamera_clicked()
{
if (capture.isOpened())
{
//decide if capture is already opened; if so,close it
capture.release();
}
//open the default camera
capture.open(0);
if (capture.isOpened())
{
// rate= capture.get(CV_CAP_PROP_FPS);
// qDebug() << "rate = " << rate;
if(NULL != timer)
{
//set timer match with FPS
timer->setInterval(1000/30);
timer->start();
}
}
}
void MainWindow::on_btnProcess_clicked()
{
cv::Mat cannyImg ;
cv::Canny(frame, cannyImg, 0, 30, 3);
cv::namedWindow("Canny");
cv::imshow("Canny", cannyImg);
}
void MainWindow::on_btnStartREC_clicked()
{
writer.open("./myrec.avi", CV_FOURCC('P','I','M','1'), /*capture.get(CV_CAP_PROP_FPS)*/30, cv::Size(frame.cols, frame.rows),true);
int t=100;
while(t--) {writer.write(frame);} //record 100 frames
//if successfully start videoWriter, disable the button
ui->btnStartREC->setDisabled(true);
}
void MainWindow::on_btnStopREC_clicked()
{
if (writer.isOpened())
{
writer.release();
}
ui->btnStartREC->setDisabled(false);
}
参考文章:
http://www.cnblogs.com/annt/p/ant003.html#3380613