网上移植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