libjpeg庫的簡單使用,rgb565與rgb888互轉,以及色塊的尋找

最近用的攝像頭OV2640攝像頭,支持RGB565、JPEG、YUV和YCbCr格式的輸出,想要對採集的圖像進行色塊識別,這樣一般需要用到RGB格式的輸出會比較好處理,數字圖像處理中常用的採用模型是RGB(紅,綠,藍)模型和HSV(色調,飽和度,亮度),RGB廣泛應用於彩色監視器和彩色視頻攝像機,我們平時的圖片一般都是RGB模型。別人是RGB的LCD屏幕作爲上位機,而我卻沒有LCD屏幕作爲上位機,輸出JPEG我可以存爲.jpg爲後綴的文件,輸出RGB565的數據不好將圖片保存下來,存RGB格式一般存爲bmp位圖,就想着既然板子都是作爲客戶端採集圖像傳出來,在服務器端將JPEG的數據轉換成RGB數據在做色塊識別的處理,就瞭解到libjpeg這個庫,libjpeg是一款功能強大的開源jpeg圖像庫工具軟件,jpeg是一個國際圖像壓縮標準,圖像的後綴一般爲jpeg或者jpg,利用libjpeg可以讀取jpeg圖像數據,libjpeg庫是用於編碼數據爲jpeg格式或者解碼jpeg格式圖片的常用庫。

既然傳出來的數據是JPEG,這裏需要做的就是JPEG的解碼,下面簡單的說說libjpeg庫的使用:

一、libjpeg庫的簡單使用

1、設置出錯處理函數並初始化編解碼結構對象

 在libjpeg庫中,實現了默認錯誤處理函數,當錯誤發生時,比如如果內存不足(非常可能發生,後面會介紹)等,則默認錯誤處理函數將會調用exit函數結束整個進程,詳細內容可以參考jerror.c文件。在C語言中沒有C++的異常處理機制,但是提供了setjmp和longjmp機制來實現類似的功能,設置完出錯處理就初始化編解碼結構對象

編碼:

 /*  Step 1: allocate and initialize JPEG compression object */

    cinfo.err = jpeg_std_error(&jerr);

    /*  Now we can initialize the JPEG compression object. */

jpeg_create_compress(&cinfo);

解碼:

/*  We set up the normal JPEG error routines, then override error_exit. */

 cinfo.err = jpeg_std_error(&jerr);

/*  Now we can initialize the JPEG decompression object. */

jpeg_create_decompress(&cinfo);

2、初始化源數據

 在libjpeg庫中僅僅提供了文件作爲輸入數據的接口,在example.c中代碼如下:jpeg_stdio_src(&cinfo, infile);

3、讀取jpeg文件的頭信息

調用jpeg_read_header(&cinfo, TRUE)讀取jpeg文件頭信息,這個和初始化解碼對象一樣,是必須要調用的,是約定

    (void) jpeg_read_header(&cinfo, TRUE);

    /*  源信息 */

    printf("image_width = %d\n", cinfo.image_width);

    printf("image_height = %d\n", cinfo.image_height);

    printf("num_components = %d\n", cinfo.num_components);

4、設置解碼參數

很多情況下,這步非常重要。比如設置輸出格式,設置scale(縮放)等等功能都是在這一步設置。參數設置通過修改上步得到cinfo的值來實現。這裏簡單介紹一下一些常用的字段。out_color_space:輸出的顏色格式,libjpeg定義如下:

typedef enum {  

    JCS_UNKNOWN,        /* error/unspecified */  

    JCS_GRAYSCALE,        /* monochrome */  

    JCS_RGB,        /* red/green/blue */  

    JCS_YCbCr,        /* Y/Cb/Cr (also known as YUV) */  

    JCS_CMYK,        /* C/M/Y/K */  

    JCS_YCCK,        /* Y/Cb/Cr/K */   

 } J_COLOR_SPACE;

不設置的話通常就是JCS_RGB,RGB888的格式,除此之外,還可以設置縮放大小等,scale_num,scale_denom:因爲實際的顯示設備千變萬化,我們可能需要根據實際情況對輸出數據進行一些縮放才能夠顯示。libjpeg支持對輸出數據進行縮放(scale),這個變量就是用來設置縮放的參數。

