处理图像

SDK提供了丰富的图像处理接口,可用于实现图像显示、图像保存、像素格式转换、图像重组和录像等功能。采集到图像后,您可以直接其传入到这些接口中进行图像处理。

本节内容包含:

图像渲染

采集到图像后,您可参照如下示例,调用 MV_CC_DisplayOneFrameEx2() 将图像显示在指定窗口。
// 1. 获取图像相关数据
MV_CC_IMAGE stImage = {0};
stImage.nWidth = stImageInfo.stFrameInfo.nExtendWidth;
stImage.nHeight = stImageInfo.stFrameInfo.nExtendHeight;
stImage.enPixelType = stImageInfo.stFrameInfo.enPixelType;
stImage.pImageBuf = stImageInfo.pBufAddr;
stImage.nImageBufLen = stImageInfo.stFrameInfo.nFrameLenEx;
// 2. 设置渲染模式
unsigned int enRenderMode = 0;
// 3. 显示图像
nRet = MV_CC_DisplayOneFrameEx2(handle,(void*)g_hwnd, &stImage , enRenderMode);
Check(nRet);
  1. 获取图像宽、高、像素格式、图像缓存及图像长度。
  2. 设置图像渲染模式。此处设置为0,表示默认模式,即通过OpenGL模式渲染。
  3. 通过 MV_CC_DisplayOneFrameEx2() ,将获取的图像通过指定模式渲染。


保存图像

在采集到图像后,您可将图像保存至本地或内存中:
如下示例代码演示了如何将图像保存成本地BMP文件。
// 存原始数据bmp图片
char chImageName[IMAGE_NAME_LEN] = { 0 };
MV_CC_IMAGE stImage;
memset(&stImage, 0, sizeof(MV_CC_IMAGE));
MV_CC_SAVE_IMAGE_PARAM stSaveImageParam;
memset(&stSaveImageParam, 0, sizeof(MV_CC_SAVE_IMAGE_PARAM));
stImage.enPixelType = stImageInfo.stFrameInfo.enPixelType;
stImage.nHeight = stImageInfo.stFrameInfo.nExtendWidth;
stImage.nWidth = stImageInfo.stFrameInfo.nExtendHeight;
stImage.nImageBufLen = stImageInfo.stFrameInfo.nFrameLenEx;
stImage.pImageBuf = stImageInfo.pBufAddr;
stSaveImageParam.enImageType = MV_Image_Bmp;
stSaveImageParam.iMethodValue = 1;
stSaveImageParam.nQuality = 99;
sprintf_s(chImageName, IMAGE_NAME_LEN, "InPut_w%d_h%d_fn%03d.bmp", stImage.nWidth, stImage.nHeight, stImageInfo.stFrameInfo.nFrameNum);
nRet = MV_CC_SaveImageToFileEx2(handle, &stImage, &stSaveImageParam, chImageName);
Check(nRet);


像素格式转换

采集到图像后,您可调用 MV_CC_ConvertPixelTypeEx() ,将图像转换成其他像素格式。
例如,您可将Bayer格式转换成RGB/BGR格式。在对Bayer格式图像进行插值时,还支持一些算法功能,如平滑滤波、Gamma矫正和CCM矫正等,具体支持的功能,可参考图像处理 相关内容。
如下示例代码演示了如何将图像转换成RGB格式。
// 设置插值方法为均衡
Check(nRet);
unsigned char *pConvertData = NULL;
unsigned int nConvertDataSize = 0;
nConvertDataSize = stOutFrame.stFrameInfo.nExtendWidth * stOutFrame.stFrameInfo.nExtendHeight* 3;
pConvertData = (unsigned char*)malloc(nConvertDataSize);
if (NULL == pDataForRGB)
{
printf("pConvertData is null\n");
break;
}
// 像素格式转换
MV_CC_PIXEL_CONVERT_PARAM_EX stConvertParam = {0};
stConvertParam.nWidth = stOutFrame.stFrameInfo.nExtendWidth;
stConvertParam.nHeight = stOutFrame.stFrameInfo.nExtendHeight;
stConvertParam.pSrcData = stOutFrame.pBufAddr;
stConvertParam.nSrcDataLen = stOutFrame.stFrameInfo.nFrameLenEx;
stConvertParam.enSrcPixelType = stOutFrame.stFrameInfo.enPixelType;
stConvertParam.pDstBuffer = pConvertData ;
stConvertParam.nDstBufferSize = nConvertDataSize ;
nRet = MV_CC_ConvertPixelTypeEx(handle, &stConvertParam);
Check(nRet);


解码图像

