主頁 >  其他 > Linux環境中對海康威視工業相機SDK進行二次開發(QT+CMake+Opencv+海康SDK)

Linux環境中對海康威視工業相機SDK進行二次開發(QT+CMake+Opencv+海康SDK)

2021-12-30 11:15:32 其他

  • 關于在Windows環境中對海康威視工業相機SDK進行二次開發的話,可以參考這兩篇博客,
    海康威視工業相機SDK二次開發(VS+Opencv+QT+海康SDK+C++)(一)
    海康威視工業相機SDK二次開發(VS+Opencv+QT+海康SDK+C++)(二)

  • 然后最近因為××原因,又要轉到Linux環境下對海康威視工業相機的SDK進行二次開發使用,還是在虛擬機中搞的,,,

  • 之前一直用的都是Visual Studio編譯器,雖然有過Qt的界面開發經驗,但都是借助VS中的Qt 設計師,這次在Ubuntu16.04系統中用Qt Creator進行開發,編譯用CMake完成,

目錄

  • 1.關于CMake編譯工具與專案構建
    • 1.1 C++程式編譯程序
    • 1.2 Make和Makefile的關系
    • 1.3 CMake和CMakeLists的關系
    • 1.4 關于CMakeLists的撰寫
  • 2.原始碼
    • 說明:
      • ①關于SDK的原始碼版本
      • ②關于彩色和黑白的疑問
      • ③關于Linux中的路徑問題
      • ④關于曝光和增益的理解
      • ⑤在QLineEdit中使用setValidator設定區間
    • 2.1 CMakeLists.txt
    • 2.2 MvCamera.h
    • 2.3 mythread.h
    • 2.4 widget.h
    • 2.5 main.cpp
    • 2.6 MvCamera.cpp
    • 2.7 mythread.cpp
    • 2.8 widget.cpp
    • 2.9 widget.ui
    • 2.10 運行效果

1.關于CMake編譯工具與專案構建

(由于之前一直都沒用過CMake對專案進行管理,特別感謝這篇文章,寫的不錯,)https://mp.weixin.qq.com/s/WglXaNNDETKKu6zICRYswQ)

1.1 C++程式編譯程序

??編譯分為四個程序:預處理階段、編譯階段、匯編階段、鏈接階段,

  • ??預處理階段:處理以#開頭的指令,生成.i預編譯檔案,
  • ??編譯階段:將原始碼的.cpp檔案翻譯成.s匯編代碼,
  • ??匯編階段:將匯編代碼.s翻譯成機器指令.o檔案,
  • ??鏈接階段:對于匯編階段生成的.o檔案,并不會立刻執行,因為可能出現在原始碼的.cpp檔案中參考了另一個.cpp檔案中的東西,則鏈接的目的就是將這些檔案對應的目標檔案連接成一個整體,從而生成可執行的程式.exe檔案,

1.2 Make和Makefile的關系

??當源檔案比較多時,一般不適合直接通過gcc來編譯代碼,這時就需要一個自動化的編譯工具,

??Make(GNU Make)是一個自動化軟體,用于將源代碼檔案編譯為可執行的二進制檔案從而完成自動化編譯,Make工具編譯的時候需要Makefile檔案提供編譯規則,Makefile定義了一系列的編譯規則,包括編譯的先后順序,哪些檔案需要重新編譯等操作,

??利用Make工具可以自動完成編譯作業,如果修改了某幾個源檔案,則只重新編譯這幾個源檔案,如果某個頭檔案被修改了,則重新編譯所有包含該頭檔案的源檔案,利用這種自動編譯極大地提高了開發效率,避免了不必要的重新編譯,

1.3 CMake和CMakeLists的關系

??簡單來說,CMake強大在其是跨平臺的專案管理工具,它能夠輸出各種Makefile檔案或工程檔案,例如,在Windows環境下它能生成Visual Studio的工程,在Linux環境下它會生成Makefile檔案,也就是說,Cmake能夠按照同一個抽象規則為各個編譯器生成工程檔案,從而忽略不同平臺的差異,抽象成為一個一致的環境,

??CMake命令的執行所按照的規則也就是由CMakeLists.txt檔案撰寫的,
在這里插入圖片描述
??通過CMake工具可以讀入所有源檔案,自動生成Makefile,開發的基本流程如下:

  • 撰寫源檔案
  • 撰寫CMakeLists.txt
  • 由CMake根據CMakeLists.txt生成Makefile
  • 由Make根據Makefile,呼叫gcc生成可執行檔案
    在這里插入圖片描述

1.4 關于CMakeLists的撰寫

這篇博文寫的很詳細:https://blog.csdn.net/afei__/article/details/81201039

??CMakeLists.txt的撰寫主要包含以下步驟

  • cmake_minimum_required(VERSION 2.8.0):用于指定cmake所需最低版本;
  • project(Project) :用于指定專案名稱;
  • include_directories() :用于包含頭檔案目錄;
  • aux_source_directory(src dir_srcs):用于包含源檔案目錄;
  • set(TEST_MATH) :用于設定環境變數,編譯用到的源檔案全部都要放到這里;
  • add_executable(${PROJECT_NAME} ${TEST_MATH}):用于添加要編譯的可執行檔案;
  • target_link_libraries(${PROJECT_NAME} m):用于添加可執行檔案所需要的庫;

??link_libraries和target_link_libraries的區別:

  • link_libraries是指定要鏈接的庫檔案路徑,自己生成的庫檔案可以用該指令指定目錄的路徑以便工程能夠找到,
  • target_link_libraries是將目標檔案與庫檔案進行鏈接,可以指定動態庫/靜態庫,如果只提供庫名稱,系統會根據鏈接庫目錄搜索xxx.so 或者 xxx.a 檔案;或者指定給出全路徑,

資料參考:
CMAKE find_path和find_library命令的用法和解釋
QT 使用cmakelist.txt 匯入opencv
CMakeLists.txt添加opencv庫注意事項
CMakeList.txt設定OpenCv路徑
常用庫(QT,PCL,OPENCV,EIGEN3等)的cmakelists.txt模板

2.原始碼

說明:

①關于SDK的原始碼版本

  • ??一開始我是直接復制的之前在Windows環境下開發的相關代碼,經過幾個SDK的原始碼對比,發現還是有一點不一樣,有些API可能改名或者就沒有了,如果某些功能你在Windows中能夠實作,到了Linux環境中卻實作不了了,可以修改CameraParams.hMvCameraControl.hMvErrorDefine.hPixelType.h這幾個檔案,以滿足專案的需求,

②關于彩色和黑白的疑問

  • ??之前在Windows環境下開發用的是海康的彩色相機,這次在Linux環境下用的是海康的黑白相機,我直接移植了之前的代碼并配置了相關環境,發現在Qt中通過QLabel顯示的影像和相機實際拍到的不一樣(QLabel中顯示的影像很模糊),一開始以為是彩色和黑白的區別,但通過保存影像的按鈕發現保存的圖片沒什么問題,那就是QLabel的顯示問題了,
    后來查了下QImage影像格式解讀:(我也沒看懂哪里是灰度影像的格式)https://blog.csdn.net/weixin_39485901/article/details/88047291
    最后將QImage::Format_Indexed8改成了QImage::Format_RGB888,問題就解決了,(這里有個疑問,QImage::Format_RGB888 影像存盤使用8-8-8 24位RGB格式,這里明顯是彩色影像3個通道的,而黑白的海康威視工業相機我經過列印確認通道是1個,那為什么用QImage::Format_RGB888就可以呢???不理解,如有大佬知曉希望告知,)

③關于Linux中的路徑問題

  • 在設定背景圖時,我默認Windows環境中的當前工程目錄為相對路徑,就想弄個圖片作為背景圖,發現不是同一個路徑,
  • 比如我的專案名稱是sdkCamera,則該工程專案的檔案夾是build-sdkCamera-Desktop_Qt_5_12_9_GCC_64bit-Debug