mem:可以指定內存管理相關的內容,比如分配和釋放內存,指定libjpeg可以使用的最大內存。默認情況下不同的平臺下面都有一個libjpeg默認最大可用內存值,比如Android平臺上面該值爲10000000L(10M),請參考jmemxxxx.c文件中的DEFAULT_MAX_MEM,瞭解不同平臺的默認最大內存值。通過修改mem->pub.max_memory_to_use的值,庫的使用者可以自定義libjpeg可以使用的最大內存值。

5、開始解碼

經過前面的參數設置,接着調用jpeg_start_decompress(&cinfo);開始解碼。

6、對解碼出來的數據做處理

    /*  Step 6: while (scan lines remain to be read) */

    /*            jpeg_read_scanlines(...); */


    while (cinfo.output_scanline < cinfo.output_height)

    {

        row_pointer[0] = & rdata[(cinfo.output_scanline)*cinfo.image_width*cinfo.num_components];

        jpeg_read_scanlines(&cinfo,row_pointer ,1);

        //(void) jpeg_read_scanlines(&cinfo, buffer, 1);

        /*  Assume put_scanline_someplace wants a pointer and sample count. */

        //put_scanline_someplace(buffer[0], row_stride);

    }

解碼出來的數據是一行一行的,我這裏讀到rdata裏面,這裏根據個人需求改。

解碼JPEG文件輸出RGB888數據到out_buf

int read_JPEG_file (char * filename, unsigned char *out_buf,int size)

{

    struct jpeg_decompress_struct           cinfo;

    struct jpeg_error_mgr                   jerr;

    /*  More stuff */

    FILE                                    *infile;                /*  source file */

    int                                     row_stride;               /*  physical row width in output buffer */

    unsigned char                           *rdata;

    JSAMPROW                                row_pointer[1];

    int                                     image_size = 0 ;





    if ((infile = fopen(filename, "rb")) == NULL)

    {

        fprintf(stderr, "can't open %s\n", filename);

        return -1;

    }



    /*  Step 1: allocate and initialize JPEG decompression object */



    /*  We set up the normal JPEG error routines, then override error_exit. */

    cinfo.err = jpeg_std_error(&jerr);

    /*  Now we can initialize the JPEG decompression object. */

    jpeg_create_decompress(&cinfo);



    /*  Step 2: specify data source (eg, a file) */



    jpeg_stdio_src(&cinfo, infile);



    /*  Step 3: read file parameters with jpeg_read_header() */



    (void) jpeg_read_header(&cinfo, TRUE);

    /*  源信息 */

    printf("image_width = %d\n", cinfo.image_width);

    printf("image_height = %d\n", cinfo.image_height);

    printf("num_components = %d\n", cinfo.num_components);

    image_size = cinfo.image_width*cinfo.image_height*cinfo.num_components ;

    //傳進來的字符數組沒有足夠大的空間

    if(size < image_size )

    {

        printf("buf size too small!\n") ;

        return -2 ;

    }

    /*   分配內存存儲字節   */

    rdata=(unsigned char*)calloc(image_size,1);


    /*  Step 4: set parameters for decompression */



    //設置輸出的顏色類型

    cinfo.out_color_space=JCS_RGB;



    /*  Step 5: Start decompressor */



    (void) jpeg_start_decompress(&cinfo);

    /*  輸出的圖象的信息 */

    printf("output_width = %d\n", cinfo.output_width);

    printf("output_height = %d\n", cinfo.output_height);

    printf("output_components = %d\n", cinfo.output_components);//解壓的是rgb,故爲3元素



    /*  JSAMPLEs per row in output buffer */

    row_stride = cinfo.output_width * cinfo.output_components;//一行的數據長度

    /*  Make a one-row-high sample array that will go away when done with image */



    /*  Step 6: while (scan lines remain to be read) */

    /*            jpeg_read_scanlines(...); */



    while (cinfo.output_scanline < cinfo.output_height)

    {

        row_pointer[0] = & rdata[(cinfo.output_scanline)*cinfo.image_width*cinfo.num_components];

        jpeg_read_scanlines(&cinfo,row_pointer ,1);

        //(void) jpeg_read_scanlines(&cinfo, buffer, 1);

        /*  Assume put_scanline_someplace wants a pointer and sample count. */

        //put_scanline_someplace(buffer[0], row_stride);

    }



    memcpy(out_buf, rdata, image_size) ;

    free(rdata) ;



    (void) jpeg_finish_decompress(&cinfo);

    /*  Step 8: Release JPEG decompression object */



    /*  This is an important step since it will release a good deal of memory. */

    jpeg_destroy_decompress(&cinfo);



    fclose(infile);



    /*  And we're done! */

    return image_size;

}