部分相机支持对图像进行编码压缩,发送压缩的图像,您可以调用 MV_CC_HB_Decode() 对图像进行解码。
注意
解码前需要判断输入图像是否完整,如果因为网络等因素导致图像丢失了部分数据包,该接口可能会解码失败。 您可以通过 MV_FRAME_OUT_INFO_EX 结构体中的nLostPacket(本帧丢包数)字段进行检测,如果nLostPacket大于0,则当前帧有丢包。
如下示例代码演示了如何解码压缩图像。
unsigned char* pDstBuf = NULL;
MV_FRAME_OUT stImageInfo = {0};
MV_CC_HB_DECODE_PARAM stDecodeParam = {0};
// 检测丢包情况
if (0 == stImageInfo.stFrameInfo.nLostPacket)
{
// 无损压缩解码
stDecodeParam.pSrcBuf = stImageInfo.pBufAddr;
stDecodeParam.nSrcLen = stImageInfo.stFrameInfo.nFrameLen;
if (NULL == pDstBuf)
{
pDstBuf = (unsigned char *)malloc(sizeof(unsigned char) * (nPayloadSize));
if (NULL == pDstBuf)
{
printf("malloc pDsrData fail!\n");
break;
}
}
stDecodeParam.pDstBuf = pDstBuf;
stDecodeParam.nDstBufSize = nPayloadSize;
nRet = MV_CC_HB_Decode(handle, &stDecodeParam);
Check(nRet);
}
else
{
printf("Frame [%d] lost packet [%d] \n",stImageInfo.stFrameInfo.nFrameNum,stImageInfo.stFrameInfo.nLostPacket)
}


录像

您可以通过SDK将从相机接收到的图像保存成录像文件,其方法如下:
  1. 调用 MV_CC_StartRecord() ,开始录像,您需要配置录像的各种参数。
  2. 调用 MV_CC_InputOneFrame() ,循环放入图像数据。
  3. 在完成录像时,调用 MV_CC_StopRecord() ,停止录像。
如下示例代码演示了如何将图像保存成录像文件。
  1. 开始录像:调用 MV_CC_StartRecord() 配置录像的参数,需要的参数可以从相机中获取,也可以从图像中获取。以下代码演示了从相机中获取宽、高、像素格式等参数。

    MV_CC_RECORD_PARAM stRecordPar;
    MVCC_INTVALUE stParam = {0};
    nRet = MV_CC_GetIntValue(handle, "Width", &stParam);
    Check(nRet);
    stRecordPar.nWidth = stParam.nCurValue;
    nRet = MV_CC_GetIntValue(handle, "Height", &stParam);
    Check(nRet);
    stRecordPar.nHeight = stParam.nCurValue;
    MVCC_ENUMVALUE stEnumValue = {0};
    nRet = MV_CC_GetEnumValue(handle, "PixelFormat", &stEnumValue);
    Check(nRet);
    stRecordPar.enPixelType = MvGvspPixelType(stEnumValue.nCurValue);
    MVCC_FLOATVALUE stFloatValue;
    nRet = MV_CC_GetFloatValue(handle, "ResultingFrameRate", &stFloatValue);
    Check(nRet);
    stRecordPar.fFrameRate = stFloatValue.fCurValue;
    stRecordPar.nBitRate = 1000;
    stRecordPar.strFilePath= "./Recording.avi";
    nRet = MV_CC_StartRecord(handle, &stRecordPar);
    Check(nRet);
  2. 放入图像到录像中:循环调用 MV_CC_InputOneFrame(),将从相机获取的图像数据放入录像中。

    static unsigned int __stdcall WorkThread(void* handle)
    {
    int nRet = MV_OK;
    MV_FRAME_OUT stImageInfo = {0};
    MV_CC_INPUT_FRAME_INFO stInputFrameInfo = {0};
    while(1)
    {
    nRet = MV_CC_GetImageBuffer(handle, &stImageInfo, 1000);
    if (nRet == MV_OK)
    {
    printf("Get Image Buffer: Width[%d], Height[%d], FrameNum[%d]\n",
    stImageInfo.stFrameInfo.nWidth, stImageInfo.stFrameInfo.nHeight, stImageInfo.stFrameInfo.nFrameNum);
    stInputFrameInfo.pData = stImageInfo.pBufAddr;
    stInputFrameInfo.nDataLen = stImageInfo.stFrameInfo.nFrameLen;
    nRet = MV_CC_InputOneFrame(handle, &stInputFrameInfo);
    Check(nRet);
    nRet = MV_CC_FreeImageBuffer(handle, &stImageInfo);
    Check(nRet);
    }
    if(g_bExit)
    {
    break;
    }
    }
    return 0;
    }
  3. 停止录像:调用 MV_CC_StopRecord() ,停止录像。

    Check(nRet);