④關于曝光和增益的理解

  • 曝光和增益是直接控制傳感器(CCD/CMOS)上讀出來的資料,是要優先調節的,以調節曝光時間為主,在不過曝的前提下,增加曝光時間可以增加信噪比,使影像清晰,當然,對于很弱的信號,曝光也不能無限增加,因為隨著曝光時間的增加,噪音也會積累, 曝光補償就是增加拍攝時的曝光量,
  • 增益一般只是在信號弱,但不想增加曝光時間的情況下使用,一般相機增益都產生很大噪音,工業相機在不同增益時影像的成像質量不一樣,增益越小,噪點越小;增益越大,噪點越多,特別是在暗處,數碼相機的ISO就是這里說的增益,增大ISO,是增加感光器件對光的靈敏度,高感光度對低光照靈敏,同時對噪雜信號也靈敏,信噪比小,所以高感光度噪點也多(可利用圖片軟體的降噪功能減輕或去除),
    調節亮度增益說白了就是改變ISO,改變CMOS傳感器的感光性能,但是會影響到畫質,調節曝光補償則是為了改變快門速度,不改變ISO不會影響畫質,

⑤在QLineEdit中使用setValidator設定區間

參考:https://blog.csdn.net/qq78442761/article/details/80276764/

2.1 CMakeLists.txt

對于一個習慣了用Visual Studio編譯器編程、除錯、配置環境的人,一開始轉到CMake,撰寫CMakeLists.txt檔案時,我是一臉懵逼的,還要用Qt Creator進行除錯編譯,,,
有幸看了上面一些大佬寫的關于CMakeLists.txt檔案的撰寫,再對照當初在Visual Studio中的環境配置程序,慢慢的自己也配置成功了海康威視SDK和OpenCV,

Windows下的MVS配置
附加包含目錄:D:MVS\MVS\Development\Includes
附加庫目錄:D:MVS\MVS\Development\Libraries\win64
附加依賴項:MvCameraControl.lib
工程專案添加:MvCamera.h、MvCamera.cpp

Windows下的OpenCV配置
包含目錄:D:\opencv4.4\opencv\build\include\opencv2
D:\opencv4.4\opencv\build\include
庫目錄: D:\opencv4.4\opencv\build\x64\vc15\lib
聯結器: opencv_world440d.lib
opencv_world440.lib

這是我的CMakeLists.txt源檔案:

cmake_minimum_required(VERSION 3.5)

project(aubo_camera LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set( CMAKE_CXX_FLAGS "-std=c++11" )

set(OpenCV_DIR /home/aubo/opencv-4.4.0/build)
find_package( OpenCV 4 REQUIRED)
include_directories( ${OpenCV_INCLUDE_DIRS} )

# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check http://doc.qt.io/qt-5/deployment-android.html for more information.
# They need to be set before the find_package(Qt5 ...) call.

#if(ANDROID)
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
#    if (ANDROID_ABI STREQUAL "armeabi-v7a")
#        set(ANDROID_EXTRA_LIBS
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
#    endif()
#endif()

find_package(Qt5 COMPONENTS Widgets REQUIRED)

if(ANDROID)
  add_library(aubo_camera SHARED
      main.cpp
      widget.cpp
      MvCamera.cpp
      mythread.cpp
      mythread.h
      MvCamera.h
      widget.h
      widget.ui
  )
else()
  add_executable(aubo_camera
      main.cpp
      widget.cpp
      MvCamera.cpp
      mythread.cpp
      mythread.h
      MvCamera.h
      widget.h
      widget.ui
  )
endif()

find_library(CAMERA_LIB libMvCameraControl.so libMvCameraControl.so.3.1.3.0 /home/aubo/MVS-2.1.0_x86_64_20201228/MVS/lib/64/)
find_path(MVS_PATH CameraParams.h MvCameraControl.h MvErrorDefine.h PixelType.h /home/aubo/MVS-2.1.0_x86_64_20201228/MVS/include)
INCLUDE_DIRECTORIES(${MVS_PATH})

target_link_libraries(aubo_camera PRIVATE Qt5::Widgets ${CAMERA_LIB} ${OpenCV_LIBS})

關于Linux環境下海康威視SDK的下載安裝和OpenCV的原始碼編譯,請移步于:
VMware虛擬機中Ubuntu16.04系統下通過MVS運行海康威視工業相機
VMware虛擬機中Ubuntu16.04系統下進行OpenCV4.4的安裝編譯

下面在CMakeList.txt中的檔案安裝目錄根據自己的實際安裝位置為準,
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

2.2 MvCamera.h

#ifndef MVCAMERA_H
#define MVCAMERA_H

#include "MvCameraControl.h"
#include <string.h>

#ifndef MV_NULL
#define MV_NULL 0
#endif

#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/types_c.h"

class CMvCamera
{
public:
    CMvCamera();
    ~CMvCamera();

    // ch:獲取SDK版本號 | en:Get SDK Version
    static int GetSDKVersion();

    // ch:列舉設備 | en:Enumerate Device
    static int EnumDevices(unsigned int nTLayerType,
                           MV_CC_DEVICE_INFO_LIST *pstDevList);

    // ch:判斷設備是否可達 | en:Is the device accessible
    static bool IsDeviceAccessible(MV_CC_DEVICE_INFO *pstDevInfo,
                                   unsigned int nAccessMode);

    // ch:打開設備 | en:Open Device
    int Open(MV_CC_DEVICE_INFO *pstDeviceInfo);

    // ch:關閉設備 | en:Close Device
    int Close();

    // ch:判斷相機是否處于連接狀態 | en:Is The Device Connected
    bool IsDeviceConnected();

    // ch:注冊影像資料回呼 | en:Register Image Data CallBack
    int RegisterImageCallBack(
        void(__stdcall *cbOutput)(unsigned char *pData,
                                  MV_FRAME_OUT_INFO_EX *pFrameInfo,
                                  void *pUser),
        void *pUser);

    // ch:開啟抓圖 | en:Start Grabbing
    int StartGrabbing();

    // ch:停止抓圖 | en:Stop Grabbing
    int StopGrabbing();

    // ch:主動獲取一幀影像資料 | en:Get one frame initiatively
    int GetImageBuffer(MV_FRAME_OUT *pFrame, int nMsec);

    // ch:釋放影像快取 | en:Free image buffer
    int FreeImageBuffer(MV_FRAME_OUT *pFrame);

    // ch:主動獲取一幀影像資料 | en:Get one frame initiatively
    int GetOneFrameTimeout(unsigned char *pData, unsigned int *pnDataLen,
                           unsigned int nDataSize,
                           MV_FRAME_OUT_INFO_EX *pFrameInfo, int nMsec);

    // ch:顯示一幀影像 | en:Display one frame image
    int DisplayOneFrame(MV_DISPLAY_FRAME_INFO *pDisplayInfo);

    // ch:設定SDK內部影像快取節點個數 | en:Set the number of the internal image
    // cache nodes in SDK
    int SetImageNodeNum(unsigned int nNum);

    // ch:獲取設備資訊 | en:Get device information
    int GetDeviceInfo(MV_CC_DEVICE_INFO *pstDevInfo);

    // ch:獲取GEV相機的統計資訊 | en:Get detect info of GEV camera
    int GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT *pMatchInfoNetDetect);

    // ch:獲取U3V相機的統計資訊 | en:Get detect info of U3V camera
    int GetU3VAllMatchInfo(MV_MATCH_INFO_USB_DETECT *pMatchInfoUSBDetect);

    // ch:獲取和設定Int型引數,如 Width和Height,詳細內容參考SDK安裝目錄下的
    // MvCameraNode.xlsx 檔案 en:Get Int type parameters, such as Width and
    // Height, for details please refer to MvCameraNode.xlsx file under SDK
    // installation directory
    // int GetIntValue(IN const char* strKey, OUT MVCC_INTVALUE_EX* pIntValue);
    int GetIntValue(IN const char *strKey, OUT unsigned int *pnValue);
    int SetIntValue(IN const char *strKey, IN int64_t nValue);

    // ch:獲取和設定Enum型引數,如 PixelFormat,詳細內容參考SDK安裝目錄下的
    // MvCameraNode.xlsx 檔案 en:Get Enum type parameters, such as PixelFormat,
    // for details please refer to MvCameraNode.xlsx file under SDK installation
    // directory
    int GetEnumValue(IN const char *strKey, OUT MVCC_ENUMVALUE *pEnumValue);
    int SetEnumValue(IN const char *strKey, IN unsigned int nValue);
    int SetEnumValueByString(IN const char *strKey, IN const char *sValue);

    // ch:獲取和設定Float型引數,如
    // ExposureTime和Gain,詳細內容參考SDK安裝目錄下的 MvCameraNode.xlsx 檔案
    // en:Get Float type parameters, such as ExposureTime and Gain, for details
    // please refer to MvCameraNode.xlsx file under SDK installation directory
    int GetFloatValue(IN const char *strKey, OUT MVCC_FLOATVALUE *pFloatValue);
    int SetFloatValue(IN const char *strKey, IN float fValue);

    // ch:獲取和設定Bool型引數,如 ReverseX,詳細內容參考SDK安裝目錄下的
    // MvCameraNode.xlsx 檔案 en:Get Bool type parameters, such as ReverseX, for
    // details please refer to MvCameraNode.xlsx file under SDK installation
    // directory
    int GetBoolValue(IN const char *strKey, OUT bool *pbValue);
    int SetBoolValue(IN const char *strKey, IN bool bValue);

    // ch:獲取和設定String型引數,如 DeviceUserID,詳細內容參考SDK安裝目錄下的
    // MvCameraNode.xlsx 檔案UserSetSave en:Get String type parameters, such as
    // DeviceUserID, for details please refer to MvCameraNode.xlsx file under
    // SDK installation directory
    int GetStringValue(IN const char *strKey, MVCC_STRINGVALUE *pStringValue);
    int SetStringValue(IN const char *strKey, IN const char *strValue);

    // ch:執行一次Command型命令,如 UserSetSave,詳細內容參考SDK安裝目錄下的
    // MvCameraNode.xlsx 檔案 en:Execute Command once, such as UserSetSave, for
    // details please refer to MvCameraNode.xlsx file under SDK installation
    // directory
    int CommandExecute(IN const char *strKey);

    // ch:探測網路最佳包大小(只對GigE相機有效) | en:Detection network optimal
    // package size(It only works for the GigE camera)
    int GetOptimalPacketSize(unsigned int *pOptimalPacketSize);

    // ch:注冊訊息例外回呼 | en:Register Message Exception CallBack
    int RegisterExceptionCallBack(
        void(__stdcall *cbException)(unsigned int nMsgType, void *pUser),
        void *pUser);

    // ch:注冊單個事件回呼 | en:Register Event CallBack
    int RegisterEventCallBack(
        const char *pEventName,
        void(__stdcall *cbEvent)(MV_EVENT_OUT_INFO *pEventInfo, void *pUser),
        void *pUser);

    // ch:強制IP | en:Force IP
    int ForceIp(unsigned int nIP, unsigned int nSubNetMask,
                unsigned int nDefaultGateWay);

    // ch:配置IP方式 | en:IP configuration method
    int SetIpConfig(unsigned int nType);

    // ch:設定網路傳輸模式 | en:Set Net Transfer Mode
    int SetNetTransMode(unsigned int nType);

    // ch:像素格式轉換 | en:Pixel format conversion
    int ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM *pstCvtParam);

    // ch:保存圖片 | en:save image
    int SaveImage(MV_SAVE_IMAGE_PARAM_EX *pstParam);

    // ch:保存圖片為檔案 | en:Save the image as a file
    int SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM *pstParam);

    //設定是否為觸發模式
    int setTriggerMode(unsigned int TriggerModeNum);

    //設定觸發源
    int setTriggerSource(unsigned int TriggerSourceNum);

    //軟觸發
    int softTrigger();

    //讀取buffer
    int ReadBuffer(cv::Mat &image);

    //設定曝光時間
    int setExposureTime(float ExposureTimeNum);

