在QT中使用映美精双目相机保存图片

交了不少智商税之后终于解决了这个问题,为了以后少走弯路,把自己的程序记录下来供大家参考。

一:准备工作
相机:映美精
编译环境:VS2015+QT5.7.1
相机IP分配软件:GigECam IP Configuration
附加库:IC Imaging Control 3.4和OpenCV3.4.1
二:相机控制类简介
主要使用Grabber和FrameHandlerSink,其中Grabber的功能在前文已有解释,FrameHandlerSink用于从图像流中抓取(复制)帧的SinkType,包含一个MemBufferCollection,可选择允许用户指定一个或多个负责将图像数据复制到MemBufferCollection缓冲区的IFrameFilter,可以在复制的过程中执行用户定义的转换,也可以删除不需要的帧。
帧从一个接一个地复制到MemBufferCollection,从集合的第一个缓冲区开始。 将帧复制到最后一个缓冲区时,下一帧将复制到第一个缓冲区,依此类推。类似于堆栈的方式,所以在保存图片的时候,我们只需要得到最后一帧的缓存区数据即可。
头文件:tisudshl.h
命名空间:DShowLib
三:代码
QT界面设计:
四个按钮:LeftButton、RightButton、SaveLButton和SaveRButton
两个label:LeftLabel和RightLabel
label大小是我根据相机成像大小等比例缩放的,我用的相机分辨率是1280×960,label大小为320×240,你也可以设置为自适应大小。
在QT中使用映美精双目相机保存图片_第1张图片

设置包含库文件,包括相机和OpenCV,在QT.pro文件最后加入下面两行代码(将xxx改为你的电脑用户名):

#添加相机库文件
#$$quote关键字是为了加入带空格的路径
INCLUDEPATH += $$quote(C:\Users\asus\Documents\IC Imaging Control 3.4\classlib\include)
LIBS += $$quote(C:\Users\xxx\Documents\IC Imaging Control 3.4\classlib\x64\debug\TIS_UDSHL11d_x64.lib)
//添加OpenCV库
INCLUDEPATH += X:\xxx\opencv\build\include\opencv2 \
               X:\xxx\opencv\build\include\opencv  \
               X:\xxx\opencv\build\include

LIBS +=  X:\xxx\opencv\build\x64\vc14\lib\opencv_world341d.lib \

为了方便以后其他程序的设计,这里我建立了一个相机类Camera,相机图像的显示和保存均在MyCamera.cpp中完成。
在QT中使用映美精双目相机保存图片_第2张图片
mycamera.h中主要构建了一个相机类,在MyWidget.h中使用该类定义了两个相机对象LeftCamera和RightCamera,具体如下:

#ifndef MYCAMERA_H
#define MYCAMERA_H
#include<tisudshl.h>
#include<opencv2/opencv.hpp>
#include <QLabel>
#include<string>
using namespace std;
class Camera//相机构造类
{
public:
    Camera();
    ~Camera();
    void cameraONOFF();                                      //相机开关
    bool getCameraHWND(QLabel *windowName);                  //获取窗口句柄
    void SaveImage(string str);                              //保存图像
    void CreateSaveDir();                                    //创建文件保存路径
    void setpHander();                                       //初始化操作
public:
    DShowLib::Grabber *m_Grabber;
    HWND appwnd;                    //窗口句柄
    int m_hWnd,m_wWnd;
    smart_ptr<DShowLib::FrameHandlerSink> pHanderSink;
    cv::Size Imgsize;             //图像的大小//记录相机保存的图片数量
    bool  m_IsOpen;              //相机开启的标志位
};
#endif // MYCAMERA_H

MyWidget.h中定义了两个相机类的对象,四个槽函数均由按钮直接转到槽自动生成。

#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include<mycamera.h>
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MyWidget(QWidget *parent = 0);
    ~MyWidget();
    Camera LeftCamera,RightCamera;//左右相机
private slots:
    void on_LeftButton_clicked();//左相机开关
    void on_RightButton_clicked();//右相机开关
    void on_SaveLButton_clicked();//保存左相机图像
    void on_SaveRButton_clicked();//保存右相机图像
private:
    Ui::MyWidget *ui;
};
#endif // MYWIDGET_H

main.cpp主程序保持内容不变,MyWidget.cpp主要用来设定保存路径,其他功能通过调用函数完成:

#include "MyWidget.h"
#include "ui_MyWidget.h"
#include <QMessageBox>
MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);
}
MyWidget::~MyWidget()
{
    delete ui;
}
void MyWidget::on_LeftButton_clicked()
{
    LeftCamera.getCameraHWND(ui->LeftLabel);
    LeftCamera.cameraONOFF();
}
void MyWidget::on_RightButton_clicked()
{
    RightCamera.getCameraHWND(ui->RightLabel);
    RightCamera.cameraONOFF();
}
void MyWidget::on_SaveLButton_clicked()
{
    // 记录采集图像的数量
    static int leftCameraImages = 0;
    ++leftCameraImages;
    string 
    //设置图像保存路径,这里的Save文件夹是在MyCamera.cpp中自动生成的,也可以根据需要自行修改
    str=cv::format("F:/QT/CameraControl/Save/LeftCamera/%d.bmp",leftCameraImages);
    if(LeftCamera.m_IsOpen)
    {
     LeftCamera.SaveImage(str);
     string info=cv::format("左相机图像已保存%d张",leftCameraImages);
     QString qStr=QString(QString::fromLocal8Bit(info.c_str()));//防止中文在转换过程中出现乱码问题
     QMessageBox::about (NULL,"inform",qStr);
    }
    else
    {
          QMessageBox::about(NULL,"inform","open the camera first");
    }
}
void MyWidget::on_SaveRButton_clicked()
{
    // 记录采集图像的数量
    static int  rightCameraImages = 0;
     ++rightCameraImages;
    string str=cv::format("F:/QT/CameraControl/Save/RightCamera/%d.bmp",rightCameraImages);
    if(RightCamera.m_IsOpen)
    {
     RightCamera.SaveImage(str);
     string info=cv::format("右相机图像已保存%d张",rightCameraImages);
     QString qStr=QString(QString::fromLocal8Bit(info.c_str()));
     QMessageBox::about(NULL,"inform",qStr);
    }
    else
    {
          QMessageBox::about(NULL,"inform","open the camera first");
    }

}

