PallasSDK - 图像采集及BMP存储

最近在熟悉大恒的 PallasSDK,在其提供的 sample - GxSingleCamMono 中,将采集到的图像保存为 ppm格式。虽然这种格式 OPenCV 也支持。但是我就是想给它增加点东西,保存为 BMP格式。

C应用 -BMP图片存储格式及生成 中,介绍了 BMP的存储格式 及如何使用C语言生成图像。

现在我们把它搬到 SDK中,获取一帧数据(一般相机的SDK都会提供),保存为bmp格式

其实很简单~ 其实并不难~

BMP存储

值得注意的是:对于 8bit灰度图,需要使用 调色版,否则 BMP图像 显示是不正常的

void SaveBMPFile(unsigned char *image,uint32_t w,uint32_t h)
{
    int l = (w*3+3)/4*4;

    //调色板
    unsigned char *palette = new unsigned char[256*4];
    for (int i = 0; i < 256; ++i)
    {
        palette[i*4] = i;
        palette[i*4 + 1] = i;
        palette[i*4 + 2] = i;
        palette[i*4 + 3] = 0;
    }
    
    int bmi[]= {l*h+54+1024,0,54+1024,40,w,-h,1|((8)<<16),0,l*h,0,0,0,0};
    //创建/打开文件
    FILE *fp = fopen("bmpimage.bmp","wb");
    //写入BMP标志
    fprintf(fp,"BM");
    //写入位图头文件信息+信息数据
    fwrite(&bmi,52,1,fp);
    //写入调色板
    fwrite(palette,1024,1,fp);
    //写入位图数据
    fwrite(image,1,g_nPayloadSize,fp);
    fclose(fp);
}

更简单的采集Demo

个人认为,GxSingleCamMono 还不够简单。

分享我修改后的 demo

#include "GxIAPI.h"
#include "DxImageProc.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>


//设备句柄
GX_DEV_HANDLE g_hDevice = NULL;
//image buffer
unsigned char* g_pMonoImageBuf = NULL; 
int64_t g_nPayloadSize = 0; 

#define PIXFMT_CVT_FAIL         -1              ///< PixelFormatConvert fail
#define PIXFMT_CVT_SUCCESS      0               ///< PixelFormatConvert success
#define FILE_NAME_LEN           50              ///< Save image file name length
#define ACQ_BUFFER_NUM          5

#define GX_VERIFY_EXIT(status) \
    if (status != GX_STATUS_SUCCESS)     \
    {                                      \
        GetErrorString(status);          \
        GXCloseDevice(g_hDevice);          \
        g_hDevice = NULL;                  \
        GXCloseLib();                      \
        printf("<App Exit!>\n");           \
        return status;                   \
    }

//Show error message
#define GX_VERIFY(mStatus) \
    if (mStatus != GX_STATUS_SUCCESS)     \
    {                                      \
        GetErrorString(mStatus);          \
        return mStatus;                   \
    }

//Get description of error
void GetErrorString(GX_STATUS);
//Convert frame date to suitable pixel format
int PixelFormatConvert(PGX_FRAME_BUFFER);
//Save one frame to PPM image file
void SavePPMFile(uint32_t, uint32_t);
void SaveBMPFile(unsigned char *image,uint32_t w,uint32_t h);