public:
    void *m_hDevHandle;
    unsigned int m_nTLayerType;

public:
    unsigned char *m_pBufForSaveImage; // 用于保存影像的快取
    unsigned int m_nBufSizeForSaveImage;

    unsigned char *m_pBufForDriver; // 用于從驅動獲取影像的快取
    unsigned int m_nBufSizeForDriver;
};

#endif // MVCAMERA_H

2.3 mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include "QThread"
#include "MvCamera.h"
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

using namespace std;
using namespace cv;

class MyThread :public QThread
{
        Q_OBJECT

public:
        MyThread();
        ~MyThread();

        void run();
        void getCameraPtr(CMvCamera* camera);
        void getImagePtr(Mat* image);
        void getCameraIndex(int index);

signals:
        void mess();
        void Display(const Mat* image, int index);

private:
        CMvCamera* cameraPtr = NULL;
        cv::Mat* imagePtr = NULL;
        int cameraIndex = NULL;
        int TriggerMode;

};

#endif // MYTHREAD_H

2.4 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include <QMessageBox>
#include <QCloseEvent>
#include <QSettings>

#include "MvCamera.h"
#include "mythread.h"

#define MAX_DEVICE_NUM     2
#define TRIGGER_SOURCE     7
#define EXPOSURE_TIME      40000
#define FRAME              30
#define TRIGGER_ON         1
#define TRIGGER_OFF        0
#define START_GRABBING_ON  1
#define START_GRABBING_OFF 0
#define IMAGE_NAME_LEN     64

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

public:
    CMvCamera *m_pcMyCamera[MAX_DEVICE_NUM]; // 相機指標物件
    MV_CC_DEVICE_INFO_LIST m_stDevList;      // 存盤設備串列
    cv::Mat *myImage_L = new cv::Mat(); //保存左相機影像的影像指標物件
    cv::Mat *myImage_R = new cv::Mat(); //保存右相機有影像的影像指標物件
    int devices_num;

public:
    MyThread *myThread_Camera_show = NULL; //相機實時顯示執行緒物件

private slots:
    void on_pbn_enum_camera_clicked();
    void on_pbn_open_camera_clicked();
    void on_rdo_continue_mode_clicked();
    void on_rdo_softigger_mode_clicked();
    void on_pbn_start_grabbing_clicked();
    void on_pbn_stop_grabbing_clicked();
    void on_pbn_software_once_clicked();
    void display_myImage_L(const Mat *imagePrt, int cameraIndex);
    void on_pbn_close_camera_clicked();
    void on_pbn_save_BMP_clicked();
    void on_pbn_save_JPG_clicked();
    void on_le_set_exposure_textChanged(const QString &arg1);
    void on_le_set_gain_textChanged(const QString &arg1);

public:
    // 狀態
    bool m_bOpenDevice;                  // 是否打開設備
    bool m_bStartGrabbing;               // 是否開始抓圖
    int m_nTriggerMode;                  // 觸發模式
    int m_bContinueStarted;              // 開啟過連續采集影像
    MV_SAVE_IAMGE_TYPE m_nSaveImageType; // 保存影像格式

private:
    QString PrintDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo, int num_index);
    void OpenDevices();
    void CloseDevices();
    void SaveImage();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

2.5 main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

2.6 MvCamera.cpp

#include "MvCamera.h"

CMvCamera::CMvCamera()
{
    m_hDevHandle = MV_NULL;
}

CMvCamera::~CMvCamera()
{
    if (m_hDevHandle) {
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = MV_NULL;
    }
}

