海康威视GidE工业相机的Bayer格式图像数据处理

接上篇海康威视GigE工业相机的python调用demo-CSDN博客

  • Bayer格式数据

        取到了图像数据后,就需要对数据进行处理。我手里的这台CU系列面阵相机,在MVS中可以看到它的数据默认格式是Bayer RG8:

        Bayer RG8图像格式,采用 RGGB 布局。在这种布局中,红色(R)、绿色(G)和蓝色(B)像素点交错排列。具体来说,奇数扫描行按 R、G、R、G…… 顺序排列,偶数扫描行按 G、B、G、B…… 顺序排列,每个像素仅需一个颜色通道的数据,数据量仅为 RGB8 格式的三分之一。从图像缓存中获取到了数据后,需要进行一些处理才能转换成常规的RGB三通道数据。

  • 使用opencv转换Bayer RG8到RGB格式

        使用opencv转换Bayer RG8到RGB格式并保存文件的demo:

image_data = np.frombuffer(self.buf_save_image, dtype=np.uint8).reshape((height, width))
rgb_image = cv2.cvtColor(image_data, cv2.COLOR_BAYER_RG2RGB)
cv2.imwrite(file_path, rgb_image)

        实测3072*2048的图像数据,i510代CPU,转换时间为7ms,还算是比较迅速的。

  • 使用海康威视厂家提供的SDK转换Bayer RG8到RGB格式

厂家的ConvertPixelType.py提供了转换Bayer RG8到RGB格式的代码,核心部分:

stOutFrame = MV_FRAME_OUT()    # 创建输出帧
    memset(byref(stOutFrame), 0, sizeof(stOutFrame))   # 开辟内存区

    ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)   # 获取帧数据
    if None != stOutFrame.pBufAddr and 0 == ret :
        print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]"  % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))

        nRGBSize = stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 3   # 转换后的rgb数据长度
        stConvertParam = MV_CC_PIXEL_CONVERT_PARAM_EX()    # 创建转换参数集
        memset(byref(stConvertParam), 0, sizeof(stConvertParam))    # 开辟内存区
        stConvertParam.nWidth = stOutFrame.stFrameInfo.nWidth    # 宽
        stConvertParam.nHeight = stOutFrame.stFrameInfo.nHeight   # 高
        stConvertParam.pSrcData = stOutFrame.pBufAddr   # 源数据指针
        stConvertParam.nSrcDataLen = stOutFrame.stFrameInfo.nFrameLen   # 源数据长度
        stConvertParam.enSrcPixelType = stOutFrame.stFrameInfo.enPixelType     # 源数据像素格式
        stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed   # 目标数据像素格式
        stConvertParam.pDstBuffer = (c_ubyte * nRGBSize)()   # 目标数据指针
        stConvertParam.nDstBufferSize = nRGBSize   # 目标数据长度

        ret = cam.MV_CC_ConvertPixelTypeEx(stConvertParam)   # 转换数据

实测,同样配置下,厂家自带的SDK,转换时间为13ms左右,比OpenCV慢了不少。

所以,从代码简洁和运行效率两方面,opencv是优解。

  • 结合上一篇,创建适合自己使用的相机模型:

# -*- coding: utf-8 -*-
import inspect
import time

import cv2
import numpy as np

from MvCameraControl_class import *
import threading
import msvcrt
from ctypes import *



