海康彩色工业相机图像格式转换方法(Bayer转RGB)

海康彩色工业相机图像格式转换方法

    • 1.彩色相机是如何变成彩色的-Bayer的由来
    • 2.工业相机支持的图像格式
    • 3.图像格式转化
    • 4.一些其他的问题

1.彩色相机是如何变成彩色的-Bayer的由来

提到工业相机图像格式,尤其是彩色相机的图像格式,不得不先讲一下bayer图像格式,网上有很多介绍这种图像格式的文档,随意引用一篇简单介绍下,引用链接: 图像bayer格式介绍以及bayer插值原理.
大致原理呢,就是相机上面的图像传感器只能感受光强而无法感知光的波长,然而光的颜色却是由波长决定的,因此图像传感器是无法记录颜色的。
虽然可以在相机的内部内置三个图像传感器来分别记录红、绿、蓝三元色,然后将这三种颜色合并得到最终的彩色图像,但是这样做的成本太高。
因此,柯达这个公司,提出的解决方案就是,使用一个图像传感器,在图像传感器的前面,放置一个滤光层,滤光层的滤光点与图像传感器的像素一一对应,每个滤光点只能通过红、绿、蓝三种光其中之一;
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第1张图片
通过规律性的排列不同颜色的滤光点,我们就能在传感器上面有规律的获得不同颜色的光强值,也就是R、G、B的灰度值;
根据不同于颜色的排列,我们把Bayer分为BayerRG、BayerBG、BayerGB、BayerBG四种
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第2张图片
但是呢,这样得到一幅图像,其实仅仅是灰度图,它并不能表达呈现真实世界的图像
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第3张图片
放大看
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第4张图片海康彩色工业相机图像格式转换方法(Bayer转RGB)_第5张图片
如果想要呈现真实的色彩世界,那么就需要弥补每个像素所缺少的其他色彩分量,用相邻的像素值补充进来,这个过程就叫做bayer差值,也叫“去马赛克”(如要简单理解原理,可以去看开篇引用的链接)

当然,相机实现彩色图像原理,肯定不止这一种,但是,出于成本、生产技术等因素,目前你所能接触到的大部分相机,工业相机,数码相机,原始数据,都是有bayer转换产生的;
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第6张图片

2.工业相机支持的图像格式

前面讲了,传感器的彩色由来,那么就接下来讲讲工业相机支持的图像格式种类,以海康工业相机为例子

相机种类 图像格式 细分 说明
黑白相机 Mono Mono8、Mono10、Mono12,Mono10 Packed、Mono12 Packed
彩色相机 Bayer Bayer8、Bayer10、Bayer12 、Bayer10 Packed、Bayer12 Packed Bayer根据sensor遮挡层排列不同,分为BG、GR、GB、BR四种
彩色相机 YUV YUV 422 (YUYV) Packed、YUV 422 Packed
彩色相机 RGB RGB8 Packed、BGR8 Packed 两者的区别就是R、B排列是相反的

mono10、mono12:分别代表10位、12位黑白图像,在内存中以16位数据存储,不够的数据位填0补充
Mono10 Packed、Mono12 Packed:这种数据跟上面的mono10、mono12没有本质上的区别,差异就是,在数据排列上面,16位数据存储,原来补0的位置,被下一帧图像数据填充,这样的好处就是节约了传输带宽,坏处就是小小的增加了解码的难度
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第7张图片
Bayer8、Bayer10、Bayer12:分别代表8位、10位、12位的彩色相机相机原始数据格式,传感器采样最原始的数据是Bayer12,Bayer8、Bayer10都是由Bayer12下采样过来的
Bayer10 Packed、Bayer12 Packed:与mono10 Packed,mono12 Packed一样的道理,数据排列方式不同
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第8张图片

YUV 422 Packed、YUV 422 (YUYV) Packed:YUV是由bayer数据先转化为RGB,然后RGB转化为YUV数据得到的,其中Y代表亮度值,数据排列分别是UYVY、与YUYV两种,它们都是16位存储的,Packed就是数据填充方式