// ch:獲取SDK版本號 | en:Get SDK Version
int CMvCamera::GetSDKVersion()
{
    return MV_CC_GetSDKVersion();
}

// ch:列舉設備 | en:Enumerate Device
int CMvCamera::EnumDevices(unsigned int nTLayerType,
                           MV_CC_DEVICE_INFO_LIST *pstDevList)
{
    return MV_CC_EnumDevices(nTLayerType, pstDevList);
}

// ch:判斷設備是否可達 | en:Is the device accessible
bool CMvCamera::IsDeviceAccessible(MV_CC_DEVICE_INFO *pstDevInfo,
                                   unsigned int nAccessMode)
{
    return MV_CC_IsDeviceAccessible(pstDevInfo, nAccessMode);
}

// ch:打開設備 | en:Open Device
int CMvCamera::Open(MV_CC_DEVICE_INFO *pstDeviceInfo)
{
    if (MV_NULL == pstDeviceInfo) {
        return MV_E_PARAMETER;
    }

    if (m_hDevHandle) {
        return MV_E_CALLORDER;
    }

    int nRet = MV_CC_CreateHandle(&m_hDevHandle, pstDeviceInfo);
    if (MV_OK != nRet) {
        return nRet;
    }

    nRet = MV_CC_OpenDevice(m_hDevHandle);
    if (MV_OK != nRet) {
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = MV_NULL;
    }

    return nRet;
}

// ch:關閉設備 | en:Close Device
int CMvCamera::Close()
{
    if (MV_NULL == m_hDevHandle) {
        return MV_E_HANDLE;
    }

    MV_CC_CloseDevice(m_hDevHandle);

    int nRet = MV_CC_DestroyHandle(m_hDevHandle);
    m_hDevHandle = MV_NULL;

    return nRet;
}

// ch:判斷相機是否處于連接狀態 | en:Is The Device Connected
bool CMvCamera::IsDeviceConnected()
{
    return MV_CC_IsDeviceConnected(m_hDevHandle);
}

// ch:注冊影像資料回呼 | en:Register Image Data CallBack
int CMvCamera::RegisterImageCallBack(
    void(__stdcall *cbOutput)(unsigned char *pData,
                              MV_FRAME_OUT_INFO_EX *pFrameInfo, void *pUser),
    void *pUser)
{
    return MV_CC_RegisterImageCallBackEx(m_hDevHandle, cbOutput, pUser);
}

// ch:開啟抓圖 | en:Start Grabbing
int CMvCamera::StartGrabbing()
{
    return MV_CC_StartGrabbing(m_hDevHandle);
}

// ch:停止抓圖 | en:Stop Grabbing
int CMvCamera::StopGrabbing()
{
    return MV_CC_StopGrabbing(m_hDevHandle);
}

// ch:主動獲取一幀影像資料 | en:Get one frame initiatively
int CMvCamera::GetImageBuffer(MV_FRAME_OUT *pFrame, int nMsec)
{
    return MV_CC_GetImageBuffer(m_hDevHandle, pFrame, nMsec);
}

// ch:釋放影像快取 | en:Free image buffer
int CMvCamera::FreeImageBuffer(MV_FRAME_OUT *pFrame)
{
    return MV_CC_FreeImageBuffer(m_hDevHandle, pFrame);
}

// ch:主動獲取一幀影像資料 | en:Get one frame initiatively
int CMvCamera::GetOneFrameTimeout(unsigned char *pData, unsigned int *pnDataLen,
                                  unsigned int nDataSize,
                                  MV_FRAME_OUT_INFO_EX *pFrameInfo, int nMsec)
{
    if (NULL == pnDataLen) {
        return MV_E_PARAMETER;
    }

    int nRet = MV_OK;

    *pnDataLen = 0;

    nRet = MV_CC_GetOneFrameTimeout(m_hDevHandle, pData, nDataSize, pFrameInfo,
                                    nMsec);
    if (MV_OK != nRet) {
        return nRet;
    }

    *pnDataLen = pFrameInfo->nFrameLen;

    return nRet;
}

// ch:設定顯示視窗句柄 | en:Set Display Window Handle
int CMvCamera::DisplayOneFrame(MV_DISPLAY_FRAME_INFO *pDisplayInfo)
{
    return MV_CC_DisplayOneFrame(m_hDevHandle, pDisplayInfo);
}

// ch:設定SDK內部影像快取節點個數 | en:Set the number of the internal image
// cache nodes in SDK
int CMvCamera::SetImageNodeNum(unsigned int nNum)
{
    return MV_CC_SetImageNodeNum(m_hDevHandle, nNum);
}

// ch:獲取設備資訊 | en:Get device information
int CMvCamera::GetDeviceInfo(MV_CC_DEVICE_INFO *pstDevInfo)
{
    return MV_CC_GetDeviceInfo(m_hDevHandle, pstDevInfo);
}

// ch:獲取GEV相機的統計資訊 | en:Get detect info of GEV camera
int CMvCamera::GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT *pMatchInfoNetDetect)
{
    if (MV_NULL == pMatchInfoNetDetect) {
        return MV_E_PARAMETER;
    }

    MV_CC_DEVICE_INFO stDevInfo = { 0 };
    GetDeviceInfo(&stDevInfo);
    if (stDevInfo.nTLayerType != MV_GIGE_DEVICE) {
        return MV_E_SUPPORT;
    }

    MV_ALL_MATCH_INFO struMatchInfo = { 0 };

    struMatchInfo.nType = MV_MATCH_TYPE_NET_DETECT;
    struMatchInfo.pInfo = pMatchInfoNetDetect;
    struMatchInfo.nInfoSize = sizeof(MV_MATCH_INFO_NET_DETECT);
    memset(struMatchInfo.pInfo, 0, sizeof(MV_MATCH_INFO_NET_DETECT));

    return MV_CC_GetAllMatchInfo(m_hDevHandle, &struMatchInfo);
}

// ch:獲取U3V相機的統計資訊 | en:Get detect info of U3V camera
int CMvCamera::GetU3VAllMatchInfo(MV_MATCH_INFO_USB_DETECT *pMatchInfoUSBDetect)
{
    if (MV_NULL == pMatchInfoUSBDetect) {
        return MV_E_PARAMETER;
    }

    MV_CC_DEVICE_INFO stDevInfo = { 0 };
    GetDeviceInfo(&stDevInfo);
    if (stDevInfo.nTLayerType != MV_USB_DEVICE) {
        return MV_E_SUPPORT;
    }

    MV_ALL_MATCH_INFO struMatchInfo = { 0 };

    struMatchInfo.nType = MV_MATCH_TYPE_USB_DETECT;
    struMatchInfo.pInfo = pMatchInfoUSBDetect;
    struMatchInfo.nInfoSize = sizeof(MV_MATCH_INFO_USB_DETECT);
    memset(struMatchInfo.pInfo, 0, sizeof(MV_MATCH_INFO_USB_DETECT));

    return MV_CC_GetAllMatchInfo(m_hDevHandle, &struMatchInfo);
}

// ch:獲取和設定Int型引數,如 Width和Height,詳細內容參考SDK安裝目錄下的
// MvCameraNode.xlsx 檔案 en:Get Int type parameters, such as Width and Height,
// for details please refer to MvCameraNode.xlsx file under SDK installation
// directory
int CMvCamera::GetIntValue(IN const char *strKey, OUT unsigned int *pnValue)
{
    if (NULL == strKey || NULL == pnValue) {
        return MV_E_PARAMETER;
    }

    MVCC_INTVALUE stParam;
    memset(&stParam, 0, sizeof(MVCC_INTVALUE));
    int nRet = MV_CC_GetIntValue(m_hDevHandle, strKey, &stParam);
    if (MV_OK != nRet) {
        return nRet;
    }

    *pnValue = stParam.nCurValue;

    return MV_OK;
}

