基于qt和opencv的远程视频监控与播放

来源:互联网 发布:c语言读入txt文本文件 编辑:程序博客网 时间:2024/05/16 10:54

当有摄像头接入时,则采集实时视频显示到界面并且使用子线程保存视频,并且当检测到有服务器连接时,则发送每帧图像到服务器,并且实时显示。当没有检测到摄像头时,可以打开保存的录像视频,显示到界面播放的同时通过tcp协议发送到服务器端显示。源代码已上传:http://download.csdn.net/detail/lidefu1000810218/9839045

部分代码如下:

server:

#ifndef SERVER_H
#define SERVER_H

#include <QWidget>
#include<QTcpSocket>
#include<QTcpServer>
#include<QString>
#include<QtNetwork>
#include<QMessageBox>
#include<QImage>


namespace Ui {
class Server;
}


class Server : public QWidget
{
    Q_OBJECT


public:
    explicit Server(QWidget *parent = 0);
    ~Server();
    QTcpServer *tcpServer;
    QTcpSocket *tcpServerConnection;
    QStringList *fortunes;
    QImage *img;
    quint64 basize;
public slots:
    void sendFortune();
   // QByteArray GetPicData(QString fromPic);
    void DisplayError(QAbstractSocket::SocketError socketError);
    void ReadMyData();
    void ShowImage(QByteArray ba);

private:
    Ui::Server *ui;
};

#endif // SERVER_H

#include "server.h"
#include "ui_server.h"
/*
1.创建tcpServer ,tcpServer = new QTcpServer(this);使之监听本机的某个端口,tcpServer->listen(QHostAddress("192.168.1.100"),6666)
2,关联信号newConnection和槽函数sendMessage, connect(tcpServer,SIGNAL(newConnection()),this,SLOT(sendMessage()));其中信号newConnection在有客户端的连接请求(即客户端执行tcpSocket->connectToHost)时发射
3.实现槽函数sendMessage,在里面从tcpServer取得已经建立但挂起的QTcpSocket连接
QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
用clientConnection 传输数据给客户
 QByteArray block;
 clientConnection->write(block);
*/
Server::Server(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Server)
{
    ui->setupUi(this);
    ui->image_label->setScaledContents(true);
    tcpServer = new QTcpServer(this);
    if(!tcpServer->listen(QHostAddress::Any,8888))
    {
        QMessageBox::critical(this,tr("Fortune Server"),tr("Unable to start the server:%l.").arg(tcpServer->errorString()));
        close();
        return;
    }
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));
}
Server::~Server()
{
    delete ui;
}
void Server::sendFortune()
{
    basize=0;


    tcpServerConnection = tcpServer->nextPendingConnection();
    QByteArray message;
    QDataStream out(&message,QIODevice::WriteOnly);
    //out.setVersion(QDataStream::Qt_4_6);
    out<<(quint16) 0;
    out<<tr("OK");//当有连接时则发送一个OK信号给客户端,通知其发送数据


    out.device()->seek(0); //定位到第一个16位, 是写入的数据的大小
    out<<(quint16)(message.size()-sizeof(quint16));



    tcpServerConnection->write(message); //写入发送的数据


    connect(tcpServerConnection,SIGNAL(readyRead()),
            this,SLOT(ReadMyData()));//当有数据到来时,读取图像数据
    connect(tcpServerConnection,SIGNAL(error(QAbstractSocket::SocketError)),
            this,SLOT(DisplayError(QAbstractSocket::SocketError)));


}

