qt:我qt调用笔记本摄像头摄像头做拍照功能。摄像头的图像能显示,但是capture的功能上有问题

Linux下基于OpenCV的摄像头数据采集与传输_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Linux下基于OpenCV的摄像头数据采集与传输
来源:Linux社区&
作者:丁卫兵
最近一段时间在搞摄像头的采集和传输。采集通过OpenCV自带的函数库,不用自己编写V4L2,省去了很多事情。主要工作就是在视频的传输了。主要思路是:将采集的一帧视频图像压缩成jpg格式的图片,这样进行过压缩的数据量大大减少。然后通过socket的UDP传输协议将图片通过网络传送到客户端。我之前用的TCP传的,总是有部分数据丢失重传,导致现实界面偶尔出现闪动,出现的错误提示:Corrupt JPEG data: premature end of data segment 本以为网络足够好,可有用下TCP,看来还是没设计好,就转用的UDP协议传输,问题就解决了。
在linux下QT环境中进行的程序编写,服务器端用的是linux C socket编写的,客户端是QT封装的QUdpSocket类编写的,成功实现了传输。但是将客户端放在windows下就没有数据传输,客户端一直不能readyread(),一直没有找到原因,看来还要继续寻找了。
服务器端代码:
#ifndef WIDGET_H#define WIDGET_H
#include &QWidget&#include &opencv2/opencv.hpp&#include &QImage&#include &QTimer&
#include &sys/socket.h&#include &sys/types.h&#include &stdio.h&#include &stdlib.h&#include &string.h&#include &errno.h&#include &unistd.h&#include &netdb.h&#include &netinet/in.h&#include &arpa/inet.h&
#define PORTNUMBER 4444#define MAX_SIZE 1024;
namespace Ui {class W}
class Widget : public QWidget{& & Q_OBJECT& & public:& & explicit Widget(QWidget *parent = 0);& & ~Widget();
& & int init_socket();& & private:& & Ui::Widget *
& & cv::VideoC& //摄像头& & cv::M& & //帧图像& & QTimer *& & //定时器& & QI& & & //QT 图像
& && & struct sockaddr_in server_
private slots:& & void slot_timer();
#include "widget.h"#include "ui_widget.h"#include &QFile&
Widget::Widget(QWidget *parent) :& & QWidget(parent),& & ui(new Ui::Widget){& & ui-&setupUi(this);
& & timer = new QTimer(this);& & connect(timer, SIGNAL(timeout()), this, SLOT(slot_timer()));
& & timer-&start(33);& //启动定时器,设置帧率
& & capture = cv::VideoCapture(1); //打开摄像头,这里使用了固定的摄像头,随机的话为-1
& & sockfd = init_socket();& //初始化套接字}
Widget::~Widget(){& && && & capture.release();}
int Widget::init_socket(){& && & if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 )& & {& & & & perror("Socket error");& & & & exit(1);& & }
& & bzero(&server_addr, sizeof(server_addr));& & server_addr.sin_family = AF_INET;& & server_addr.sin_port = htons(PORTNUMBER);& & //server_addr.sin_addr.s_addr = htonl(INADDR_ANY);& & server_addr.sin_addr.s_addr = inet_addr("192.168.1.115"); //主机IP
void Widget::slot_timer(){& & capture&&& //将摄像头的每一帧放入frame& & if(frame.empty())& & {& & & & printf("frame is empty\n");& & & && & }&
/*将opencv采集的BGR格式的图像转化成QT下的RGB格式的图像*/& & cv::cvtColor(frame, frame, CV_BGR2RGB);& & img = QImage((unsigned const char*)frame.data, frame.cols, frame.rows, QImage::Format_RGB888 );& & img.save("test.jpg", "JPEG");
& & QFile file("test.jpg");& & if(!file.open(QIODevice::ReadOnly))& & {& & & & perror("File open error");& & & && & }
& & QByteArray buffer = file.readAll();& & file.flush();& //好像这里没起作用
& & if(sendto(sockfd, buffer.data(),buffer.size(), 0, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr_in)) & 0)& & {& & & & printf("send fail %d\n", buffer.size());& & & & perror("sendto error");& & }
& & file.close();}
客户端程序:
#ifndef WIDGET_H#define WIDGET_H
#include &QWidget&#include &QUdpSocket&#include &QImage&
namespace Ui {class W}
class Widget : public QWidget{& & Q_OBJECT& & public:& & explicit Widget(QWidget *parent = 0);& & ~Widget();& & private:& & Ui::Widget *& & QI& & QUdpSocket*
private slots:& & void processPendingDatagram();
#endif // WIDGET_H
#include "widget.h"#include "ui_widget.h"#include &QFile&#include &QtNetwork&
#define PORTNUMBER 4444
Widget::Widget(QWidget *parent) :& & QWidget(parent),& & ui(new Ui::Widget){& & ui-&setupUi(this);
& & receiver = new QUdpSocket(this);& & bool result = receiver-&bind(PORTNUMBER, QUdpSocket::ShareAddress);& & if(result)& & {& & & & printf("bind right\n");& & }& & else& & {& & & & printf("Bind error");& & }& & connect(receiver, SIGNAL(readyRead()), this, SLOT(processPendingDatagram()));}
void Widget::processPendingDatagram(){& & qint64 num = receiver-&pendingDatagramSize();&
//printf("receive size = %ld\n", num);
& & QByteA& & buffer.resize(num);& & receiver-&readDatagram((char*)buffer.data(), num);& //将接收到的数据放入buffer中
& & QFile file("test.jpg");& & if(!file.open(QIODevice::WriteOnly))& & {& & & & printf("file open error\n");& & & && & }
& & file.write(buffer);& //将数据写到硬盘,保存成JPG格式图片& & file.flush();& & file.close();
& & img = QImage("test.jpg");& & ui-&label-&setPixmap(QPixmap::fromImage(img));&
// 在label中显示图片& & ui-&label-&resize(ui-&label-&pixmap()-&size());}
Widget::~Widget(){& &}
如果有客户端在Windows下的QT实现的还请大神指教。
推荐阅读:
12.04 安装 OpenCV2.4.2
下OpenCV无法读取视频文件
Ubuntu 12.04下安装OpenCV 2.4.5总结
Ubuntu 10.04中安装OpenCv2.1九步曲
基于QT和OpenCV的人脸识别系统
相关资讯 & & &
& (03月27日)
& (01月12日)
& (11月04日)
& (03月12日)
& (12/31/:28)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款拒绝访问 | www.th7.cn | 百度云加速
请打开cookies.
此网站 (www.th7.cn) 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(434ae3-ua98).
重新安装浏览器,或使用别的浏览器Qt调用摄像头(截取并保存图片)
& & Qt如何调用系统摄像设备进行显示、截图、录制?
& & QCamera:系统摄像设备(摄像头)
QCameraViewfinder:摄像取景器部件
QCameraImageCapture:截图部件
capture按钮:用于截图(截图后在右上角显示)
save按钮:用于保存截取后的图片(此处测试路径为:F:\a.jpg)
exit按钮:退出界面
效果如下:
代码如下:
#include "test_capture.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent)
this-&resize(600, 400);
camera = new QCamera();
view_finder = new QCameraViewfinder();
camera_image_capture = new QCameraImageCapture(camera);
capture_button = new QPushButton();
save_button = new QPushButton();
exit_button = new QPushButton();&
display_label = new QLabel();
QHBoxLayout *main_layout = new QHBoxLayout();
QVBoxLayout *v_layout = new QVBoxLayout();
display_label-&setFixedSize(150, 150);
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);
camera_image_capture-&setCaptureDestination(QCameraImageCapture::CaptureToFile);
camera-&setCaptureMode(QCamera::CaptureStillImage);
camera-&setViewfinder(view_finder);
camera-&start(); //启动摄像头
this-&setLayout(main_layout);
this-&translateLanguage();
Dialog::~Dialog()
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)
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");
& 技术在于交流、沟通,转载请注明出处并保持作品的完整性。
作者:&&原文:。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。博客访问: 638457
博文数量: 95
博客积分: 1255
博客等级: 少校
技术积分: 1926
注册时间:
认证徽章:
求道勿远,求心勿近
分类: LINUX 16:58:23
下面写的文章也许网上也有类似的,但是大多数都没有给出思路及背景,让初学者每次都只能学到一点皮毛,不少知识需要大量搜索零碎地拼凑起来。题外话,虽然现在是碎片化信息时代,但正是这样信息整合能力也显得非常重要,为读者提供高质量的文章是我以后的目标。我以后会注意分析应用背景及些过程的解析。
不想看下面笔者对编译环境的理解的,可以直接在本页Ctrl+F查找“编译过程”看,因为下面有很大段笔者心酸的回忆,嘻嘻。
opencv是一个非常优秀的图形图像处理类库,里面的类或者结构体,封装了很多实用的图像处理算法,调用其提供的API,等于使用一些复杂的图像处理算法,真是解放生产力啊。这里笔者用的是linux版本的opencv2.2源码,几十M,稳定版本够用即可,没必要时刻追着新版本。不过在linux上的opencv各种版本都是如笔者那样编译即可用。
思考一下,为什么我们要下源码来编译?不是像windows上的直接发布一个压缩包即可用么?我们这次编译为是得到什么?其实很简单,opencv里有专门处理摄像头的API,我们要用它,就得有它的头文件及动态库(或静态库)。而我们拿到源码往往不是为了去研究其代码(如果是做这算法方面的研究便是例外了),而是拿到“本地”编译。至于为何,笔者认为是大家内核版本版本的不统一,编译器版本也不统一导致这样做的的。如果使用Ubuntu之类的,很简单,一个apt-get什么都不用管,因为Ubuntu提供了适应你的内核版本编译器编译的库。知道的同学希望指教一下。
下载请移步:
虚拟机上的摄像头,一般都是用USB连接,如果是笔记本自带的,也是把虚拟机里的connect上即可。连接外设的方法:在虚拟机顶栏菜单,VM->Removable&Devices->XX&WebCam->connect&&&&&show&in&status&Bar(前者把设备从win环境解除,连接到虚拟机环境,后者是显示在虚拟机右下角的状态栏)。
具体看下图:
&&&QT,版本其实与opencv版本没有什么关系,因为代码编译出来,最终都是翻译成机器码,QT源码是C++写的,OPENCV源码也是C/C++写的,编译器认识他们即可。笔者一起也是担心版本问题,网上的文章往往都是写着qt4.7.2+opencv2.0XXX,或者qtcreator2.0+opencv2.3.1在Ubuntu11上编译成功之类的文章,我那时就很担心,又要确定QT版本,又要确定opencv版本,还得确定linux版本吗?linux怎么那么复杂啊?就是他们的标题及其内容都没有明确指出他们方法的通用性。笔者在这里就说明一下:这文章在linux上的适用,QT版本(4.6,4.7,5.0等无论什么版本都可以,whatever),opencv版本(1.0,2.0,2.2,2.3,2.4,whatever都可以),linux(各种发行版本(内核是2.6以上的),只要别用2.4的内核就好。)
编译过程:
摄像头在虚拟机上(当然,从物理上说你还是得有摄像头才行)安装上面的图看一下即可。下面主要是opencv的编译:主要参考opencv中文论坛的文章
./configure //头文件和库文件一般都是默认安装到/usr/local/include /usr/local/lib内
make install
具体代码:
先讲最终要实现什么,很简单,一个窗口,里面有一个label显示摄像头的图像。
然后讲讲原理:每隔一段时间我们就去摄像头抓取一帧图像,然后放到ui->label上面,如果取的时间快,就造成“视频”的感觉了。(可以想到,其实摄像头拍照也是很简单,我们就把其中一帧取出来即可。)
新建一个工程,继承QDialog(用什么窗体都可以),在UI上拖出一个label放在中间,
拉到适当大小。
在工程xxx.pro里面添加必要的库及头文件的路径:
INCLUDEPATH += /usr/local/include/opencv
LIBS += /usr/local/lib/libcv.so \
&&&&&&&&/usr/local/lib/libhighgui.so \
&&&&&&&&/usr/local/lib/libcxcore.so \
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <cv.h>
#include <highgui.h>
#include <QTimer>
#include <QPixmap>
namespace Ui {
&&&&class Dialog;
class Dialog : public QDialog
&&&&Q_OBJECT
&&&&explicit Dialog(QWidget *parent = 0);
&&&&~Dialog();
&&&&Ui::Dialog *ui;
&&&&CvCapture *capture; //highgui 里提供的一个专门处理摄像头图像的结构体
&&&&IplImage *frame; //摄像头每次抓取的图像为一帧,使用该指针指向一帧图像的内存空间
&&&&QTimer *timer; //定时器用于定时取帧,上面说的隔一段时间就去取就是用这个实现。
private slots:
&&&&void getFrame(); //实现定时从摄像头取图并显示在label上的功能。
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
Dialog::Dialog(QWidget *parent) :
&&&&QDialog(parent),
&&&&ui(new Ui::Dialog)
&&&&ui->setupUi(this);
&&&&timer = new QTimer(this);
&&&&capture = cvCaptureFromCAM(0); //cvCaptureFromCAM其实是一个宏,就是cvCreateCameraCapture的别名,0代表第一个摄像头。-1代表默认摄像头。
&&&&if(capture==NULL){
&&&&&&&&qDebug()<<"error!";
&&&&timer->start(50); //1000为1秒,50毫秒去取一帧
&&&&connect(timer,SIGNAL(timeout()),this,SLOT(getFrame())); //超时就去取
void Dialog::getFrame()
&&&&frame = cvQueryFrame(capture); //从摄像头取帧
&&&&QImage image = QImage((const uchar*)frame->imageData, frame->width, frame->height, QImage::Format_RGB888).rgbSwapped(); //简单地转换一下为Image对象,rgbSwapped是为了显示效果色彩好一些。
&&&&ui->label->setPixmap(QPixmap::fromImage(image));
Dialog::~Dialog()
&&&&timer->stop(); //停止取帧
&&&&cvReleaseCapture(&capture); //释放资源是个好习惯
&&&&delete ui;
本文参考资料:
源码编译:
QT中使用OPENCV库
Debian/Ubuntu
欢迎技术交流,邮箱
这是noiplee的技术博客,我写博客的目的是想通过快速分享来达到掌握知识的目的,同时希望和各位网友交流共同进步。我经常关注linux,嵌入式,读书,思维导图,冥想等领域。如果您看了我的文章有任何的建议或者观点,非常欢迎留言和评论,有任何问题我们都可以一起探讨,我会及时回复的。
阅读(18669) | 评论(4) | 转发(4) |
给主人留下些什么吧!~~
:呵呵&很不错的文章
求问&main&函数怎么写 |
请问&main&函数怎么写呢?新手求教
呵呵&很不错的文章
opencv示例源码:http://www.eyesourcecode.com/forum-OpenCV-1.html
请登录后评论。如何直接读取QCamera的一帧数据
参考文章请看 感谢这位大神的指引.
为了方便我转发过来了详情请看
The QCamera class provides interface for system camera devices.
QCamera can be used with QCameraViewfinder for viewfinder display, QMediaRecorder for video recording and QCameraImageCapture for image taking.
依上理解:
QCameraViewfinder:用于显示
QMediaRecorder::用于录像
QCameraImageCapture:用于采集图像
我这里只想获取数据所以使用QCameraImageCapture,查看qt例程如下:
camera = new QC
imageCapture = new QCameraImageCapture(camera);
camera-&setCaptureMode(QCamera);
camera-&start();
camera-&searchAndLock();
imageCapture-&capture();
camera-&unlock();
注:viewfinder是我注释掉的,不影响capture,你也可以直接查看camera例程
这里关键是capture这个方法,看说明:
[slot] int QCameraImageCapture::capture(const QString &file = QString())
Capture the image and save it to file. This operation is asynchronous in majority of cases, followed by signals QCameraImageCapture::imageExposed(), QCameraImageCapture::imageCaptured(), QCameraImageCapture::imageSaved() or QCameraImageCapture::error().
If an empty file is passed, the camera backend choses the default location and naming scheme for photos on the system, if only file name without full path is specified, the image will be saved to the default directory, with a full path reported with imageCaptured() and imageSaved() signals.
QCamera saves all the capture parameters like exposure settings or image processing parameters, so changes to camera parameters after capture() is called do not affect previous capture requests.
QCameraImageCapture::capture returns the capture Id parameter, used with imageExposed(), imageCaptured() and imageSaved() signals.
See also isReadyForCapture().
简单说就是capture是用来获取图像并保存(无论你是否写路径,它都会自动保存,这在快速处理数据时就要喊蛋蛋了.),而且它之后还紧跟随着4个信号发射--采集完毕,保存完毕,曝光完毕,发生错误,例程里的处理就是使用的QCameraImageCapture::imageCaptured()这个信号,如下:
void Camera(const QCameraInfo &cameraInfo)
imageCapture = new QCameraImageCapture(camera);
connect(imageCapture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(processCapturedImage(int,QImage)));
void Camera(int requestId, const QImage& img)
Q_UNUSED(requestId);
QImage scaledImage = img.scaled(ui-&viewfinder-&size(),
ui-&lastImagePreviewLabel-&setPixmap(QPixmap(scaledImage));
displayCapturedImage();
QTimer(4000, this, SLOT(displayViewfinder()));
如前所述,我只想采集摄像头数据处理,用这方法就烦了,总是给我自动保存,不知道qt怎么想的.
博文中的大神的方法经我测试在window下也是可行的,网上还有个方法如下,可惜window下不支持CaptureToBuffer这个属性.
Make sure that the buffer destination is supported:
.isCaptureDestinationSupported(::CaptureToBuffer)
If so, set the buffer destination, and buffer format and resolution, etc.
Finally, receive the captured frames in a slot connected to the imageAvailable(int, const QVideoFrame &) signal.
void CCamWorker::setCamera(const QByteArray &device_name)
delete imageC
delete camera;
if(device_name.isEmpty())
camera = new QCamera(QCameraInfo::defaultCamera());
camera = new QCamera(device_name);
connect(camera, SIGNAL(error(QCamera::Error)), this, SLOT(displayCameraError()));
_cameraFrameGrabber = new CameraFrameGrabber();
camera-&setViewfinder(_cameraFrameGrabber);
connect(_cameraFrameGrabber, SIGNAL(frameAvailable(int,QImage)), this, SLOT(processCapturedImage(int,QImage)));
if(camera-&isCaptureModeSupported(QCamera::CaptureStillImage))
camera-&setCaptureMode(QCamera::CaptureStillImage);
camera-&start();
void CCamWorker(int requestId, const QImage &img)
Q_UNUSED(requestId);
QImage tmpimage = img.copy();
if(!isGettingImage)
preview_image =
if(display_label)
pmap = pmap.fromImage(tmpimage);
display_label-&setPixmap(pmap);
void CCamWorker(QImage &image){
isGettingImage = true;
image = preview_
isGettingImage = false;
注:processCapturedImage中不能直接将img赋给preview_image,不然出错.发现很多情况下QT都是这样的,不能将通过信号发送来的图片直接显示或赋值给另一个对象.不然出莫名其妙的错误(比如在这行,在另一个平台就不行之类的).机理不明.
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 qt opencv 调用摄像头 的文章

 

随机推荐