int main(int argc, char const *argv[])
{
	GX_STATUS mStatus = GX_STATUS_SUCCESS;

	//初始化设备库,申请资源
	mStatus = GXInitLib();
	if (mStatus != GX_STATUS_SUCCESS)
	{
		GetErrorString(mStatus);
		return 0;
	}

	//枚举可用设备
	uint32_t nDeviceNum = 0;
	mStatus = GXUpdateDeviceList(&nDeviceNum,1000);
	if(mStatus != GX_STATUS_SUCCESS && nDeviceNum <= 0)
	{
		GetErrorString(mStatus);
		GXCloseLib();
		return 0;
	}

	//通过序号打开设备
	mStatus = GXOpenDeviceByIndex(1, &g_hDevice);
	if (mStatus != GX_STATUS_SUCCESS)
	{
		GetErrorString(mStatus);
		GXCloseLib();
		return 0;
	}

	//功能控制
	//
	//检查当前相机是否支持Bayer格式
	bool bColorFilter = false;
    mStatus = GXIsImplemented(g_hDevice, GX_ENUM_PIXEL_COLOR_FILTER, &bColorFilter);
    GX_VERIFY_EXIT(mStatus);

    mStatus = GXGetInt(g_hDevice, GX_INT_PAYLOAD_SIZE, &g_nPayloadSize);
    GX_VERIFY(mStatus);

    //This app only support mono cameras
    if (bColorFilter)
    {
        printf("<This app only support mono cameras! App Exit!>\n");
        GXCloseDevice(g_hDevice);
        g_hDevice = NULL;
        GXCloseLib();
        return 0;
    }

    //设置枚举类型的当前值
    //Set acquisition mode
    mStatus = GXSetEnum(g_hDevice, GX_ENUM_ACQUISITION_MODE, GX_ACQ_MODE_CONTINUOUS);
    GX_VERIFY_EXIT(mStatus);

    //Set trigger mode
    mStatus = GXSetEnum(g_hDevice, GX_ENUM_TRIGGER_MODE, GX_TRIGGER_MODE_OFF);
    GX_VERIFY_EXIT(mStatus);

    //设置采集队列的缓冲区数量
    uint64_t nBufferNum = ACQ_BUFFER_NUM;
    mStatus = GXSetAcqusitionBufferNumber(g_hDevice, nBufferNum);
    GX_VERIFY_EXIT(mStatus);

    g_pMonoImageBuf = new unsigned char[g_nPayloadSize];

    //开采
    mStatus = GXStreamOn(g_hDevice);
    if(mStatus != GX_STATUS_SUCCESS)
    {
    	//采集失败处理
	    if (g_pMonoImageBuf != NULL)
	    {
	        delete[] g_pMonoImageBuf;
	        g_pMonoImageBuf = NULL;
	    }
    	GX_VERIFY_EXIT(mStatus);
    }

    PGX_FRAME_BUFFER pFrameBuffer = NULL;

    // 获取一帧数据到pFrameBuffer,完成后需要调用GxQBuf接口,否则采集将无法继续
    mStatus = GXDQBuf(g_hDevice, &pFrameBuffer, 1000);
    if(mStatus != GX_STATUS_SUCCESS)
    {
        GetErrorString(mStatus);
    }

    if(pFrameBuffer->nStatus != GX_FRAME_STATUS_SUCCESS)
    {
        printf("<Abnormal Acquisition: Exception code: %d>\n", pFrameBuffer->nStatus);
    }
    else
    {
        //帧格式转化为像素格式
        int nRet = PixelFormatConvert(pFrameBuffer);
        if (nRet == PIXFMT_CVT_SUCCESS)
        {
        	//保存为PPM图片
            SavePPMFile(pFrameBuffer->nWidth, pFrameBuffer->nHeight);

            SaveBMPFile((unsigned char *)g_pMonoImageBuf,pFrameBuffer->nWidth, pFrameBuffer->nHeight);
        }
        else
        {
            printf("PixelFormat Convert failed!\n");
        }
    }

    mStatus = GXQBuf(g_hDevice, pFrameBuffer);
    if(mStatus != GX_STATUS_SUCCESS)
    {
        GetErrorString(mStatus);
    }


	//关闭设备
	mStatus = GXCloseDevice(g_hDevice);

	//释放资源
	mStatus = GXCloseLib();
	return 0;
}




