网上移植Opencv到ARM+linux上的教程很多,叫我们如何把OV9650采集的数据传递给opencv使用的教程也很多,但是说的模棱两可,没有一个确切的说法。我在这里总结一下。
一般我们OV9650采集的数据得先经过OpenCV处理以后才会给qt显示,所以要转换两次:第一次是OV9650采集的数据要放到IplImage结构里面,这样Opencv才能使用,第二次是经OpenCV处理以后的图像要传给qt显示。
一、先说第一次转换。OV9650可以采集的数据类型是RGB565、RAW RGB、YUV,这三种数据格式各有特点,RGB565是每个像素16位,即两个字节,数据是交叉排列:[R0,G0,B0] [ R1,G1,B1].... RAW RGB是摄像头采集到的数据还没有进行排列,每个像素都有三种颜色,每一个的值在0~255之间,之后我们要进行插值,我们可以插成RGB24,也可以插成BGR24,YUV格式比较流行,但是在我们这里不大适合,因为IlpImage结构中的数据数组一定是深度为8位RGB格式的数据结构,即我们转换的目标是RGB24。
先熟悉IplImage结构:
所以我们只需要创建一个深度为8,通道数为3的IplImage结构:
IplImage* image = cvCreateImage(cvSize(WIDTH*HEIHT), 8, 3),然后再把IplImage结构的数据数组指针*imageData给下面的转换函数,把转换成的RGB24数据放到imageData数组里就行了。
1、RGB565转IlpImage
思路:先把RGB565中的每个分量放到一个字节里面,这样就转成了RGB24见下图:
那么RGB565一个像素位2字节,RGB24一个像素3个字节,也就是24位,一下代码是网上摘来:
方式一:
- #define RGB565_MASK_RED 0xF800
- #define RGB565_MASK_GREEN 0x07E0
- #define RGB565_MASK_BLUE 0x001F
- unsigned short *pRGB16 = (unsigned short *)lParam; // lParam为OV9650采集数据的缓冲数组,数组类型一定要是unsigned short,也就是16位
- //转换以后的数组放在一个char数组里面,数组大小是高乘以宽的三倍
- for(int i=0; i<176*144; i++)
- {
- unsigned short RGB16 = *pRGB16;
- g_rgbbuf[i*3+2] = (RGB16&RGB565_MASK_RED) >> 11;
- g_rgbbuf[i*3+1] = (RGB16&RGB565_MASK_GREEN) >> 5;
- g_rgbbuf[i*3+0] = (RGB16&RGB565_MASK_BLUE);
- g_rgbbuf[i*3+2] <<= 3;
- g_rgbbuf[i*3+1] <<= 2;
- g_rgbbuf[i*3+0] <<= 3;
- pRGB16++;
- }
- <br style="TEXT-ALIGN: left; WIDOWS: 2; TEXT-TRANSFORM: none; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; FONT: 12px/26px 宋体, Arial; WORD-WRAP: break-word; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(102,102,102); WORD-SPACING: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><span style="color:#666666;TEXT-ALIGN: left; WIDOWS: 2; TEXT-TRANSFORM: none; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; DISPLAY: inline !important; FONT: 12px/26px 宋体, Arial; WHITE-SPACE: normal; ORPHANS: 2; FLOAT: none; LETTER-SPACING: normal; WORD-SPACING: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">方式二:</span><br style="TEXT-ALIGN: left; WIDOWS: 2; TEXT-TRANSFORM: none; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; FONT: 12px/26px 宋体, Arial; WORD-WRAP: break-word; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(102,102,102); WORD-SPACING: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">
- rgb5652rgb888(unsigned char *image,unsigned char *image888)
- {
- unsigned char R,G,B;
- B=(*image) & 0x1F;//000BBBBB
- G=( *(image+1) << 3 ) & 0x38 + ( *image >> 5 ) & 0x07 ;//得到00GGGGGG00
- R=( *(image+1) >> 3 ) & 0x1F; //得到000RRRRR
- *(image888+0)=B * 255 / 63; // 把5bits映射到8bits去,自己可以优化一下算法,下同
- *(image888+1)=G * 255 / 127;
- *(image888+2)=R * 255 / 63;
- }
下面是我根据第一种修改的代码:
- <span style="font-size:18px;"> IplImage* temp = cvCreateImage(cvSize(WIDTH*HEIHT), 8, 3); //创建结构体
- int ret=-1;
- if ((ret=read(fd,&buf,size_2)) != size_2) //read 1 fram
- //读取一帧
- {
- perror("read");
- return -1;
- }
- for(int i=0; i<size_1; i++) //convert RGB565 to RGB24
- {
- *(temp->imageData+i*3+2) = (buf[i]&RGB565_MASK_RED) >> 11;
- *(temp->imageData+i*3+1) = (buf[i]&RGB565_MASK_GREEN) >> 5;
- *(temp->imageData+i*3+0) = (buf[i]&RGB565_MASK_BLUE);
- *(temp->imageData+i*3+2) <<= 3;
- *(temp->imageData+i*3+1) <<= 2;
- *(temp->imageData+i*3+0) <<= 3;
- }
- </span>
2、RGB565转成bmp图像保存下来,使用OpenCV函数加载
- /**********************RBG565 TO BMP*************************************/
- struct tagBITMAPFILEHEADER{
- unsigned long bfSize;
- unsigned long bfLeft;
- unsigned long bfOffBits;
- };
- struct tagBITMAPINFOHEADER{
- unsigned long biSize;
- unsigned long bmpWidth;
- unsigned long bmpHeight;
- unsigned short biPlanes;
- unsigned short bicolors;
- unsigned long isCompressed;
- unsigned long biMapSize;
- unsigned long biHorizontal;
- unsigned long biVertical;
- unsigned long biusedcolors;
- unsigned long biimportcolors;
- };
- int writebmp(unsigned short *bmp,int height,int width,char *filepath)
- {
- int i,j,size;
- int fd;
- struct tagBITMAPFILEHEADER bfhead;
- struct tagBITMAPINFOHEADER binfohead;
- size=height*width;
- bfhead.bfSize=0x36+size*2;
- bfhead.bfLeft=0;
- bfhead.bfOffBits=0x36;
- binfohead.biSize=0x28;
- binfohead.bmpWidth=width;
- binfohead.bmpHeight=height;
- binfohead.biPlanes=1;
- binfohead.bicolors=0x10;
- binfohead.isCompressed=0;
- binfohead.biMapSize=size*2;
- binfohead.biHorizontal=0x0b13;
- binfohead.biVertical=0x0b13;
- binfohead.biusedcolors=0;
- binfohead.biimportcolors=0;
- if(access(filepath,F_OK)!=0) //For the first time
- {
- fd=open(filepath,O_CREAT |O_RDWR);
- write(fd,"BM",2);
- i=write(fd,&bfhead,sizeof(struct tagBITMAPFILEHEADER)); //Write filehead
- i=write(fd,&binfohead,sizeof(struct tagBITMAPINFOHEADER)); //Write infohead
- i=write(fd,bmp,size*2); //Write bitmap
- // lseek(fd,SEEK_SET,4); //move th point
- }
- else
- {
- fd=open(filepath,O_RDWR);
- int headsize=sizeof(struct tagBITMAPFILEHEADER)+sizeof(struct tagBITMAPINFOHEADER);
- lseek(fd,headsize,SEEK_SET);
- write(fd,bmp,size*2); //Write bitmap
- }
- return 1;
- }
- int grab(unsigned short *buff1)
- {
- unsigned short bmp[WIDTH*HEIGHT];
- int i,j;
- /*RBG565_TO_RGB555*/
- for(i=0;i<HEIGHT;i++)
- for(j=0;j<WIDTH;j++)
- {
- *(bmp+i*WIDTH+j)=((*(buff1+i*WIDTH+j)&0xf800)>>1)|((*(buff1+i*WIDTH+j)&0x07c0)>>1)|(*(buff1+i*WIDTH+j)&0x1f);
- //printf("%x\t",*(bmp+i*WIDTH+j));
- }
- i=HEIGHT,j=WIDTH;
- writebmp(bmp, i, j,"/process"); //抓图保存在为/process.bmp
- }
- /***********************************************************/
3、RAW RGB排列成RGB24
网上有教程。
4、YUV转成JPEG图片,使用OpenCV函数加载。下面给出转换代码
源文件
- #include "yuyv_covert_jpeg.h"
- typedef mjpg_destination_mgr *mjpg_dest_ptr;
- struct buffer * buffers = NULL;
- FILE *file_fd;
- METHODDEF(void) init_destination(j_compress_ptr cinfo)
- {
- mjpg_dest_ptr dest = (mjpg_dest_ptr) cinfo->dest;
- dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof(JOCTET));
- *(dest->written) = 0;
- dest->pub.next_output_byte = dest->buffer;
- dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
- }
- METHODDEF(boolean) empty_output_buffer(j_compress_ptr cinfo)
- {
- mjpg_dest_ptr dest = (mjpg_dest_ptr) cinfo->dest;
- memcpy(dest->outbuffer_cursor, dest->buffer, OUTPUT_BUF_SIZE);
- dest->outbuffer_cursor += OUTPUT_BUF_SIZE;
- *(dest->written) += OUTPUT_BUF_SIZE;
- dest->pub.next_output_byte = dest->buffer;
- dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
- return TRUE;
- }
- METHODDEF(void) term_destination(j_compress_ptr cinfo)
- {
- mjpg_dest_ptr dest = (mjpg_dest_ptr) cinfo->dest;
- size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
- /* Write any data remaining in the buffer */
- memcpy(dest->outbuffer_cursor, dest->buffer, datacount);
- dest->outbuffer_cursor += datacount;
- *(dest->written) += datacount;
- }
- void dest_buffer(j_compress_ptr cinfo, unsigned char *buffer, int size, int *written)
- {
- mjpg_dest_ptr dest;
- if (cinfo->dest == NULL) {
- cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(mjpg_destination_mgr));
- }
- dest = (mjpg_dest_ptr)cinfo->dest;
- dest->pub.init_destination = init_destination;
- dest->pub.empty_output_buffer = empty_output_buffer;
- dest->pub.term_destination = term_destination;
- dest->outbuffer = buffer;
- dest->outbuffer_size = size;
- dest->outbuffer_cursor = buffer;
- dest->written = written;
- }
- //摄像头采集的YUYV格式转换为JPEG格式
- int compress_yuyv_to_jpeg(unsigned char *buf, unsigned char *buffer, int size, int quality)
- {
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- JSAMPROW row_pointer[1];
- unsigned char *line_buffer, *yuyv;
- int z;
- static int written;
- line_buffer = (unsigned char*)calloc (WIDTH * 3, 1);
- yuyv = buf;//将YUYV格式的图片数据赋给YUYV指针
- //printf("compress start...\n");
- cinfo.err = jpeg_std_error (&jerr);
- jpeg_create_compress (&cinfo);
- /* jpeg_stdio_dest (&cinfo, file); */
- dest_buffer(&cinfo, buffer, size, &written);
- cinfo.image_width = WIDTH;
- cinfo.image_height = HEIGHT;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
- jpeg_set_defaults (&cinfo);
- jpeg_set_quality (&cinfo, quality, TRUE);
- jpeg_start_compress (&cinfo, TRUE);
- z = 0;
- while (cinfo.next_scanline < HEIGHT) {
- int x;
- unsigned char *ptr = line_buffer;
- for (x = 0; x < WIDTH; x++) {
- int r, g, b;
- int y, u, v;
- if (!z)
- y = yuyv[0] << 8;
- else
- y = yuyv[2] << 8;
- u = yuyv[1] - 128;
- v = yuyv[3] - 128;
- r = (y + (359 * v)) >> 8;
- g = (y - (88 * u) - (183 * v)) >> 8;
- b = (y + (454 * u)) >> 8;
- *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
- *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
- *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);
- if (z++) {
- z = 0;
- yuyv += 4;
- }
- }
- row_pointer[0] = line_buffer;
- jpeg_write_scanlines (&cinfo, row_pointer, 1);
- }
- jpeg_finish_compress (&cinfo);
- jpeg_destroy_compress (&cinfo);
- free (line_buffer);
- return (written);
- }
头文件
- #ifndef __YVYV2JPEG__
- #define __YVYV2JPEG__
- extern "C" {
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <getopt.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <errno.h>
- #include <malloc.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/mman.h>
- #include <sys/ioctl.h>
- #include <asm/types.h>
- #include <linux/videodev2.h>
- #include <jpeglib.h>
- #define OUTPUT_BUF_SIZE 4096
- #define WIDTH 320
- #define HEIGHT 240
- struct buffer {
- void *start;
- size_t length;
- };
- typedef struct {
- struct jpeg_destination_mgr pub;
- JOCTET * buffer;
- unsigned char *outbuffer;
- int outbuffer_size;
- unsigned char *outbuffer_cursor;
- int *written;
- } mjpg_destination_mgr;
- METHODDEF(void) init_destination(j_compress_ptr cinfo);
- METHODDEF(boolean) empty_output_buffer(j_compress_ptr cinfo);
- METHODDEF(void) term_destination(j_compress_ptr cinfo);
- void dest_buffer(j_compress_ptr cinfo, unsigned char *buffer, int size, int *written);
- //摄像头采集的YUYV格式转换为JPEG格式
- int compress_yuyv_to_jpeg(unsigned char *buf, unsigned char *buffer, int size, int quality);
- }
- #endif