#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：CameraImpl.py
@Description：
@Author：XSH
@Time：2025/11/12 11:00
@Department：研发部
@Copyright：©2025 乐辰生物
"""
from pypylon import pylon
import cv2
import numpy as np
from PyQt5                                          import Qt
from AppContexts.Contexts                           import CameraContext
from AppInterfaces.ImplInterfaces                   import CameraImplInterface
from AppInterfaces.AppTimeLoop                      import AppTimeLoop
from AppUtils.AppUtils                              import AppUtils
from AppCore.Requests                               import CameraRequest
from AppCore.Levels                                 import ObjectiveLevel
from AppCore.AppDBModels.DBModels                   import CameraModel, CameraInterface, SlideModelInterface
from AppSettings.Settings           import (RECODE_FAILURE, RECODE_SUCCEED, SIGNAL_CONNECTION_TYPE)
CAMERA_DEFAULT_DELAY    : int = 50
MaxCameraRequestTimes   : int = 1000

class CameraImpl(Qt.QObject, CameraImplInterface):
    Model: CameraInterface


    def __init__(self, parent: Qt.QObject = None):
        super(CameraImpl, self).__init__(parent=parent)
        self.Level = ObjectiveLevel.Objective1
        self.initContext()
        self.Initialization('CameraImpl', self, parent)


    def initValue(self):
        super(CameraImpl, self).initValue()
        self.initTlFactory()
        self.initDevices()

        
    @property
    def model(self) -> CameraInterface:
        return None if not self.hasModel else self.Model


    
    
    @property
    def isValid(self) -> bool:
        return self.hasManager and self.hasParameter and self.hasTlFactory and self.hasDeviceInfo and self.hasModel

    @property
    def IsOpen(self) -> bool:
        return self.isValid and self.Manager.IsOpen()

    @property
    def isEnabled(self) -> bool:
        return self.isValid and self.Manager.IsOpen()

    @property
    def isDisable(self) -> bool:
        return not self.isEnabled

    @property
    def isAvailable(self) -> bool:
        return self.isValid and self.Manager.IsOpen()

    @property
    def IsGrabbing(self) -> bool:
        return self.hasManager and self.Manager.IsGrabbing()

    @property
    def isCorrect(self) -> bool:
        if not self.hasDeviceInfo:
            self.deleManager()
            self.initDeviceInfo()
        if not self.hasModel:
            self.deleManager()
        if self.hasDeviceInfo and self.hasModel:
            model_names: list[str] = self.Model.ModelName.split(',')

            return self.Model.Level == self.Level and self.DeviceInfo.GetModelName () in model_names and self.DeviceInfo.GetVendorName() == self.Model.VendorName
        return False

    @property
    def isMono(self) -> bool:
        return self.hasModel and self.Model.isMono()

    def initColorCameraConfig(self):
        """设置彩色相机"""
        if not self.IsOpen or not self.hasModel:
            return
        if self.Model.isMono():
            return
        from AppCore.DBModels import CameraColorModel, CameraModel, ColorAdjustmentSelector

        try:
            if self.Model.hasLightSourcePreset:
                self.Manager.LightSourcePreset.Value = str(self.Model.LightSourcePreset)

            ColorParameter: CameraColorModel = CameraColorModel.getConfig(self.Model.Level)
            self.Manager.BalanceRatioSelector.IntValue = 0
            self.Manager.BalanceRatio.Value = ColorParameter.BalanceRatio0
            self.Manager.BalanceRatioSelector.IntValue = 1
            self.Manager.BalanceRatio.Value = ColorParameter.BalanceRatio1
            self.Manager.BalanceRatioSelector.IntValue = 2
            self.Manager.BalanceRatio.Value = ColorParameter.BalanceRatio2

            self.Manager.ColorTransformationValueSelector.IntValue = int(0)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue0)
            self.Manager.ColorTransformationValueSelector.IntValue = int(1)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue1)
            self.Manager.ColorTransformationValueSelector.IntValue = int(2)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue2)

            self.Manager.ColorTransformationValueSelector.IntValue = int(3)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue0)
            self.Manager.ColorTransformationValueSelector.IntValue = int(4)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue1)
            self.Manager.ColorTransformationValueSelector.IntValue = int(5)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue2)

            self.Manager.ColorTransformationValueSelector.IntValue = int(6)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue20)
            self.Manager.ColorTransformationValueSelector.IntValue = int(7)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue21)
            self.Manager.ColorTransformationValueSelector.IntValue = int(8)
            self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue22)
            models: list[ColorAdjustmentSelector] = ColorAdjustmentSelector.all()
            item: ColorAdjustmentSelector
            for item in models:
                if item.isAvailable:
                    try:
                        self.Manager.ColorAdjustmentSelector.Value      = item.AdjustmentSelector      #
                        self.Manager.ColorAdjustmentHue.Value           = item.AdjustmentHue           #
                        self.Manager.ColorAdjustmentSaturation.Value    = item.AdjustmentSaturation    #
                    except Exception as ColorAdjustmentE:
                        AppUtils.print_Exception(ColorAdjustmentE)
        except Exception as e:
            AppUtils.print_Exception(e)


    
    def initModel(self) -> bool:
        if not self.hasLevel:
            self.Level = ObjectiveLevel.ObjectiveNone
        if not self.hasModel or self.Model.Level != self.Level:
            from AppSettings.AppStatusSetting import AppStatus
            self.Model = AppStatus.getCameraModel(self.Level)
        return self.hasModel and self.Level == self.Model.Level

    
    def initTlFactory(self) -> bool:
        if not self.hasTlFactory:
            self.TlFactory = pylon.TlFactory.GetInstance()
        return self.hasTlFactory

    
    def initDevices(self) -> bool:
        self.initTlFactory()
        if not self.hasDevices:
            if not self.hasTlFactory:
                self.Devices = None
            else:
                self.Devices = self.TlFactory.EnumerateDevices()
            if self.hasDevices:
                from AppLog.logHelper import logCAMERA
                logCAMERA << f'{[device.GetModelName() for device in self.Devices]}'
        return self.hasDevices

    
    def initDeviceInfo(self) -> bool:
        self.initTlFactory  ()
        self.initDevices    ()
        self.initModel      ()
        if not self.hasDevices or not self.hasModel:
            self.DeviceInfo = None
            self.deleManager()
        else:
            model_names: str = self.Model.ModelName.split(',')
            for device in self.Devices:
                if device.GetVendorName() == self.Model.VendorName and device.GetModelName() in model_names:
                    self.DeviceInfo = device
                    break
        return self.hasDeviceInfo

    
    def initContext(self):
        if not self.hasParameter:
            from AppSettings.AppSetting import AppSetting, AppConfig
            self.Parameter = AppConfig.Camera.copy()
        if not self.hasParameter:
            self.Parameter = CameraContext()


    
    def Open(self, level: int, timeOut: int = 1000, **args) -> int:
        endtime: Qt.QDateTime
        endtime = Qt.QDateTime.currentDateTime().addMSecs(abs(timeOut))
        self.initContext()
        self.Level = level
        while True:
            if self.waitForFindDevice(timeOut):
                break
            if Qt.QDateTime.currentDateTime() > endtime:
                break
            AppTimeLoop.processGlobalEvents(CAMERA_DEFAULT_DELAY)
        if not self.hasManager:
            return RECODE_FAILURE

        endtime = Qt.QDateTime.currentDateTime().addMSecs(abs(timeOut))
        while True:
            if not self.waitForStopGrabbing(timeOut):
                break
            if Qt.QDateTime.currentDateTime() > endtime:
                break
            AppTimeLoop.processGlobalEvents(CAMERA_DEFAULT_DELAY)

        self.Parameter.IsGrabbing   = self.IsGrabbing
        self.Parameter.IsOpen       = self.IsOpen
        try:
            if not self.isCorrect:
                self.deleManager()
                self.initManager()
            endtime = Qt.QDateTime.currentDateTime().addMSecs(abs(timeOut))
            while True:
                if self.waitForDeviceOpen(timeOut):
                    break
                if Qt.QDateTime.currentDateTime() > endtime:
                    break
                AppTimeLoop.processGlobalEvents(CAMERA_DEFAULT_DELAY)
            self.Parameter.IsGrabbing   = self.IsGrabbing
            self.Parameter.IsOpen       = self.IsOpen
            if self.IsOpen:
                from AppSettings.AppStatusSetting import AppStatus
                self.Model = AppStatus.getCameraModel(self.Level)
                self.initCameraConfig()
        except Exception as e:
            from AppLog.logHelper import logCAMERA

            logCAMERA << AppUtils.toString(e)

        return RECODE_SUCCEED if self.IsOpen else RECODE_FAILURE

    
    def Close(self, timeOut: int = 1000, **args) -> int:
        self.initContext()
        if self.hasManager:
            self.waitForStopGrabbing(timeOut)
            self.waitForClose(timeOut)
            self.Parameter.IsGrabbing   = self.IsGrabbing   #
            self.Parameter.IsOpen       = self.IsOpen       #
        return RECODE_FAILURE if self.Parameter.IsOpen else RECODE_SUCCEED

    
    def initManager(self, **args):
        from AppLog.logHelper import logCAMERA
        self.initContext()
        try:
            if not self.initTlFactory():
                return
            if not self.hasDevices:
                self.initDevices()
                return
            if not self.hasDevices:
                return

            if self.isCorrect:
                return
            if not self.initDeviceInfo():
                return
            print(f'{self.__class__.__name__} load {self.DeviceInfo.GetModelName()} {self.DeviceInfo.GetFullName()}')
            self.Manager = pylon.InstantCamera(self.TlFactory.CreateDevice(self.DeviceInfo.GetFullName()))
        except Exception as e:
            error: str = AppUtils.toString(e)
            logCAMERA << error
            self.Manager = None


    def deleManager(self):
        try:
            self.StopGrabbing()
            self.Close()
            if self.hasManager:
                del self.Manager
        except Exception as e:
            pass

        self.Manager = None
        self.TlFactory = None
        self.DeviceInfo = None

    
    def waitForStopGrabbing(self, waittimes: int = 3000) -> bool:
        global CAMERA_DEFAULT_DELAY, MaxCameraRequestTimes
        endtime: Qt.QDateTime
        if not self.hasManager:
            return False
        endtime = Qt.QDateTime.currentDateTime().addMSecs(abs(waittimes))
        while True:
            if not self.IsGrabbing or Qt.QDateTime.currentDateTime() > endtime:
                break
            self.StopGrabbing()
            AppTimeLoop.processGlobalEvents(CAMERA_DEFAULT_DELAY)
        return self.IsGrabbing

    
    def waitForClose(self, waittimes: int = 3000) -> bool:
        global CAMERA_DEFAULT_DELAY, MaxCameraRequestTimes
        endtime: Qt.QDateTime
        if not self.hasManager:
            return False

        endtime = Qt.QDateTime.currentDateTime().addMSecs(abs(waittimes))
        while True:
            if not self.IsOpen or Qt.QDateTime.currentDateTime() > endtime:
                break
            if not self.Manager.IsOpen():
                break
            try:
                self.Manager.Close()
            except Exception as e:
                break

            AppTimeLoop.processGlobalEvents(CAMERA_DEFAULT_DELAY)
        return self.IsOpen

    
    def waitForFindDevice(self, waittimes: int = 3000) -> bool:
        global CAMERA_DEFAULT_DELAY, MaxCameraRequestTimes
        endtime: Qt.QDateTime
        if self.hasManager and self.isCorrect:
            return True
        endtime = Qt.QDateTime.currentDateTime().addMSecs(abs(waittimes))
        self.initContext()
        while True:
            self.initManager()
            if self.hasManager or Qt.QDateTime.currentDateTime() > endtime:
                break
            AppTimeLoop.processGlobalEvents(CAMERA_DEFAULT_DELAY)

    
    def waitForDeviceOpen(self, waittimes: int = 3000) -> bool:
        global CAMERA_DEFAULT_DELAY, MaxCameraRequestTimes
        endtime: Qt.QDateTime
        if not self.isCorrect:
            return False
        if not self.hasManager:
            return False
        endtime = Qt.QDateTime.currentDateTime().addMSecs(abs(waittimes))
        while True:
            self.Manager.Open()
            if self.IsOpen or Qt.QDateTime.currentDateTime() > endtime:
                break
            AppTimeLoop.processGlobalEvents(CAMERA_DEFAULT_DELAY)
        return self.IsOpen

    
    def setModel(self, level: int):
        from AppSettings.AppStatusSetting import AppStatus
        self.Level = level if level in ObjectiveLevel.all() else self.Level
        self.Model = AppStatus.getCameraModel(level)
        if not self.isCorrect:
            self.deleManager()
            self.ReOpen(level)
        self.initCameraGama()
        if not self.Model.isMono():
            self.initColorCameraConfig()

    def setPixelParameter(self, level: int):
        from AppSettings.AppStatusSetting import AppStatus
        self.Level = level if level in ObjectiveLevel.all() else self.Level
        self.Model = AppStatus.getCameraModel(level)
        self.initCameraConfig()

    
    def changedObjective(self, level: int, timeOut: int = 1000):
        if self.hasLevel and level == self.Level:
            self.setLevel(level)
            return RECODE_SUCCEED
        else:
            self.Close()
            return self.ReOpen(level, timeOut)

    
    def StartGrabbing(self):
        if not self.hasManager:
            return
        if not self.IsOpen:
            return
        self.initContext()

        self.Parameter.IsGrabbing = self.Manager.IsGrabbing()
        if self.Manager.IsGrabbing():
            return
        self.Manager.StartGrabbing(pylon.GrabStrategy_LatestImages)
        self.Parameter.IsGrabbing = self.Manager.IsGrabbing()

    
    def StopGrabbing(self):
        if not self.IsOpen:
            return
        if self.IsGrabbing:
            self.Manager.StopGrabbing()

        self.Parameter.IsGrabbing = self.Manager.IsGrabbing()

    
    def GetNumpy(self, classifier: str = 'Aberration', **args) -> np.ndarray:
        return self.RequestNumpy(self.model, classifier, **args)

    
    def StartFocusing(self, level: int, timeOut: int = 1000, **args):
        self.Level = level
        if not self.isCorrect:
            self.DeviceInfo = None
            self.ReOpen(level, timeOut, **args)
        if not self.IsOpen:
            return
        if not self.Manager.IsGrabbing():
            self.Manager.StartGrabbing(pylon.GrabStrategy_LatestImages)
        self.Parameter.IsGrabbing = self.Manager.IsGrabbing()

    
    def StopFocusing(self):
        return self.StopGrabbing()


    def getSlideGrabNumber(self, item, **args):
        if not isinstance(item, SlideModelInterface):
            return
        if item.hasCamera:
            item.initCamera()

        classifier: str
        if item.hasPreview and item.preview.has_classifier:
            classifier = item.preview.classifier
        elif item.hasCollect and item.collect.has_classifier:
            classifier = item.collect.classifier
        elif ObjectiveLevel.isMicronucleus(item.ObjectiveLevel):
            classifier = 'Micronucleus'
        else:
            classifier = 'Aberration'
        return self.GetRequestData(item.camera, classifier, **args)



    def GetFocusingNumpy(self, classifier: str = 'Aberration', **args) -> np.ndarray:
        return self.GetNumpyData(classifier, **args)

    
    def GetFocusingData(self, classifier: str = 'Aberration', **args) -> np.ndarray:
        return self.GetNumpyData(classifier, **args)

    
    def GetRequestData(self, request: ('CameraRequest', 'SlideModelInterface'), classifier: str = 'Aberration', **args) -> int:
        isWrong: int = RECODE_FAILURE
        camera: CameraRequest
        if isinstance(request, CameraRequest):
            if not request.has_StartTime:
                request.StartTime = Qt.QDateTime.currentDateTime()
            request.ImageSource = self.GetNumpyData(classifier, **args)
            request.FinishTime = Qt.QDateTime.currentDateTime()
            isWrong = RECODE_SUCCEED if request.hasImageSource else RECODE_FAILURE
        elif isinstance(request, SlideModelInterface):
            if not request.hasCamera:
                request.initCamera()
            if not request.camera.has_StartTime:
                request.camera.StartTime = Qt.QDateTime.currentDateTime()
            request.camera.ImageSource = self.GetNumpyData(classifier, **args)
            request.camera.FinishTime = Qt.QDateTime.currentDateTime()
            isWrong = RECODE_SUCCEED if request.camera.hasImageSource else RECODE_FAILURE
        return isWrong

    
    def GetNumpyData(self, classifier: str = 'Aberration', **args) -> np.ndarray:
        result_image: np.ndarray = None
        if not self.hasModel:
            return result_image
        if self.Parameter.IsOpen:
            try:
                ImageFrame      : pylon.GrabResult
                ExposureTime    : int
                isMono          : bool = self.Model.isMono()
                if self.isAberration(classifier):
                    ExposureTime = self.Model.AberrationExposureTime
                elif self.isMicronucleus(classifier):
                    ExposureTime = self.Model.MicronucleusExposureTime
                    isMono = False
                elif self.isKaryotyping(classifier):
                    ExposureTime = self.Model.KaryotypingExposureTime
                else:
                    ExposureTime = self.Model.ExposureTime
                if self.getExposureTime() != ExposureTime:
                    self.ChangedCameraExposureTime(self.Manager, ExposureTime, self.Model)
                if self.IsGrabbing:
                    waittimes = int(ExposureTime)
                    endtime = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
                    while self.Manager.IsGrabbing():
                        ImageFrame = self.Manager.RetrieveResult(int(ExposureTime), pylon.TimeoutHandling_ThrowException)
                        if isinstance(ImageFrame, pylon.GrabResult) and ImageFrame.GrabSucceeded():
                            source_image = ImageFrame.GetArray()
                            result_image = self.ImageToColor(source_image, self.Model.PixelFormat, isMono)
                            break
                        if Qt.QDateTime.currentDateTime() > endtime:
                            break
                else:
                    self.Manager.StartGrabbingMax(int(self.Model.ImageCount))
                    ImageFrame = self.Manager.RetrieveResult(int(ExposureTime))
                    if isinstance(ImageFrame, pylon.GrabResult) and ImageFrame.GrabSucceeded():
                        source_image = ImageFrame.GetArray()
                        result_image = self.ImageToColor(source_image, self.Model.PixelFormat, isMono)

            except Exception as e:
                from AppLog.logHelper import logCAMERA
                logCAMERA << AppUtils.toString(e)
        return result_image



    
    def GetRequest(self, request: ('CameraRequest', 'SlideModelInterface'), classifier: str = 'Aberration', **args) -> int:
        isWrong: int = RECODE_FAILURE
        camera: CameraRequest
        if isinstance(request, CameraRequest):
            if not request.has_StartTime:
                request.StartTime = Qt.QDateTime.currentDateTime()
            request.ImageSource = self.GetNumpy(classifier, *args)
            request.FinishTime = Qt.QDateTime.currentDateTime()
            isWrong = RECODE_SUCCEED if request.hasImageSource else RECODE_FAILURE
        elif isinstance(request, SlideModelInterface):
            if not request.hasCamera:
                request.initCamera()
            if not request.camera.has_StartTime:
                request.camera.StartTime = Qt.QDateTime.currentDateTime()
            request.camera.ImageSource = self.GetNumpy(classifier, *args)
            request.camera.FinishTime = Qt.QDateTime.currentDateTime()
            isWrong = RECODE_SUCCEED if request.camera.hasImageSource else RECODE_FAILURE
        return isWrong

    
    def RequestMultiple(self, parameter: 'CameraInterface', ExposureTimes: list[int], **args) -> list[np.ndarray]:
        images: list[np.ndarray] = self.RequestMultipleNumpy(parameter, ExposureTimes,**args)
        self.StopGrabbing()
        self.ChangedCameraExposureTime(self.Manager, self.Model.ExposureTime, self.Model)
        return images

    
    def RequestMultipleArray(self, parameter: 'CameraInterface', ExposureTimes: list[int], ImageArray: list[np.ndarray], **args):
        if parameter is None:
            return
        self.RequestMultipleNumpyArray(parameter, ExposureTimes, ImageArray,**args)
        self.ChangedCameraExposureTime(self.Manager, parameter.ExposureTime, self.Model)
        return

    
    def RequestNumpy(self, parameter: 'CameraInterface', classifier: str = 'Aberration', **args) -> np.ndarray:
        from AppLog.logHelper import logCAMERA
        result_image: np.ndarray = None
        if not isinstance(parameter, CameraInterface):
            return result_image
        ExposureTime: int = int(parameter.ExposureTime)
        isMono: bool = parameter.isMono()
        if self.isAberration(classifier):
            ExposureTime = int(parameter.AberrationExposureTime)
        elif self.isKaryotyping(classifier):
            ExposureTime = int(parameter.KaryotypingExposureTime)
        elif self.isMicronucleus(classifier):
            ExposureTime = int(parameter.MicronucleusExposureTime)
            isMono       = False


        if not isinstance(ExposureTime, (float, int)):
            return result_image

        if self.IsOpen:
            try:
                if self.getExposureTime() != ExposureTime:
                    self.ChangedCameraExposureTime(self.Manager, ExposureTime, parameter)

                if self.Manager.IsGrabbing():
                    waittimes = int(ExposureTime)
                    endtime = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
                    while self.Manager.IsGrabbing():
                        ImageFrame = self.Manager.RetrieveResult(int(ExposureTime), pylon.TimeoutHandling_ThrowException)
                        if isinstance(ImageFrame, pylon.GrabResult) and ImageFrame.GrabSucceeded():
                            source_image = ImageFrame.GetArray()
                            result_image = self.ImageToColor(source_image, parameter.PixelFormat, isMono)
                            break
                        if Qt.QDateTime.currentDateTime() > endtime:
                            break
                else:
                    self.Manager.StartGrabbingMax(int(parameter.ImageCount))
                    ImageFrame: pylon.GrabResult = self.Manager.RetrieveResult(int(ExposureTime))
                    if ImageFrame is not None and ImageFrame.GrabSucceeded():
                        source_image = ImageFrame.GetArray()
                        result_image = self.ImageToColor(source_image, parameter.PixelFormat, isMono)

            except Exception as e:
                from AppLog.logHelper import logCAMERA
                logCAMERA << AppUtils.toString(e)
        return result_image

    
    def RequestMultipleImage(self, parameter: 'CameraInterface', ExposureTime: int, **args) -> np.ndarray:
        from AppLog.logHelper import logCAMERA

        if not isinstance(parameter, CameraInterface) or not isinstance(ExposureTime, (int, float)):
            return None
        if not self.hasModel:
            return None
        result_image: np.ndarray = None
        isMono      : bool       = parameter.isMono()
        if self.IsOpen:
            try:
                if self.getExposureTime() != ExposureTime:
                    self.ChangedCameraExposureTime(self.Manager, ExposureTime, parameter)
                if self.Manager.IsGrabbing():
                    waittimes = int(ExposureTime)
                    endtime = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
                    while self.Manager.IsGrabbing():
                        ImageFrame = self.Manager.RetrieveResult(int(ExposureTime), pylon.TimeoutHandling_ThrowException)
                        if isinstance(ImageFrame, pylon.GrabResult) and ImageFrame.GrabSucceeded():
                            source_image = ImageFrame.GetArray()
                            result_image = self.ImageToColor(source_image, parameter.PixelFormat, isMono)
                            break
                        if Qt.QDateTime.currentDateTime() > endtime:
                            break
                else:
                    self.Manager.StartGrabbingMax(int(parameter.ImageCount))
                    ImageFrame: pylon.GrabResult = self.Manager.RetrieveResult(int(ExposureTime))
                    if ImageFrame is not None and ImageFrame.GrabSucceeded():
                        source_image = ImageFrame.GetArray()
                        result_image = self.ImageToColor(source_image, parameter.PixelFormat, isMono)
                if result_image is not None:
                    if len(result_image.shape) == 2:
                        result_image = np.stack((result_image,) * 3, axis=-1)
            except Exception as e:
                from AppLog.logHelper import logCAMERA
                logCAMERA << AppUtils.toString(e)

        return result_image

    
    def RequestMultipleNumpy(self, parameter: 'CameraInterface', ExposureTimes: list[int], **args) -> list[np.ndarray]:
        from AppLog.logHelper import logCAMERA
        if not isinstance(parameter, CameraInterface) or not isinstance(ExposureTimes, list) or len(ExposureTimes) <= 0:
            return None
        if not self.hasModel:
            return None

        isMono              : bool = parameter.isMono()
        images              : list[np.ndarray] = []
        ImageFrame          : pylon.GrabResult
        ImageFrame          : pylon.GrabResult
        waittimes           : int
        ExposureTime        : int
        endtime             : Qt.QDateTime
        if self.IsOpen:
            try:
                for Index, ExposureTime in enumerate(ExposureTimes):
                    if self.getExposureTime() != ExposureTime:
                        self.ChangedCameraExposureTime(self.Manager, ExposureTime, parameter)
                    if self.Manager.IsGrabbing():
                        waittimes = int(ExposureTime)
                        endtime = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
                        while self.Manager.IsGrabbing():
                            ImageFrame = self.Manager.RetrieveResult(int(ExposureTime), pylon.TimeoutHandling_ThrowException)
                            if isinstance(ImageFrame, pylon.GrabResult) and ImageFrame.GrabSucceeded():
                                source_image = ImageFrame.GetArray()
                                images.append(self.ImageToColor(source_image, parameter.PixelFormat, isMono))
                                break
                            if Qt.QDateTime.currentDateTime() > endtime:
                                break
                    else:
                        self.Manager.StartGrabbingMax(int(parameter.ImageCount))
                        ImageFrame: pylon.GrabResult = self.Manager.RetrieveResult(int(ExposureTime))
                        if ImageFrame is not None and ImageFrame.GrabSucceeded():
                            source_image = ImageFrame.GetArray()
                            images.append(self.ImageToColor(source_image, parameter.PixelFormat, isMono))

            except Exception as e:
                from AppLog.logHelper import logCAMERA
                logCAMERA << AppUtils.toString(e)
        return images

    
    def RequestMultipleNumpyArray(self, parameter: 'CameraInterface', ExposureTimes: list[int], ImageArray: list[np.ndarray], **args) -> list[np.ndarray]:
        from AppLog.logHelper import logCAMERA
        if not isinstance(parameter, CameraInterface) or not isinstance(ExposureTimes, list) or len(ExposureTimes) <= 0:
            return
        if not isinstance(ImageArray, list):
            return

        ImageFrame          : pylon.GrabResult  #
        waittimes           : int  #
        ExposureTime        : int  #
        endtime             : Qt.QDateTime  #
        result_image        : np.ndarray = None
        isMono              : bool = parameter.isMono()
        if self.IsOpen:
            try:
                for Index, ExposureTime in enumerate(ExposureTimes):
                    if self.getExposureTime() != ExposureTime:
                        self.ChangedCameraExposureTime(self.Manager, ExposureTime, parameter)
                    if self.Manager.IsGrabbing():
                        waittimes = int(ExposureTime)
                        endtime = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
                        while self.Manager.IsGrabbing():
                            ImageFrame = self.Manager.RetrieveResult(int(ExposureTime), pylon.TimeoutHandling_ThrowException)
                            if isinstance(ImageFrame, pylon.GrabResult) and ImageFrame.GrabSucceeded():
                                source_image = ImageFrame.GetArray()
                                ImageArray.append(self.ImageToColor(source_image, parameter.PixelFormat, isMono))
                                break
                            if Qt.QDateTime.currentDateTime() > endtime:
                                break
                    else:
                        self.Manager.StartGrabbingMax(int(parameter.ImageCount))
                        ImageFrame: pylon.GrabResult = self.Manager.RetrieveResult(int(ExposureTime))
                        if ImageFrame is not None and ImageFrame.GrabSucceeded():
                            source_image = ImageFrame.GetArray()
                            ImageArray.append(self.ImageToColor(source_image,parameter.PixelFormat, isMono))

            except Exception as e:
                from AppLog.logHelper import logCAMERA
                logCAMERA << AppUtils.toString(e)
        # self.StopGrabbing()
        return

    
    def CameraRequest(self, model: ('CameraRequest', 'SlideModelInterface'), parameter: 'CameraInterface', classifier: str = 'Aberration', **args):
        isWrong: int = RECODE_FAILURE
        if isinstance(model, CameraRequest):

            model.StartTime = Qt.QDateTime.currentDateTime()
            model.ImageSource = self.RequestNumpy(parameter, classifier, **args)
            isWrong = RECODE_SUCCEED if model.hasImageSource else RECODE_FAILURE
            model.FinishTime = Qt.QDateTime.currentDateTime()
        elif isinstance(model, SlideModelInterface):
            if not model.hasCamera:
                model.initCamera()
            model.camera.StartTime = Qt.QDateTime.currentDateTime()
            model.camera.ImageSource = self.RequestNumpy(parameter, classifier, **args)
            isWrong = RECODE_SUCCEED if model.hasImageSource else RECODE_FAILURE
            model.camera.FinishTime = Qt.QDateTime.currentDateTime()
        return isWrong

    
    def setGain(self, value):
        try:
            if self.hasManager:
                self.Manager.Gain.Value = float(value)
        except Exception as e:
            from AppLog.logHelper import logCAMERA

            logCAMERA << AppUtils.toString(e)

    
    def setGamma(self, value):
        try:
            if self.hasManager :
                self.Manager.Gamma.Value = float(value)
        except Exception as e:
            from AppLog.logHelper import logCAMERA

            logCAMERA << AppUtils.toString(e)

    
    def setExposureTime(self, value):
        try:
            if self.hasManager and self.Manager.IsOpen():
                self.Manager.ExposureTime.Value = int(value)  # 曝光时间
        except Exception as e:
            from AppLog.logHelper import logCAMERA

            logCAMERA << AppUtils.toString(e)


    def getExposureTime(self):
        ExposureTime: int = self.model.ExposureTime
        if self.hasManager:
            try:
                ExposureTime = int(self.Manager.ExposureTime.Value)
            except Exception as e:
                AppUtils.print_Exception(e)
        return ExposureTime

    def setImageROI(self, offsetX, offsetY, width, height, CenterX: bool = True, CenterY: bool = True):
        try:
            # 读取相机最大宽度和高度
            MAX_W: int = int(self.Manager.WidthMax.Value)
            MAX_H: int = int(self.Manager.HeightMax.Value)
            ROI_W: int = offsetX * 2 + width
            ROI_H: int = offsetY * 2 + height
            _OffsetX: int = int(offsetX) if ROI_W <= MAX_W and ROI_H <= MAX_H   else self.Model.OffsetX     #
            _OffsetY: int = int(offsetY) if ROI_W <= MAX_W and ROI_H <= MAX_H   else self.Model.OffsetY     #
            _Dst_W: int = int(width) if ROI_W <= MAX_W and ROI_H <= MAX_H       else self.Model.Width       #
            _Dst_H: int = int(height) if ROI_W <= MAX_W and ROI_H <= MAX_H      else self.Model.Height      #
            self.Manager.OffsetX.Value  = _OffsetX
            self.Manager.OffsetY.Value  = _OffsetY
            self.Manager.Width.Value    = _Dst_W
            self.Manager.Height.Value   = _Dst_H

        except Exception as e:
            from AppLog.logHelper import logCAMERA

            logCAMERA << AppUtils.toString(e)

    
    def setPixelFormat(self, value: int):
        try:
            if self.Model.hasPixelFormat:
                self.Manager.PixelFormat.Value = str(self.Model.PixelFormat)
        except Exception as e:
            from AppLog.logHelper import logCAMERA

            logCAMERA << AppUtils.toString(e)

    
    def initCameraConfig(self):
        if not self.hasManager or not self.hasDeviceInfo or not self.hasModel:
            return

        from AppLog.logHelper import logCAMERA

        try:

            MAX_W: int = int(self.Manager.WidthMax.Value)
            MAX_H: int = int(self.Manager.HeightMax.Value)
            try:
                self.Manager.Height.Value = int(self.Model.Height) if int(self.Model.Height) <= MAX_H else int(MAX_H)  # 宽度
                self.Manager.Width.Value = int(self.Model.Width) if int(self.Model.Width) <= MAX_W else int(MAX_W)  # 高度
                self.Manager.CenterX.Value = bool(self.Model.CenterX) if self.Model.hasCenterX else True  # X距中
                self.Manager.CenterY.Value = bool(self.Model.CenterY) if self.Model.hasCenterY else True  # X距中
                self.Manager.ReverseX.Value = bool(self.Model.ReverseX) if self.Model.hasReverseX else False  # X镜像
                self.Manager.ReverseY.Value = bool(self.Model.ReverseY) if self.Model.hasReverseY else False  # Y镜像
            except Exception as e:
                AppUtils.print_Exception(e)
            if self.Model.hasPixelFormat:
                try:
                    self.Manager.PixelFormat.Value = str(self.Model.PixelFormat)
                except Exception as e:
                    AppUtils.print_Exception(e)

            if self.Model.hasExposureTime:
                try:
                    self.Manager.ExposureTime.Value = float(self.Model.ExposureTime)  # 曝光时间
                except Exception as e:
                    AppUtils.print_Exception(e)

            if self.Model.hasGain:
                try:
                    self.Manager.Gain.Value = float(self.Model.Gain)  # 增益数值
                except Exception as e:
                    AppUtils.print_Exception(e)

            if self.Model.hasGamma:
                try:
                    self.Manager.Gamma.Value = float(self.Model.Gamma)  # 伽马数值
                except Exception as e:
                    AppUtils.print_Exception(e)

            if self.Model.hasBlackLevel:
                try:
                    self.Manager.BlackLevel.Value = float(self.Model.BlackLevel)  # 黑电平值
                except Exception as e:
                    AppUtils.print_Exception(e)

            if self.Model.hasExposureMode:
                try:
                    self.Manager.ExposureMode.IntValue = int(self.Model.ExposureMode)
                except Exception as e:
                    AppUtils.print_Exception(e)
            if self.Model.hasTriggerMode:
                try:
                    self.Manager.TriggerMode.IntValue = int(self.Model.TriggerMode)  # ('Off', 'On')
                except Exception as e:
                    AppUtils.print_Exception(e)
            if self.Model.hasShutterMode:
                try:
                    self.Manager.ShutterMode.IntValue = int(self.Model.ShutterMode)
                except Exception as e:
                    AppUtils.print_Exception(e)

            if self.Model.hasGainAuto:
                try:
                    self.Manager.GainAuto.IntValue = int(self.Model.GainAuto)  # 自动增益
                except Exception as e:
                    AppUtils.print_Exception(e)

            from AppSettings.SystemSetting import SystemConfig
            if self.DeviceInfo.GetModelName() in SystemConfig.camera_names and self.Model.PixelFormat != 'Mono8':
                '''设置彩色相机'''
                if self.Model.hasLightSourcePreset:
                    try:
                        self.Manager.LightSourcePreset.Value = str(self.Model.LightSourcePreset)
                    except Exception as e:
                        AppUtils.print_Exception(e)
                try:
                    ColorParameter: CameraColorModel = CameraColorModel.getConfig(self.Model.Level)
                    self.Manager.BalanceRatioSelector.IntValue = 0
                    self.Manager.BalanceRatio.Value = ColorParameter.BalanceRatio0
                    self.Manager.BalanceRatioSelector.IntValue = 1
                    self.Manager.BalanceRatio.Value = ColorParameter.BalanceRatio1
                    self.Manager.BalanceRatioSelector.IntValue = 2
                    self.Manager.BalanceRatio.Value = ColorParameter.BalanceRatio2

                    self.Manager.ColorTransformationValueSelector.IntValue = int(0)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue0)
                    self.Manager.ColorTransformationValueSelector.IntValue = int(1)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue1)
                    self.Manager.ColorTransformationValueSelector.IntValue = int(2)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue2)

                    self.Manager.ColorTransformationValueSelector.IntValue = int(3)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue0)
                    self.Manager.ColorTransformationValueSelector.IntValue = int(4)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue1)
                    self.Manager.ColorTransformationValueSelector.IntValue = int(5)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue2)

                    self.Manager.ColorTransformationValueSelector.IntValue = int(6)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue20)
                    self.Manager.ColorTransformationValueSelector.IntValue = int(7)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue21)
                    self.Manager.ColorTransformationValueSelector.IntValue = int(8)
                    self.Manager.ColorTransformationValue.IntValue = int(ColorParameter.ColorTransformationValue22)

                except Exception as e:
                    AppUtils.print_Exception(e)
        except Exception as e:
            logCAMERA << AppUtils.toString(e)
        else:
            logCAMERA << "设置相机参数"

    
    def initCameraGama(self):
        if not self.IsOpen:
            return
        try:
            if self.Model.hasGain:
                try:
                    self.Manager.Gain.Value = float(self.Model.Gain)  # 增益数值
                except Exception as e:
                    AppUtils.print_Exception(e)

            if self.Model.hasGamma:
                try:
                    self.Manager.Gamma.Value = float(self.Model.Gamma)  # 伽马数值
                except Exception as e:
                    AppUtils.print_Exception(e)

            if self.Model.hasBlackLevel:
                try:
                    self.Manager.BlackLevel.Value = float(self.Model.BlackLevel)  # 黑电平值
                except Exception as e:
                    AppUtils.print_Exception(e)
        except Exception as e:
            AppUtils.print_Exception(e)

    
    def WhiteAutoOnce(self):
        if self.hasManager and self.IsOpen:
            try:
                self.Manager.BalanceWhiteAuto.Value = 'Once'  # ('Off', 'Once', 'Continuous')
                endtime: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(2000)
                while True:
                    if Qt.QDateTime.currentDateTime() > endtime:
                        break
                    AppTimeLoop.processGlobalEvents(1000)
                self.Manager.BalanceWhiteAuto.Value = 'Off'
            except Exception as e:
                AppUtils.print_Exception(e)