void GetErrorString(GX_STATUS emErrorStatus)
{
    char *error_info = NULL;
    size_t size = 0;
    GX_STATUS emStatus = GX_STATUS_SUCCESS;
    
    // Get length of error description
    emStatus = GXGetLastError(&emErrorStatus, NULL, &size);
    if(emStatus != GX_STATUS_SUCCESS)
    {
        printf("<Error when calling GXGetLastError>\n");
        return;
    }
    
    // Alloc error resources
    error_info = new char[size];
    if (error_info == NULL)
    {
        printf("<Failed to allocate memory>\n");
        return ;
    }
    
    // Get error description
    emStatus = GXGetLastError(&emErrorStatus, error_info, &size);
    if (emStatus != GX_STATUS_SUCCESS)
    {
        printf("<Error when calling GXGetLastError>\n");
    }
    else
    {
        printf("%s\n", (char*)error_info);
    }

    // Realease error resources
    if (error_info != NULL)
    {
        delete []error_info;
        error_info = NULL;
    }
}

int PixelFormatConvert(PGX_FRAME_BUFFER pFrameBuffer)
{
    GX_STATUS emStatus = GX_STATUS_SUCCESS;
    VxInt32 emDXStatus = DX_OK;

    // Convert RAW8 or RAW16 image to RGB24 image
    switch (pFrameBuffer->nPixelFormat)
    {
        case GX_PIXEL_FORMAT_MONO8:
        {
        	printf("MONO8\n");
            memcpy(g_pMonoImageBuf, pFrameBuffer->pImgBuf, g_nPayloadSize);
            break;
        }
        case GX_PIXEL_FORMAT_MONO10:
        case GX_PIXEL_FORMAT_MONO12:
        {
        	printf("MONO10/12\n");
            //Convert to the Raw8 image
            emDXStatus = DxRaw16toRaw8((unsigned char*)pFrameBuffer->pImgBuf, g_pMonoImageBuf, pFrameBuffer->nWidth, pFrameBuffer->nHeight, DX_BIT_2_9);
            if (emDXStatus != DX_OK)
            {
                printf("DxRaw16toRaw8 Failed, Error Code: %d\n", emDXStatus);
                return PIXFMT_CVT_FAIL;
            }
            break;
        }
        default:
        {
            printf("Error : PixelFormat of this camera is not supported\n");
            return PIXFMT_CVT_FAIL;
        }
    }
    return PIXFMT_CVT_SUCCESS;
}

void SavePPMFile(uint32_t ui32Width, uint32_t ui32Height)
{
    char szName[FILE_NAME_LEN] = {0};

    static int nRawFileIndex = 0;
    FILE* phImageFile = NULL;
    sprintf(szName, "Frame_%d.ppm", nRawFileIndex++);
    phImageFile = fopen(szName,"wb");
    if (phImageFile == NULL)
    {
        printf("Save %s failed!\n", szName);
        return;
    }

    if(g_pMonoImageBuf != NULL)
    {
        fprintf(phImageFile, "P5\n" "%u %u 255\n", ui32Width, ui32Height);
        fwrite(g_pMonoImageBuf, 1, g_nPayloadSize, phImageFile);
        fclose(phImageFile);
        printf("Save %s successed\n", szName);
    }
    else
    {
        printf("Save %s failed!\n", szName);
    }
    return;
}

void SaveBMPFile(unsigned char *image,uint32_t w,uint32_t h)
{
    int l = (w*3+3)/4*4;

    //调色板
    unsigned char *palette = new unsigned char[256*4];
    for (int i = 0; i < 256; ++i)
    {
        palette[i*4] = i;
        palette[i*4 + 1] = i;
        palette[i*4 + 2] = i;
        palette[i*4 + 3] = 0;
    }
    
    int bmi[]= {l*h+54+1024,0,54+1024,40,w,-h,1|((8)<<16),0,l*h,0,0,0,0};
    //创建/打开文件
    FILE *fp = fopen("bmpimage.bmp","wb");
    //写入BMP标志
    fprintf(fp,"BM");
    //写入位图头文件信息+信息数据
    fwrite(&bmi,52,1,fp);
    //写入调色板
    fwrite(palette,1024,1,fp);
    //写入位图数据
    fwrite(image,1,g_nPayloadSize,fp);
    fclose(fp);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值