# 海康威视直连IPGigE相机
class HiKGidECamera(MvCamera):
    def __init__(self, deviceIp, netIp):
        super().__init__()
        self.buffRGB8 = None  # RGB8格式的图像缓存数据
        self.save_file_path = ""
        self.hThreadHandle = None  # 用于取流和存图的线程句柄
        self.ui_winHandle = 0  # ui显示窗口的句柄,0表示不显示。etc:ui.widgetDisplay.winId()
        self.save_pre_path = ""  # 保存图像的前置路径
        self.save_jpg_quality = 80   # 保存的jpg图像质量
        self.stSaveParam = MV_SAVE_IMAGE_TO_FILE_PARAM_EX()  # 保存图像文件的参数集
        self.stDisplayParam = MV_DISPLAY_FRAME_INFO()   # 显示图像的参数集
        self.stConvertParam = MV_CC_PIXEL_CONVERT_PARAM()  # 转换图像像素格式的参数集
        self.buf_image = None  # 用以保存和处理的图像buffer
        self.save_type = "bmp"  # 保存图像的类型
        self.model_name = ""
        self.user_defined_name = ""
        self.netIpList = []
        self.deviceIpList = []
        self.stDevInfo = MV_CC_DEVICE_INFO()  # 设备信息
        self.stGigEDev = MV_GIGE_DEVICE_INFO()  # 设备信息
        self.deviceIp = deviceIp  # 相机IP
        self.netIp = netIp  # 相机接入的网卡IP
        self.isOpened = False  # 相机是否打开
        self.isGrabbing = False  # 相机是否正在采集图像
        self.is_trigger_mode = True  # 是否触发模式
        # self.b_exit = True  # 退出取流的标志
        self.buf_lock = threading.Lock()  # 取图和存图的buffer锁

        self.b_save_bmp = False  # 是否保存bmp文件
        self.b_save_jpg = False  # 是否保存jpg文件
        self.buf_image = None  # 从缓存区中拷贝的图像buffer,用以保存和处理

    # 强制关闭线程
    def Async_raise(self, tid, exctype):
        tid = ctypes.c_long(tid)
        if not inspect.isclass(exctype):
            exctype = type(exctype)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
        if res == 0:
            raise ValueError("invalid thread id")
        elif res != 1:
            ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
            raise SystemError("PyThreadState_SetAsyncExc failed")


    # 停止线程
    def Stop_thread(self, thread):
        self.Async_raise(thread.ident, SystemExit)


    # 转为16进制字符串
    def To_hex_str(self, num):
        chaDic = {10: 'a', 11: 'b', 12: 'c', 13: 'd', 14: 'e', 15: 'f'}
        hexStr = ""
        if num < 0:
            num = num + 2 ** 32
        while num >= 16:
            digit = num % 16
            hexStr = chaDic.get(digit, str(digit)) + hexStr
            num //= 16
        hexStr = chaDic.get(num, str(num)) + hexStr
        return hexStr


    # 解码操作
    def decoding_char(self, c_ubyte_value):
        c_char_p_value = ctypes.cast(c_ubyte_value, ctypes.c_char_p)
        try:
            decode_str = c_char_p_value.value.decode('gbk')  # Chinese characters
        except UnicodeDecodeError:
            decode_str = str(c_char_p_value.value)
        return decode_str


    # 是否是Mono图像
    def Is_mono_data(self, enGvspPixelType):
        if PixelType_Gvsp_Mono8 == enGvspPixelType or PixelType_Gvsp_Mono10 == enGvspPixelType \
                or PixelType_Gvsp_Mono10_Packed == enGvspPixelType or PixelType_Gvsp_Mono12 == enGvspPixelType \
                or PixelType_Gvsp_Mono12_Packed == enGvspPixelType:
            return True
        else:
            return False


    # 是否是彩色图像
    def Is_color_data(self, enGvspPixelType):
        if PixelType_Gvsp_BayerGR8 == enGvspPixelType or PixelType_Gvsp_BayerRG8 == enGvspPixelType \
                or PixelType_Gvsp_BayerGB8 == enGvspPixelType or PixelType_Gvsp_BayerBG8 == enGvspPixelType \
                or PixelType_Gvsp_BayerGR10 == enGvspPixelType or PixelType_Gvsp_BayerRG10 == enGvspPixelType \
                or PixelType_Gvsp_BayerGB10 == enGvspPixelType or PixelType_Gvsp_BayerBG10 == enGvspPixelType \
                or PixelType_Gvsp_BayerGR12 == enGvspPixelType or PixelType_Gvsp_BayerRG12 == enGvspPixelType \
                or PixelType_Gvsp_BayerGB12 == enGvspPixelType or PixelType_Gvsp_BayerBG12 == enGvspPixelType \
                or PixelType_Gvsp_BayerGR10_Packed == enGvspPixelType or PixelType_Gvsp_BayerRG10_Packed == enGvspPixelType \
                or PixelType_Gvsp_BayerGB10_Packed == enGvspPixelType or PixelType_Gvsp_BayerBG10_Packed == enGvspPixelType \
                or PixelType_Gvsp_BayerGR12_Packed == enGvspPixelType or PixelType_Gvsp_BayerRG12_Packed == enGvspPixelType \
                or PixelType_Gvsp_BayerGB12_Packed == enGvspPixelType or PixelType_Gvsp_BayerBG12_Packed == enGvspPixelType \
                or PixelType_Gvsp_YUV422_Packed == enGvspPixelType or PixelType_Gvsp_YUV422_YUYV_Packed == enGvspPixelType:
            return True
        else:
            return False


    # 注册相机
    def register(self):
        self.deviceIpList = self.deviceIp.split('.')  # 相机的主机IP
        self.netIpList = self.netIp.split('.')  # 连接相机的网卡IP
        self.stGigEDev.nCurrentIp = (int(self.deviceIpList[0]) << 24) | (int(self.deviceIpList[1]) << 16) | (
                int(self.deviceIpList[2]) << 8) | int(self.deviceIpList[3])  # 设置相机IP
        self.stGigEDev.nNetExport = (int(self.netIpList[0]) << 24) | (int(self.netIpList[1]) << 16) | (
                int(self.netIpList[2]) << 8) | int(
            self.netIpList[3])  # 设置网卡IP
        self.stDevInfo.nTLayerType = MV_GIGE_DEVICE  # 设备类型为GigE
        self.stDevInfo.SpecialInfo.stGigEInfo = self.stGigEDev  # 传入GigE相机信息


    # 打开设备
    def open_device(self):
        if self.isOpened:
            print("相机已打开!")
            return
        # 选择设备并创建句柄
        ret = self.MV_CC_CreateHandle(self.stDevInfo)  # 创建设备句柄
        if ret != 0:
            print("create handle fail! ret[0x%x]" % ret)
            return ret
        ret = self.MV_CC_OpenDevice()  # 打开设备
        if ret != 0:
            print("open device fail! ret[0x%x]" % ret)
            return ret
        else:
            # 探测网络最佳包大小
            nPacketSize = self.MV_CC_GetOptimalPacketSize()
            if int(nPacketSize) > 0:
                ret = self.MV_CC_SetIntValue("GevSCPSPacketSize", nPacketSize)
                if ret != 0:
                    print("Warning: Set Packet Size fail! ret[0x%x]" % ret)
                    return ret
                self.isOpened = True  # 相机已打开

                # 获取相机信息
                deviceList = MV_CC_DEVICE_INFO_LIST()  # 所有在线相机的设备信息列表
                n_layer_type = MV_GIGE_DEVICE  # 只使用GigE相机
                ret = MvCamera.MV_CC_EnumDevices(n_layer_type, deviceList)  # 返回值为0表示成功
                if ret != 0:
                    print(f"enum devices fail! ret = {self.To_hex_str(ret)}")
                    return -1

                for i in range(0, deviceList.nDeviceNum):
                    mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents  # 设备信息
                    # 相机的IP地址
                    nip1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24)
                    nip2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16)
                    nip3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8)
                    nip4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff)

                    # 如果相机在线,则获取相机的信息
                    if str(nip1) == self.deviceIpList[0] and str(nip2) == self.deviceIpList[1] and str(nip3) == \
                            self.deviceIpList[2] and str(nip4) == self.deviceIpList[3]:
                        # self.n_gide_device = i  # GidE设备序号
                        self.user_defined_name = self.decoding_char(
                            mvcc_dev_info.SpecialInfo.stGigEInfo.chUserDefinedName)  # 设备的用户定义名称(支持中文名称)
                        self.model_name = self.decoding_char(mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName)  # 相机的型号
                        print("user_defined_name:", self.user_defined_name)
                        print("model_name:", self.model_name)
                        break

                    if i == deviceList.nDeviceNum - 1:
                        print("指定的相机不在线!")
                        return -1

                print("open device successfully!")
                return 0
            else:
                print("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize)

    # 关闭设备
    def close_device(self):
        if not self.isOpened:
            print("相机已关闭!")
            return
        else:
            # 退出取流线程
            if self.isGrabbing:
                self.stop_grabbing()  # 停止取流
            ret = self.MV_CC_CloseDevice()  # 关闭设备
            if ret != 0:
                print("关闭相机失败!")
                return -1
            self.isOpened = False
            self.MV_CC_DestroyHandle()   # 销毁句柄
            print("close device successfully!")
            return 0

    # 设置连续取流模式(亦即关闭触发模式)
    def set_continue_mode(self):
        if not self.isOpened:
            print("相机未打开!")
            return -1
        if self.is_trigger_mode:
            # ret = self.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)  # 关闭触发模式
            ret = self.MV_CC_SetEnumValue("TriggerMode", 0)  # 关闭触发模式
            if ret != 0:
                print(f"设置连续模式失败:ret = {self.To_hex_str(ret)}")
                return ret
            self.is_trigger_mode = False

        return 0

    # 设置软触发模式
    def set_software_trigger_mode(self):
        # ret = self.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_ON)  # 打开触发模式
        ret = self.MV_CC_SetEnumValue("TriggerMode", 1)  # 打开触发模式
        if ret != 0:
            print(f"设置软触发模式失败!ret = {self.To_hex_str(ret)}")
            return -1
        # ret = self.MV_CC_SetEnumValue("TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE)  # 设置触发源为软触发
        self.is_trigger_mode = True
        ret = self.MV_CC_SetEnumValue("TriggerSource", 7)  # 设置触发源为软触发
        if ret != 0:
            print(f"设置触发源失败! ret = {self.To_hex_str(ret)}")
            return ret
        return 0

    # 软触发一次
    def Trigger_once(self):
        if self.isOpened and self.isGrabbing:
            return self.MV_CC_SetCommandValue("TriggerSoftware")

    # 设置线路0外部触发模式
    def set_line0_trigger_mode(self):
        ret = self.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_ON)  # 打开触发模式
        if ret != 0:
            print(f"设置外部触发模式失败!ret = {self.To_hex_str(ret)}")
            return ret
        self.is_trigger_mode = True
        ret = self.MV_CC_SetEnumValue("TriggerSource", MV_TRIGGER_SOURCE_LINE0)  # 设置触发源为线路0
        if ret != 0:
            print(f"设置触发源失败!ret = {self.To_hex_str(ret)}")
            return ret
        return 0

    # 设置线路2外部触发模式
    def set_line2_trigger_mode(self):
        ret = self.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_ON)  # 打开触发模式
        if ret != 0:
            print(f"设置外部触发模式失败!ret = {self.To_hex_str(ret)}")
            return ret
        self.is_trigger_mode = True
        ret = self.MV_CC_SetEnumValue("TriggerSource", MV_TRIGGER_SOURCE_LINE2)  # 设置触发源为线路0
        if ret != 0:
            print(f"设置触发源失败!ret = {self.To_hex_str(ret)}")
            return ret
        return 0

    # 开始取流
    def start_grabbing(self, winHandle):
        if not self.isOpened:
            print("相机未打开!")
            return -1
        if self.isGrabbing:
            print("相机正在取流!")
            return
        ret = self.MV_CC_StartGrabbing()   # 开始取流
        if ret != 0:
            print(f"start grabbing fail! ret = {self.To_hex_str(ret)}")
            return ret
        try:
            # 创建取流线程
            self.isGrabbing = True  # 正在取流
            self.hThreadHandle = threading.Thread(target=self.work_thread, args=(winHandle,))  # 创建取流线程
            self.hThreadHandle.start()  # 启动取流线程

            return 0
        finally:
            pass

    # 停止取流
    def stop_grabbing(self):
        if not self.isOpened:
            print("相机未打开!")
            return -1
        if self.isGrabbing:
            ret = self.MV_CC_StopGrabbing()

            if ret != 0:
                print("stop grabbing fail!", ret)
                return ret
            else:
                # 停止取流线程
                self.Stop_thread(self.hThreadHandle)
                self.isGrabbing = False
            print("stop grabbing successfully!")
        else:
            print("相机未处于取流状态!")
            return -1
        self.isGrabbing = False  # 正在取流
        return 0

    # 取流的线程
    def work_thread(self, winHandle):
        stOutFrame = MV_FRAME_OUT()   # 输出图像帧
        memset(byref(stOutFrame), 0, sizeof(stOutFrame))   # 初始化输出图像帧的内存区

        while True:
            ret = self.MV_CC_GetImageBuffer(stOutFrame, 1000)   # 获取一帧图像到缓存
            if 0 == ret:
                # 拷贝图像和图像信息
                if self.buf_image is None:  # 创建图像的内存空间
                    self.buf_image = (c_ubyte * stOutFrame.stFrameInfo.nFrameLen)()
                self.st_frame_info = stOutFrame.stFrameInfo   # 图像的帧信息

                self.buf_lock.acquire()    # 获取线程锁
                cdll.msvcrt.memcpy(byref(self.buf_image), stOutFrame.pBufAddr, self.st_frame_info.nFrameLen)  # 从缓存中拷贝图像

                # ##############################获取显示图像需要的帧数据#############################################
                memset(byref(self.stDisplayParam), 0, sizeof(self.stDisplayParam))
                self.stDisplayParam.hWnd = int(winHandle)
                self.stDisplayParam.nWidth = self.st_frame_info.nWidth
                self.stDisplayParam.nHeight = self.st_frame_info.nHeight
                self.stDisplayParam.enPixelType = self.st_frame_info.enPixelType
                self.stDisplayParam.pData = self.buf_image
                self.stDisplayParam.nDataLen = self.st_frame_info.nFrameLen
                self.MV_CC_DisplayOneFrame(self.stDisplayParam)

                # ##############################获取保存图像需要的帧数据#############################################
                self.stSaveParam.enPixelType = self.st_frame_info.enPixelType  # 相机对应的像素格式
                self.stSaveParam.nWidth = self.st_frame_info.nWidth  # 相机对应的宽
                self.stSaveParam.nHeight = self.st_frame_info.nHeight  # 相机对应的高
                self.stSaveParam.nDataLen = self.st_frame_info.nFrameLen  # 帧的数据长度
                self.stSaveParam.pData = cast(self.buf_image, POINTER(c_ubyte))  # 图像数据的指针
                self.save_file_path = self.save_pre_path + str(self.st_frame_info.nFrameNum)  # 保存图像的文件名
                self.stSaveParam.iMethodValue = 1  # 保存图像的参数

                # ##############################获取转换像素需要的帧数据#############################################
                # 获取帧数据的参数
                self.stConvertParam.nWidth = self.st_frame_info.nWidth   # 宽度
                self.stConvertParam.nHeight = self.st_frame_info.nHeight   # 高度
                
                
                self.buf_lock.release()   # 释放线程锁
                print("get one frame: Width[%d], Height[%d], nFrameNum[%d]"
                      % (self.st_frame_info.nWidth, self.st_frame_info.nHeight, self.st_frame_info.nFrameNum))
                # 释放缓存
                self.MV_CC_FreeImageBuffer(stOutFrame)

            else:
                print(f"no data, ret = {self.To_hex_str(ret)}")
                continue

            # 是否退出
            if not self.isGrabbing:
                print("停止取流")
                if self.buf_image is not None:
                    del self.buf_image
                break


    def Save_Bmp(self):
        if self.buf_image is not None:
            # 获取缓存锁
            self.buf_lock.acquire()
            self.save_file_path += ".bmp"
            path = self.save_file_path.encode('utf-8')
            self.stSaveParam.enImageType = MV_Image_Bmp  # 需要保存的图像类型
            self.stSaveParam.pcImagePath = ctypes.create_string_buffer(path)  # 保存的文件名

            ret = self.MV_CC_SaveImageToFileEx(self.stSaveParam)    # 保存图像
            if ret != 0:
                print(f"保存bmp文件失败: {ret}")
                return ret
            self.buf_lock.release()
            print("保存bmp文件成功!")
            return ret
        else:
            print("无可用的图像缓存!")
            return -1


    def Save_bmp_opencv(self):
        if self.buf_image is not None:

            self.save_file_path += ".bmp"
            path = self.save_file_path.encode('utf-8')

            image_data = self.convert2RGB8()
            # 获取缓存锁
            self.buf_lock.acquire()
            _, img_encoded = cv2.imencode('.bmp', image_data)  # 使用编码的方式规避opencv不支持中文名的缺陷
            # 将图像数据写入文件
            with open(path, 'wb') as f:
                f.write(img_encoded.tobytes())
            print("保存bmp文件成功!")

            self.buf_lock.release()
            return 0
        else:
            print("无可用的图像缓存!")
            return -1


    def Save_jpg(self):
        if self.buf_image is not None:
            # 获取缓存锁
            self.buf_lock.acquire()
            self.save_file_path += ".jpg"
            path = self.save_file_path.encode('utf-8')
            self.stSaveParam.enImageType = MV_Image_Jpeg  # 需要保存的图像类型
            self.stSaveParam.pcImagePath = ctypes.create_string_buffer(path)  # 保存的文件名
            self.stSaveParam.nQuality = 80
            ret = self.MV_CC_SaveImageToFileEx(self.stSaveParam)    # 保存图像
            if ret != 0:
                print(f"保存jpg文件失败: {ret}")
                self.buf_lock.release()
                return ret
            self.buf_lock.release()
            print("保存jpg文件成功!")
            return ret
        else:
            print("无可用的图像缓存!")
            return -1


    def Save_jpg_opencv(self):
        if self.buf_image is not None:

            self.save_file_path += ".jpg"
            path = self.save_file_path.encode('utf-8')


            image_data = self.convert2RGB8()
            # 获取缓存锁
            self.buf_lock.acquire()
            _, img_encoded = cv2.imencode('.jpg', image_data)   # 使用编码的方式规避opencv不支持中文名的缺陷
            # 将图像数据写入文件
            with open(path, 'wb') as f:
                f.write(img_encoded.tobytes())
            print("保存jpg文件成功!")

            self.buf_lock.release()
            return 0
        else:
            print("无可用的图像缓存!")
            return -1



    # 转换像素到RGB8格式
    def convert2RGB8(self):
        if self.buf_image is not None:
            # 获取缓存锁
            self.buf_lock.acquire() # 转换bayer数据到RGB格式#########
            image_data = np.frombuffer(self.buf_image, dtype=np.uint8).reshape((self.stConvertParam.nHeight,self.stConvertParam.nWidth))
            rgb_image = cv2.cvtColor(image_data, cv2.COLOR_BAYER_RG2RGB)
            print("转换像素格式成功!")
            self.buf_lock.release()
            return rgb_image
        else:
            print("无可用的图像缓存!")
            return None


