通过相机获取bayer 图像数据转换成RGB888数据并保存
前面的文章使用opencv 库的方法实现了转换bayer的灰度图像转换成彩色图像,但是颜色跟实际颜色差距太大。
后来想直接在从相机中获取的bayer图像数据转换成RGB888 的真彩bmp图片。中间遇到过图片保存过打开出错的问题并在前面的博客中说明了问题与原因并解决。
我使用的是映美精扳机相机。通过usb连接到linux 系统PC机上。
以下是读取bayer图像数据,转换成RGB888数据并保存为图片的源程序:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mman.h> #include <linux/videodev2.h> #include <libv4l2.h> #include <libv4l1.h> /*位图头文件数据结构*/ typedef struct tagBITMAPFILEHEADER { unsigned char bfType[2]; //位图文件类型,必须为'B' 'M' unsigned long bfSize; //位图文件大小(以字节为单位) unsigned short bfReserved1; //位图文件保留字,必须为0 unsigned short bfReserved2; //位图文件保留字,必须为0 unsigned long bfOffBits; //位图数据的起始位置,以相对位图文件头的偏移量(单位字节) }BITMAPFILEHEADER ; //共14Byte /*位图信息数据结构*/ typedef struct tagBITMAPINFOHEADER{ unsigned long biSize; //本结构所占用字节数 long biWidth; //位图宽度,以像素为单位 long biHeight; //位图高度,以像素为单位 unsigned short biPlanes; //目标设备级别,必须为1 unsigned short biBitCount; //每个像素所需的位数,1(双色),4(16色),8(256色),24(真彩色) unsigned long biCompression; //位图的压缩类型,必须是0(示不压缩),1(BI_RLE8压缩类型),2(BI_RLE4压缩类型)之一 unsigned long biSizeImage; //位图大小以字节为单位 long biXPixPerMeter; //图像水平分辨率,每米像素数 long biYPixPerMeter; //图像垂直分辨率,每米像素数 unsigned long biClrUsed; //位图实际使用的颜色表中的颜色数 unsigned long biClrImporant; //位图显示过程中重要的颜色数 }BITMAPINFOHEADER; //共40Byte struct buffer { void *start; size_t length; }; #define CLEAR(x) memset(&(x), 0, sizeof(x)) static void xioctl(int fh, int request, void *arg) { int r; do { r = ioctl(fh, request, arg); } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); if (r == -1) { fprintf(stderr, "error %d, %s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } } void saveImage(void *data,int imageWidth,int imageHeight) { BITMAPFILEHEADER *bitmapFileHeader; BITMAPINFOHEADER *bitmapInfoHeader; FILE *fp; if((fp=fopen("2345.bmp", "wb"))==NULL){ fprintf(stderr, "file cannot open\n"); exit(1); } bitmapFileHeader=(BITMAPFILEHEADER *)malloc(sizeof(BITMAPFILEHEADER)); bitmapInfoHeader=(BITMAPINFOHEADER *)malloc(sizeof(BITMAPINFOHEADER)); printf("%d\n",sizeof( bitmapFileHeader->bfType[2])); bitmapFileHeader->bfType[0] = 'B'; bitmapFileHeader->bfType[1] = 'M'; bitmapFileHeader->bfReserved1 = 0x0000; bitmapFileHeader->bfReserved2 = 0x0000; bitmapFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER); bitmapInfoHeader->biWidth = (long)2592; bitmapInfoHeader->biHeight = (long)-1944; bitmapInfoHeader->biPlanes = 0x0001; bitmapInfoHeader->biBitCount = 0x0018; //24位图 bitmapInfoHeader->biCompression = 0x0000; //不压缩 bitmapInfoHeader->biSizeImage = -bitmapInfoHeader->biWidth*bitmapInfoHeader->biHeight * 3; bitmapInfoHeader->biXPixPerMeter = 3780; /*96dpi*/ bitmapInfoHeader->biYPixPerMeter = 3780; /*96dpi*/ bitmapInfoHeader->biClrUsed = 0; bitmapInfoHeader->biClrImporant = 0; bitmapFileHeader->bfSize = bitmapFileHeader->bfOffBits + bitmapInfoHeader->biSizeImage; fwrite((unsigned char *)bitmapFileHeader->bfType, 2, 1, fp); fwrite((unsigned char *)&bitmapFileHeader->bfSize, 4, 1, fp); fwrite((unsigned char *)&bitmapFileHeader->bfReserved1, 2, 1, fp); fwrite((unsigned char *)&bitmapFileHeader->bfReserved2, 2, 1, fp); fwrite((unsigned char *)&bitmapFileHeader->bfOffBits, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biSize, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biWidth, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biHeight, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biPlanes, 2, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biBitCount, 2, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biCompression, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biSizeImage, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biXPixPerMeter, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biYPixPerMeter, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biClrUsed, 4, 1, fp); fwrite((unsigned char *)&bitmapInfoHeader->biClrImporant, 4, 1, fp); printf("white image header success\n"); char *buffer=(char *)malloc(imageWidth*imageHeight*3); char *ch=(char *)data; unsigned char r,g,b; union NUM{ int number; char str[4]; }num; int k; for(int i=0,j=0;i<1944;i+=2){ for(j=0;j<2592;j+=2){ r=ch[i*2592+j]; g=ch[i*2592+j+1]; b=ch[i*2592+2592+j+1]; buffer[i*2592*3+j*3+2]=b; buffer[(i+1)*2592*3+j*3+2]=b; buffer[i*2592*3+j*3+5]=b; buffer[(i+1)*2592*3+j*3+5]=b; buffer[i*2592*3+j*3+1]=g; buffer[(i+1)*2592*3+j*3+1]=g; buffer[i*2592*3+j*3+4]=g; buffer[(i+1)*2592*3+j*3+4]=g; buffer[i*2592*3+j*3]=r; buffer[(i+1)*2592*3+j*3]=r; buffer[i*2592*3+j*3+3]=r; buffer[(i+1)*2592*3+j*3+3]=r; } } printf("convert bayer data to rgb888 success\n"); fwrite(buffer,imageWidth*imageHeight*3,1,fp); printf("write data to image success\n"); fclose(fp); } int grabberandprocess(char*dev_name, int imageWidth, int imageHeight) { struct v4l2_format fmt; struct v4l2_buffer buf; struct v4l2_requestbuffers req; enum v4l2_buf_type type; fd_set fds; struct timeval tv; int r, fd = -1; unsigned int i, n_buffers; struct buffer *buffers; fd = open(dev_name, O_RDWR | O_NONBLOCK, 0); if (fd < 0) { perror("Cannot open device"); exit(EXIT_FAILURE); } CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = imageWidth; fmt.fmt.pix.height = imageHeight; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; fmt.fmt.pix.field = V4L2_FIELD_ANY; xioctl(fd, VIDIOC_S_FMT, &fmt);//VIDIOC_S_FMT set the video capture format if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_GREY) { printf("Libv4l didn't accept GREY format. Can't proceed.\n"); exit(EXIT_FAILURE); } else printf("set GREY OK!\n"); if ((fmt.fmt.pix.width != imageWidth) || (fmt.fmt.pix.height != imageHeight)) printf("Warning: driver is sending image at %dx%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height); else printf("set resolution OK!\n"); CLEAR(req); //亮度设置 struct v4l2_control control_s; control_s.id=V4L2_CID_BRIGHTNESS; control_s.value=20; ioctl(fd,VIDIOC_S_CTRL,&control_s); //曝光值 control_s.id=V4L2_CID_EXPOSURE_AUTO; control_s.value=V4L2_EXPOSURE_MANUAL; ioctl(fd,VIDIOC_S_CTRL,&control_s); control_s.id=V4L2_CID_EXPOSURE_ABSOLUTE; control_s.value=1200; ioctl(fd,VIDIOC_S_CTRL,&control_s); //自动曝光 /*control_s.id = V4L2_CID_EXPOSURE_AUTO; control_s.value = V4L2_EXPOSURE_APERTURE_PRIORITY; ioctl(fd, VIDIOC_S_CTRL, &control_s);*/ //自动白平衡 control_s.id=V4L2_CID_AUTO_WHITE_BALANCE; control_s.value=1; ioctl(fd,VIDIOC_S_CTRL,&control_s); //手动白平衡 /*control_s.id = V4L2_CID_AUTO_WHITE_BALANCE; control_s.value = 0; ioctl(fd, VIDIOC_S_CTRL, &control_s); //设置白平衡值 control_s.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE; control_s.value = 4600; ioctl(fd, VIDIOC_S_CTRL, &control_s);*/ //对比度 control_s.id=V4L2_CID_CONTRAST; control_s.value=32; ioctl(fd,VIDIOC_S_CTRL,&control_s); //增益 control_s.id=V4L2_CID_GAIN; control_s.value=0; ioctl(fd,VIDIOC_S_CTRL,&control_s); req.count = 3; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; xioctl(fd, VIDIOC_REQBUFS, &req);//VIDIOC_REQBUFS request buffers buffers = (struct buffer*)calloc(req.count, sizeof(*buffers)); for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; xioctl(fd, VIDIOC_QUERYBUF, &buf); buffers[n_buffers].length = buf.length; buffers[n_buffers].start = mmap(NULL, buf.length,PROT_READ | PROT_WRITE, MAP_SHARED,fd, buf.m.offset); if (MAP_FAILED == buffers[n_buffers].start) { perror("mmap"); exit(EXIT_FAILURE); } xioctl(fd, VIDIOC_QBUF, &buf);//read data from buffer } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; xioctl(fd, VIDIOC_STREAMON, &type);//open video display function buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; __u32 shouldused; shouldused = imageWidth*imageHeight; do{ xioctl(fd, VIDIOC_DQBUF, &buf);//put back the data to buffer }while(buf.bytesused != shouldused); saveImage(buffers[buf.index].start,imageWidth,imageHeight); xioctl(fd, VIDIOC_QBUF, &buf);//read data from buffer type = V4L2_BUF_TYPE_VIDEO_CAPTURE; xioctl(fd, VIDIOC_STREAMOFF, &type);//close video display function for (i = 0; i < n_buffers; ++i) { munmap(buffers[i].start, buffers[i].length); } close(fd); return 0; } int main(int argc, char **argv) { int imageWidth = 2592; int imageHeight = 1944; if (argc == 3) { //printf("Usage: ./webcam [outputImageWidth] [outputImageHeight]\nE.g. ./webcam 1920 1280\n"); imageWidth = atoi(argv[1]); imageHeight = atoi(argv[2]); } char device[]="/dev/video0"; grabberandprocess(device,imageWidth, imageHeight); }
浙公网安备 33010602011771号