赞
踩
文章导读:相机为大恒相机,接口是USB3.0,水星系列产品。本项目采用Qt5.12.10版本编码,编译器为MSVC2017,opencv410版本对图像进行处理,最终完成了图像的实时采集图像显示,与图像存储为bmp格式且可控制存储帧数的功能。
【软件程序执行逻辑】:打开相机(初始化库-枚举列表-通过获取sn序列号的方式打开)—>开始采集(设置相机参数-实时显示帧数图像-保存到本地bmp文件)
步骤:
1.手动添加库文件;
2.pro中加入本项目需要使用到的功能声明
# Camera drive config
unix|win32: LIBS += -L$$PWD/build-FlawDetection_51210_MSVC2017_64-Release/CameraDrive/lib/x64/ -lGxIAPICPPEx
INCLUDEPATH += $$PWD/build-FlawDetection_51210_MSVC2017_64-Release/CameraDrive/lib/x64
DEPENDPATH += $$PWD/build-FlawDetection_51210_MSVC2017_64-Release/CameraDrive/lib/x64
DEPENDPATH += $$PWD/build-FlawDetection_51210_MSVC2017_64-Release/CameraDrive/inc
INCLUDEPATH += $$PWD/build-FlawDetection_51210_MSVC2017_64-Release/CameraDrive/inc
# Camera drive config
# opencv config
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/build-FlawDetection_51210_MSVC2017_64-Release/opencv/x64/vc15/lib/ -lopencv_world410
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/build-FlawDetection_51210_MSVC2017_64-Release/opencv/x64/vc15/lib/ -lopencv_world410d
else:unix: LIBS += -L$$PWD/build-FlawDetection_51210_MSVC2017_64-Release/opencv/x64/vc15/lib/ -lopencv_world410
INCLUDEPATH += $$PWD/build-FlawDetection_51210_MSVC2017_64-Release/opencv/x64/vc15
INCLUDEPATH += $$PWD/build-FlawDetection_51210_MSVC2017_64-Release/opencv/opencv2
INCLUDEPATH += $$PWD/build-FlawDetection_51210_MSVC2017_64-Release/opencv
DEPENDPATH += $$PWD/build-FlawDetection_51210_MSVC2017_64-Release/opencv/x64/vc15
# opencv config
QT += core gui sql charts printsupport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = RailMeasurement
CONFIG += c++11
LIBS += User32.LIB
# utf-8 字体设置,防止编译报错
msvc {
QMAKE_CFLAGS += /utf-8
QMAKE_CXXFLAGS += /utf-8
}
# utf-8 字体设置,防止编译报错
camerawidget.h : 相机操作类,需要包含ui文件
cgxbitmap.h : 图像处理类
drawwidget.h :控件绘图类,这里采用的是自己定义的类,将控件widget提升为drawwidget类,来绘图,原因是可对图像进行细化操作,例如放大缩小及一些自定义处理。
camerawidget.h ↓
#ifndef CAMERAWIDGET_H #define CAMERAWIDGET_H #include "GalaxyIncludes.h" #include "Log/logReport.h" #include "cgxbitmap.h" #include "drawwidget.h" #include <QWidget> #include <QLabel> #include <QPixmap> #include <QtGlobal> #include <iostream> #include <QMessageBox> #include <opencv2/opencv.hpp> namespace Ui { class CameraWidget; } class CameraWidget : public QWidget { Q_OBJECT public: explicit CameraWidget(QWidget *parent = nullptr); ~CameraWidget(void); public: class CSampleCaptureEventHandler : public ICaptureEventHandler { public: void DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam) { if (objImageDataPointer->GetStatus() == GX_FRAME_STATUS_SUCCESS) { CameraWidget* cameraShow = (CameraWidget*)pUserParam; //cameraShow->ShowImageProcess(objImageDataPointer); void* pRaw8Buffer = NULL; pRaw8Buffer = objImageDataPointer->ConvertToRaw8(GX_BIT_0_7); std::memcpy(cameraShow->mCurImgMat.data, pRaw8Buffer, (objImageDataPointer->GetHeight())*(objImageDataPointer->GetWidth())); //cv::flip(cameraShow->mCurImgMat, cameraShow->mCurImgMat, 0);//大恒的图像要进行翻转,但是此处似乎不需要翻转 //调用自定义绘图函数进行绘制实时采集图像 cameraShow->showCurImgInLabel(cameraShow->mImgShow, cameraShow->mCurImgMat); if (cameraShow->mFps < 10) {//存储帧数,可修改为通过传参方式设置需要保存的帧数,目前默认设置10帧(10张图片) std::string PathAndName = cameraShow->mFilePath.toUtf8().data() + std::to_string(cameraShow->mFps) + ".bmp"; cameraShow->m_pBitmap->SaveBmp(objImageDataPointer, PathAndName);//保存单帧图像 cameraShow->mFps ++; } } } }; class CSampleDeviceOfflineEventHandler : public IDeviceOfflineEventHandler { public: void DoOnDeviceOfflineEvent(void* pUserParam) { QMessageBox::warning(0, "警告", "设备相机已掉线!"); writeLog("CSampleDeviceOfflineEventHandler", "设备相机已掉线!", TYPE_INFOR); } }; public: //绘制实时采集图像成比例 void showCurImgInLabel(QLabel* ptrLabelToShow, cv::Mat& CVMat); QImage cvMatToQImage(const cv::Mat &inMat); //cvMat转换为QImage QPixmap cvMatToQPixmap(const cv::Mat &inMat); //cvMat转换为Qpixmap public slots: int openCamera(void); //打开相机 void closeCamera(void); //关闭相机 void startCollection(void); //开始采集 void stopCollection(void); //停止采集 public: //-----相机参数 int64_t mWidth; //图像宽度 int64_t mHeight; //图像高度 QString mBitDepth; //像素深度(Bpp8) QString mCamera, mCameraNumber;//相机名称, 型号 QString mSerialNumName; //序列号 QString mIpName; //ip地址 QString mMaskName; //掩码 QString mMacName; //MAC地址 QString mAcquisitionMode; //采集模式(单拍: SingleFrame, 连拍: Continuous) QString mTriggerMode = "off"; //触发模式(on:软件触发) QString mTriggerSource; //触发源 bool mIsOffline = false; //设备是否掉线 bool mIsOpenCam = false; //相机是否打开 bool mIsOpenStream = false; //相机流是否打开 bool mIsTrigger = false; //相机是否触发 float mExposeTime = 0; //曝光时间 CGXDeviceInfo mDeviceInfo; //设备信息 CGXDevicePointer mObjDevicePtr; //当前界面操作的相机指针 CGXStreamPointer mObjStreamPtr; //流采集指针, 采集控制和采集数据统计的属性访问控制器 GX_DEVICE_CLASS_LIST mObjDeviceClass; //设备类型 CImageProcessConfigPointer mObjImageProcessPtr; //图像处理对象 CGXFeatureControlPointer mObjRemoteFeatureControlPtr; //远端设备控制器 CGXFeatureControlPointer mObjFeatureControlPtr; //本地和流属性控制器 ICaptureEventHandler* pCaptureEventHandler; //注册回调事件指针 IDeviceOfflineEventHandler* pDeviceOfflineEventHandler = nullptr; //注册掉线事件 GX_DEVICE_OFFLINE_CALLBACK_HANDLE mDeviceOffline = nullptr; //掉线事件 //-----相机参数 //图像参数及保存(bmp格式) int mFps = 0; DrawWidget* mDrawWidget = nullptr;//提升窗口指针,使用drawqimage显示实时图像 QLabel *mImgShow = nullptr; cv::Mat mCurImgMat; //实时窗口的Mat CGXBitmap* m_pBitmap = nullptr; //保存图像指针 QString mFilePath; //图像参数及保存(bmp格式) private: Ui::CameraWidget *ui; }; #endif // CAMERAWIDGET_H
camerawidget.cpp↓
#include "camerawidget.h" #include "ui_camerawidget.h" #include <QDebug> #include <QMessageBox> CameraWidget::CameraWidget(QWidget *parent) : QWidget(parent), ui(new Ui::CameraWidget) { ui->setupUi(this); setAttribute(Qt::WA_TranslucentBackground, true); setWindowFlags(Qt::FramelessWindowHint);//设置无边窗体 //设置提升后的控件属性 mImgShow = ui->label_imageShow; mDrawWidget = ui->widget; mDrawWidget->setSize(); //设置提升后的控件属性 mFilePath = MakeMyDirectory();//创建文件夹 mFilePath = QDir::toNativeSeparators(mFilePath) + "\\";//将正'/' 转为'\\',因为接口函数调用保存图像路径是避免找不到 } CameraWidget::~CameraWidget(void) { delete ui; } int CameraWidget::openCamera(void) { try { if (!mIsOpenCam) { IGXFactory::GetInstance().Init();//初始化库 //枚举设备列表 GxIAPICPP::gxdeviceinfo_vector vectorDeviceInfo; IGXFactory::GetInstance().UpdateDeviceList(1000, vectorDeviceInfo); if (vectorDeviceInfo.size() == 0) { writeLog("openCamera", "无可用设备,请检查相机连接状态!", TYPE_ERROR); return -1; } //枚举设备列表 //打开第一台设备 GxIAPICPP::gxstring strSN = vectorDeviceInfo[0].GetSN(); mObjDevicePtr = IGXFactory::GetInstance().OpenDeviceBySN(strSN, GX_ACCESS_EXCLUSIVE); //打开第一台设备 //相机控制对象赋值 mObjRemoteFeatureControlPtr = mObjDevicePtr->GetRemoteFeatureControl();//包含主要设备信息,比如宽高、曝光增益等 mObjFeatureControlPtr = mObjDevicePtr->GetFeatureControl();//包含一些本地属性,不同类型的设备具备的功能也不一样。 //相机控制对象赋值 //设备信息获取 mDeviceInfo = mObjDevicePtr->GetDeviceInfo(); //设备信息获取 //设备具体值获取 mCamera = mDeviceInfo.GetVendorName(); //获取相机名称 mCameraNumber = mDeviceInfo.GetModelName(); //获取相机型号 mSerialNumName = mDeviceInfo.GetSN(); //获取相机序列号 mIpName = mDeviceInfo.GetIP(); //获取相机IP mMaskName = mDeviceInfo.GetSubnetMask(); //获取相机掩码 mMacName = mDeviceInfo.GetMAC(); //获取相机MAC地址 mWidth = mObjRemoteFeatureControlPtr->GetIntFeature("AAROIWidth")->GetValue(); //获取图像的宽 mHeight = mObjRemoteFeatureControlPtr->GetIntFeature("AAROIHeight")->GetValue(); //获取图像的宽 mBitDepth = mObjRemoteFeatureControlPtr->GetEnumFeature("PixelSize")->GetValue(); //设备具体值获取 //为Mat矩阵开辟空间 mCurImgMat.create(mHeight, mWidth, CV_8UC1); //为Mat矩阵开辟空间 //判断图像对象是否为空 if (m_pBitmap != nullptr) { delete m_pBitmap; m_pBitmap = nullptr; } //判断图像对象是否为空 //为画图对象分配内存 m_pBitmap = new CGXBitmap(mObjDevicePtr); //为画图对象分配内存 mIsOpenCam = true; writeLog("openCamera", "open camera success", TYPE_KEY); return 1; // //软件默认设置曝光时间 // if (mExposeTime > 0 && mExposeTime < 200000) // mObjRemoteFeatureControlPtr->GetFloatFeature("ExposureTime")->SetValue(mExposeTime); // else // mExposeTime = 30000; // //软件默认设置曝光时间 // //采集模式:(单拍:, 连拍:Continuous) // mObjRemoteFeatureControlPtr->GetEnumFeature("AcquisitionMode")->SetValue("Continuous"); // //触发模式 // mObjRemoteFeatureControlPtr->GetEnumFeature("TriggerSelector")->SetValue("FrameStart"); // mObjRemoteFeatureControlPtr->GetEnumFeature("TriggerMode")->SetValue("Off"); // //自动曝光 // mObjRemoteFeatureControlPtr->GetEnumFeature("ExposureAuto")->SetValue("Off"); // mCurImgMat.create(mHeight, mWidth, CV_8UC1);//为Mat矩阵开辟空间 } } catch (CGalaxyException& e) { writeLog("openCamera", QString("错误码:%1, 错误描述信息:%2").arg(e.GetErrorCode()).arg(e.what()), TYPE_ERROR); } writeLog("openCamera", "open camera faild, The camera is on", TYPE_KEY); return -2; } void CameraWidget::closeCamera(void) { if (mIsOpenCam) { if (mIsOpenStream) { //发送停采命令 mObjRemoteFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute(); mObjStreamPtr->StopGrab(); mObjStreamPtr->UnregisterCaptureCallback();//注销采集回调 mObjStreamPtr->Close(); //关闭相机流 mIsOpenStream = false; writeLog("openCamera", "close camera stream", TYPE_INFOR); } if (mObjDeviceClass == GX_DEVICE_CLASS_GEV) { //注销掉线回调事件 mObjDevicePtr->UnregisterDeviceOfflineCallback(mDeviceOffline); delete pDeviceOfflineEventHandler; pDeviceOfflineEventHandler = nullptr; } mObjDevicePtr->Close(); IGXFactory::GetInstance().Uninit(); //释放GxIAPICPPEx申请的所有资源 mIsOpenCam = false; writeLog("openCamera", "close camera", TYPE_KEY); } } void CameraWidget::startCollection(void) { try { if (mIsOpenCam) { //千兆网系列相机设置 mObjDeviceClass = mObjDevicePtr->GetDeviceInfo().GetDeviceClass(); if (mObjDeviceClass == GX_DEVICE_CLASS_GEV) { //提高网络相机的采集性 if (mObjFeatureControlPtr->IsImplemented("GevSCPSPacketSize")) {//判断设备是否支持流通道数据包功能 //获取当前网络环境的最优包长值 int nPacketSize = mObjStreamPtr->GetOptimalPacketSize(); //将最优包长值设置为当前设备的流通道包长值 mObjRemoteFeatureControlPtr->GetIntFeature("GevSCPSPacketSize")->SetValue(nPacketSize); } } //注册掉线事件 pDeviceOfflineEventHandler = new CSampleDeviceOfflineEventHandler(); mDeviceOffline = mObjDevicePtr->RegisterDeviceOfflineCallback(pDeviceOfflineEventHandler, this); //注册掉线事件 //千兆网系列相机设置 uint32_t nStreamNum = mObjDevicePtr->GetStreamCount(); if ((nStreamNum > 0) && (!mIsOpenStream)) { mObjStreamPtr = mObjDevicePtr->OpenStream(0); mIsOpenStream = true; } //注册采集回调函数 pCaptureEventHandler = new CSampleCaptureEventHandler(); mObjStreamPtr->RegisterCaptureCallback(pCaptureEventHandler, this); //注册采集回调函数 //给设备发送开采命令 mObjStreamPtr->StartGrab(); mObjRemoteFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute(); //给设备发送开采命令 writeLog("startCollection", "start collection...", TYPE_KEY); } } catch (CGalaxyException& e) { writeLog("startCollection", QString("错误码:%1, 错误描述信息:%2").arg(e.GetErrorCode()).arg(e.what()), TYPE_ERROR); } } void CameraWidget::stopCollection(void) { if (mIsOpenStream) { //发送停采命令 mObjRemoteFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute(); mObjStreamPtr->StopGrab(); mIsOpenStream = false; writeLog("stopCollection", "stop collection...", TYPE_KEY); } } void CameraWidget::showCurImgInLabel(QLabel *ptrLabelToShow, cv::Mat &CVMat) { //获取要显示图片的label的大小 QSize LabelSize = ptrLabelToShow->size(); QImage QSrcImg = cvMatToQImage(CVMat);//获取一个QImage QImage QSrcImgRatio = QSrcImg.scaled(LabelSize, Qt::IgnoreAspectRatio);//重新调整图像大小以适应窗口 ptrLabelToShow->setPixmap(QPixmap::fromImage(QSrcImgRatio));//显示 } QImage CameraWidget::cvMatToQImage(const cv::Mat &inMat) { switch (inMat.type()) { // 8-bit, 4 channel case CV_8UC4: { QImage image( inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_ARGB32); return image; } // 8-bit, 3 channel case CV_8UC3: { QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_RGB888); return image.rgbSwapped(); } // 8-bit, 1 channel case CV_8UC1: { #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_Grayscale8); #else static QVector<QRgb> sColorTable; // only create our color table the first time if (sColorTable.isEmpty()) { sColorTable.resize(256); for (int i = 0; i < 256; ++i) { sColorTable[i] = qRgb(i, i, i); } } QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_Indexed8 ); image.setColorTable(sColorTable); #endif return image; } default: //qWarning() << "ASM::cvMatToQImage() - cv::Mat image type not handled in switch:" << inMat.type(); break; } return QImage(); } QPixmap CameraWidget::cvMatToQPixmap(const cv::Mat &inMat) { return QPixmap::fromImage(CameraWidget::cvMatToQImage(inMat)); }
cgxbitmap.h↓
#ifndef CGXBITMAP_H #define CGXBITMAP_H //------------------------------------------------------------------------ /* \file GXBitmap.h \brief 此类主要用于图像的显示和存储,图像显示和存储可以自适应黑白彩色相机, 图像存储可以存储为Bmp、Raw,对图像显示和存储进行了声明 */ //------------------------------------------------------------------------ #include "GalaxyIncludes.h" #include "Log/logReport.h" #include <string> #include <Windows.h> #include <QDir>//文件夹需要包含的头文件 #include <QFile> //文件需要包含的头文件 #include <QCoreApplication> //用于获取运行路径需要包含的头文件 class CGXBitmap { public: CGXBitmap(CGXDevicePointer& objCGXDevicePointer); ~CGXBitmap(void); void Show(CImageDataPointer& objCImageDataPointer);//显示图像 void ShowImageProcess(CImageProcessConfigPointer& objCfg,CImageDataPointer& objCImageDataPointer);//图像处理后并显示图像 void SaveBmp(CImageDataPointer& objCImageDataPointer,const std::string& strFilePath);//存储Bmp图像 void SaveRaw(CImageDataPointer& objCImageDataPointer,const std::string& strFilePath);//存储Raw图像 GX_VALID_BIT_LIST GetBestValudBit(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry);//通过GX_PIXEL_FORMAT_ENTRY获取最优Bit位 private: bool __IsPixelFormat8(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry);//判断PixelFormat是否为8位 void __ColorPrepareForShowImg(); //为彩色相机图像显示准备资源 void __MonoPrepareForShowImg(); //为黑白相机图像显示准备资源 bool __IsCompatible(BITMAPINFO *pBmpInfo, uint64_t nWidth, uint64_t nHeight);//判断是否兼容 void __UpdateBitmap(CImageDataPointer& objCImageDataPointer);//更新Bitmap的信息 int64_t __GetStride(int64_t nWidth, bool bIsColor);//计算宽度所占的字节数 private: bool m_bIsColor = false; //是否支持彩色相机 int64_t m_nImageWidth = 0; //原始图像宽 int64_t m_nImageHeight = 0; //原始图像高 char m_chBmpBuf[2048]; //BIMTAPINFO 存储缓冲区,m_pBmpInfo即指向此缓冲区 BYTE *m_pImageBuffer = nullptr; //保存翻转后的图像用于显示 BITMAPINFO *m_pBmpInfo = nullptr; //BITMAPINFO 结构指针,显示图像时使用 private: CGXBitmap& operator = (const CGXBitmap&); CGXBitmap(const CGXBitmap&); }; //全局函数 std::wstring StringToWString( const std::string &s);//将string转换为wstring类,便于利用大恒接口写文件 QString MakeMyDirectory();//创建文件夹Image //全局函数 #endif // CGXBITMAP_H
cgxbitmap.cpp↓
#include "cgxbitmap.h" #include <cstring> //------------------------------------------------------------------------ /* \file GXBitmap.cpp \brief 此类主要用于图像的显示和存储,图像显示和存储可以自适应黑白彩色相机, 图像存储可以存储为Bmp、Raw,对图像显示和存储进行了实现 */ //------------------------------------------------------------------------ CGXBitmap::CGXBitmap(CGXDevicePointer& objCGXDevicePointer) { if (objCGXDevicePointer.IsNull()) { writeLog("CGXBitmap", "Argument is error", TYPE_ERROR); } memset(m_chBmpBuf, 0, sizeof(m_chBmpBuf)); gxstring strValue = ""; //获得图像宽度、高度等 m_nImageWidth = (int64_t)objCGXDevicePointer->GetRemoteFeatureControl()->GetIntFeature("Width")->GetValue(); m_nImageHeight = (int64_t)objCGXDevicePointer->GetRemoteFeatureControl()->GetIntFeature("Height")->GetValue(); //获取是否为彩色相机 if (objCGXDevicePointer->GetRemoteFeatureControl()->IsImplemented("PixelColorFilter")) { strValue = objCGXDevicePointer->GetRemoteFeatureControl()->GetEnumFeature("PixelColorFilter")->GetValue(); if (strValue != "None") { m_bIsColor = true; } } if (m_bIsColor) { __ColorPrepareForShowImg(); } else { __MonoPrepareForShowImg(); } } CGXBitmap::~CGXBitmap(void) { //释放pDC //::ReleaseDC(m_pWnd->m_hWnd, m_hDC); if (m_pImageBuffer != NULL) { delete m_pImageBuffer; m_pImageBuffer = NULL; } } //---------------------------------------------------------------------------------- /* \brief 判断PixelFormat是否为8位 \param emPixelFormatEntry 图像数据格式 \return true为8为数据,false为非8位数据 */ //---------------------------------------------------------------------------------- bool CGXBitmap::__IsPixelFormat8(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry) { bool bIsPixelFormat8 = false; const unsigned PIXEL_FORMATE_BIT = 0x00FF0000; //用于与当前的数据格式进行与运算得到当前的数据位数 unsigned uiPixelFormatEntry = (unsigned)emPixelFormatEntry; if ((uiPixelFormatEntry & PIXEL_FORMATE_BIT) == GX_PIXEL_8BIT) { bIsPixelFormat8 = true; } return bIsPixelFormat8; } //---------------------------------------------------------------------------------- /* \brief 通过GX_PIXEL_FORMAT_ENTRY获取最优Bit位 \param emPixelFormatEntry 图像数据格式 \return 最优Bit位 */ //---------------------------------------------------------------------------------- GX_VALID_BIT_LIST CGXBitmap::GetBestValudBit(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry) { GX_VALID_BIT_LIST emValidBits = GX_BIT_0_7; switch (emPixelFormatEntry) { case GX_PIXEL_FORMAT_MONO8: case GX_PIXEL_FORMAT_BAYER_GR8: case GX_PIXEL_FORMAT_BAYER_RG8: case GX_PIXEL_FORMAT_BAYER_GB8: case GX_PIXEL_FORMAT_BAYER_BG8: { emValidBits = GX_BIT_0_7; break; } case GX_PIXEL_FORMAT_MONO10: case GX_PIXEL_FORMAT_BAYER_GR10: case GX_PIXEL_FORMAT_BAYER_RG10: case GX_PIXEL_FORMAT_BAYER_GB10: case GX_PIXEL_FORMAT_BAYER_BG10: { emValidBits = GX_BIT_2_9; break; } case GX_PIXEL_FORMAT_MONO12: case GX_PIXEL_FORMAT_BAYER_GR12: case GX_PIXEL_FORMAT_BAYER_RG12: case GX_PIXEL_FORMAT_BAYER_GB12: case GX_PIXEL_FORMAT_BAYER_BG12: { emValidBits = GX_BIT_4_11; break; } case GX_PIXEL_FORMAT_MONO14: { //暂时没有这样的数据格式待升级 break; } case GX_PIXEL_FORMAT_MONO16: case GX_PIXEL_FORMAT_BAYER_GR16: case GX_PIXEL_FORMAT_BAYER_RG16: case GX_PIXEL_FORMAT_BAYER_GB16: case GX_PIXEL_FORMAT_BAYER_BG16: { //暂时没有这样的数据格式待升级 break; } default: break; } return emValidBits; } //--------------------------------------------------------------------------------- /* \brief 为彩色相机图像显示准备资源 \return 无 */ //---------------------------------------------------------------------------------- void CGXBitmap::__ColorPrepareForShowImg() { //-------------------------------------------------------------------- //---------------------------初始化bitmap头--------------------------- m_pBmpInfo = (BITMAPINFO *)m_chBmpBuf; m_pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); m_pBmpInfo->bmiHeader.biWidth = (LONG)m_nImageWidth; m_pBmpInfo->bmiHeader.biHeight = (LONG)m_nImageHeight; m_pBmpInfo->bmiHeader.biPlanes = 1; m_pBmpInfo->bmiHeader.biBitCount = 24; m_pBmpInfo->bmiHeader.biCompression = BI_RGB; m_pBmpInfo->bmiHeader.biSizeImage = 0; m_pBmpInfo->bmiHeader.biXPelsPerMeter = 0; m_pBmpInfo->bmiHeader.biYPelsPerMeter = 0; m_pBmpInfo->bmiHeader.biClrUsed = 0; m_pBmpInfo->bmiHeader.biClrImportant = 0; } //--------------------------------------------------------------------------------- /* \brief 为黑白相机图像显示准备资源 \return 无 */ //---------------------------------------------------------------------------------- void CGXBitmap::__MonoPrepareForShowImg() { //--------------------------------------------------------------------- //----------------------初始化bitmap头--------------------------------- m_pBmpInfo = (BITMAPINFO *)m_chBmpBuf; m_pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); m_pBmpInfo->bmiHeader.biWidth = (LONG)m_nImageWidth; m_pBmpInfo->bmiHeader.biHeight = (LONG)m_nImageHeight; m_pBmpInfo->bmiHeader.biPlanes = 1; m_pBmpInfo->bmiHeader.biBitCount = 8; // 黑白图像为8 m_pBmpInfo->bmiHeader.biCompression = BI_RGB; m_pBmpInfo->bmiHeader.biSizeImage = 0; m_pBmpInfo->bmiHeader.biXPelsPerMeter = 0; m_pBmpInfo->bmiHeader.biYPelsPerMeter = 0; m_pBmpInfo->bmiHeader.biClrUsed = 0; m_pBmpInfo->bmiHeader.biClrImportant = 0; // 黑白图像需要初始化调色板 for(int i=0;i<256;i++) { m_pBmpInfo->bmiColors[i].rgbBlue =i; m_pBmpInfo->bmiColors[i].rgbGreen =i; m_pBmpInfo->bmiColors[i].rgbRed =i; m_pBmpInfo->bmiColors[i].rgbReserved=i; } //为经过翻转后的图像数据分配空间 if (m_pImageBuffer != NULL) { delete m_pImageBuffer; m_pImageBuffer = NULL; } m_pImageBuffer = new BYTE[(size_t)(m_nImageWidth * m_nImageHeight)]; if (m_pImageBuffer == NULL) { throw std::runtime_error("Fail to allocate memory"); } } //---------------------------------------------------------------------------------- /* \brief 判断是否兼容 \param pBmpInfo BITMAPINFO指针 \param nWidth 图像宽 \param nHeight 图像高 \return true为一样,false不一样 */ //---------------------------------------------------------------------------------- bool CGXBitmap::__IsCompatible(BITMAPINFO *pBmpInfo, uint64_t nWidth, uint64_t nHeight) { if (pBmpInfo == NULL || pBmpInfo->bmiHeader.biHeight != nHeight || pBmpInfo->bmiHeader.biWidth != nWidth) { return false; } return true; } //---------------------------------------------------------------------------------- /* \brief 检查图像是否改变并更新Buffer并为图像显示准备资源 \param objCImageDataPointer 图像数据对象 \return 无 */ //---------------------------------------------------------------------------------- void CGXBitmap::__UpdateBitmap(CImageDataPointer& objCImageDataPointer) { if (!__IsCompatible(m_pBmpInfo, objCImageDataPointer->GetWidth(), objCImageDataPointer->GetHeight())) { m_nImageWidth = objCImageDataPointer->GetWidth(); m_nImageHeight = objCImageDataPointer->GetHeight(); if (m_bIsColor) { __ColorPrepareForShowImg(); } else { __MonoPrepareForShowImg(); } } } //---------------------------------------------------------------------------------- /* \brief 计算宽度所占的字节数 \param nWidth 图像宽度 \param bIsColor 是否是彩色相机 \return 图像一行所占的字节数 */ //---------------------------------------------------------------------------------- int64_t CGXBitmap::__GetStride(int64_t nWidth, bool bIsColor) { return bIsColor ? nWidth * 3 : nWidth; } //---------------------------------------------------------------------------------- /* \brief 用于显示图像 \param objCImageDataPointer 图像数据对象 \return 无 */ //---------------------------------------------------------------------------------- void CGXBitmap::Show(CImageDataPointer& objCImageDataPointer) { GX_VALID_BIT_LIST emValidBits = GX_BIT_0_7; BYTE* pBuffer = NULL; if (objCImageDataPointer.IsNull()){ writeLog("Show", "NULL pointer dereferenced", TYPE_ERROR); return; } //检查图像是否改变并更新Buffer __UpdateBitmap(objCImageDataPointer); emValidBits = GetBestValudBit(objCImageDataPointer->GetPixelFormat()); if (m_bIsColor) { pBuffer = (BYTE*)objCImageDataPointer->ConvertToRGB24(emValidBits, GX_RAW2RGB_NEIGHBOUR, true); } else { if (__IsPixelFormat8(objCImageDataPointer->GetPixelFormat())) { pBuffer = (BYTE*)objCImageDataPointer->GetBuffer(); } else { pBuffer = (BYTE*)objCImageDataPointer->ConvertToRaw8(emValidBits); } // 黑白相机需要翻转数据后显示 for (int i = 0; i < m_nImageHeight; i++) { memcpy(m_pImageBuffer+i*m_nImageWidth, pBuffer+(m_nImageHeight-i-1)*m_nImageWidth, (size_t)m_nImageWidth); } } } //---------------------------------------------------------------------------------- /* \brief 用于图像处理后并显示图像 \param objCfg 图像处理调节参数对象 \param objCImageDataPointer 图像数据对象 \return 无 */ //---------------------------------------------------------------------------------- void CGXBitmap::ShowImageProcess(CImageProcessConfigPointer& objCfg,CImageDataPointer& objCImageDataPointer) { if ((objCfg.IsNull()) || (objCImageDataPointer.IsNull())) { writeLog("ShowImageProcess", "NULL pointer dereferenced", TYPE_ERROR); return; } //检查图像是否改变并更新Buffer __UpdateBitmap(objCImageDataPointer); BYTE* pBuffer = (BYTE*)objCImageDataPointer->ImageProcess(objCfg); if (!m_bIsColor) { // 黑白相机需要翻转数据后显示 for (int i = 0; i < m_nImageHeight; i++) { memcpy(m_pImageBuffer + i * m_nImageWidth, pBuffer + (m_nImageHeight - i -1) * m_nImageWidth, (size_t)m_nImageWidth); } } } //---------------------------------------------------------------------------------- /* \brief 存储Bmp图像 \param objCImageDataPointer 图像数据对象 \param strFilePath 显示图像文件名 \return 无 */ //---------------------------------------------------------------------------------- void CGXBitmap::SaveBmp(CImageDataPointer& objCImageDataPointer,const std::string& strFilePath) { GX_VALID_BIT_LIST emValidBits = GX_BIT_0_7; BYTE* pBuffer = NULL; if ((objCImageDataPointer.IsNull()) || (strFilePath == "")) { writeLog("SaveBmp", "Argument is error", TYPE_ERROR); return; } //检查图像是否改变并更新Buffer __UpdateBitmap(objCImageDataPointer); emValidBits = GetBestValudBit(objCImageDataPointer->GetPixelFormat()); if (m_bIsColor) { pBuffer = (BYTE*)objCImageDataPointer->ConvertToRGB24(emValidBits, GX_RAW2RGB_NEIGHBOUR, true); } else { if (__IsPixelFormat8(objCImageDataPointer->GetPixelFormat())) { pBuffer = (BYTE*)objCImageDataPointer->GetBuffer(); } else { pBuffer = (BYTE*)objCImageDataPointer->ConvertToRaw8(emValidBits); } // 黑白相机需要翻转数据后显示 for(int i = 0;i < m_nImageHeight; i++) { memcpy(m_pImageBuffer + i * m_nImageWidth, pBuffer + (m_nImageHeight - i -1) * m_nImageWidth, (size_t)m_nImageWidth); } pBuffer = m_pImageBuffer; } DWORD dwImageSize = (DWORD)(__GetStride(m_nImageWidth,m_bIsColor) * m_nImageHeight); BITMAPFILEHEADER stBfh = {0}; DWORD dwBytesRead = 0; stBfh.bfType = (WORD)'M' << 8 | 'B'; //定义文件类型 stBfh.bfOffBits = m_bIsColor ?sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) :sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (256 * 4); //定义文件头大小true为彩色,false为黑白 stBfh.bfSize = stBfh.bfOffBits + dwImageSize; //文件大小 DWORD dwBitmapInfoHeader = m_bIsColor ?sizeof(BITMAPINFOHEADER) :sizeof(BITMAPINFOHEADER) + (256 * 4); //定义BitmapInfoHeader大小true为彩色,false为黑白 //创建文件 std::wstring s = StringToWString(strFilePath); LPCTSTR LPCSTR_ImgFileName = s.c_str();//使用了我自定义的一个转换函数,并且连续调用了.c_str(),并对下面CreateFile进行了修改 HANDLE hFile = ::CreateFile(LPCSTR_ImgFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { writeLog("SaveBmp", "Handle is invalid", TYPE_ERROR); return; } ::WriteFile(hFile, &stBfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL); ::WriteFile(hFile, m_pBmpInfo, dwBitmapInfoHeader, &dwBytesRead, NULL); //黑白和彩色自适应 ::WriteFile(hFile, pBuffer, dwImageSize, &dwBytesRead, NULL); CloseHandle(hFile); } //---------------------------------------------------------------------------------- /* \brief 存储Raw图像 \param objCImageDataPointer 图像数据对象 \param strFilePath 显示图像文件名 \return 无 */ //---------------------------------------------------------------------------------- void CGXBitmap::SaveRaw(CImageDataPointer& objCImageDataPointer,const std::string& strFilePath) { if ((objCImageDataPointer.IsNull()) || (strFilePath == "")) { writeLog("SaveRaw", "Argument is error", TYPE_ERROR); return; } //检查图像是否改变并更新Buffer __UpdateBitmap(objCImageDataPointer); DWORD dwImageSize = (DWORD)objCImageDataPointer->GetPayloadSize(); // 写入文件的长度 DWORD dwBytesRead = 0; // 文件读取的长度 BYTE* pbuffer = (BYTE*)objCImageDataPointer->GetBuffer(); if (!m_bIsColor) { // 黑白相机需要翻转数据后显示 for(int i = 0; i < m_nImageHeight; i++) { memcpy(m_pImageBuffer + i * m_nImageWidth, pbuffer + (m_nImageHeight - i -1) * m_nImageWidth, (size_t)m_nImageWidth); } pbuffer = m_pImageBuffer; } // 创建文件 std::wstring s = StringToWString(strFilePath); LPCTSTR LPCSTR_ImgFileName = s.c_str();//使用了我自定义的一个转换函数,并且连续调用了.c_str(),并对下面CreateFile进行了修改 HANDLE hFile = ::CreateFile(LPCSTR_ImgFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { // 创建失败则返回 throw std::runtime_error("Handle is invalid"); } else { // 保存Raw图像 ::WriteFile(hFile, pbuffer, dwImageSize, &dwBytesRead, NULL); CloseHandle(hFile); } } std::wstring StringToWString(const std::string &s) { std::wstring wsTmp(s.begin(), s.end()); std::cout << s; return wsTmp; } QString MakeMyDirectory() { QString strTemp, strAppPath; strTemp = QCoreApplication::applicationDirPath();//运行路径 int m = strTemp.lastIndexOf("/"); if (m != -1) { strAppPath = strTemp.left(m); } //设置日志存放路径 QString strLogDir;//创建单独存放日志的文件夹 strLogDir = strAppPath + "/Image"; //创建 if (createDir(strLogDir)) { return strLogDir; } else { return ""; } }
drawwidget.h↓
#ifndef DRAWWIDGET_H #define DRAWWIDGET_H #include <QImage> #include <QWidget> #include <QPainter> class DrawWidget : public QWidget { Q_OBJECT public: explicit DrawWidget(QWidget *parent = nullptr); void ReSizeImg(QImage inputImg);//将输入的Qimage调整为和窗口大小一致 void setSize(); protected: void paintEvent(QPaintEvent *event); public: QImage imgToDraw; private: QSize drawWigetSize; }; #endif // DRAWWIDGET_H
drawwidget.cpp↓
#include "drawwidget.h" DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent) { } void DrawWidget::ReSizeImg(QImage inputImg) { imgToDraw = inputImg.scaled(drawWigetSize, Qt::IgnoreAspectRatio); } void DrawWidget::setSize() { drawWigetSize = this->size(); } void DrawWidget::paintEvent(QPaintEvent *event) { QPainter p(this); p.drawImage(0, 0, imgToDraw); }
补充说明:代码中的创建文件夹函数(createDir()函数)是在另外一个类中写的,如下补充截图:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。