void Server::DisplayError(QAbstractSocket::SocketError socketError)
{
    tcpServerConnection->close();
}
void Server::ReadMyData()
{
    QByteArray message;//存放从服务器接收到的字符串
    QDataStream in(tcpServerConnection);
    in.setVersion(QDataStream::Qt_4_6);
    if (basize==0)
    {
        //判断接收的数据是否有两字节(文件大小信息)
        //如果有则保存到basize变量中,没有则返回,继续接收数据
        if (tcpServerConnection->bytesAvailable()<(int)sizeof(quint64))
        {
            return;
        }
        in>>basize;
    }
    //如果没有得到全部数据,则返回继续接收数据
    if (tcpServerConnection->bytesAvailable()<basize)
    {
        return;
    }
    in>>message;//将接收到的数据存放到变量中
    ShowImage(message);
}


void Server::ShowImage(QByteArray ba)
{
    QString ss=QString::fromLatin1(ba.data(),ba.size());
    QByteArray rc;
    rc=QByteArray::fromBase64(ss.toLatin1());
    QByteArray rdc=qUncompress(rc);
    QImage img;
    img.loadFromData(rdc);
    ui->image_label->setPixmap(QPixmap::fromImage(img));
    ui->image_label->resize(img.size());
    update();
}


client:

#ifndef CAMARAGET_H
#define CAMARAGET_H
#include <QWidget>
#include <QImage>
#include <QTimer>     // 设置采集数据的间隔时间
#include<QtNetwork>
#include<QTcpServer>
#include<QTcpSocket>
#include<QtGui>

#include <highgui.h>  //包含opencv库头文件
#include <cv.h>
#include<camthread.h>
using namespace cv;
namespace Ui {
    class camaraGet;
}


class camaraGet : public QWidget
{
    Q_OBJECT


public:
    explicit camaraGet(QWidget *parent = 0);
    ~camaraGet();
private slots:
    void openCamara();      // 打开摄像头
    void readFarme(QImage );       // 读取当前帧信息
    void closeCamara();     // 关闭摄像头。
    void takingPictures();  // 拍照
    //void warn();
    void openvideo();
    void readFarme();
    void readMessage();

private:
    Ui::camaraGet *ui;
    Camthread *camthread;
    QTimer    *timer;
    VideoCapture cap;
    bool video;
    int op;
    QImage    image;
    QTcpSocket* tcpSocket; //创建tcpsocket
    quint16 blockSize;       //存放文件的大小信息
    QString message;

};
#endif // CAMARAGET_H


#include "camaraget.h"

#include "ui_camaraGet.h"


camaraGet::camaraGet(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::camaraGet)
{
    ui->setupUi(this);
    op=0;
    ui->label->setScaledContents(true);
    ui->label_2->setScaledContents(true);
    video=0;
    timer=new QTimer();
    camthread=new Camthread();
    tcpSocket=new QTcpSocket();
    /*信号和槽*/
    //message=QString("OK");
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readMessage()));
    connect(camthread,SIGNAL(sig_GetOneFrame(QImage)),this,SLOT(readFarme(QImage )));
    //connect(timer, SIGNAL(timeout()), this, SLOT(readFarme()));  // 时间到,读取当前摄像头信息
    connect(ui->open, SIGNAL(clicked()), this, SLOT(openCamara()));
    connect(ui->pic, SIGNAL(clicked()), this, SLOT(takingPictures()));
    connect(ui->closeCam, SIGNAL(clicked()), this, SLOT(closeCamara()));
  //  connect(tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,
  //          SLOT(displayError(QAbstractSocket::SocketError)));

}




void camaraGet::openCamara()
{


    if(op==1)
    {
        return ;
    }
    connect(camthread,SIGNAL(sig_err(QString)),this,SLOT( openvideo()));
    camthread->startPlay();
    op=1;
}