那么如何查询自己手上的工业相机,支持的图像格式,以海康工业相机为例,使用其MVS客户端,打开相机后,在相机属性中找到Pixel Format点击即可查看,切换图像格式,需要再非预览模式状态下
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第9张图片

3.图像格式转化

以海康工业相机的格式转换例程为例,讲讲图像格式如何转化
先来看一下他们提供的代码

#include 
#include 
#include 
#include "MvCameraControl.h"
// ch:等待按键输入 | en:Wait for key press
void WaitForKeyPress(void)
{
    while(!_kbhit())
    {
        Sleep(10);
    }
    _getch();
}
bool PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
{
    if (NULL == pstMVDevInfo)
    {
        printf("The Pointer of pstMVDevInfo is NULL!\n");
        return false;
    }
    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);
        // ch:打印当前相机ip和用户自定义名字 | en:print current ip and user defined name
        printf("CurrentIp: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);
        printf("UserDefinedName: %s\n\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);
    }
    else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE)
    {
        printf("UserDefinedName: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
        printf("Serial Number: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chSerialNumber);
        printf("Device Number: %d\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.nDeviceNumber);
    }
    else
    {
        printf("Not support.\n");
    }
    return true;
}
bool IsColor(MvGvspPixelType enType)
{
    switch(enType)
    {
    case PixelType_Gvsp_BGR8_Packed:
    case PixelType_Gvsp_YUV422_Packed:
    case PixelType_Gvsp_YUV422_YUYV_Packed:
    case PixelType_Gvsp_BayerGR8:
    case PixelType_Gvsp_BayerRG8:
    case PixelType_Gvsp_BayerGB8:
    case PixelType_Gvsp_BayerBG8:
    case PixelType_Gvsp_BayerGB10:
    case PixelType_Gvsp_BayerGB10_Packed:
    case PixelType_Gvsp_BayerBG10:
    case PixelType_Gvsp_BayerBG10_Packed:
    case PixelType_Gvsp_BayerRG10:
    case PixelType_Gvsp_BayerRG10_Packed:
    case PixelType_Gvsp_BayerGR10:
    case PixelType_Gvsp_BayerGR10_Packed:
    case PixelType_Gvsp_BayerGB12:
    case PixelType_Gvsp_BayerGB12_Packed:
    case PixelType_Gvsp_BayerBG12:
    case PixelType_Gvsp_BayerBG12_Packed:
    case PixelType_Gvsp_BayerRG12:
    case PixelType_Gvsp_BayerRG12_Packed:
    case PixelType_Gvsp_BayerGR12:
    case PixelType_Gvsp_BayerGR12_Packed:
        return true;
    default:
        return false;
    }
}
bool IsMono(MvGvspPixelType enType)
{
    switch(enType)
    {
    case PixelType_Gvsp_Mono10:
    case PixelType_Gvsp_Mono10_Packed:
    case PixelType_Gvsp_Mono12:
    case PixelType_Gvsp_Mono12_Packed:
        return true;
    default:
        return false;
    }
}
int main()
{
    int nRet = MV_OK;
    void* handle = NULL;
    unsigned char *pConvertData = NULL;
    unsigned int nConvertDataSize = 0;
    do 
    {
        // ch:枚举设备 | en:Enum device
        MV_CC_DEVICE_INFO_LIST stDeviceList;
        memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
        nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
        if (MV_OK != nRet)
        {
            printf("Enum Devices fail! nRet [0x%x]\n", nRet);
            break;
        }
        if (stDeviceList.nDeviceNum > 0)
        {
            for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++)
            {
                printf("[device %d]:\n", i);
                MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
                if (NULL == pDeviceInfo)
                {
                    break;
                } 
                PrintDeviceInfo(pDeviceInfo);            
            }  
        } 
        else
        {
            printf("Find No Devices!\n");
            break;
        }
        printf("Please Input camera index(0-%d):", stDeviceList.nDeviceNum-1);
        unsigned int nIndex = 0;
        scanf_s("%d", &nIndex);

        if (nIndex >= stDeviceList.nDeviceNum)
        {
            printf("Input error!\n");
            break;
        }
        // ch:选择设备并创建句柄 | en:Select device and create handle
        nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
        if (MV_OK != nRet)
        {
            printf("Create Handle fail! nRet [0x%x]\n", nRet);
            break;
        }
        // ch:打开设备 | en:Open device
        nRet = MV_CC_OpenDevice(handle);
        if (MV_OK != nRet)
        {
            printf("Open Device fail! nRet [0x%x]\n", nRet);
            break;
        }
        // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
        if (stDeviceList.pDeviceInfo[nIndex]->nTLayerType == MV_GIGE_DEVICE)
        {
            int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
            if (nPacketSize > 0)
            {
                nRet = MV_CC_SetIntValue(handle,"GevSCPSPacketSize",nPacketSize);
                if(nRet != MV_OK)
                {
                    printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);
                }
            }
            else
            {
                printf("Warning: Get Packet Size fail nRet [0x%x]!", nPacketSize);
            }
        }
        nRet = MV_CC_SetEnumValue(handle, "TriggerMode", MV_TRIGGER_MODE_OFF);
        if (MV_OK != nRet)
        {
            printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);
            break;
        }
        // ch:开始取流 | en:Start grab image
        nRet = MV_CC_StartGrabbing(handle);
        if (MV_OK != nRet)
        {
            printf("Start Grabbing fail! nRet [0x%x]\n", nRet);
            break;
        }
        MV_FRAME_OUT stImageInfo = {0};
        nRet = MV_CC_GetImageBuffer(handle, &stImageInfo, 1000);
        if (nRet == MV_OK)
        {
            printf("Get One Frame: Width[%d], Height[%d], nFrameNum[%d]\n", 
                stImageInfo.stFrameInfo.nWidth, stImageInfo.stFrameInfo.nHeight, stImageInfo.stFrameInfo.nFrameNum);
            MvGvspPixelType enDstPixelType = PixelType_Gvsp_Undefined;
            unsigned int nChannelNum = 0;
            char chFileName[MAX_PATH] = {0};
            //如果是彩色则转成RGB8
            if (IsColor(stImageInfo.stFrameInfo.enPixelType))
            {
                nChannelNum = 3;
                enDstPixelType = PixelType_Gvsp_RGB8_Packed;
                sprintf(chFileName, "AfterConvert.rgb");
            }
            //如果是黑白则转换成Mono8
            else if (IsMono(stImageInfo.stFrameInfo.enPixelType))
            {
                nChannelNum = 1;
                enDstPixelType = PixelType_Gvsp_Mono8;
                sprintf(chFileName, "AfterConvert.gray");
            }
            else
            {
                printf("Don't need to convert!\n");
            }         
            if (enDstPixelType != PixelType_Gvsp_Undefined)
            {
                pConvertData = (unsigned char*)malloc(stImageInfo.stFrameInfo.nWidth * stImageInfo.stFrameInfo.nHeight * nChannelNum);
                if (NULL == pConvertData)
                {
                    printf("malloc pConvertData fail!\n");
                    nRet = MV_E_RESOURCE;
                    break;
                }
                nConvertDataSize = stImageInfo.stFrameInfo.nWidth * stImageInfo.stFrameInfo.nHeight * nChannelNum;
                // ch:像素格式转换 | en:Convert pixel format 
                MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};
                stConvertParam.nWidth = stImageInfo.stFrameInfo.nWidth;                 //ch:图像宽 | en:image width
                stConvertParam.nHeight = stImageInfo.stFrameInfo.nHeight;               //ch:图像高 | en:image height
                stConvertParam.pSrcData = stImageInfo.pBufAddr;                         //ch:输入数据缓存 | en:input data buffer
                stConvertParam.nSrcDataLen = stImageInfo.stFrameInfo.nFrameLen;         //ch:输入数据大小 | en:input data size
                stConvertParam.enSrcPixelType = stImageInfo.stFrameInfo.enPixelType;    //ch:输入像素格式 | en:input pixel format
                stConvertParam.enDstPixelType = enDstPixelType;                         //ch:输出像素格式 | en:output pixel format
                stConvertParam.pDstBuffer = pConvertData;                               //ch:输出数据缓存 | en:output data buffer
                stConvertParam.nDstBufferSize = nConvertDataSize;                       //ch:输出缓存大小 | en:output buffer size
                nRet = MV_CC_ConvertPixelType(handle, &stConvertParam);
                if (MV_OK != nRet)
                {
                    printf("Convert Pixel Type fail! nRet [0x%x]\n", nRet);
                    break;
                }
                FILE* fp = NULL;
                errno_t err = fopen_s(&fp, chFileName, "wb");
                if (0 != err || NULL == fp)
                {
                    printf("Open file failed\n");
                    nRet = MV_E_RESOURCE;
                    break;
                }
                fwrite(stConvertParam.pDstBuffer, 1, stConvertParam.nDstLen, fp);
                fclose(fp);
                printf("Convert pixeltype succeed\n");
            }
            MV_CC_FreeImageBuffer(handle, &stImageInfo);
        }
        else
        {
            printf("Get Image fail! nRet [0x%x]\n", nRet);
        }
        // ch:停止取流 | en:Stop grab image
        nRet = MV_CC_StopGrabbing(handle);
        if (MV_OK != nRet)
        {
            printf("Stop Grabbing fail! nRet [0x%x]\n", nRet);
            break;
        }
        // ch:关闭设备 | en:Close device
        nRet = MV_CC_CloseDevice(handle);
        if (MV_OK != nRet)
        {
            printf("Close Device fail! nRet [0x%x]\n", nRet);
            break;
        }
        // ch:销毁句柄 | en:Destroy handle
        nRet = MV_CC_DestroyHandle(handle);
        if (MV_OK != nRet)
        {
            printf("Destroy Handle fail! nRet [0x%x]\n", nRet);
            break;
        }
    } while (0);
    if (pConvertData)
    {
        free(pConvertData);
        pConvertData = NULL;
    }
    if (nRet != MV_OK)
    {
        if (handle != NULL)
        {
            MV_CC_DestroyHandle(handle);
            handle = NULL;
        }
    }
    printf("Press a key to exit.\n");
    WaitForKeyPress();
    return 0;
}

