Newer
Older
CasicIrisIdentify / device / AcquisitionThread.cpp
tanyue on 16 Dec 2023 16 KB 20231216 debug on ubuntu arm
//--------------------------------------------------------------------------------
/**
\file     AcquisitionThread.cpp
\brief    CAcquisitionThread Class implementation file

\version  v1.0.1807.9271
\date     2018-07-27

<p>Copyright (c) 2017-2018</p>
*/
//----------------------------------------------------------------------------------
#include "AcquisitionThread.h"

//----------------------------------------------------------------------------------
/**
\Constructor
*/
//----------------------------------------------------------------------------------
CAcquisitionThread::CAcquisitionThread(QObject *parent) :
    QThread(parent),
    m_ui64AcquisitionBufferNum(0),
    m_nFrameCount(0),
    m_bAcquisitionThreadFlag(false),
    m_hDevice(NULL),
    m_bSoftTriggerOn(false),
    m_i64ColorFilter(0),
    m_i64ImageMaxWidth(0),
    m_i64ImageWidth(0),
    m_i64ImageMaxHeight(0),
    m_i64ImageHeight(0),
    m_bColorFilter(false),
    m_bColorCorrection(false),
    m_bGammaRegulation(false),
    m_bContrastRegulation(false),
    m_i64ColorCorrection(0),
    m_pGammaLut(NULL),
    m_pContrastLut(NULL),
    m_pstarrFrameBuffer(NULL),
    m_pRaw8Image(NULL),
    m_pImageElement0(NULL),
    m_pImageElement1(NULL),
    m_pImageElement2(NULL),
    m_objParamMutex(QMutex::Recursive),
    m_objDequeMutex(QMutex::Recursive)
{

}
//----------------------------------------------------------------------------------
/**
\Destructor
*/
//----------------------------------------------------------------------------------
CAcquisitionThread::~CAcquisitionThread()
{
    // Release all resources
    RELEASE_ALLOC_MEM(m_pImageElement0);
    RELEASE_ALLOC_MEM(m_pImageElement1);
    RELEASE_ALLOC_MEM(m_pImageElement2);
    RELEASE_ALLOC_ARR(m_pRaw8Image);

    RELEASE_ALLOC_ARR(m_pGammaLut);
    RELEASE_ALLOC_ARR(m_pContrastLut);

    RELEASE_ALLOC_ARR(m_pstarrFrameBuffer);
}

//----------------------------------------------------------------------------------
/**
\Main function of Acquisition-thread, Acquisition-thread run start from here
\param[in]
\param[out]
\return void
*/
//----------------------------------------------------------------------------------
void CAcquisitionThread::run()
{
    GX_STATUS   emStatus = GX_STATUS_SUCCESS;
    PROC_STATUS emProcStatus = PROC_SUCCESS;
    uint32_t    ui32FrameNum = 0;

    // Acquisition frame count reset
    m_nFrameCount = 0;

    // Acquisition thread loop
    while (m_bAcquisitionThreadFlag)
    {
        // Acquire ui32FrameElementNum frame data from buffer queue
        emStatus = GXDQAllBufs(m_hDevice, m_pstarrFrameBuffer, m_ui64AcquisitionBufferNum, &ui32FrameNum, 1000);

        // Continue when GXDQAllBufs timeout, other error will quit acquisiton loop
        if (emStatus != GX_STATUS_SUCCESS)
        {
            if (emStatus == GX_STATUS_TIMEOUT)
            {
                continue;
            }
            else
            {
                //Get Acquisition error and send it to main thread
                GetAcquistionErrorString(emStatus);
                break;
            }
        }

        // Return all bufs back when met the last frame is incomplete
        if (m_pstarrFrameBuffer[ui32FrameNum - 1]->nStatus != GX_FRAME_STATUS_SUCCESS)
        {
            emStatus = GXQAllBufs(m_hDevice);
            continue;
        }

        // Get a buffer for process new image
        QImage *pobjImageBuffer = PopFrontFromEmptyBufferDeque();
        // If buffer deque is empty, get one buffer from image show deque
        if (pobjImageBuffer == NULL)
        {
            pobjImageBuffer = PopFrontFromShowImageDeque();
        }

        // Assign the address of the first pixel of the QImage to a temporary variable for image processing
        unsigned char* pImageProcess = pobjImageBuffer->bits();

        // Image processing, Raw to RGB24 and image improvment, if process failed put buffer back to buffer deque
        emProcStatus = ImageProcess(m_pstarrFrameBuffer[ui32FrameNum - 1], pImageProcess);
        if (emProcStatus != PROC_SUCCESS)
        {
            emStatus = GXQAllBufs(m_hDevice);
            PushBackToEmptyBufferDeque(pobjImageBuffer);
            break;
        }

        // Image processing is done push processed buffer to show image deque
        PushBackToShowImageDeque(pobjImageBuffer);

        // Put all buffers back to deque
        emStatus = GXQAllBufs(m_hDevice);
        if (emStatus != GX_STATUS_SUCCESS)
        {
            //Get Acquisition error and send it to main thread
            GetAcquistionErrorString(emStatus);
            break;
        }

        // Get acquisition frame rate
        for (uint32_t i = 0; i < ui32FrameNum; i++)
        {
            m_nFrameCount++;
        }
    }

    // Clear both deque when acquisition is stop
    ClearDeque();

    return;
}