if __name__ == "__main__":
    # 初始化SDK
    MvCamera.MV_CC_Initialize()
    cam = HiKGidECamera("192.168.100.100", "192.168.100.1")  # 相机IP和网卡IP
    cam.register()  # 注册相机
    cam.open_device()  # 打开设备
    time.sleep(5)
    cam.set_continue_mode()  # 设置连续取流模式
    cam.start_grabbing(0)  # 开始取流

    i = 0
    cam.save_pre_path = "连续取图"  # 保存图像的路径
    while i < 3:
        time.sleep(2)
        cam.Save_Bmp()  # 保存bmp文件
        i += 1

    i = 0
    cam.save_pre_path = "连续取图"  # 保存图像的路径
    while i < 3:
        time.sleep(2)
        cam.Save_jpg()  # 保存jpg文件
        i += 1

    i = 0
    cam.save_pre_path = "opencv存图"  # 保存图像的路径
    while i < 3:
        time.sleep(2)
        cam.Save_bmp_opencv()  # opencv保存bmp文件
        cam.Save_jpg_opencv()  # opencv保存jpg文件
        i += 1

    i = 0
    cam.save_pre_path = "软触发"  # 保存图像的路径
    cam.set_software_trigger_mode()  # 设置软触发模式
    while i < 3:
        time.sleep(2)
        cam.Trigger_once()  # 软触发一次
        cam.Save_Bmp()  # 保存bmp文件
        i += 1


    cam.stop_grabbing()
    cam.close_device()  # 关闭设备

    # ch:销毁句柄 | Destroy handle
    ret = cam.MV_CC_DestroyHandle()
    if ret != 0:
        print("destroy handle fail! ret[0x%x]" % ret)

    # ch:反初始化SDK | en: finalize SDK
    MvCamera.MV_CC_Finalize()
    sys.exit()

你可能感兴趣的:(海康威视GidE工业相机的Bayer格式图像数据处理)