关键的几句代码如下,要看MV_CC_GetImageBuffer函数后面,拿到一帧图像之后,调用MV_CC_ConvertPixelType进行图像转换图像格式,在其SDK开发文档中,我们可以看见这个函数作用范围
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第10张图片
格式转换的总体思路如下:

Created with Raphaël 2.2.0 相机拍照 采集一帧图像 彩色格式? 格式转换目标格式:RGB 格式转换 输出Mono or RGB图像 黑白格式? 格式转换目标格式:Mono8 yes no yes

第一步,黑白彩色相机判断;

  • 示例代码中,是根据帧结构体来判断的,如下所示
//如果是彩色则转成RGB8
//IsColor这个函数,列举了相机支持的所有彩色图像格式
//然后再与stImageInfo.stFrameInfo结构体里面相机传递上来的enPixelType做对比判断
if (IsColor(stImageInfo.stFrameInfo.enPixelType))
{
	//----
	//转换的目标格式设置为RGB
	enDstPixelType = PixelType_Gvsp_RGB8_Packed;//部分使用OpenCV的朋友,这里要修改成PixelType_Gvsp_BGR8_Packed
}
//如果是黑白则转成mono8
//IsMono这个函数,列举了相机支持的所有黑白图像格式
//然后再与stImageInfo.stFrameInfo结构体里面相机传递上来的enPixelType做对比判断
else if (IsMono(stImageInfo.stFrameInfo.enPixelType))
{
	//----
	//转换的目标格式设置为mon8
	 enDstPixelType = PixelType_Gvsp_Mono8;
}

