网上移植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++; }
方式二:
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; }
下面是我根据第一种修改的代码:
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;
}
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