void camaraGet::openvideo()
{
    op=0;
    QMessageBox::warning(this,"Warning","Cameras are not found.");
    //connect(ui->open, SIGNAL(clicked()), this, SLOT(openvideo()));
    QString filename = QFileDialog::getOpenFileName(this,tr("action"),
                       "./",
                        "Image file(*.AVI *.MP4)",0) ;
    if (!filename.isEmpty())
    {
        cap.open(filename.toLatin1().data());
     }
    if(!cap.isOpened()){
        QMessageBox::information(this,tr("提示"),tr("视频没有打开"));
        video=0;
    }
    else
       video=1;


    timer->start(50);
    connect(timer, SIGNAL(timeout()), this, SLOT(readFarme()));
    connect(ui->open, SIGNAL(clicked()), this, SLOT(openCamara()));
    connect(ui->pic, SIGNAL(clicked()), this, SLOT(takingPictures()));
    connect(ui->closeCam, SIGNAL(clicked()), this, SLOT(closeCamara()));
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readMessage()));
}


void camaraGet::readMessage()
{
     qDebug()<<4;
     qDebug() << message;
    QDataStream in(tcpSocket);
     //in.setVersion(QDataStream::Qt_4_6);
     if (blockSize == 0) {
            //判断接收的数据是否大于两字节,也就是文件的大小信息所占的空间
            //如果是则保存到blockSize变量中,否则直接返回,继续接收数据
            if(tcpSocket->bytesAvailable() < (int)sizeof(quint16)) return;  //bytesAvailable()返回字节数
            in >> blockSize;
        }
     if(tcpSocket->bytesAvailable() < blockSize) return;
        // 将接收到的数据存放到变量中
         in >> message;
         // 显示接收到的数据*/
        // qDebug() << message;


}


void camaraGet::readFarme()
{
    blockSize=0;//数据大小初始化为0
    tcpSocket->abort();//取消已有链接
    //连接到某个ip的某个端口,
    tcpSocket->connectToHost(QHostAddress::LocalHost,8888);
    if(video)
    {
        qDebug()<<"baofang shipin !";
        Mat frame;
        //cap>>frame;
        if(cap.read(frame))
       {
            cvtColor(frame,frame,CV_BGR2RGB);
            QImage image1((unsigned const char*)frame.data,
                     frame.cols,frame.rows,QImage::Format_RGB888);
            if(message=="OK")
            {
                QByteArray ba; //用于暂存要发送的数据
                QDataStream out(&ba,QIODevice::WriteOnly); //使用数据流写入数据
            //out.setVersion(QDataStream::Qt_4_6);
                //设置数据流的版本,客户端和服务器端使用的版本要相同
                QByteArray byte;
                QBuffer buf(&byte);
                image1.save(&buf,"JPEG");
                QByteArray ss=qCompress(byte,1);
                QByteArray vv=ss.toBase64();
                out<<(quint64)0;
                out<<vv;
                out.device()->seek(0);
                out<<(quint64)(ba.size()-sizeof(quint64));
            //发送数据
                tcpSocket->write(ba);
            }
            else ;
           // tcpSocket->disconnectFromHost();
            if(op==1)
            ui->label->setPixmap(QPixmap::fromImage(image1));  // 将图片显示到label上
        }
        else
        {
            timer->stop();
            op=0;
        }
    }
}
void camaraGet::readFarme(QImage img)
{
    blockSize=0;//数据大小初始化为0
    tcpSocket->abort();//取消已有链接
    //连接到某个ip的某个端口,
    tcpSocket->connectToHost(QHostAddress::LocalHost,8888);
    image=img;
    //qDebug()<<"tcp";
    if(message=="OK")
    {
        QByteArray ba; //用于暂存要发送的数据
        QDataStream out(&ba,QIODevice::WriteOnly); //使用数据流写入数据
    //out.setVersion(QDataStream::Qt_4_6);
        //设置数据流的版本,客户端和服务器端使用的版本要相同
        QByteArray byte;
        QBuffer buf(&byte);
        image.save(&buf,"JPEG");
        QByteArray ss=qCompress(byte,1);
        QByteArray vv=ss.toBase64();
        out<<(quint64)0;
        out<<vv;
        out.device()->seek(0);
        out<<(quint64)(ba.size()-sizeof(quint64));
    //发送数据
        tcpSocket->write(ba);
    }
    else ;
    if(op==1)
    {
        ui->label->setPixmap(QPixmap::fromImage(image));  // 将图片显示到label上
    }
}
void camaraGet::takingPictures()
{
    //frame = cvQueryFrame(cam);// 从摄像头中抓取并返回每一帧
    // 将抓取到的帧,转换为QImage格式。QImage::Format_RGB888不同的摄像头用不同的格式。
    //QImage image((const uchar*)frame->imageData, frame->width, frame->height, QImage::Format_RGB888);
    //QImage image = QImage((const uchar*)frame->imageData, frame->width, frame->height, QImage::Format_RGB888).rgbSwapped();
    // frame=cvLoadImage((filename.toLatin1()).data());
    //ui->CameraLabel->setPixmap(QPixmap::fromImage(image));
    op=0;
    QString filename = QFileDialog::getSaveFileName(this,tr("action"),
                       "./",
                        "Image file(*.bmp *.jpg)",0) ;
    if (!filename.isEmpty())
            if(!image.save(filename))
              QMessageBox::information(this,
                          tr("Warnning"),
                          tr("Failed to save the image!"));
    op=1;
    ui->label_2->setPixmap(QPixmap::fromImage(image));  // 将图片显示到label上


}