第二步,调用接口进行图像格式转换,这里的变量enDstPixelType就是目标格式

if (enDstPixelType != PixelType_Gvsp_Undefined)
{
	pConvertData = (unsigned char*)malloc(stImageInfo.stFrameInfo.nWidth * stImageInfo.stFrameInfo.nHeight * nChannelNum);
	if (NULL == pConvertData)
	{
		printf("malloc pConvertData fail!\n");
		nRet = MV_E_RESOURCE;
		break;
		}
        nConvertDataSize = stImageInfo.stFrameInfo.nWidth * stImageInfo.stFrameInfo.nHeight * nChannelNum;
		 // ch:像素格式转换 | en:Convert pixel format 
		MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};
		stConvertParam.nWidth = stImageInfo.stFrameInfo.nWidth;                 //ch:图像宽 | en:image width
		stConvertParam.nHeight = stImageInfo.stFrameInfo.nHeight;               //ch:图像高 | en:image height
		stConvertParam.pSrcData = stImageInfo.pBufAddr;                         //ch:输入数据缓存 | en:input data buffer
		stConvertParam.nSrcDataLen = stImageInfo.stFrameInfo.nFrameLen;         //ch:输入数据大小 | en:input data size
		stConvertParam.enSrcPixelType = stImageInfo.stFrameInfo.enPixelType;    //ch:输入像素格式 | en:input pixel format
		//这里就是目标格式
		stConvertParam.enDstPixelType = enDstPixelType;                         //ch:输出像素格式 | en:output pixel format
		//输出的mono8或者RGB8数据
		stConvertParam.pDstBuffer = pConvertData;                               //ch:输出数据缓存 | en:output data buffer
		stConvertParam.nDstBufferSize = nConvertDataSize;                       //ch:输出缓存大小 | en:output buffer size
		nRet = MV_CC_ConvertPixelType(handle, &stConvertParam);
		if (MV_OK != nRet)
		{
			printf("Convert Pixel Type fail! nRet [0x%x]\n", nRet);
			break;
		}
		FILE* fp = NULL;
		errno_t err = fopen_s(&fp, chFileName, "wb");
		if (0 != err || NULL == fp)
		{
			printf("Open file failed\n");
			nRet = MV_E_RESOURCE;
			break;
		}
		fwrite(stConvertParam.pDstBuffer, 1, stConvertParam.nDstLen, fp);
		fclose(fp);
		printf("Convert pixeltype succeed\n");
	}
}