int CMvCamera::SetIntValue(IN const char *strKey, IN int64_t nValue)
{
    return MV_CC_SetIntValueEx(m_hDevHandle, strKey, nValue);
}

// ch:獲取和設定Enum型引數,如 PixelFormat,詳細內容參考SDK安裝目錄下的
// MvCameraNode.xlsx 檔案 en:Get Enum type parameters, such as PixelFormat, for
// details please refer to MvCameraNode.xlsx file under SDK installation
// directory
int CMvCamera::GetEnumValue(IN const char *strKey,
                            OUT MVCC_ENUMVALUE *pEnumValue)
{
    return MV_CC_GetEnumValue(m_hDevHandle, strKey, pEnumValue);
}

int CMvCamera::SetEnumValue(IN const char *strKey, IN unsigned int nValue)
{
    return MV_CC_SetEnumValue(m_hDevHandle, strKey, nValue);
}

int CMvCamera::SetEnumValueByString(IN const char *strKey,
                                    IN const char *sValue)
{
    return MV_CC_SetEnumValueByString(m_hDevHandle, strKey, sValue);
}

// ch:獲取和設定Float型引數,如 ExposureTime和Gain,詳細內容參考SDK安裝目錄下的
// MvCameraNode.xlsx 檔案 en:Get Float type parameters, such as ExposureTime and
// Gain, for details please refer to MvCameraNode.xlsx file under SDK
// installation directory
int CMvCamera::GetFloatValue(IN const char *strKey,
                             OUT MVCC_FLOATVALUE *pFloatValue)
{
    return MV_CC_GetFloatValue(m_hDevHandle, strKey, pFloatValue);
}

int CMvCamera::SetFloatValue(IN const char *strKey, IN float fValue)
{
    return MV_CC_SetFloatValue(m_hDevHandle, strKey, fValue);
}

// ch:獲取和設定Bool型引數,如 ReverseX,詳細內容參考SDK安裝目錄下的
// MvCameraNode.xlsx 檔案 en:Get Bool type parameters, such as ReverseX, for
// details please refer to MvCameraNode.xlsx file under SDK installation
// directory
int CMvCamera::GetBoolValue(IN const char *strKey, OUT bool *pbValue)
{
    return MV_CC_GetBoolValue(m_hDevHandle, strKey, pbValue);
}

int CMvCamera::SetBoolValue(IN const char *strKey, IN bool bValue)
{
    return MV_CC_SetBoolValue(m_hDevHandle, strKey, bValue);
}

// ch:獲取和設定String型引數,如 DeviceUserID,詳細內容參考SDK安裝目錄下的
// MvCameraNode.xlsx 檔案UserSetSave en:Get String type parameters, such as
// DeviceUserID, for details please refer to MvCameraNode.xlsx file under SDK
// installation directory
int CMvCamera::GetStringValue(IN const char *strKey,
                              MVCC_STRINGVALUE *pStringValue)
{
    return MV_CC_GetStringValue(m_hDevHandle, strKey, pStringValue);
}

int CMvCamera::SetStringValue(IN const char *strKey, IN const char *strValue)
{
    return MV_CC_SetStringValue(m_hDevHandle, strKey, strValue);
}

// ch:執行一次Command型命令,如 UserSetSave,詳細內容參考SDK安裝目錄下的
// MvCameraNode.xlsx 檔案 en:Execute Command once, such as UserSetSave, for
// details please refer to MvCameraNode.xlsx file under SDK installation
// directory
int CMvCamera::CommandExecute(IN const char *strKey)
{
    return MV_CC_SetCommandValue(m_hDevHandle, strKey);
}

// ch:探測網路最佳包大小(只對GigE相機有效) | en:Detection network optimal
// package size(It only works for the GigE camera)
int CMvCamera::GetOptimalPacketSize(unsigned int *pOptimalPacketSize)
{
    if (MV_NULL == pOptimalPacketSize) {
        return MV_E_PARAMETER;
    }

    int nRet = MV_CC_GetOptimalPacketSize(m_hDevHandle);
    if (nRet < MV_OK) {
        return nRet;
    }

    *pOptimalPacketSize = (unsigned int)nRet;

    return MV_OK;
}

// ch:注冊訊息例外回呼 | en:Register Message Exception CallBack
int CMvCamera::RegisterExceptionCallBack(
    void(__stdcall *cbException)(unsigned int nMsgType, void *pUser),
    void *pUser)
{
    return MV_CC_RegisterExceptionCallBack(m_hDevHandle, cbException, pUser);
}

// ch:注冊單個事件回呼 | en:Register Event CallBack
int CMvCamera::RegisterEventCallBack(
    const char *pEventName,
    void(__stdcall *cbEvent)(MV_EVENT_OUT_INFO *pEventInfo, void *pUser),
    void *pUser)
{
    return MV_CC_RegisterEventCallBackEx(m_hDevHandle, pEventName, cbEvent,
                                         pUser);
}

// ch:強制IP | en:Force IP
int CMvCamera::ForceIp(unsigned int nIP, unsigned int nSubNetMask,
                       unsigned int nDefaultGateWay)
{
    return MV_GIGE_ForceIpEx(m_hDevHandle, nIP, nSubNetMask, nDefaultGateWay);
}

// ch:配置IP方式 | en:IP configuration method
int CMvCamera::SetIpConfig(unsigned int nType)
{
    return MV_GIGE_SetIpConfig(m_hDevHandle, nType);
}

// ch:設定網路傳輸模式 | en:Set Net Transfer Mode
int CMvCamera::SetNetTransMode(unsigned int nType)
{
    return MV_GIGE_SetNetTransMode(m_hDevHandle, nType);
}

// ch:像素格式轉換 | en:Pixel format conversion
int CMvCamera::ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM *pstCvtParam)
{
    return MV_CC_ConvertPixelType(m_hDevHandle, pstCvtParam);
}

// ch:保存圖片 | en:save image
int CMvCamera::SaveImage(MV_SAVE_IMAGE_PARAM_EX *pstParam)
{
    return MV_CC_SaveImageEx2(m_hDevHandle, pstParam);
}

 ch:保存圖片為檔案 | en:Save the image as a file
// int CMvCamera::SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM *pstSaveFileParam)
//{
//    return MV_CC_SaveImageToFile(m_hDevHandle, pstSaveFileParam);
//}

//設定是否為觸發模式
int CMvCamera::setTriggerMode(unsigned int TriggerModeNum)
{
    // 0:Off  1:On
    int tempValue =
        MV_CC_SetEnumValue(m_hDevHandle, "TriggerMode", TriggerModeNum);
    if (tempValue != 0) {
        return -1;
    } else {
        return 0;
    }
}

//設定觸發源
int CMvCamera::setTriggerSource(unsigned int TriggerSourceNum)
{
    // 0:Line0  1:Line1  7:Software
    int tempValue =
        MV_CC_SetEnumValue(m_hDevHandle, "TriggerSource", TriggerSourceNum);
    if (tempValue != 0) {
        return -1;
    } else {
        return 0;
    }
}

//發送軟觸發
int CMvCamera::softTrigger()
{
    int tempValue = MV_CC_SetCommandValue(m_hDevHandle, "TriggerSoftware");
    if (tempValue != 0) {
        return -1;
    } else {
        return 0;
    }
}

