在qt上OpenCV处理OV9650采集的图像

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

 

typedef struct _IplImage
{
int nSize;         /* IplImage大小 */
int ID;            /* 版本 (=0)*/
int nChannels;     /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */
int alphaChannel; /* 被OpenCV忽略 */
int depth;         /* 像素的位深度,主要有以下支持格式: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,IPL_DEPTH_16S, IPL_DEPTH_32S,
IPL_DEPTH_32F 和IPL_DEPTH_64F */
char colorModel[4]; /* 被OpenCV忽略 */
char channelSeq[4]; /* 同上 */
int dataOrder;     /* 0 - 交叉存取 颜色通道, 1 - 分开的颜色通道.
只有cvCreateImage可以创建交叉存取图像 */
int origin;        /*图像原点位置: 0表示顶-左结构,1表示底-左结构 */
int align;         /* 图像行排列方式 (4 or 8),在 OpenCV 被忽略,使用 widthStep 代替 */
int width;        /* 图像宽像素数 */
int height;        /* 图像高像素数*/
struct _IplROI *roi; /* 图像感兴趣区域,当该值非空时,
只对该区域进行处理 */
struct _IplImage *maskROI; /* 在 OpenCV中必须为NULL */
void *imageId;     /* 同上*/
struct _IplTileInfo *tileInfo; /*同上*/
int imageSize;     /* 图像数据大小(在交叉存取格式下ImageSize=image->height*image->widthStep),单位字节*/
char *imageData;    /* 指向排列的图像数据 */
int widthStep;     /* 排列的图像行大小,以 字节为单位 */
int BorderMode[4]; /* 边际结束模式, 在 OpenCV 被忽略*/
int BorderConst[4]; /* 同上 */
char *imageDataOrigin; /*   指针指向一个不同的图像 数据结构(不是必须排列的),是为了纠正图像 内存分配准备的 */
} IplImage;

    所以我们只需要创建一个深度为8,通道数为3的IplImage结构:

      IplImage* image = cvCreateImage(cvSize(WIDTH*HEIHT), 8, 3),然后再把IplImage结构的数据数组指针*imageData给下面的转换函数,把转换成的RGB24数据放到imageData数组里就行了。

 

    1、RGB565转IlpImage

         思路:先把RGB565中的每个分量放到一个字节里面,这样就转成了RGB24见下图:

在qt上OpenCV处理OV9650采集的图像_第1张图片  

那么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 


 

   

你可能感兴趣的:(qt,opencv,OV9650)