需要注意的是,如果你想使用10bit、12bit的数据,那么你需要先在相机端,设置相机的图像格式为mono10、mono12等,这样拿到的raw数据才会是其他位数,同时,不去做格式转换;上面格式转换的目的是转换成常用的8bit数据

4.一些其他的问题

  1. mono8 、mono10、mono12之间的区别
    首先,要了解一个灰阶的概念,通常来说,液晶屏幕上人们肉眼所见的一个点,即一个像素,它是由红、绿、蓝(RGB)三原色组成的。每一个基色,其背后的光源都可以显现出不同的亮度级别。而灰阶代表了由最暗到最亮之间不同亮度的层次级别。
    在数字信息存贮中,计算设备用2进制数来表示,每个0或1就是一个位(bit)。 假设1代表黑、0代表白,在黑白双色系统中最少有2bit。单基色为nbit,画面位数就为2 ⁿbit,位数越大,灰度越多,颜色也越多,彩色系统中同理。视频画面10bit含义就是画面能以10为二进制数的数量控制色彩层次(即灰阶)。通常8bit相当于256级灰阶——即常说得24位真彩色;而10bit就相当于1024级灰阶。三基色混合成彩色,增加1 bit就意味色彩数增加8倍。10bit就相当于1024的三次方——1073741824,约为10.7亿色。远大于8bit的1670万色。
    那么,mono8,就是2^8=256灰阶,因此你看见的黑白mono8图像,灰度值范围时0-255;
    同理,mono10,mono12分别是2^10、 2^12, 图像灰度值范围0-1024、0-4096,但是如果你将图像数据存储下来,在计算机内存里面,只能按照8、16、24、32等位深存储的,那么10、12位数据就会被补0,灰度范围就会被拉伸到2^16,也就是0-65536

