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