將RGB888數據編碼保存生成文件

int write_JPEG_file (char * filename,unsigned char *image_buffer, int image_width, int image_height, int quality )

{

    struct jpeg_compress_struct cinfo;

    struct jpeg_error_mgr jerr;

    /*  More stuff */

    FILE * outfile;               /*  target file */

    JSAMPROW row_pointer[1];      /*  pointer to JSAMPLE row[s] */

    int row_stride;               /*  physical row width in image buffer */



    /*  Step 1: allocate and initialize JPEG compression object */

    cinfo.err = jpeg_std_error(&jerr);

    /*  Now we can initialize the JPEG compression object. */

    jpeg_create_compress(&cinfo);



    /*  Step 2: specify data destination (eg, a file) */

    /*  Note: steps 2 and 3 can be done in either order. */



    if ((outfile = fopen(filename, "w+")) == NULL) {

        fprintf(stderr, "can't open %s\n", filename);

        return -1;

    }

    jpeg_stdio_dest(&cinfo, outfile);



    /*  Step 3: set parameters for compression */

    cinfo.image_width = image_width;      /*  image width and height, in pixels */

    cinfo.image_height = image_height;

    cinfo.input_components = 3;           /*  # of color components per pixel */

    cinfo.in_color_space = JCS_RGB;       /*  colorspace of input image */



    jpeg_set_defaults(&cinfo);

    jpeg_set_quality(&cinfo, quality, TRUE /*  limit to baseline-JPEG values */);



    /*  Step 4: Start compressor */



    jpeg_start_compress(&cinfo, TRUE);



    /*  Step 5: while (scan lines remain to be written) */

    row_stride = image_width * 3; /*  JSAMPLEs per row in image_buffer */



    while (cinfo.next_scanline < cinfo.image_height) {

        row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];

        (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);

    }



    /*  Step 6: Finish compression */



    jpeg_finish_compress(&cinfo);

    /*  After finish_compress, we can close the output file. */

    fclose(outfile);



    /*  Step 7: release JPEG compression object */



    /*  This is an important step since it will release a good deal of memory. */

    jpeg_destroy_compress(&cinfo);



    /*  And we're done! */

    return 0 ;

}

參考:https://www.iteye.com/blog/canlynet-1433259

 

二、RGB888與RGB565互相轉換

在我們的計算機中圖像是以RGB888格式顯示圖像的,24位圖每個像素保存了32bit的數據,即RGB888+Alpha,Alpha就是半透明填充字節……但是對於真彩的圖像而言,肉眼在16bit的時候已經難以分辨了,因此,有些時候,可以講RGB888轉換爲RGB565來存儲,減少了存儲器的容量的同時,降低了數據量

1、RGB888->RGB565

方法只要提取相應單色高位即可(R5 G6 B5),但會導致低位的缺失,影響精度,而且無法恢復。

2、RGB565->RGB888

方法只要補充相應單色低位即可(R3 G2 B3)。

這裏做的就是簡單的轉換,就會有精度的丟失,如果要求精度可能就要做量化補償

RGB888用unsigned int 32位字節存儲

0

0

0

0

0

0

0

0

R7

R6

R5

R4

R3

R2

R1

R0

G7

G6

G5

G4

G3

G2

G1

G0

B7

B6

B5

B4

B3

B2

B1

B0

 

RGB565用unsigned short 16位字節存儲

R7

R6

R5

R4

R3

G7

G6

G5

G4

G3

G2

B7

B6

B5

B4

B3

 

 

rgb888rgb565