2.Bayer转RGB,注意事项

  • bayer插值算法差异
    海康提供的sdk接口中,提供了3种不同的bayer转RGB算法,调用MV_CC_SetBayerCvtQuality()接口实现,接口调用在其Opendevice函数之后即可
BayerCvtQuality Value 备注
0 快速 速度最快,图像边缘有锯齿感
1 均衡 效果适中
2 最优 图像效果最好,速度最慢,cpu 消耗较高

下图来看一下不同插值算法的效果,从上到下,依次是快速,均衡,最优
当对格式转换速度有要求时,可以尝试下不同插值算法,从中做取舍
海康彩色工业相机图像格式转换方法(Bayer转RGB)_第11张图片
3.其他的格式转换方法

  • halcon
    halcon也提供了算子做图像格式转化:cfa_to_rgb (ImageCFA, RGBImage, ‘bayer_gb’, ‘bilinear’),最后一个参数“bilinear”就是不同的插值算法,也有三种选择可配【halcon参考文档】,同样的,不同的插值算法也有不同的优劣势,用户需要自行测试;
    bayer格式需要看相机输出什么,需要根据相机参数进行填写
    海康彩色工业相机图像格式转换方法(Bayer转RGB)_第12张图片
/************************************************************************
 *  @fn     ConvertBayer8ToHalcon()
 *  @brief  Bayer8转换为Halcon格式数据
 *  @param  Hobj                   [OUT]          转换后的输出Hobject数据
 *  @param  nHeight                [IN]           图像高度
 *  @param  nWidth                 [IN]           图像宽度
 *  @param  nPixelType             [IN]           源数据格式
 *  @param  pData                  [IN]           源数据
 *  @return 成功,返回STATUS_OK;错误,返回STATUS_ERROR 
 ************************************************************************/
int ConvertBayer8ToHalcon(Halcon::Hobject *Hobj, int nHeight, int nWidth, MvGvspPixelType nPixelType, unsigned char *pData)
{
    if(NULL == Hobj || NULL == pData)
    {
        return MV_E_PARAMETER;
    }

    gen_image1(Hobj, "byte", nWidth, nHeight, (Hlong)pData);

    if (nPixelType == PixelType_Gvsp_BayerGR8)
    {
        cfa_to_rgb(*Hobj, Hobj, "bayer_gr", "bilinear");
    }
    else if (nPixelType == PixelType_Gvsp_BayerRG8)
    {
        cfa_to_rgb(*Hobj, Hobj, "bayer_rg", "bilinear");
    }
    else if (nPixelType == PixelType_Gvsp_BayerGB8)
    {
        cfa_to_rgb(*Hobj, Hobj, "bayer_gb", "bilinear");
    }
    else if (nPixelType == PixelType_Gvsp_BayerBG8)
    {
        cfa_to_rgb(*Hobj, Hobj, "bayer_bg", "bilinear");
    }

    return MV_OK;
}
  • OpenCV
    使用OpenCV提供的接口,也能将bayer数据快速转化为RGB/BGRcvtColor(source, destination, CV_BayerRG2BGR),但是似乎没有更多的插值方法可以选择
	Mat bayer2rgb;
    bayer2rgb.create(ImageBuffer.rows,ImageBuffer.cols,CV_8UC3);
    cvtColor(ImageBuffer,bayer2rgb,CV_BayerRG2BGR);
    //BayerRG需要事先知道bayer数据的种类
    //OpenCV要使用BGR而非RGB,如果要转RGB,CV_BayerRG2BGR需要替换为CV_BayerRG2RGB

海康彩色工业相机图像格式转换方法(Bayer转RGB)_第13张图片

  • 其他的方法

    还有很多bayer转RGB的接口,暂时没遇到或者没有学到,靠大家来分享,共同学习

你可能感兴趣的:(工业相机SDK)