//讀取相機中的影像
// int ReadBuffer(cv::Mat &image);
int CMvCamera::ReadBuffer(cv::Mat &image)
{
    cv::Mat *getImage = new cv::Mat();
    unsigned int nRecvBufSize = 0;
    MVCC_INTVALUE stParam;
    memset(&stParam, 0, sizeof(MVCC_INTVALUE));
    int tempValue = MV_CC_GetIntValue(m_hDevHandle, "PayloadSize", &stParam);
    if (tempValue != 0) {
        return -1;
    }
    nRecvBufSize = stParam.nCurValue;
    unsigned char *pDate;
    pDate = (unsigned char *)malloc(nRecvBufSize);

    MV_FRAME_OUT_INFO_EX stImageInfo = { 0 };
    tempValue = MV_CC_GetOneFrameTimeout(m_hDevHandle, pDate, nRecvBufSize,
                                         &stImageInfo, 500);
    if (tempValue != 0) {
        return -1;
    }
    m_nBufSizeForSaveImage =
        stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
    unsigned char *m_pBufForSaveImage;
    m_pBufForSaveImage = (unsigned char *)malloc(m_nBufSizeForSaveImage);

    bool isMono;
    switch (stImageInfo.enPixelType) {
    case PixelType_Gvsp_Mono8:
    case PixelType_Gvsp_Mono10:
    case PixelType_Gvsp_Mono10_Packed:
    case PixelType_Gvsp_Mono12:
    case PixelType_Gvsp_Mono12_Packed:
        isMono = true;
        break;
    default:
        isMono = false;
        break;
    }
    if (isMono) {
        *getImage =
            cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC1, pDate);
        // imwrite("d:\\測驗opencv_Mono.tif", image);
    } else {
        //轉換影像格式為BGR8
        MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 };
        memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
        stConvertParam.nWidth = stImageInfo.nWidth; // ch:影像寬 | en:image
                                                    // width
        stConvertParam.nHeight =
            stImageInfo.nHeight; // ch:影像高 | en:image height
        // stConvertParam.pSrcData = m_pBufForDriver; //ch:輸入資料快取 |
        // en:input data buffer
        stConvertParam.pSrcData =
            pDate; // ch:輸入資料快取 | en:input data buffer
        stConvertParam.nSrcDataLen =
            stImageInfo.nFrameLen; // ch:輸入資料大小 | en:input data size
        stConvertParam.enSrcPixelType =
            stImageInfo.enPixelType; // ch:輸入像素格式 | en:input pixel format
        stConvertParam.enDstPixelType =
            PixelType_Gvsp_BGR8_Packed; // ch:輸出像素格式 | en:output pixel
                                        // format  適用于OPENCV的影像格式
        // stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed;
        //輸出像素格式 | en:output pixel format
        stConvertParam.pDstBuffer =
            m_pBufForSaveImage; // ch:輸出資料快取 | en:output data buffer
        stConvertParam.nDstBufferSize =
            m_nBufSizeForSaveImage; // ch:輸出快取大小 | en:output buffer size
        MV_CC_ConvertPixelType(m_hDevHandle, &stConvertParam);

        *getImage = cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC3,
                            m_pBufForSaveImage);
    }
    (*getImage).copyTo(image);
    (*getImage).release();
    free(pDate);
    free(m_pBufForSaveImage);
    return 0;
}

//設定曝光時間
int CMvCamera::setExposureTime(float ExposureTimeNum)
{
    int tempValue =
        MV_CC_SetFloatValue(m_hDevHandle, "ExposureTime", ExposureTimeNum);
    if (tempValue != 0) {
        return -1;
    } else {
        return 0;
    }
}

2.7 mythread.cpp

#include "mythread.h"

MyThread::MyThread()
{
}

MyThread::~MyThread()
{
    terminate();
    if (cameraPtr != NULL) {
        delete cameraPtr;
    }
    if (imagePtr != NULL) {
        delete imagePtr;
    }
}

void MyThread::getCameraPtr(CMvCamera *camera)
{
    cameraPtr = camera;
}

void MyThread::getImagePtr(Mat *image)
{
    imagePtr = image;
}

void MyThread::getCameraIndex(int index)
{
    cameraIndex = index;
}

void MyThread::run()
{
    if (cameraPtr == NULL) {
        return;
    }

    if (imagePtr == NULL) {
        return;
    }

    while (!isInterruptionRequested()) {
        std::cout << "Thread_Trigger:" << cameraPtr->softTrigger() << std::endl;
        std::cout << "Thread_Readbuffer:" << cameraPtr->ReadBuffer(*imagePtr)
                  << std::endl;
        /*emit mess();*/
        emit Display(imagePtr, cameraIndex); //發送信號lbl_camera_L接收并顯示
        msleep(30);
    }
}

2.8 widget.cpp

#include "widget.h"
#include "./ui_widget.h"

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->lbl_camera_L->setPixmap(QPixmap("back_img.jpg"));
    ui->lbl_camera_L->setScaledContents(true);

    ui->lbl_camera_R->setPixmap(QPixmap("back_img.jpg"));
    ui->lbl_camera_R->setScaledContents(true);

    // 相機初始化控制元件
    ui->pbn_enum_camera->setEnabled(true);
    ui->pbn_open_camera->setEnabled(false);
    ui->pbn_close_camera->setEnabled(false);
    ui->cmb_camera_index->setEnabled(false);

    // 影像采集控制元件
    ui->rdo_continue_mode->setEnabled(false);
    ui->rdo_softigger_mode->setEnabled(false);
    ui->pbn_start_grabbing->setEnabled(false);
    ui->pbn_stop_grabbing->setEnabled(false);
    ui->pbn_software_once->setEnabled(false);

    // 引數控制元件
    ui->le_set_exposure->setEnabled(false);
    ui->le_set_gain->setEnabled(false);

    // 保存影像控制元件
    ui->pbn_save_BMP->setEnabled(false);
    ui->pbn_save_JPG->setEnabled(false);

    // 執行緒物件實體化
    myThread_Camera_show = new MyThread; //左相機執行緒物件

    // 初始化變數
    int devices_num = 0;
    int m_nTriggerMode = TRIGGER_ON;
    int m_bStartGrabbing = START_GRABBING_ON;
    int m_bContinueStarted = 0;
    MV_SAVE_IAMGE_TYPE m_nSaveImageType = MV_Image_Bmp;

    connect(myThread_Camera_show, SIGNAL(Display(const Mat *, int)), this,
            SLOT(display_myImage_L(const Mat *, int)));

    // 曝光和增益的輸入控制元件限制值
    QRegExp int_rx("100000|([0-9]{0,5})");
    ui->le_set_exposure->setValidator(new QRegExpValidator(int_rx, this));
    QRegExp double_rx("15|([0-9]{0,1}[0-5]{1,2}[\.][0-9]{0,1})");
    ui->le_set_gain->setValidator(new QRegExpValidator(double_rx, this));
}

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

void Widget::on_pbn_enum_camera_clicked()
{
    memset(&m_stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
    int nRet = MV_OK;
    nRet = CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &m_stDevList);

    devices_num = m_stDevList.nDeviceNum;
    if (devices_num == 0) {
        QString cameraInfo;
        cameraInfo =
            QString::fromLocal8Bit("暫無設備可連接,請檢查設備是否連接正確!");
        ui->lbl_camera_messagee->setText(cameraInfo);
    }
    if (devices_num > 0) {
        QString cameraInfo;
        for (int i = 0; i < devices_num; i++) {
            MV_CC_DEVICE_INFO *pDeviceInfo = m_stDevList.pDeviceInfo[i];
            QString cameraInfo_i = PrintDeviceInfo(pDeviceInfo, i);
            cameraInfo.append(cameraInfo_i);
            cameraInfo.append("\n");
            ui->cmb_camera_index->addItem(QString::number(i));
        }
        ui->lbl_camera_messagee->setText(cameraInfo);
        ui->pbn_open_camera->setEnabled(true);
        ui->cmb_camera_index->setEnabled(true);
    }
}