//----------------------------------------------------------------------------------
/**
\Push back to empty buffer deque
\param[in]      pobjImage      Buffer pointer to push back
\param[out]
\return  void
*/
//----------------------------------------------------------------------------------
void CAcquisitionThread::PushBackToEmptyBufferDeque(QImage* pobjImage)
{
    QMutexLocker locker(&m_objDequeMutex);
    m_objEmptyBufferDeque.push_back(pobjImage);

    return;
}

//----------------------------------------------------------------------------------
/**
\Push back to show image deque
\param[in]      pobjImage      Buffer pointer to push back
\param[out]
\return  void
*/
//----------------------------------------------------------------------------------
void CAcquisitionThread::PushBackToShowImageDeque(QImage* pobjImage)
{
    QMutexLocker locker(&m_objDequeMutex);
    m_objShowImageDeque.push_back(pobjImage);

    return;
}

//----------------------------------------------------------------------------------
/**
\Pop front from empty buffer deque
\param[in]
\param[out]
\return  QImage*    pobjImage   If deque not empty return a buffer pointer
                    NULL        If deque is empty return NULL
*/
//----------------------------------------------------------------------------------
QImage* CAcquisitionThread::PopFrontFromEmptyBufferDeque()
{
    QMutexLocker locker(&m_objDequeMutex);

    if (m_objEmptyBufferDeque.empty())
    {
        return NULL;
    }

    QImage* pobjImage = m_objEmptyBufferDeque.front();
    m_objEmptyBufferDeque.pop_front();

    return pobjImage;
}

//----------------------------------------------------------------------------------
/**
\Pop front from show image deque
\param[in]
\param[out]
\return  QImage*    pobjImage   If deque not empty return a buffer pointer
                    NULL        If deque is empty return NULL
*/
//----------------------------------------------------------------------------------
QImage* CAcquisitionThread::PopFrontFromShowImageDeque()
{
    QMutexLocker locker(&m_objDequeMutex);

    if (m_objShowImageDeque.empty())
    {
        return NULL;
    }

    QImage* pobjImage = m_objShowImageDeque.front();
    m_objShowImageDeque.pop_front();

    return pobjImage;
}

//----------------------------------------------------------------------------------
/**
\Clear both deque
\param[in]
\param[out]
\return  void
*/
//----------------------------------------------------------------------------------
void CAcquisitionThread::ClearDeque()
{
    QMutexLocker locker(&m_objDequeMutex);

    m_objEmptyBufferDeque.clear();
    m_objShowImageDeque.clear();

    return;
}