相机的主要设置和保存图片均在MyCamera.cpp中完成,这里为了方便直接使用OpenCV的一些函数来完成图像的格式设置和保存。

#include<mycamera.h>
#include<QMessageBox>
#include<MyWidget.h>
//生成保存文件夹所用头文件
#include <direct.h>
#include<io.h>
#include<QMessageBox>
Camera::Camera()
{
    Camera::CreateSaveDir();
    Camera::setpHander();
}
Camera::~Camera()
{
     delete m_Grabber;
}

void  Camera::setpHander()
{
    if (!DShowLib::InitLibrary()) //相机控制初始化函数,必须在程序初始化时调用,调用成功返回True否则返回false
    { return ; }
    atexit(DShowLib::ExitLibrary); //注册终止函数(即main执行结束后调用的函数
   m_Grabber=new DShowLib::Grabber();
   assert(m_Grabber);                 //如果创建失败程序报错
   // Create a sink containing a MemBufferCollection of 1 RGB24 buffers.
   pHanderSink = DShowLib::FrameHandlerSink::create(DShowLib::eRGB24, 1);//指定缓冲区的图像格式
   /*Changes this sink's operating mode between Grab and Snap mode.
    * In grab mode, all frames reaching the sink are presented to the frame filter
    * or filter chain and then copied into the MemBufferCollection. After that,
    *  the frameReady event of the GrabberListener is called. In snap mode, snapImages or
    * snapImagesAsync has to be called in order to trigger the image acquisition process. */
   pHanderSink->setSnapMode(true);//设置图像帧保存时为抓取还是复制,具体解释见上面英语示意
   // Set the sink.
   m_Grabber->setSinkType(pHanderSink);
   m_IsOpen=false;
}
void Camera::cameraONOFF()
{
   if (!m_Grabber->isDevOpen())//检查相机是否被打开
     {
    if(m_Grabber->showDevicePage())//相机选择界面
    {
     m_Grabber->setHWND(appwnd);//指定窗口句柄
     m_Grabber->setDefaultWindowPosition(false);
     //Sets the size of the video window.
     m_Grabber->setWindowSize(m_wWnd,m_hWnd);
     Imgsize=cv::Size(m_Grabber->getAcqSizeMaxX(),m_Grabber->getAcqSizeMaxY());
     m_Grabber->startLive();
     m_IsOpen=true;              //图像成功显示则保存标志位置为true,为下一步运行做准备
    }
     else
     {
        QMessageBox::warning(NULL, "warning", "fail to open",
                            QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
        m_Grabber->closeDev();
     }
    }
    else//关闭图像
    {
        m_Grabber->stopLive();
        m_Grabber->closeDev();
        m_IsOpen=false;
    }

}
//获取显示窗口句柄
bool Camera::getCameraHWND(QLabel *windowName)
{
    m_hWnd=windowName->height();
    m_wWnd=windowName->width();
    appwnd=(HWND)windowName->winId();
    return true;
}
//保存图像
void Camera::SaveImage(string str)
{
    if(!m_Grabber->isLive())
    {
        QMessageBox::information(NULL, "Title", "open deviceL first",
                                 QMessageBox::Yes | QMessageBox::No,
                                 QMessageBox::Yes);
        return;
    }
    cv::Mat img=cv::Mat(Imgsize,CV_8UC3,cv::Scalar(0,0,0));
    // Snap one image and copy it into the MemBufferCollection.
    pHanderSink->snapImages(1, 2000);//把一帧图像复制到缓冲区
    img.data=pHanderSink->getLastAcqMemBuffer()->getPtr();//从缓存区中读取图片数据
    cv::flip(img, img, 0);//垂直反转
    cv::imshow(" ",img);
            cv::waitKey(50);
    cv::imwrite(str,img); //按指定路径保存图像
    return;
}
//设置文件保存路径,自动生成文件夹,可根据需要修改为自己的保存路径
void Camera::CreateSaveDir()
{
    string folderPath = "F:/QT/CameraControl/Save";//检查保存路径是否存在,如不存在则在工程文件夹下创建一个
    if (_access(folderPath.c_str(), 0))
         _mkdir(folderPath.c_str());
    folderPath = ("F:/QT/CameraControl/Save/LeftCamera");
    if (_access(folderPath.c_str(), 0))
        _mkdir(folderPath.c_str());
    folderPath = ("F:/QT/CameraControl/Save/RightCamera");
    if (_access(folderPath.c_str(), 0))
        _mkdir(folderPath.c_str());
}

最终结果如下:
在QT中使用映美精双目相机保存图片_第3张图片
尚未解决的问题:
我在第一次生成文件夹时本想用相对地址进行写入,但不知为什么总是无法生成和写入,所以这里直接简单粗暴地使用了绝对地址,如果有知道为什么的小大神欢迎指教,先谢谢啦。

欢迎大家指正和交流。

你可能感兴趣的:(视觉测量)