QString Widget::PrintDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo, int num_index)
{
    QString cameraInfo_index;
    cameraInfo_index = QString::fromLocal8Bit("相機序號:");
    cameraInfo_index.append(QString::number(num_index));
    cameraInfo_index.append("\t\t");
    // 海康GIGE協議的相機
    if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE) {
        int nIp1 =
            ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >>
             24);
        int nIp2 =
            ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >>
             16);
        int nIp3 =
            ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >>
             8);
        int nIp4 =
            (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);

        cameraInfo_index.append(QString::fromLocal8Bit("相機型號:"));
        std::string str_name =
            (char *)pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName;
        cameraInfo_index.append(QString::fromStdString(str_name));
        cameraInfo_index.append("\n");
        cameraInfo_index.append(QString::fromLocal8Bit("當前相機IP地址:"));
        cameraInfo_index.append(QString::number(nIp1));
        cameraInfo_index.append(".");
        cameraInfo_index.append(QString::number(nIp2));
        cameraInfo_index.append(".");
        cameraInfo_index.append(QString::number(nIp3));
        cameraInfo_index.append(".");
        cameraInfo_index.append(QString::number(nIp4));
        cameraInfo_index.append("\t");
    } else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE) {
        cameraInfo_index.append(QString::fromLocal8Bit("相機型號:"));
        std::string str_name =
            (char *)pstMVDevInfo->SpecialInfo.stUsb3VInfo.chModelName;
        cameraInfo_index.append(QString::fromStdString(str_name));
        cameraInfo_index.append("\n");
    } else {
        cameraInfo_index.append(QString::fromLocal8Bit("相機型號:未知"));
    }
    cameraInfo_index.append(QString::fromLocal8Bit("相機品牌:海康"));
    return cameraInfo_index;
}

void Widget::on_pbn_open_camera_clicked()
{
    ui->pbn_open_camera->setEnabled(false);
    ui->pbn_close_camera->setEnabled(true);
    ui->rdo_continue_mode->setEnabled(true);
    ui->rdo_softigger_mode->setEnabled(true);

    ui->rdo_continue_mode->setCheckable(true);
    // 參資料控制元件
    ui->le_set_exposure->setEnabled(true);
    ui->le_set_gain->setEnabled(true);

    OpenDevices();
}

void Widget::OpenDevices()
{
    int nRet = MV_OK;
    // 創建相機指標物件
    for (unsigned int i = 0, j = 0; j < m_stDevList.nDeviceNum; j++, i++) {
        m_pcMyCamera[i] = new CMvCamera;
        // 相機物件初始化
        m_pcMyCamera[i]->m_pBufForDriver = NULL;
        m_pcMyCamera[i]->m_pBufForSaveImage = NULL;
        m_pcMyCamera[i]->m_nBufSizeForDriver = 0;
        m_pcMyCamera[i]->m_nBufSizeForSaveImage = 0;
        m_pcMyCamera[i]->m_nTLayerType =
            m_stDevList.pDeviceInfo[j]->nTLayerType;

        nRet = m_pcMyCamera[i]->Open(m_stDevList.pDeviceInfo[j]); //打開相機
        //設定觸發模式
        m_pcMyCamera[i]->setTriggerMode(TRIGGER_ON);
        //設定觸發源為軟觸發
        m_pcMyCamera[i]->setTriggerSource(TRIGGER_SOURCE);
        //設定曝光時間,初始為40000,并關閉自動曝光模式
        m_pcMyCamera[i]->setExposureTime(EXPOSURE_TIME);
        m_pcMyCamera[i]->SetEnumValue("ExposureAuto",
                                      MV_EXPOSURE_AUTO_MODE_OFF);
    }
}

void Widget::on_rdo_continue_mode_clicked()
{
    ui->pbn_start_grabbing->setEnabled(true);
    m_nTriggerMode = TRIGGER_ON;
}

void Widget::on_rdo_softigger_mode_clicked()
{
    // 如果開始選擇的連續模式,切換到觸發模式之前,需要先停止采集
    if (m_bContinueStarted == 1) {
        on_pbn_stop_grabbing_clicked(); //先執行停止采集
    }

    ui->pbn_start_grabbing->setEnabled(false);
    ui->pbn_software_once->setEnabled(true);

    m_nTriggerMode = TRIGGER_OFF;
    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
        m_pcMyCamera[i]->setTriggerMode(m_nTriggerMode);
    }
}

void Widget::on_pbn_start_grabbing_clicked()
{
    // 觸發模式標記一下,切換觸發模式時先執行停止采集影像函式
    m_bContinueStarted = 1;

    // 影像采集控制元件
    ui->pbn_start_grabbing->setEnabled(false);
    ui->pbn_stop_grabbing->setEnabled(true);
    // 保存影像控制元件
    ui->pbn_save_BMP->setEnabled(true);
    ui->pbn_save_JPG->setEnabled(true);

    int camera_Index = 0;

    // 先判斷什么模式,再判斷是否正在采集
    if (m_nTriggerMode == TRIGGER_ON) {
        // 開始采集之后才創建workthread執行緒
        for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
            //開啟相機采集
            m_pcMyCamera[i]->StartGrabbing();
            camera_Index = i;
            if (camera_Index == 0) {
                myThread_Camera_show->getCameraPtr(
                    m_pcMyCamera[0]); //執行緒獲取左相機指標
                myThread_Camera_show->getImagePtr(
                    myImage_L); //執行緒獲取左影像指標
                myThread_Camera_show->getCameraIndex(0); //左相機 Index==0

                if (!myThread_Camera_show->isRunning()) {
                    myThread_Camera_show->start();
                    m_pcMyCamera[0]->softTrigger();
                    m_pcMyCamera[0]->ReadBuffer(*myImage_L); //讀取Mat格式的影像
                }
            }
        }
    }
}

void Widget::on_pbn_stop_grabbing_clicked()
{
    ui->pbn_start_grabbing->setEnabled(true);
    ui->pbn_stop_grabbing->setEnabled(false);

    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
        //關閉相機
        if (myThread_Camera_show->isRunning()) {
            m_pcMyCamera[0]->StopGrabbing();
            myThread_Camera_show->requestInterruption();
            myThread_Camera_show->wait();
        }
    }
}

void Widget::on_pbn_software_once_clicked()
{
    // 保存影像控制元件
    ui->pbn_save_BMP->setEnabled(true);
    ui->pbn_save_JPG->setEnabled(true);

    if (m_nTriggerMode == TRIGGER_OFF) {
        int nRet = MV_OK;
        for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
            //開啟相機采集
            m_pcMyCamera[i]->StartGrabbing();

            if (i == 0) {
                nRet = m_pcMyCamera[i]->CommandExecute("TriggerSoftware");
                m_pcMyCamera[i]->ReadBuffer(*myImage_L);
                display_myImage_L(myImage_L, i); //左相機影像
            }
        }
    }
}

void Widget::display_myImage_L(const Mat *imagePrt, int cameraIndex)
{
    cv::Mat rgb;
    cv::cvtColor(*imagePrt, rgb, CV_BGR2RGB);

    QImage QmyImage_L;
    QmyImage_L = QImage((const unsigned char *)(rgb.data), rgb.cols,
                            rgb.rows, QImage::Format_RGB888);

    QmyImage_L = (QmyImage_L)
                     .scaled(ui->lbl_camera_L->size(), Qt::IgnoreAspectRatio,
                             Qt::SmoothTransformation); //飽滿填充
    //顯示影像
    ui->lbl_camera_L->setPixmap(QPixmap::fromImage(QmyImage_L));
}

void Widget::CloseDevices()
{
    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
        // 關閉執行緒、相機
        if (myThread_Camera_show->isRunning()) {
            myThread_Camera_show->requestInterruption();
            myThread_Camera_show->wait();
            m_pcMyCamera[0]->StopGrabbing();
        }

        m_pcMyCamera[i]->Close();
    }

    // 關閉之后再列舉一遍
    memset(&m_stDevList, 0,
           sizeof(MV_CC_DEVICE_INFO_LIST)); // 初始化設備資訊串列
    int devices_num = MV_OK;
    devices_num =
        CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE,
                               &m_stDevList); // 列舉子網內所有設備,相機設備數量
}