/* *

 *   RGB888用unsigned int 32位字節存儲:

 *    0   0   0   0   0   0 R7  R6  R5  R4  R3  R2  R1  R0  G7  G6  G5  G4  G3  G2  G1  G0  B7  B6  B5  B4  B3  B2  B1  B0

 *   RGB565用unsigned short 16位字節存儲

 *      R7 R6  R5  R4  R3  G7  G6  G5  G4  G3  G2  B7  B6  B5  B4  B3

 * */

int  rgb888torgb565(unsigned char* rgb888_buf, int rgb888_size, unsigned short *rgb565_buf, int rgb565_size)

{

    int                         i = 0 ;

    unsigned char               Red = 0 ;

    unsigned char               Green = 0 ;

    unsigned char               Blue = 0 ;

    int                         count = 0 ;



    if(rgb888_buf == NULL || rgb888_size <= 0 || rgb565_buf == NULL || rgb565_size <= 0 || (rgb565_size < (rgb888_size/3)*2 ) )

    {

        printf("Invail input parameter in %s\n", __FUNCTION__) ;

        return -1 ;

    }

    for(i = 0; i<rgb888_size; i += 3)

    {

        Red = rgb888_buf[i] >> 3;

        Green = rgb888_buf[i+1] >> 2 ;

        Blue = rgb888_buf[i+2] >> 3;

        

        rgb565_buf[count++] = ( (Red<<11)|(Green<<5)|(Blue) ) ;

    }



    return count ;

}

RGB565轉RGB888

int rgb565torgb888(unsigned short *rgb565_buf, int rgb565_size,unsigned char*rgb888_buf, int rgb888_size)

{

    int                         i = 0 ;

    unsigned char               Red = 0 ;

    unsigned char               Green = 0 ;

    unsigned char               Blue = 0 ;

    int                         count = 0 ;



    if(rgb565_buf == NULL || rgb565_size <= 0|| rgb888_buf == NULL || rgb888_size <= 0 )

    {

        printf("Invaild input parameter in %s\n",__FUNCTION__) ;

        return -1 ;

    }

    for(i=0; i<rgb565_size; i++)

    {

        // 獲取RGB單色,並填充低位

        Red = (rgb565_buf[i] & RGB565_RED) >> 8 ;

        Green = (rgb565_buf[i] & RGB565_GREEN) >> 3 ;

        Blue = (rgb565_buf[i] & RGB565_BLUE) << 3 ;

        // 連接

        rgb888_buf[count++] = Red ;

        rgb888_buf[count++] = Green ;

        rgb888_buf[count++] = Blue ;

    }


    return count ;

}

參考:https://blog.csdn.net/oxunfeng/article/details/9635513

三、色塊識別

最後就是色塊的識別,這裏是從STM32代碼搬過來用的

 

兩個字節表示一個RGB圖像像素

/**************************************************

尋找色塊參數

RED_MIN 紅色分量最小值

RED_MAX 紅色分量最大值

GREEN_MIN 綠色分量最小值

GREEN_MAX綠色分量最大值

BLUE_MIN 藍色分量最小值

BLUE_MAX 藍色分量最大值

Ball_W_MIN£ 球寬度最小值

Ball_H_MIN 球高度最小值

Ball_W_MAX 球寬度最大值

Ball_H_MAX 球高度最大值

**************************************************/

int BALL_RED_MIN=16;

int BALL_RED_MAX=31;



int BALL_GREEN_MIN=0;

int BALL_GREEN_MAX=25;



int BALL_BLUE_MIN=0;

int BALL_BLUE_MAX=18;



//小球的大小

int Ball_W_MIN=5;

int Ball_H_MIN=5;

int Ball_W_MAX=100;

int Ball_H_MAX=100;

/******************

匹配小球色塊

******************/

unsigned char Ball_Match_Color(unsigned short colorRGB565)

{

    unsigned char R,G,B;//拆分顏色

    R=(colorRGB565>>11)&0x1f;//右移11位取低五位爲R

    G=(colorRGB565>>5)&0x3f;//右移5位後取六位爲G

    B=colorRGB565&0x1f;//取第五位爲B

    

    if((R>=BALL_RED_MIN)&&(R<=BALL_RED_MAX) && (G>=BALL_GREEN_MIN)&&(G<=BALL_GREEN_MAX) && (B>=BALL_BLUE_MIN)&&(B<=BALL_BLUE_MAX))

        return 1;//符合這個球最小顏色分量以及大小返回1

    else

        return 0;

}