void camaraGet::closeCamara()
{
    ui->label_2->clear();
    //this->close();
}


camaraGet::~camaraGet()
{
    delete ui;
}


#ifndef CAMTHREAD_H
#define CAMTHREAD_H


#include<QThread>
#include <QTimer>     // 设置采集数据的间隔时间
#include <highgui.h>  //包含opencv库头文件
#include <cv.h>
#include <QImage>


class Camthread:public QThread
{
    Q_OBJECT
public:
    explicit Camthread();
    ~Camthread();


    void startPlay();


  signals:
      void sig_GetOneFrame(QImage); //每获取到一帧图像 就发送此信号
      void sig_err(QString); //每获取到一帧图像 就发送此信号


  private:
      void run();
    CvVideoWriter* writer;
      QTimer    *timer;
      CvCapture *cam;// 视频获取结构, 用来作为视频获取函数的一个参数
      IplImage  *frame;//申请IplImage类型指针,就是申请内存空间来存放每一帧图像
private slots:
      void readFrame( );       // 读取当前帧信息
};
#endif // CAMTHREAD_H



#include"camthread.h"
#include<QtGui>
Camthread::Camthread()
{
    cam     = NULL;
    timer   = new QTimer(this);
}
Camthread::~Camthread()
{
    timer->stop();         // 停止读取数据。
    cvReleaseCapture(&cam);//释放内存;
    cvReleaseVideoWriter(&writer);

}
void Camthread::startPlay()
{

    cam = cvCreateCameraCapture(0);//打开摄像头,从摄像头中获取视频
    if(!cam)
    {


        emit sig_err("error");
        //return;
          //QMessageBox::warning(,"Warning","Cameras are not found.");


    }
    else
    {
        timer->start(50);              // 开始计时,超时则发出timeout()信号
        start();
    }
}
void Camthread::run()
{
    // 时间到,读取当前摄像头信息
    double fps=30;
    frame = cvQueryFrame(cam);
    CvSize size=cvGetSize(frame);
    writer=cvCreateVideoWriter("Video from CAMERA.avi",CV_FOURCC('X','V','I','D'),
                                              fps,size,1);
    connect(timer, SIGNAL(timeout()), this, SLOT(readFrame()));


}
void Camthread::readFrame( )
{
    frame = cvQueryFrame(cam);// 从摄像头中抓取并返回每一帧
    QImage image = QImage((const uchar*)frame->imageData, frame->width, frame->height,
                          QImage::Format_RGB888).rgbSwapped();
 
    emit sig_GetOneFrame(image);

}






1 0
原创粉丝点击