void Widget::on_pbn_close_camera_clicked()
{
    ui->pbn_open_camera->setEnabled(true);
    ui->pbn_close_camera->setEnabled(false);
    // 影像采集控制元件
    ui->rdo_continue_mode->setEnabled(false);
    ui->rdo_softigger_mode->setEnabled(false);
    ui->pbn_start_grabbing->setEnabled(false);
    ui->pbn_stop_grabbing->setEnabled(false);
    ui->pbn_software_once->setEnabled(false);
    // 引數控制元件
    ui->le_set_exposure->setEnabled(false);
    ui->le_set_gain->setEnabled(false);
    // 保存影像控制元件
    ui->pbn_save_BMP->setEnabled(false);
    ui->pbn_save_JPG->setEnabled(false);

    // 關閉設備,銷毀執行緒
    CloseDevices();
    ui->lbl_camera_messagee->clear();
    ui->lbl_camera_L->clear();
    ui->lbl_camera_R->clear();
}

void Widget::on_pbn_save_BMP_clicked()
{
    m_nSaveImageType = MV_Image_Bmp;
    SaveImage();
}

void Widget::on_pbn_save_JPG_clicked()
{
    m_nSaveImageType = MV_Image_Jpeg;
    SaveImage();
}

void Widget::SaveImage()
{
    // 獲取1張圖
    MV_FRAME_OUT_INFO_EX stImageInfo = { 0 };
    memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
    unsigned int nDataLen = 0;
    int nRet = MV_OK;
    for (int i = 0; i < devices_num; i++) {
        // 僅在第一次保存影像時申請快取,在CloseDevice時釋放
        if (NULL == m_pcMyCamera[i]->m_pBufForDriver) {
            unsigned int nRecvBufSize = 0;
            unsigned int nRet =
                m_pcMyCamera[i]->GetIntValue("PayloadSize", &nRecvBufSize);

            m_pcMyCamera[i]->m_nBufSizeForDriver = nRecvBufSize; // 一幀資料大小

            m_pcMyCamera[i]->m_pBufForDriver =
                (unsigned char *)malloc(m_pcMyCamera[i]->m_nBufSizeForDriver);
        }

        nRet = m_pcMyCamera[i]->GetOneFrameTimeout(
            m_pcMyCamera[i]->m_pBufForDriver, &nDataLen,
            m_pcMyCamera[i]->m_nBufSizeForDriver, &stImageInfo, 1000);
        if (MV_OK == nRet) {
            // 僅在第一次保存影像時申請快取,在 CloseDevice 時釋放
            if (NULL == m_pcMyCamera[i]->m_pBufForSaveImage) {
                // BMP圖片大小:width * height * 3 + 2048(預留BMP頭大小)
                m_pcMyCamera[i]->m_nBufSizeForSaveImage =
                    stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;

                m_pcMyCamera[i]->m_pBufForSaveImage = (unsigned char *)malloc(
                    m_pcMyCamera[i]->m_nBufSizeForSaveImage);
            }
            // 設定對應的相機引數
            MV_SAVE_IMAGE_PARAM_EX stParam = { 0 };
            stParam.enImageType = m_nSaveImageType; // 需要保存的影像型別
            stParam.enPixelType = stImageInfo.enPixelType; // 相機對應的像素格式
            stParam.nBufferSize =
                m_pcMyCamera[i]->m_nBufSizeForSaveImage; // 存盤節點的大小
            stParam.nWidth = stImageInfo.nWidth;         // 相機對應的寬
            stParam.nHeight = stImageInfo.nHeight;       // 相機對應的高
            stParam.nDataLen = stImageInfo.nFrameLen;
            stParam.pData = m_pcMyCamera[i]->m_pBufForDriver;
            stParam.pImageBuffer = m_pcMyCamera[i]->m_pBufForSaveImage;
            stParam.nJpgQuality = 90; // jpg編碼,僅在保存Jpg影像時有效

            nRet = m_pcMyCamera[i]->SaveImage(&stParam);

            QString image_name;
            char chImageName[IMAGE_NAME_LEN] = { 0 };
            if (MV_Image_Bmp == stParam.enImageType) {
                if (i == 0) {
                    snprintf(chImageName, IMAGE_NAME_LEN,
                             "Image_w%d_h%d_fn%d_L.bmp", stImageInfo.nWidth,
                             stImageInfo.nHeight, stImageInfo.nFrameNum);
                    image_name = "Image_w";
                    image_name.append(QString::number(stImageInfo.nWidth));
                    image_name.append("_h");
                    image_name.append(QString::number(stImageInfo.nHeight));
                    image_name.append("_fn");
                    image_name.append(QString::number(stImageInfo.nFrameNum));
                    image_name.append("_L.bmp");
                }
                if (i == 1) {
                    snprintf(chImageName, IMAGE_NAME_LEN,
                             "Image_w%d_h%d_fn%03d_R.bmp", stImageInfo.nWidth,
                             stImageInfo.nHeight, stImageInfo.nFrameNum);
                }

            } else if (MV_Image_Jpeg == stParam.enImageType) {
                if (i == 0) {
                    snprintf(chImageName, IMAGE_NAME_LEN,
                             "Image_w%d_h%d_fn%d_L.jpg", stImageInfo.nWidth,
                             stImageInfo.nHeight, stImageInfo.nFrameNum);
                    image_name = "Image_w";
                    image_name.append(QString::number(stImageInfo.nWidth));
                    image_name.append("_h");
                    image_name.append(QString::number(stImageInfo.nHeight));
                    image_name.append("_fn");
                    image_name.append(QString::number(stImageInfo.nFrameNum));
                    image_name.append("_L.jpg");
                }
                if (i == 1) {
                    snprintf(chImageName, IMAGE_NAME_LEN,
                             "Image_w%d_h%d_fn%03d_R.jpg", stImageInfo.nWidth,
                             stImageInfo.nHeight, stImageInfo.nFrameNum);
                }
            }

            FILE *fp = fopen(chImageName, "wb");

            fwrite(m_pcMyCamera[i]->m_pBufForSaveImage, 1, stParam.nImageLen,
                   fp);
            fclose(fp);

            ui->lbl_camera_R->setPixmap(QPixmap(image_name));
            ui->lbl_camera_R->setScaledContents(true);
        }
    }
}

void Widget::on_le_set_exposure_textChanged(const QString &arg1)
{
    //設定曝光時間
    QString str = ui->le_set_exposure->text(); // 讀取
    int exposure_Time = str.toInt();

    for (int i = 0; i < devices_num; i++) {
        m_pcMyCamera[i]->SetEnumValue("ExposureAuto",
                                      MV_EXPOSURE_AUTO_MODE_OFF);
        m_pcMyCamera[i]->SetFloatValue("ExposureTime", exposure_Time);
    }
}

void Widget::on_le_set_gain_textChanged(const QString &arg1)
{
    QString str = ui->le_set_gain->text(); // 讀取
    float gain = str.toFloat();

    for (int i = 0; i < devices_num; i++) {
        m_pcMyCamera[i]->SetEnumValue("GainAuto", 0);
        int nRet = m_pcMyCamera[i]->SetFloatValue("Gain", gain);
    }
}

2.9 widget.ui

在這里插入圖片描述

2.10 運行效果

在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

參考:
海康Camera MVS Linux SDK二次開發封裝ROS packge程序記錄(c++):
https://blog.csdn.net/weixin_41965898/article/details/116801491
linux下qt封裝海康SDK(這個是安防相機的,up主提供了qt的原始碼):https://www.bilibili.com/video/BV1u64y1o76T?spm_id_from=333.1007.top_right_bar_window_history.content.click

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/397523.html

標籤:其他

上一篇:《人工智能及其應用》課程筆記(四)第4章 非經典推理

下一篇:如何調整照片人物年齡,此生也算共白頭,PaddleGAN開源專案安裝使用 | 機器學習

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more