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= =。暂时无法解决这个问题,不过分割的思想已经有了 == 希望有用
额,刚刚修改了一下,可以使用了,不要问我修改了哪里,都是微不足道的地方,太不认真了,需要的可以直接用啦

猜你喜欢

转载自blog.csdn.net/qq_21747841/article/details/78424439