C語言學習筆記(8)——第一次個人實戰(YUV圖像分割)

很遺憾第一次實戰並沒有達到我想要的效果,想要達到的目的是把一個n幀的3840*1920的YUV420p的圖像均分成64份。
首先來看一下YUV4:2:0格式的存儲格式,首先可以參照大神寫的http://blog.csdn.net/lin453701006/article/details/53053185這篇博文了解一下YUV格式。
簡單來講,假設有個4*4的像素點,對於420P而言,不妨假設這四個像素點Y值都爲1,U值爲2,V值爲3
那麼YUV的實際存儲方式爲
1111
1111
1111
1111
22
22
33
33
也就是一個4*4的矩陣加兩個長寬爲這個矩陣一半的矩陣。
下面就是實際的代碼:
首先是主函數,其中while(1)和readsize控制按幀讀取,讀取到3840*1920的一幀後,要把它們分成64個小文件輸出,因此設置了ij表示第i行第j列的第幾個小塊。其中filename函數可以根據ij設置輸出的文件名。YUVslice函數的功能是將圖像的64分之一放到output_buff中。

#include "YUV.h"
#define _CRT_SECURE_NO_WARNINGS  
#define IMAGEWIDTH  3840  //圖像的寬  
#define IMAGEHEIGHT 1920    //高  
#define NUM 64
//#define Y_SIZE           (IMAGEWIDTH*IMAGEHEIGHT) 
#define YUV420_SIZE    (Y_SIZE*3/2)       //4:2:0格式 

int main()
{
    FILE * input_yuvfile;    //輸入YUV420文件的指針 
    if (NULL == (input_yuvfile = fopen("Driving_in_Country_3840x1920_388p.yuv", "rb")))
    {
        printf("File input is can't open!\n");
        return -1;
    }
    int readsize;
    unsigned char *input_buff;
    input_buff = (unsigned char *)malloc(YUV420_SIZE * sizeof(unsigned char));


    while (1)
    {
        readsize = fread(input_buff, 1, YUV420_SIZE , input_yuvfile);
        if (readsize<YUV420_SIZE) //讀取的數據量少於YUV420_SIZE時跳出  
            break;

        FILE *fq = NULL;                
        for (int i = 0; i <= 7; i++)//i代表分成8*8之後的第幾行
        {
            for (int j = 0; j <= 7; j++)//j代表分成8*8之後的    
            {
                unsigned char *output_buff;
                output_buff = (unsigned char *)malloc(YUV420_SIZE * sizeof(unsigned char)/64);
                char output_yuvfile[15] = { 0 };
                filename(i, j, output_yuvfile);//設置輸出文件名
                YUVslice(i, j, input_buff, output_buff, IMAGEWIDTH, IMAGEHEIGHT);//將原圖的64分之一輸入到output_buff中
                fq = fopen(output_yuvfile, "a+");// 這裏打開寫入文件,注意使用的是a模式
                fwrite(output_buff, 1, YUV420_SIZE/64, fq);
                free(output_buff);
                output_buff = NULL;
                fclose(fq);
            }
        }   
    }
    free(input_buff);
    input_buff = NULL;
    fclose(input_yuvfile);
    return 0;
}

下面是函數的具體形式:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<malloc.h>  
#include<memory.h> 
#include <math.h>
#define _CRT_SECURE_NO_WARNINGS  
#define IMAGEWIDTH  3840  //圖像的寬  
#define IMAGEHEIGHT 1920    //高  
#define NUM 64
#define Y_SIZE          ( IMAGEWIDTH*IMAGEHEIGHT) 
#define YUV420_SIZE        (Y_SIZE*3/2)       //4:2:0格式 

char filename(int i, int j, char *output_yuvfile)
{
    //unsigned char frame_num[3];//標示輸出的是第幾幀    
    char output_yuvfile_i[3];//表示第幾行的塊
    char output_yuvfile_j[3];//表示第幾列的塊
    memset(output_yuvfile_i, 0, sizeof(output_yuvfile_i));
    memset(output_yuvfile_j, 0, sizeof(output_yuvfile_j));
    _itoa(i, output_yuvfile_i, 10);
    _itoa(j, output_yuvfile_j, 10);
    char outputfile_tail[5] = ".YUV";
    strcat(output_yuvfile, output_yuvfile_i);
    strcat(output_yuvfile, output_yuvfile_j);
    strcat(output_yuvfile, outputfile_tail);//得到要輸出的文件名
    return 0;

}

int YUVslice(int i,int j,unsigned char* input_buff,unsigned char* output_buff,int PIC_W,int  PIC_H)
{
    unsigned char *y_buf = NULL;
    y_buf = (unsigned char *)malloc(YUV420_SIZE * sizeof(unsigned char) / NUM);//y_buff是個大小爲原圖64分之一的數組
    if (y_buf == NULL)
    {
        printf("Error: malloc buf.\n");
        exit(1);
    }

    int h, v;
    //Y分量切割;  
    for (v = 0 + i*PIC_H / 8; v<PIC_H / 8 + i*PIC_H / 8; v++)
    {
        for (h = 0 + j*PIC_W / 8; h<PIC_W / 8 + j*PIC_W / 8; h++)
        {
            y_buf[(v - i*PIC_H / 8)*(PIC_W / 8) + h-j*PIC_W / 8] = input_buff[(v*PIC_W + h)];//每次調用YUVslice函數就將原圖第v行第第h列的Y值拷貝到y_buff數組的前PIC_H / sqrt(NUM)*PIC_W / sqrt(NUM)個值中。
        }
    }

    for (v = 0 + i*PIC_H / 16; v<PIC_H / 16 + i*PIC_H / 16; v++)
    {
        for (h = 0 + j*PIC_W / 16; h<PIC_W / 16 + j*PIC_W / 16; h++)//這裏原理和Y相同,但是其長寬減半,且將uv的值拷貝到y_buff的(v - i*PIC_H / 16)*(PIC_W / 16) + h+偏移的位置
        {
            y_buf[Y_SIZE / 64 + (v - i*PIC_H / 16)*(PIC_W / 16) + h- i*PIC_H / 16] = input_buff[Y_SIZE + (v*PIC_W / 2 + h)];//U 
            y_buf[Y_SIZE * 5 / 256 + (v - i*PIC_H / 16)*(PIC_W / 16) + h- i*PIC_H / 16] = input_buff[Y_SIZE * 5 / 4 + (v*PIC_W / 2 + h)];//V
        }
    }

    memcpy(output_buff, y_buf, YUV420_SIZE / 64);

    free(y_buf);


    return 1;

}

爲什麼說是一個失敗的實戰呢,是因爲它可以輸出第一幀的左上角的64分之一圖像,但是無法輸出左上角第二個64分之一的圖像。使用斷點調試,發現在運行到i=0,j=1時,在YUVslice函數中input_buff的值沒有複製到y_buff中,而且,在運行到free (y_buff)時會彈出捕捉到一個break= =。暫時無法解決這個問題,不過分割的思想已經有了 == 希望有用
額,剛剛修改了一下,可以使用了,不要問我修改了哪裏,都是微不足道的地方,太不認真了,需要的可以直接用啦

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