在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見下圖:

  

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


 

   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章