/****************************

找色塊中心大小

******************************/

unsigned char Find_Center_Size(unsigned short *p , unsigned char valid_x , unsigned char valid_y , unsigned char *sx , unsigned char *ex , unsigned char *sy , unsigned char *ey)

{

    unsigned char repeat_num=2;//中心尋找重複次數

    unsigned char step=1;//跨越步數

    

    float error_endure=0.3f;//可容忍誤差比例

    unsigned char error_endure_num=3;

    

    unsigned char find_num=0,error_num=0;//通過個數和出錯個數

   

    unsigned char x_min=0,x_max=0;

    unsigned char y_min=0,y_max=0;

    unsigned char centre_x=0,centre_y=0;//中心點    

    centre_x=valid_x;

    centre_y=valid_y;

    

    while(repeat_num--)//重複尋找中心

    {

        while(1)//X減小方向尋找邊界

        {

            find_num+=step;

            if((centre_x-find_num)<0)//超邊界,跳出循環

            {

                x_min=0;//x_min記錄

                find_num=0;

                error_num=0;

                break;

            }

            

            if(!Ball_Match_Color(p[centre_y*camera_W+centre_x-find_num]))//不匹配點

                error_num++;//不匹配點計數

            //超容忍誤差,跳出循環

            if(error_num>error_endure_num && ((float)error_num/(float)find_num)>error_endure)

            {

                x_min=centre_x-find_num;//x_min記錄

                find_num=0;

                error_num=0;

                break;

            }  

        }
 

        while(1)//X增加方向尋找邊界

        {

            find_num+=step;

            if((centre_x+find_num)>=camera_W)//超邊界,跳出循環

            {

                x_max=camera_W-1;//x_max記錄

                find_num=0;

                error_num=0;

                break;

            }

            

            if(!Ball_Match_Color(p[centre_y*camera_W+centre_x+find_num]))//不匹配點

                error_num++;//不匹配點計數

            //超出誤差容忍範圍,跳出循環

            if(error_num>error_endure_num && ((float)error_num/(float)find_num)>error_endure)

            {

                x_max=centre_x+find_num;//x_max記錄

                find_num=0;

                error_num=0;

                break;

            }  

        }

        

        while(1)//Y減小方向尋找邊界

        {

            find_num+=step;

            if((centre_y-find_num)<0)//超出邊界,跳出循環

            {

                y_min=0;//y_min記錄

                find_num=0;

                error_num=0;

                break;

            }

            

            if(!Ball_Match_Color(p[(centre_y-find_num)*camera_W+centre_x]))//不匹配點計數

                error_num++;

            //超出誤差容忍範圍,跳出循環

            if(error_num>error_endure_num && ((float)error_num/(float)find_num)>error_endure)

            {

                y_min=centre_y-find_num;//y_min記錄

                find_num=0;

                error_num=0;

                break;

            }  

        }

        

        while(1)//Y增加方向尋找邊界

        {

            find_num+=step;

            if((centre_y+find_num)>=camera_H)//超出邊界,跳出循環

            {

                y_max=camera_H-1;//y_max記錄

                find_num=0;

                error_num=0;

                break;

            }

            

            if(!Ball_Match_Color(p[(centre_y+find_num)*camera_W+centre_x]))//不匹配點計數

                error_num++;

            //超出誤差容忍範圍,跳出循環

            if(error_num>error_endure_num && ((float)error_num/(float)find_num)>error_endure)

            {

                y_max=centre_y+find_num;//y_max記錄

                find_num=0;

                error_num=0;

                break;

            }  

        }

        

        //四個方向找完計算中心點位置

        centre_x=(x_min+x_max)/2;

        centre_y=(y_min+y_max)/2;

    }

    

        if((x_max-x_min)>Ball_W_MIN && (x_max-x_min)<Ball_W_MAX && (y_max-y_min)>Ball_H_MIN && (y_max-y_min)<Ball_H_MAX )//大小匹配

        {

            *sx=x_min;

            *ex=x_max;

            *sy=y_min;

            *ey=y_max;

            return 1;//大小匹配成功

        }

        else

        {

            return 0;//大小匹配失敗

        }

}