//----------------------------------------------------------------------------------
/**
\Process Raw image to RGB image and do image improvment
\param[in]      pstFrameBuffer  Raw image acquired
\param[out]     pImageProcess   Processed image
\return  PROC_STATUS     PROC_SUCCESS   process successed
                         PROC_FAIL      process failed
*/
//----------------------------------------------------------------------------------
PROC_STATUS CAcquisitionThread::ImageProcess(const PGX_FRAME_BUFFER pstFrameBuffer, unsigned char* pImageProcess)
{
    VxInt32 emDxStatus = DX_OK;

    // Convert RAW8 or RAW16 image to RGB24 image
    switch (pstFrameBuffer->nPixelFormat)
    {
        case GX_PIXEL_FORMAT_MONO8:
        case GX_PIXEL_FORMAT_MONO8_SIGNED:
        case GX_PIXEL_FORMAT_BAYER_GR8:
        case GX_PIXEL_FORMAT_BAYER_RG8:
        case GX_PIXEL_FORMAT_BAYER_GB8:
        case GX_PIXEL_FORMAT_BAYER_BG8:
        {
            // Convert to the RGB
            emDxStatus = DxRaw8toRGB24((unsigned char*)pstFrameBuffer->pImgBuf, pImageProcess, m_i64ImageWidth, m_i64ImageHeight,
                              RAW2RGB_NEIGHBOUR, DX_PIXEL_COLOR_FILTER(m_i64ColorFilter), false);
            if (emDxStatus != DX_OK)
            {
                emit SigImageProcError(emDxStatus);
                return PROC_FAIL;
            }
            break;
        }
        case GX_PIXEL_FORMAT_MONO10:
        case GX_PIXEL_FORMAT_BAYER_GR10:
        case GX_PIXEL_FORMAT_BAYER_RG10:
        case GX_PIXEL_FORMAT_BAYER_GB10:
        case GX_PIXEL_FORMAT_BAYER_BG10:
        {
            // Convert to the Raw8 image
            emDxStatus = DxRaw16toRaw8((unsigned char*)pstFrameBuffer->pImgBuf, m_pRaw8Image, m_i64ImageWidth, m_i64ImageHeight, DX_BIT_2_9);
            if (emDxStatus != DX_OK)
            {
                emit SigImageProcError(emDxStatus);
                return PROC_FAIL;
            }
            // Convert to the RGB24 image
            emDxStatus = DxRaw8toRGB24((unsigned char*)m_pRaw8Image, pImageProcess, m_i64ImageWidth, m_i64ImageHeight,
                              RAW2RGB_NEIGHBOUR, DX_PIXEL_COLOR_FILTER(m_i64ColorFilter), false);
            if (emDxStatus != DX_OK)
            {
                emit SigImageProcError(emDxStatus);
                return PROC_FAIL;
            }
            break;
        }
        case GX_PIXEL_FORMAT_MONO12:
        case GX_PIXEL_FORMAT_BAYER_GR12:
        case GX_PIXEL_FORMAT_BAYER_RG12:
        case GX_PIXEL_FORMAT_BAYER_GB12:
        case GX_PIXEL_FORMAT_BAYER_BG12:
        {
            // Convert to the Raw8 image
            emDxStatus = DxRaw16toRaw8((unsigned char*)pstFrameBuffer->pImgBuf, m_pRaw8Image, m_i64ImageWidth, m_i64ImageHeight, DX_BIT_4_11);
            if (emDxStatus != DX_OK)
            {
                emit SigImageProcError(emDxStatus);
                return PROC_FAIL;
            }
            // Convert to the RGB24 image
            emDxStatus = DxRaw8toRGB24((unsigned char*)m_pRaw8Image, pImageProcess, m_i64ImageWidth, m_i64ImageHeight,
                              RAW2RGB_NEIGHBOUR, DX_PIXEL_COLOR_FILTER(m_i64ColorFilter), false);
            if (emDxStatus != DX_OK)
            {
                emit SigImageProcError(emDxStatus);
                return PROC_FAIL;
            }
            break;
        }
        default:
        {
            // Enter this branch when pixel format not support
            emit SigImageProcError(emDxStatus);
            return PROC_FAIL;
        }
    }

    // Image improvment params will changed in other thread, must being locked
    QMutexLocker locker(&m_objParamMutex);

    int64_t i64ColorCorrection = m_bColorCorrection ? m_i64ColorCorrection : 0;
    unsigned char* pGammaLut = m_bGammaRegulation ? m_pGammaLut : NULL;
    unsigned char* pContrastLut = m_bContrastRegulation ? m_pContrastLut : NULL;

    if (i64ColorCorrection != 0 || pGammaLut != NULL || pContrastLut != NULL)
    {
        emDxStatus = DxImageImprovment(pImageProcess, pImageProcess, m_i64ImageWidth, m_i64ImageHeight, i64ColorCorrection, pContrastLut, pGammaLut);
        if (emDxStatus != DX_OK)
        {
            emit SigImageProcError(emDxStatus);
            return PROC_FAIL;
        }
    }

    return PROC_SUCCESS;
}


//----------------------------------------------------------------------------------
/**
\Get device handle from main-thread
\param[in]
\param[out]
\return void
*/
//----------------------------------------------------------------------------------
void CAcquisitionThread::GetDeviceHandle(GX_DEV_HANDLE hDeviceHandle)
{
    m_hDevice = hDeviceHandle;
}