分时曝光拆图

  • SDK拆图
    部分相机支持分时曝光功能,并将分时曝光的整图发送给SDK,应用程序可以调用 MV_CC_ReconstructImage() ,拆分分时曝光的整图,输出每个曝光的图像。
    通过SDK端分时曝光拆图和重构图像的基本步骤如下:
    1. 调用 MV_CC_GetEnumValue() 获取“MultiLightControl”节点的值,即当前相机的曝光数量。
      注意
      • 部分相机可能没有“MultiLightControl”节点,此时,您需根据实际曝光数量进行设置。
      • 相机配置HB(High Bandwidth)模式下“MultiLightControl”节点的值,需要进行转换才能得到有效的曝光数量。
    2. 若获取的图像为HB图像,调用 MV_CC_HB_Decode() ,进行HB解码。
    3. 调用 MV_CC_ReconstructImage() ,重构图像。
    示例代码如下:
    unsigned int m_nMultiLightNum = 0; //获取多组曝光数量
    MVCC_ENUMVALUE stEnumValue = {0};
    int nRet = MV_CC_GetEnumValue(handle, "MultiLightControl", &stEnumValue);
    Check(nRet);
    m_nMultiLightNum=stEnumValue.nCurValue;
    nRet = MV_CC_GetEnumValue(handle, "ImageCompressionMode", &stEnumValue);
    Check(nRet);
    if(2 == stEnumValue.nCurValue) //HB开启
    {
    /*HB模式下,曝光数转换逻辑:
    目前固件端HB定义的灯数是从0x10起始的,实际灯数从字节低四位获取*/
    m_nMultiLightNum = m_nMultiLightNum & 0xF;
    /*HB模式下,需要对HB图像进行解码后,参考"解码图像"章节,
    之后再进行重构*/
    }
    MV_RECONSTRUCT_IMAGE_PARAM stImgReconstructionParam ;
    unsigned char* pImageBufferList[8] = {0};
    for (int k = 0; k < 8; k++)
    {
    pImageBufferList[k] = NULL;
    }
    stImgReconstructionParam.nWidth = stOutFrame.stFrameInfo.nWidth;
    stImgReconstructionParam.nHeight = stOutFrame.stFrameInfo.nHeight;
    stImgReconstructionParam.enPixelType = stOutFrame.stFrameInfo.enPixelType;
    stImgReconstructionParam.pSrcData = stOutFrame.pBufAddr;
    stImgReconstructionParam.nSrcDataLen = stOutFrame.stFrameInfo.nFrameLen;
    /*曝光数量*/
    stImgReconstructionParam.nExposureNum = m_nMultiLightNum;
    stImgReconstructionParam.enReconstructMethod = MV_SPLIT_BY_LINE;
    /*重组后的长度*/
    unsigned int nImageBufferSize = stImgReconstructionParam.nSrcDataLen / m_nMultiLightNum;;
    for (unsigned int i = 0; i < m_nMultiLightNum; i++)
    {
    if (pImageBufferList[i])
    {
    free(pImageBufferList[i]);
    pImageBufferList[i] = NULL;
    }
    pImageBufferList[i] = (unsigned char*)malloc(nImageBufferSize);
    if (NULL != pImageBufferList[i])
    {
    stImgReconstructionParam.stDstBufList[i].pBuf = pImageBufferList[i];
    stImgReconstructionParam.stDstBufList[i].nBufSize = nImageBufferSize;
    }
    else
    {
    return MV_E_RESOURCE;
    }
    }
    nRet = MV_CC_ReconstructImage(handle, &stImgReconstructionParam);
    Check(nRet);
  • 采集卡端拆图
    在通过采集卡端拆图时,您可通过 MV_FRAME_OUT_INFO_EX 结构体中的 SubImageList 获取拆图后的子图。示例代码如下。
    注解
    只有部分型号采集卡支持拆图功能。
    MV_FRAME_OUT stFrameOut = { 0 };
    int nRet = MV_CC_GetImageBuffer(pUser, &stFrameOut, 1000);
    if (nRet == MV_OK)
    {
    if (stFrameOut.stFrameInfo.nSubImageNum > 0)
    {
    for (unsigned int i = 0; i < stFrameOut.stFrameInfo.nSubImageNum; ++i)
    {
    MV_CC_IMAGE* pSubImage = &stFrameOut.stFrameInfo.SubImageList.pstSubImage[i];
    printf("SubImage buffer[%p], size[%d]\n", pSubImage->pImageBuf, pSubImage->nImageLen);
    }
    }
    MV_CC_FreeImageBuffer(pUser, &stFrameOut);
    }



    上一篇: 采集图像 下一篇:无