/***************************

在一幀RGB圖像中尋找色塊

***************************/

unsigned char Find_Ball(unsigned short *p , unsigned char start_x , unsigned char start_y , unsigned char *sx , unsigned char *ex , unsigned char *sy , unsigned char *ey)

{

    unsigned char step=2;

    unsigned char ball_sx,ball_ex,ball_sy,ball_ey;

    int x=0,y=0;

    unsigned char DIS=0;//向外拓展的距離

    unsigned char up_err=0,down_err=0,left_err=0,right_err=0;

    

    while(!up_err || !down_err || !left_err || !right_err)//圖像還沒遍歷完,就不斷尋找

    {

        DIS+=step;//向外拓展一圈

        

        //在矩形框下邊界尋找

        if((start_y-DIS)>=0)//下邊界存在判定

        {

            for(x=start_x-DIS;x<start_x+DIS;x+=step)

            {

                if(x<0)x=0;//超右邊界

                if(x>camera_W)break;//超左邊界

                

                if(Ball_Match_Color(p[(start_y-DIS)*camera_W+x]))//匹配到的點

                {

//從這個點找到匹配大小的色塊

                    if(Find_Center_Size(p,x,start_y-DIS,&ball_sx,&ball_ex,&ball_sy,&ball_ey))

                    {

                        *sx=ball_sx;

                        *ex=ball_ex;

                        *sy=ball_sy;

                        *ey=ball_ey;

                        return 1;//匹配成功

                    }

                    else

                    {

                        x+=2;

                    }

                }

            }

        }

        else

        {

            down_err=1;

        }

        

        

        //矩形框上邊界尋找

        if((start_y+DIS)<camera_H)//上邊界存在判定

        {

            for(x=start_x-DIS;x<start_x+DIS;x+=step)

            {

                if(x<0)x=0;//超右邊界

                if(x>camera_W)break;//超左邊界

            

                if(Ball_Match_Color(p[(start_y+DIS)*camera_W+x]))//匹配到的點

                {     //從這個點找到匹配大小的色塊

                    if(Find_Center_Size(p,x,start_y+DIS,&ball_sx,&ball_ex,&ball_sy,&ball_ey))

                    {

                        *sx=ball_sx;

                        *ex=ball_ex;

                        *sy=ball_sy;

                        *ey=ball_ey;

                        return 1;//匹配成功

                    }

                    else

                    {

                        x+=2;

                    }

                

                }

            }

        }

        else

        {

            up_err=1;

        }

        

        //矩形框左邊界尋找

        if((start_x+DIS)<camera_W)//左邊界存在判定

        {

            for(y=start_y-DIS;y<start_y+DIS;y+=step)

            {

                if(y<0)y=0;//超下邊界處理

                if(y>camera_H)break;//超上邊界處理

                

                if(Ball_Match_Color(p[y*camera_W+start_x+DIS]))//匹配到的點

                { //從這個點找到了匹配大小的色塊

                    if(Find_Center_Size(p,start_x+DIS,y,&ball_sx,&ball_ex,&ball_sy,&ball_ey))

                    {

                        *sx=ball_sx;

                        *ex=ball_ex;

                        *sy=ball_sy;

                        *ey=ball_ey;

                        return 1;//匹配成功

                    }

                    else

                    {

                        y+=2;

                    }

                

                }

            }

        }

        else

        {

            left_err=1;

        }

        

        

        //矩形框右邊界尋找

        if((start_x-DIS)>0)//右邊界存在判定

        {

            for(y=start_y-DIS;y<start_y+DIS;y+=step)

            {

                if(y<0)y=0;//超下邊界處理

                if(y>camera_H)break;//超上邊界處理

                

                if(Ball_Match_Color(p[y*camera_W+start_x-DIS]))//匹配到的點

                { //從這個點找到了匹配大小的色塊

                    if(Find_Center_Size(p,start_x-DIS,y,&ball_sx,&ball_ex,&ball_sy,&ball_ey))

                    {

                        *sx=ball_sx;

                        *ex=ball_ex;

                        *sy=ball_sy;

                        *ey=ball_ey;

                        return 1;//匹配成功

                    }

                    else

                    {

                        y+=2;

                    }

              

                }

            }

        }

        else

        {

            right_err=1;

        }

    }

    

    return 0;//匹配失敗

}