//----------------------------------------------------------------------------------
/**
\Alloc QImage resource for show frames on ImageLabel
\param[in]
\param[out]
\return bool    true : Prepare success
\               false: Prepare fail
*/
//----------------------------------------------------------------------------------
bool CAcquisitionThread::PrepareForShowImg()
{
    GX_STATUS emStatus = GX_STATUS_SUCCESS;
    int64_t i64ImageWidth = 0;
    int64_t i64ImageHeight = 0;

    // Release PGX_FRAME_BUFFER array
    RELEASE_ALLOC_ARR(m_pstarrFrameBuffer);

    // PGX_FRAME_DATA is pointer of GX_FRAME_DATA, pointer array for image acquisition
    try
    {
        m_pstarrFrameBuffer = new PGX_FRAME_BUFFER[m_ui64AcquisitionBufferNum];
    }
    catch (std::bad_alloc& e)
    {
        QMessageBox::about(NULL, "Error", "Start Acquisition Failed : Allocate PGX_FRAME_BUFFER array failed! ");
        return false;
    }

    // Get the type of Bayer conversion. whether is a color camera.
    emStatus = GXIsImplemented(m_hDevice, GX_ENUM_PIXEL_COLOR_FILTER, &m_bColorFilter);
    if (emStatus != GX_STATUS_SUCCESS)
    {
        return false;
    }

    // Color image
    if(m_bColorFilter)
    {
        emStatus = GXGetEnum(m_hDevice, GX_ENUM_PIXEL_COLOR_FILTER, &m_i64ColorFilter);
        if (emStatus != GX_STATUS_SUCCESS)
        {
            return false;
        }
    }

    // Get the image width
    emStatus = GXGetInt(m_hDevice, GX_INT_WIDTH, &i64ImageWidth);
    if (emStatus != GX_STATUS_SUCCESS)
    {
        return false;
    }

    // Get the image height
    emStatus = GXGetInt(m_hDevice, GX_INT_HEIGHT, &i64ImageHeight);
    if (emStatus != GX_STATUS_SUCCESS)
    {
        return false;
    }

    // If width or height is changed, realloc image buffer
    if (i64ImageWidth != m_i64ImageWidth || i64ImageHeight != m_i64ImageHeight)
    {
        m_i64ImageWidth = i64ImageWidth;
        m_i64ImageHeight = i64ImageHeight;

        RELEASE_ALLOC_ARR(m_pRaw8Image);
        RELEASE_ALLOC_MEM(m_pImageElement0);
        RELEASE_ALLOC_MEM(m_pImageElement1);
        RELEASE_ALLOC_MEM(m_pImageElement2);

        try
        {
            // Allocate raw8 frame buffer for DxRaw16toRaw8
            m_pRaw8Image = new unsigned char[m_i64ImageWidth * m_i64ImageHeight];

            // Allocate three QImage buffer for deque acquisition
            m_pImageElement0 = new QImage(m_i64ImageWidth, m_i64ImageHeight, QImage::Format_RGB888);
            m_pImageElement1 = new QImage(m_i64ImageWidth, m_i64ImageHeight, QImage::Format_RGB888);
            m_pImageElement2 = new QImage(m_i64ImageWidth, m_i64ImageHeight, QImage::Format_RGB888);
        }
        catch (std::bad_alloc& e)
        {
           QMessageBox::about(NULL, "Error", "Start Acquisition Failed : Allocate image resources failed! ");
           return false;
        }
    }

    // Clear deque if it is not empty
    if (!m_objEmptyBufferDeque.empty())
    {
        ClearDeque();
    }

    // Add buffer pointer to empty buffer deque
    PushBackToEmptyBufferDeque(m_pImageElement0);
    PushBackToEmptyBufferDeque(m_pImageElement1);
    PushBackToEmptyBufferDeque(m_pImageElement2);

    return true;
}


//----------------------------------------------------------------------------------
/**
\Get Acquisition error and send it to main thread(GXGetLastError can only get string from the thread which error occured)
\param[in]      emStatus    Error code
\param[out]
\return void
*/
//----------------------------------------------------------------------------------
void CAcquisitionThread::GetAcquistionErrorString(GX_STATUS emError)
{
    char*     error_info = NULL;
    size_t    size        = 0;
    GX_STATUS emStatus = GX_STATUS_SUCCESS;

    // Get the length of the error message and alloc memory for error info
    emStatus = GXGetLastError(&emError, NULL, &size);

    // Alloc memory for error info
    try
    {
        error_info = new char[size];
    }
    catch (std::bad_alloc& e)
    {
        emit SigAcquisitionError(QString("Alloc error info Faild!"));
        return;
    }

    // Get the error message and display
    emStatus = GXGetLastError (&emError, error_info, &size);

    if (emStatus != GX_STATUS_SUCCESS)
    {
        emit SigAcquisitionError(QString("Interface of GXGetLastError call failed!"));
    }
    else
    {
        emit SigAcquisitionError(QString("%1").arg(QString(QLatin1String(error_info))));
    }

    // Release memory alloced
    if (NULL != error_info)
    {
        delete[] error_info;
        error_info = NULL;
    }

    return;
}