Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / Linux下基于OpenCV的摄像头数据采集与传输

最近一段时间在搞摄像头的采集和传输。采集通过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(),一直没有找到原因,看来还要继续寻找了。服务器端代码:widget.h#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 Widget;
}class Widget : public QWidget
{
    Q_OBJECT
   
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();    int init_socket();
   
private:
    Ui::Widget *ui;    cv::VideoCapture capture;  //摄像头
    cv::Mat frame;    //帧图像
    QTimer *timer;    //定时器
    QImage img;      //QT 图像    int sockfd;
    struct sockaddr_in server_addr;
private slots:
    void slot_timer();};#endifwidget.c#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()
{
    delete ui;
    delete timer;
    capture.release();
}int Widget::init_socket()
{
    int sockfd;
    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    return sockfd;
}void Widget::slot_timer()
{
    capture>>frame;  //将摄像头的每一帧放入frame
    if(frame.empty())
    {
        printf("frame is empty ");
        return;
    }
 /*将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");
        return;
    }    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 ", buffer.size());
        perror("sendto error");
    }    file.close();
}客户端程序:widget.h#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>
#include <QImage>namespace Ui {
class Widget;
}class Widget : public QWidget
{
    Q_OBJECT
   
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
   
private:
    Ui::Widget *ui;
    QImage img;
    QUdpSocket* receiver;
private slots:
    void processPendingDatagram();};#endif // WIDGET_Hwidget.c#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 ");
    }
    else
    {
        printf("Bind error");
    }
    connect(receiver, SIGNAL(readyRead()), this, SLOT(processPendingDatagram()));
}void Widget::processPendingDatagram()
{
    qint64 num = receiver->pendingDatagramSize();
 //printf("receive size = %ld ", num);    QByteArray buffer;
    buffer.resize(num);
    receiver->readDatagram((char*)buffer.data(), num);  //将接收到的数据放入buffer中    QFile file("test.jpg");
    if(!file.open(QIODevice::WriteOnly))
    {
        printf("file open error ");
        return;
    }    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()
{
    delete ui;
}如果有客户端在Windows下的QT实现的还请大神指教。推荐阅读:Ubuntu 12.04 安装 OpenCV2.4.2 http://www.linuxidc.com/Linux/2012-09/70158.htmCentOS下OpenCV无法读取视频文件 http://www.linuxidc.com/Linux/2011-07/39295.htmUbuntu 12.04下安装OpenCV 2.4.5总结 http://www.linuxidc.com/Linux/2013-06/86704.htmUbuntu 10.04中安装OpenCv2.1九步曲 http://www.linuxidc.com/Linux/2010-09/28678.htm基于QT和OpenCV的人脸识别系统 http://www.linuxidc.com/Linux/2011-11/47806.htm