/**************************

畫框

******************************/

void Draw_square(unsigned short *p , int start_x , int end_x , int start_y , int end_y , unsigned short color)

{

    int x1,x2,y1,y2;

    int x,y;

    

    if(start_x==end_x || start_y==end_y)return;//如果不符合就直接返回

    /* start_x與end_x哪個大哪個賦值x2,小的賦值x1 */

    if(start_x<end_x)

    {

        x1=start_x;

        x2=end_x;

    }

    else

    {

        x2=start_x;

        x1=end_x;

    }

    /* start_y與end_y哪個大哪個賦值y2,小的賦值y1 */

    if(start_y<end_y)

    {

        y1=start_y;

        y2=end_y;

    }

    else

    {

        y2=start_y;

        y1=end_y;

    }

    //超出邊界就取邊界值

    if(x1<0)x1=0;

    if(x2>(camera_W-1))x2=camera_W-1;

    if(y1<0)y1=0;

    if(y2>(camera_H-1))y2=camera_H-1;

    

    for(x=x1;x<x2;x++)

    {

        p[start_y*camera_W+x]=color;

        p[end_y*camera_W+x]=color;  

    }

    

    for(y=y1;y<y2;y++)

    {

        p[y*camera_W+start_x]=color;

        p[y*camera_W+end_x]=color;  

    }

}



/*查找色塊並畫框標出*/

unsigned char Ball_Task(unsigned short *p)

{

    unsigned char sx,ex,sy,ey;

    

    if(Find_Ball(p,Ball_X,Ball_Y,&sx,&ex,&sy,&ey))

    {

        Ball_X=(sx+ex)/2;

        Ball_Y=(sy+ey)/2;

        Draw_square(p,sx,ex,sy,ey,0x001F);   //0x001F爲RGB565的藍色

        return 1;

    }

    else

    {

        return 0;

    }

}

 

這些函數都有了之後最後就是主函數對這些函數的調用了


int main(int argc, char **argv)

{

    int                     rv =  -1 ;

    int                     result =  0 ;

    unsigned char           buffer[320*240*3] ;

    unsigned short          rgb565_buf[320*240] ;

    unsigned char           rgb888_buf[320*240*3] ;

    

    memset(buffer,0, sizeof(buffer)) ;

    rv = read_JPEG_file ("test.jpg",buffer,sizeof(buffer)) ;//讀取OV2640採集到的JPEG圖像解碼爲RGB888數據

    if(rv < 0)

    {

        printf("read_JPEG_file() failed\n") ;

        return -1 ;

    }

    printf("jpeg decompress OK, after decompress size = %d\n",rv) ;



    memset(rgb565_buf,0,sizeof(rgb565_buf)) ;

    rv = rgb888torgb565(buffer, rv, rgb565_buf, sizeof(rgb565_buf)) ;//RGB888轉RGB565

    printf("after rgb888 to rgb565,rgb565 size=%d\n",rv) ;



    result = Ball_Task(rgb565_buf) ;//查找符合的色塊

    printf("Return value=%d\n",result) ;



    memset(rgb888_buf,0,sizeof(rgb888_buf)) ;

    rv = rgb565torgb888(rgb565_buf, rv,rgb888_buf, sizeof(rgb888_buf)) ;//RGB888轉RGB565

    printf("after rgb565 to rgb888,rgb888 size=%d\n",rv) ;

   

    write_JPEG_file("new_test.jpg",rgb888_buf,160,120,75) ;//RGB888編碼保存jpg圖片文件

    printf("rgb write jpeg compress finish!\n") ;



    return 0 ;



}/* End Of Main */

最後就是運行出來輸出的圖像,尋找紅色色塊,色塊參數閾值還沒調好,RGB圖像處理時候,容易受到光照變化或陰影的影響,就像最後的效果圖,而且RGB通道並不能很好地反映出物體具體的顏色信息 ,也可能還有RGB轉換、JPEG解碼導致精度丟失造成的原因

 

 

如果是顏色比較突兀的就比較好識別

 

 

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