验证darknet中前处理做图像缩放(双线性内插值法)scale的算法效果

该博客验证了darknet在图像处理中使用双线性内插值法进行NV12格式图像缩放的效果。通过一系列的图像缩放操作,包括352x352、100x200、32x32和16x16,展示了算法在不同尺寸下对图像的缩放能力。同时,还讨论了FFMPEG在像素格式转换中的作用,以及在特定嵌入式平台上的应用。

关于图形scale原理的介绍可以参考下面的文章

用最近邻插值(Nearest Neighbor interpolation)进行图片缩放_papaofdoudou的博客-优快云博客_最近邻插值算法原理个图片缩放的两种常见算法: 最近邻域内插法(Nearest Neighbor interpolation) 双向性内插法(bilinear interpolation)本文主要讲述最近邻插值(Nearest Neighbor interpolation算法的原理以及python实现基本原理最简单的图像缩放算法就是最近邻插值。顾名思义,就是将目标图像各点的像素值设为源图像中与其最近的点。算法优点在与简单、速度快。如下图所示,一个4*4的图片缩放为8*8的图片。步骤: ...https://blog.youkuaiyun.com/tugouxp/article/details/120110219关于darknet前处理的流程,尤其是图形SCALE部分,可以参考下面的文章:

Darknet框架解读_papaofdoudou的博客-优快云博客1.test_detector的调用路径:这里重点介绍load_alphabet函数:根据代码,这里是从data/labels/目录装载png图片,图片有8*95=760这些图片都是ASCII码,比如我们打开编号为65和97的PNG图片,看以下内容,分别是A和a.怀疑最后绘框上面的Label字母就是来源于这里,这样就不依赖于系统字库了,我们确认一下,用反证法。如果我们将所有b的图片替换成a的图片,那么bicycle应该能变成aicycle的,我们测试一下:我们..https://blog.youkuaiyun.com/tugouxp/article/details/120941276?spm=1001.2014.3001.5502DARKNET中使用的缩放算法是双线性内插值法,这里就实际验证一把DARKNET 中scale的工作原理与效果:

首先这是一张原图,画面中的是南京明城墙玄武门,玄武湖的正门。18年国庆带娃回学校的时候留念,一段令人怀念的岁月。

图像参数如下,可以看到是YUV420格式的,尺寸为1920*1080。

 首先我们将其转换为RAW YUV444P 格式,目的是为了方便做SCALE,转换工具就用FFMPEG

ffmpeg -i 165823915.jpg -pix_fmt yuv444p xuanwumen.yuv444p.yuv

转换后的RAW YUV图像,可以通过ffplay命令查看,只是由于这个时候没有PARSER信息,需要手动输入图像的分辨率:

ffplay -pix_fmt yuv444p -f rawvideo -video_size 1920x1080 ./xuanwumen.yuv444p.yuv

至此,万事俱备,只欠代码了。

我们目的是要对YUV图作SCALE,由于YUV图形是NV12格式的,我们需要对Y和U部分和V部分分别作SCALE。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <sys/ioctl.h>

#define DBG(fmt, ...)   do { printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)

typedef struct image {
    int w;
    int h;
    int c;
    unsigned char *data;
} image;

static void dump_memory(uint8_t *buf, int32_t len)
{
    int i;
 
    printf("\n\rdump file memory:");
    for (i = 0; i < len; i ++)
    {
        if ((i % 16) == 0)
        {
            printf("\n\r%p: ", buf + i);
        }
        printf("0x%02x ", buf[i]);
    }

    printf("\n\r");

    return;
}

image make_empty_image(int w, int h, int c)
{
    image out;             
    out.data = 0;
    out.h = h;                                                                                                                                                                                              
    out.w = w;
    out.c = c;
    return out;
}

image copy_image(image p)
{
	image copy = p;
    copy.data = (unsigned char*)calloc(p.h * p.w * p.c, sizeof(float));
    memcpy(copy.data, p.data, p.h*p.w*p.c*sizeof(float));
    return copy;
}

image make_image(int w, int h, int c)
{
    image out = make_empty_image(w,h,c);
    out.data = (unsigned char*)calloc(h * w * c, sizeof(char));
    return out;
}

static void set_pixel(image m, int x, int y, int c, float val)
{
    if (x < 0 || y < 0 || c < 0 || x >= m.w || y >= m.h || c >= m.c) return;

    assert(x < m.w && y < m.h && c < m.c);
    m.data[c*m.h*m.w + y*m.w + x] = val;
}

static float get_pixel(image m, int x, int y, int c)
{ 
    assert(x < m.w && y < m.h && c < m.c);
    return m.data[c*m.h*m.w + y*m.w + x];
} 

void free_image(image m)
{   
    if(m.data){
       free(m.data);
    }
} 

static void add_pixel(image m, int x, int y, int c, float val)
{            
    assert(x < m.w && y < m.h && c < m.c);
    m.data[c*m.h*m.w + y*m.w + x] += val;
}

image resize_image(image im, int w, int h)
{                                         
    if (im.w == w && im.h == h) return copy_image(im);

    image resized = make_image(w, h, im.c);
    image part = make_image(w, im.h, im.c);
    int r, c, k;                          
    float w_scale = (float)(im.w - 1) / (w - 1);
    float h_scale = (float)(im.h - 1) / (h - 1);
    for(k = 0; k < im.c; ++k){            
        for(r = 0; r < im.h; ++r){        
            for(c = 0; c < w; ++c){       
                float val = 0;            
                if(c == w-1 || im.w == 1){
                    val = get_pixel(im, im.w-1, r, k);
                } else {                  
                    float sx = c*w_scale; 
                    int ix = (int) sx;    
                    float dx = sx - ix;   
                    val = (1 - dx) * get_pixel(im, ix, r, k) + dx * get_pixel(im, ix+1, r, k);
                }                         
                set_pixel(part, c, r, k, val);
            }                             
        }                                 
    }                                     
    for(k = 0; k < im.c; ++k){            
        for(r = 0; r < h; ++r){           
           float sy = r*h_scale;         
           int iy = (int) sy;            
           float dy = sy - iy;           
           for(c = 0; c < w; ++c){       
               float val = (1-dy) * get_pixel(part, c, iy, k);
               set_pixel(resized, c, r, k, val);
           }                             
           if(r == h-1 || im.h == 1) continue;
           for(c = 0; c < w; ++c){       
               float val = dy * get_pixel(part, c, iy+1, k);
               add_pixel(resized, c, r, k, val);
           }                             
        }                                 
    }                                     

    free_image(part);                     
    return resized;                       
}

int main(int argc, char **argv)
{
	FILE *file;
	int width, height;
 
	DBG("in");

	if(argc != 4)
	{
		DBG("input error, you should use this program like that: program xxxx.yuv width height.");
		exit(-1);
	}
 
	width  = atoi(argv[2]);
	height = atoi(argv[3]);
 
	DBG("scale to width %d, height %d.", width, height);
	
	file = fopen(argv[1], "rb");
	if(file == NULL)
	{
		DBG("fatal error, open file %s failure, please check the file status.", argv[1]);
		exit(-1);
	}
 
	fseek(file, 0, SEEK_END);
	int filelen = ftell(file);
	
	DBG("file %s len %d byets.", argv[1], filelen);
 
	unsigned char *p = malloc(filelen);
	if(p == NULL)
	{
		DBG("malloc buffer failure for %s len %d.", argv[1], filelen);
		exit(-1);
	}
 
	memset(p, 0x00, filelen);
	fseek(file, 0, SEEK_SET);
 
	if(fread(p, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}

    fclose(file);
 
	dump_memory(p, 32);
	dump_memory(p + filelen - 32, 32);

    image orig_Y = make_image(1920,1080, 1);
    image orig_U = make_image(1920,1080, 1);
    image orig_V = make_image(1920,1080, 1);
    memcpy(orig_Y.data, p + 0*1920*1080,1920*1080);
    memcpy(orig_U.data, p + 1*1920*1080,1920*1080);
    memcpy(orig_V.data, p + 2*1920*1080,1920*1080);

    image outputy = resize_image(orig_Y, width,height);
    image outputu = resize_image(orig_U, width,height);
    image outputv = resize_image(orig_V, width,height);

	file = fopen("./output.yuv", "wb+");
	if(file == NULL)
	{
		DBG("fatal error, open output file failure, please check the file status.");
		exit(-1);
	}
    
	unsigned char *o = malloc(width * height);
	if(o == NULL)
	{
		DBG("malloc output buffer failure.");
		exit(-1);
	}

	memset(o, 0x00, width * height);
	memcpy(o, outputy.data, width * height);
   
	filelen = width * height;
	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}
	memset(o, 0xb0, width * height);
	memcpy(o, outputu.data, width * height);

	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}

	memset(o, 0xb0, width * height);
	memcpy(o, outputv.data, width * height);

	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}

	fflush(file);
	fsync(fileno(file));
	fclose(file);

    return 0;
}

执行如下命令:

$gcc main.c
$ffmpeg -i 165823915.jpg -pix_fmt yuv444p xuanwumen.yuv444p.yuv
$./a.out xuanwumen.yuv444p.yuv 352 352
$ffplay -pix_fmt yuv444p -f rawvideo -video_size 352x352 ./output.yuv

SCALE 352X352后输出结果:

 SCALE到 100*200的大小:

$./a.out xuanwumen.yuv444p.yuv 100 200
$ffplay -pix_fmt yuv444p -f rawvideo -video_size 100x200 ./output.yuv

scale 32*32大小:

 scale 16*16大小:

上面在程序中固定写死了输入图像的尺寸,这不是一个好做法,下面的程序将输入尺寸设置为可变的,由程序输入。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <sys/ioctl.h>

#define DBG(fmt, ...)   do { printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)

typedef struct image {
    int w;
    int h;
    int c;
    unsigned char *data;
} image;

static void dump_memory(uint8_t *buf, int32_t len)
{
    int i;
 
    printf("\n\rdump file memory:");
    for (i = 0; i < len; i ++)
    {
        if ((i % 16) == 0)
        {
            printf("\n\r%p: ", buf + i);
        }
        printf("0x%02x ", buf[i]);
    }

    printf("\n\r");

    return;
}

image make_empty_image(int w, int h, int c)
{
    image out;             
    out.data = 0;
    out.h = h;                                                                                                                                                                                              
    out.w = w;
    out.c = c;
    return out;
}

image copy_image(image p)
{
	image copy = p;
    copy.data = (unsigned char*)calloc(p.h * p.w * p.c, sizeof(float));
    memcpy(copy.data, p.data, p.h*p.w*p.c*sizeof(float));
    return copy;
}

image make_image(int w, int h, int c)
{
    image out = make_empty_image(w,h,c);
    out.data = (unsigned char*)calloc(h * w * c, sizeof(char));
    return out;
}

static void set_pixel(image m, int x, int y, int c, float val)
{
    if (x < 0 || y < 0 || c < 0 || x >= m.w || y >= m.h || c >= m.c) return;

    assert(x < m.w && y < m.h && c < m.c);
    m.data[c*m.h*m.w + y*m.w + x] = val;
}

static float get_pixel(image m, int x, int y, int c)
{ 
    assert(x < m.w && y < m.h && c < m.c);
    return m.data[c*m.h*m.w + y*m.w + x];
} 

void free_image(image m)
{   
    if(m.data){
       free(m.data);
    }
} 

static void add_pixel(image m, int x, int y, int c, float val)
{            
    assert(x < m.w && y < m.h && c < m.c);
    m.data[c*m.h*m.w + y*m.w + x] += val;
}

image resize_image(image im, int w, int h)
{                                         
    if (im.w == w && im.h == h) return copy_image(im);

    image resized = make_image(w, h, im.c);
    image part = make_image(w, im.h, im.c);
    int r, c, k;                          
    float w_scale = (float)(im.w - 1) / (w - 1);
    float h_scale = (float)(im.h - 1) / (h - 1);
    for(k = 0; k < im.c; ++k){            
        for(r = 0; r < im.h; ++r){        
            for(c = 0; c < w; ++c){       
                float val = 0;            
                if(c == w-1 || im.w == 1){
                    val = get_pixel(im, im.w-1, r, k);
                } else {                  
                    float sx = c*w_scale; 
                    int ix = (int) sx;    
                    float dx = sx - ix;   
                    val = (1 - dx) * get_pixel(im, ix, r, k) + dx * get_pixel(im, ix+1, r, k);
                }                         
                set_pixel(part, c, r, k, val);
            }                             
        }                                 
    }                                     
    for(k = 0; k < im.c; ++k){            
        for(r = 0; r < h; ++r){           
           float sy = r*h_scale;         
           int iy = (int) sy;            
           float dy = sy - iy;           
           for(c = 0; c < w; ++c){       
               float val = (1-dy) * get_pixel(part, c, iy, k);
               set_pixel(resized, c, r, k, val);
           }                             
           if(r == h-1 || im.h == 1) continue;
           for(c = 0; c < w; ++c){       
               float val = dy * get_pixel(part, c, iy+1, k);
               add_pixel(resized, c, r, k, val);
           }                             
        }                                 
    }                                     

    free_image(part);                     
    return resized;                       
}

int main(int argc, char **argv)
{
	FILE *file;
	int width, height, input_width, input_height;
 
	DBG("in");

	if(argc != 6)
	{
		DBG("input error, you should use this program like that: program xxxx.yuv width height.");
		exit(-1);
	}
 
	width  = atoi(argv[2]);
	height = atoi(argv[3]);
	input_width  = atoi(argv[4]);
	input_height = atoi(argv[5]);
 
	DBG("scale to width %d, height %d.", width, height);
	
	file = fopen(argv[1], "rb");
	if(file == NULL)
	{
		DBG("fatal error, open file %s failure, please check the file status.", argv[1]);
		exit(-1);
	}
 
	fseek(file, 0, SEEK_END);
	int filelen = ftell(file);
	
	DBG("file %s len %d byets.", argv[1], filelen);
 
	unsigned char *p = malloc(filelen);
	if(p == NULL)
	{
		DBG("malloc buffer failure for %s len %d.", argv[1], filelen);
		exit(-1);
	}
 
	memset(p, 0x00, filelen);
	fseek(file, 0, SEEK_SET);
 
	if(fread(p, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}

    fclose(file);
 
	dump_memory(p, 32);
	dump_memory(p + filelen - 32, 32);

    image orig_Y = make_image(input_width,input_height, 1);
    image orig_U = make_image(input_width,input_height, 1);
    image orig_V = make_image(input_width,input_height, 1);
    memcpy(orig_Y.data, p + 0*input_width*input_height,input_width*input_height);
    memcpy(orig_U.data, p + 1*input_width*input_height,input_width*input_height);
    memcpy(orig_V.data, p + 2*input_width*input_height,input_width*input_height);

    image outputy = resize_image(orig_Y, width,height);
    image outputu = resize_image(orig_U, width,height);
    image outputv = resize_image(orig_V, width,height);

	file = fopen("./output.yuv", "wb+");
	if(file == NULL)
	{
		DBG("fatal error, open output file failure, please check the file status.");
		exit(-1);
	}
    
	unsigned char *o = malloc(width * height);
	if(o == NULL)
	{
		DBG("malloc output buffer failure.");
		exit(-1);
	}

	memset(o, 0x00, width * height);
	memcpy(o, outputy.data, width * height);
   
	filelen = width * height;
	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}
	memset(o, 0xb0, width * height);
	memcpy(o, outputu.data, width * height);

	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}

	memset(o, 0xb0, width * height);
	memcpy(o, outputv.data, width * height);

	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}

	fflush(file);
	fsync(fileno(file));
	fclose(file);

    return 0;
}

拓展

ffmpeg是图像除了领域的瑞士军刀,总是在最关键的地方发挥关键的作用。上面我们用FFMPEG命令对图像的像素格式进行转换,那么FFMPEG支持哪些像素格式之间的转换呢?貌似HELP命令或者帮助文档中没有给出明显的信息,只能看代码了,根据关键词"YUV444P",我们在pixdesc.c中找到了AVPixFmtDescriptor这个结构体的定义,根据名字来看,我们找的是正确的:

经过整理后,得到的像素格式结果如下,竟然有这么多。

        .name = "yuv420p",
        .name = "yuyv422",
        .name = "yvyu422",
        .name = "y210le",
        .name = "y210be",
        .name = "rgb24",
        .name = "bgr24",
        .name = "x2rgb10le",
        .name = "x2rgb10be",
        .name = "x2bgr10le",
        .name = "x2bgr10be",
        .name = "yuv422p",
        .name = "yuv444p",
        .name = "yuv410p",
        .name = "yuv411p",
        .name = "yuvj411p",
        .name = "gray",
        .name = "monow",
        .name = "monob",
        .name = "pal8",
        .name = "yuvj420p",
        .name = "yuvj422p",
        .name = "yuvj444p",
        .name = "xvmc",
        .name = "uyvy422",
        .name = "uyyvyy411",
        .name = "bgr8",
        .name = "bgr4",
        .name = "bgr4_byte",
        .name = "rgb8",
        .name = "rgb4",
        .name = "rgb4_byte",
        .name = "nv12",
        .name = "nv21",
        .name = "argb",
        .name = "rgba",
        .name = "abgr",
        .name = "bgra",
        .name = "0rgb",
        .name = "rgb0",
        .name = "0bgr",
        .name = "bgr0",
        .name = "gray9be",
        .name = "gray9le",
        .name = "gray10be",
        .name = "gray10le",
        .name = "gray12be",
        .name = "gray12le",
        .name = "gray14be",
        .name = "gray14le",
        .name = "gray16be",
        .name = "gray16le",
        .name = "yuv440p",
        .name = "yuvj440p",
        .name = "yuv440p10le",
        .name = "yuv440p10be",
        .name = "yuv440p12le",
        .name = "yuv440p12be",
        .name = "yuva420p",
        .name = "yuva422p",
        .name = "yuva444p",
        .name = "yuva420p9be",
        .name = "yuva420p9le",
        .name = "yuva422p9be",
        .name = "yuva422p9le",
        .name = "yuva444p9be",
        .name = "yuva444p9le",
        .name = "yuva420p10be",
        .name = "yuva420p10le",
        .name = "yuva422p10be",
        .name = "yuva422p10le",
        .name = "yuva444p10be",
        .name = "yuva444p10le",
        .name = "yuva420p16be",
        .name = "yuva420p16le",
        .name = "yuva422p16be",
        .name = "yuva422p16le",
        .name = "yuva444p16be",
        .name = "yuva444p16le",
        .name = "rgb48be",
        .name = "rgb48le",
        .name = "rgba64be",
        .name = "rgba64le",
        .name = "rgb565be",
        .name = "rgb565le",
        .name = "rgb555be",
        .name = "rgb555le",
        .name = "rgb444be",
        .name = "rgb444le",
        .name = "bgr48be",
        .name = "bgr48le",
        .name = "bgra64be",
        .name = "bgra64le",
        .name = "bgr565be",
        .name = "bgr565le",
        .name = "bgr555be",
        .name = "bgr555le",
        .name = "bgr444be",
        .name = "bgr444le",
        .name = "vaapi",
        .name = "yuv420p9le",
        .name = "yuv420p9be",
        .name = "yuv420p10le",
        .name = "yuv420p10be",
        .name = "yuv420p12le",
        .name = "yuv420p12be",
        .name = "yuv420p14le",
        .name = "yuv420p14be",
        .name = "yuv420p16le",
        .name = "yuv420p16be",
        .name = "yuv422p9le",
        .name = "yuv422p9be",
        .name = "yuv422p10le",
        .name = "yuv422p10be",
        .name = "yuv422p12le",
        .name = "yuv422p12be",
        .name = "yuv422p14le",
        .name = "yuv422p14be",
        .name = "yuv422p16le",
        .name = "yuv422p16be",
        .name = "yuv444p16le",
        .name = "yuv444p16be",
        .name = "yuv444p10le",
        .name = "yuv444p10be",
        .name = "yuv444p9le",
        .name = "yuv444p9be",
        .name = "yuv444p12le",
        .name = "yuv444p12be",
        .name = "yuv444p14le",
        .name = "yuv444p14be",
        .name = "d3d11va_vld",
        .name = "dxva2_vld",
        .name = "ya8",
        .name = "ya16le",
        .name = "ya16be",
        .name = "videotoolbox_vld",
        .name = "gbrp",
        .name = "gbrp9le",
        .name = "gbrp9be",
        .name = "gbrp10le",
        .name = "gbrp10be",
        .name = "gbrp12le",
        .name = "gbrp12be",
        .name = "gbrp14le",
        .name = "gbrp14be",
        .name = "gbrp16le",
        .name = "gbrp16be",
        .name = "gbrap",
        .name = "gbrap16le",
        .name = "gbrap16be",
        .name = "vdpau",
        .name = "xyz12le",
        .name = "xyz12be",
        .name = "bayer_bggr8",
        .name = "bayer_bggr16le",
        .name = "bayer_bggr16be",
        .name = "bayer_rggb8",
        .name = "bayer_rggb16le",
        .name = "bayer_rggb16be",
        .name = "bayer_gbrg8",
        .name = "bayer_gbrg16le",
        .name = "bayer_gbrg16be",
        .name = "bayer_grbg8",
        .name = "bayer_grbg16le",
        .name = "bayer_grbg16be",
        .name = "nv16",
        .name = "nv20le",
        .name = "nv20be",
        .name = "qsv",
        .name = "mediacodec",
        .name = "mmal",
        .name = "cuda",
        .name = "ayuv64le",
        .name = "ayuv64be",
        .name = "p010le",
        .name = "p010be",
        .name = "p016le",
        .name = "p016be",
        .name = "gbrap12le",
        .name = "gbrap12be",
        .name = "gbrap10le",
        .name = "gbrap10be",
        .name = "d3d11",
        .name = "gbrpf32be",
        .name = "gbrpf32le",
        .name = "gbrapf32be",
        .name = "gbrapf32le",
        .name = "drm_prime",
        .name = "grayf32be",
        .name = "grayf32le",
        .name = "yuva422p12be",
        .name = "yuva422p12le",
        .name = "yuva444p12be",
        .name = "yuva444p12le",
        .name = "nv24",
        .name = "nv42",
        .name = "vulkan",
        .name = "p210be",
        .name = "p210le",
        .name = "p410be",
        .name = "p410le",
        .name = "p216be",
        .name = "p216le",
        .name = "p416be",
        .name = "p416le",

以ARGB为例:

ffmpeg -i 165823915.jpg -pix_fmt argb xuanwumen.rgb
ffplay -pix_fmt argb -f rawvideo -video_size 1920x1080 xuanwumen.rgb

NV12格式缩放

前面验证的都是测试YUV三planner数据长度相等的格式,下面验证一下NV12。

首先,将一张图像转为NV12格式:

ffmpeg -i e253d6bd7ac64bde9e7f1fb09dc908b2.png -vf scale=1920:1080 output.jpg
ffmpeg -i output.jpg -pix_fmt nv12 sousuo.nv12.yuv

原图如下:

转为1920X1080的YUV后如下:

ffplay -pix_fmt nv12 -f rawvideo -video_size 1920x1080 ./sousuo.nv12.yuv

运行NV12缩放程序,将1920X1080的NV12转换为1280X720的NV12

./a.out sousuo.nv12.yuv 1280 720 1920 1080
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <sys/ioctl.h>
 
#define DBG(fmt, ...)   do { printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)
 
typedef struct image {
    int w;
    int h;
    int c;
    unsigned char *data;
} image;
 
static void dump_memory(uint8_t *buf, int32_t len)
{
    int i;
 
    printf("\n\rdump file memory:");
    for (i = 0; i < len; i ++)
    {
        if ((i % 16) == 0)
        {
            printf("\n\r%p: ", buf + i);
        }
        printf("0x%02x ", buf[i]);
    }
 
    printf("\n\r");
 
    return;
}
 
image make_empty_image(int w, int h, int c)
{
    image out;             
    out.data = 0;
    out.h = h;                                                                                                                                                                                              
    out.w = w;
    out.c = c;
    return out;
}
 
image copy_image(image p)
{
	image copy = p;
    copy.data = (unsigned char*)calloc(p.h * p.w * p.c, sizeof(float));
    memcpy(copy.data, p.data, p.h*p.w*p.c*sizeof(float));
    return copy;
}
 
image make_image(int w, int h, int c)
{
    image out = make_empty_image(w,h,c);
    out.data = (unsigned char*)calloc(h * w * c, sizeof(char));
    return out;
}
 
static void set_pixel(image m, int x, int y, int c, float val)
{
    if (x < 0 || y < 0 || c < 0 || x >= m.w || y >= m.h || c >= m.c) return;
 
    assert(x < m.w && y < m.h && c < m.c);
    m.data[c*m.h*m.w + y*m.w + x] = val;
}
 
static float get_pixel(image m, int x, int y, int c)
{ 
    assert(x < m.w && y < m.h && c < m.c);
    return m.data[c*m.h*m.w + y*m.w + x];
} 
 
void free_image(image m)
{   
    if(m.data){
       free(m.data);
    }
} 
 
static void add_pixel(image m, int x, int y, int c, float val)
{            
    assert(x < m.w && y < m.h && c < m.c);
    m.data[c*m.h*m.w + y*m.w + x] += val;
}
 
image resize_image(image im, int w, int h)
{                                         
    if (im.w == w && im.h == h) return copy_image(im);
 
    image resized = make_image(w, h, im.c);
    image part = make_image(w, im.h, im.c);
    int r, c, k;                          
    float w_scale = (float)(im.w - 1) / (w - 1);
    float h_scale = (float)(im.h - 1) / (h - 1);
    for(k = 0; k < im.c; ++k){            
        for(r = 0; r < im.h; ++r){        
            for(c = 0; c < w; ++c){       
                float val = 0;            
                if(c == w-1 || im.w == 1){
                    val = get_pixel(im, im.w-1, r, k);
                } else {                  
                    float sx = c*w_scale; 
                    int ix = (int) sx;    
                    float dx = sx - ix;   
                    val = (1 - dx) * get_pixel(im, ix, r, k) + dx * get_pixel(im, ix+1, r, k);
                }                         
                set_pixel(part, c, r, k, val);
            }                             
        }                                 
    }                                     
    for(k = 0; k < im.c; ++k){            
        for(r = 0; r < h; ++r){           
           float sy = r*h_scale;         
           int iy = (int) sy;            
           float dy = sy - iy;           
           for(c = 0; c < w; ++c){       
               float val = (1-dy) * get_pixel(part, c, iy, k);
               set_pixel(resized, c, r, k, val);
           }                             
           if(r == h-1 || im.h == 1) continue;
           for(c = 0; c < w; ++c){       
               float val = dy * get_pixel(part, c, iy+1, k);
               add_pixel(resized, c, r, k, val);
           }                             
        }                                 
    }                                     
 
    free_image(part);                     
    return resized;                       
}
 
int main(int argc, char **argv)
{
	FILE *file;
	int width, height, input_width, input_height;
 
	DBG("in");
 
	if(argc != 6)
	{
		DBG("input error, you should use this program like that: program xxxx.yuv width height.");
		exit(-1);
	}
 
	width  = atoi(argv[2]);
	height = atoi(argv[3]);
	input_width  = atoi(argv[4]);
	input_height = atoi(argv[5]);
 
	DBG("scale to width %d, height %d.", width, height);
	
	file = fopen(argv[1], "rb");
	if(file == NULL)
	{
		DBG("fatal error, open file %s failure, please check the file status.", argv[1]);
		exit(-1);
	}
 
	fseek(file, 0, SEEK_END);
	int filelen = ftell(file);
	
	DBG("file %s len %d byets.", argv[1], filelen);
 
	unsigned char *p = malloc(filelen);
	if(p == NULL)
	{
		DBG("malloc buffer failure for %s len %d.", argv[1], filelen);
		exit(-1);
	}
 
	memset(p, 0x00, filelen);
	fseek(file, 0, SEEK_SET);
 
	if(fread(p, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}
 
    fclose(file);
 
	dump_memory(p, 32);
	dump_memory(p + filelen - 32, 32);
 
    image orig_Y = make_image(input_width,input_height, 1);
    image orig_U = make_image(input_width/2,input_height/2, 1);
    image orig_V = make_image(input_width/2,input_height/2, 1);
    memcpy(orig_Y.data, p + 0*input_width*input_height,input_width*input_height);
    /*memcpy(orig_U.data, p + 1*input_width*input_height,input_width*input_height/4);*/
    /*memcpy(orig_V.data, p + input_width*input_height *5/4,input_width*input_height/4);*/

	int i;
    int j = 0, k = 0;
	for(i = input_width * input_height; i < input_width * input_height * 3 /2 ; i ++)
	{
       if(i % 2 == 0) 
           orig_V.data[j++] = p[i];
	   else
           orig_U.data[k++] = p[i];
	}
 
    image outputy = resize_image(orig_Y, width,height);
    image outputu = resize_image(orig_U, width/2,height/2);
    image outputv = resize_image(orig_V, width/2,height/2);

	int ksize = width * height / 2;
	unsigned char *uv = malloc(ksize);

	memset(uv, 0x00, ksize);
	j = k = 0;
	for(i = 0; i < ksize; i ++)
	{
       if(i % 2 == 0) 
           uv[i] = outputv.data[j++];
	   else
           uv[i] = outputu.data[k++];
	}

 
	file = fopen("./output.yuv", "wb+");
	if(file == NULL)
	{
		DBG("fatal error, open output file failure, please check the file status.");
		exit(-1);
	}
    
	unsigned char *o = malloc(width * height);
	if(o == NULL)
	{
		DBG("malloc output buffer failure.");
		exit(-1);
	}
 
	memset(o, 0x00, width * height);
	memcpy(o, outputy.data, width * height);
   
	filelen = width * height;
	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}

	filelen = ksize;
	memset(o, 0xb0, filelen);
	memcpy(o, uv,  filelen);
 
	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}
 
#if 0
	memset(o, 0xb0, filelen);
	memcpy(o, outputv.data, filelen);
 
	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}
 
#endif
	fflush(file);
	fsync(fileno(file));
	fclose(file);
 
    return 0;
}

 输出output.yuv,执行如下命令查看,缩放效果真的不错!

ffplay -pix_fmt nv12 -f rawvideo -video_size 1280x720 ./output.yuv

480/270->352/198

ffmpeg -i e253d6bd7ac64bde9e7f1fb09dc908b2.png -vf scale=480:270 output.jpg
ffmpeg -i output.jpg -pix_fmt nv12 sousuo.nv12.yuv
ffplay -pix_fmt nv12 -f rawvideo -video_size 480x270 ./sousuo.nv12.yuv 
./a.out sousuo.nv12.yuv 352 198 480 270
ffplay -pix_fmt nv12 -f rawvideo -video_size 352x198 ./output.yuv

352/198->480/270

ffmpeg -i e253d6bd7ac64bde9e7f1fb09dc908b2.png -vf scale=352:198 output.jpg
ffmpeg -i output.jpg -pix_fmt nv12 sousuo.nv12.yuv
ffplay -pix_fmt nv12 -f rawvideo -video_size 352x198 ./sousuo.nv12.yuv
./a.out sousuo.nv12.yuv 480 270 352 198
ffplay -pix_fmt nv12 -f rawvideo -video_size 480x270 ./output.yuv

 在某款嵌入式平台上成功应用的scale算法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <sys/ioctl.h>
 
#define DBG(fmt, ...)   do { printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)
 
typedef struct image {
    int w;
    int h;
    int c;
    unsigned char *data;
} image;
 
static void dump_memory(uint8_t *buf, int32_t len)
{
    int i;
 
    printf("\n\rdump file memory:");
    for (i = 0; i < len; i ++)
    {
        if ((i % 16) == 0)
        {
            printf("\n\r%p: ", buf + i);
        }
        printf("0x%02x ", buf[i]);
    }
 
    printf("\n\r");
 
    return;
}
 
image make_empty_image(int w, int h, int c)
{
    image out;             
    out.data = 0;
    out.h = h;                                                                                                                                                                                              
    out.w = w;
    out.c = c;
    return out;
}
 
image copy_image(image p)
{
	image copy = p;
    copy.data = (unsigned char*)calloc(p.h * p.w * p.c, sizeof(float));
    memcpy(copy.data, p.data, p.h*p.w*p.c*sizeof(float));
    return copy;
}
 
image make_image(int w, int h, int c)
{
    image out = make_empty_image(w,h,c);
    out.data = (unsigned char*)calloc(h * w * c, sizeof(char));
    return out;
}
 
static void set_pixel(image m, int x, int y, int c, float val)
{
    if (x < 0 || y < 0 || c < 0 || x >= m.w || y >= m.h || c >= m.c) return;
 
    assert(x < m.w && y < m.h && c < m.c);
    m.data[c*m.h*m.w + y*m.w + x] = val;
}
 
static float get_pixel(image m, int x, int y, int c)
{ 
    assert(x < m.w && y < m.h && c < m.c);
    return m.data[c*m.h*m.w + y*m.w + x];
} 
 
void free_image(image m)
{   
    if(m.data){
       free(m.data);
    }
} 
 
static void add_pixel(image m, int x, int y, int c, float val)
{            
    assert(x < m.w && y < m.h && c < m.c);
    m.data[c*m.h*m.w + y*m.w + x] += val;
}
 
image resize_image(image im, int w, int h)
{                                         
    if (im.w == w && im.h == h) return copy_image(im);
 
    image resized = make_image(w, h, im.c);
    image part = make_image(w, im.h, im.c);
    int r, c, k;                          
    float w_scale = (float)(im.w - 1) / (w - 1);
    float h_scale = (float)(im.h - 1) / (h - 1);
    for(k = 0; k < im.c; ++k){            
        for(r = 0; r < im.h; ++r){        
            for(c = 0; c < w; ++c){       
                float val = 0;            
                if(c == w-1 || im.w == 1){
                    val = get_pixel(im, im.w-1, r, k);
                } else {                  
                    float sx = c*w_scale; 
                    int ix = (int) sx;    
                    float dx = sx - ix;   
                    val = (1 - dx) * get_pixel(im, ix, r, k) + dx * get_pixel(im, ix+1, r, k);
                }                         
                set_pixel(part, c, r, k, val);
            }                             
        }                                 
    }                                     
    for(k = 0; k < im.c; ++k){            
        for(r = 0; r < h; ++r){           
           float sy = r*h_scale;         
           int iy = (int) sy;            
           float dy = sy - iy;           
           for(c = 0; c < w; ++c){       
               float val = (1-dy) * get_pixel(part, c, iy, k);
               set_pixel(resized, c, r, k, val);
           }                             
           if(r == h-1 || im.h == 1) continue;
           for(c = 0; c < w; ++c){       
               float val = dy * get_pixel(part, c, iy+1, k);
               add_pixel(resized, c, r, k, val);
           }                             
        }                                 
    }                                     
 
    free_image(part);                     
    return resized;                       
}
 
int main(int argc, char **argv)
{
	FILE *file;
	int width, height, input_width, input_height;
 
	DBG("in");
 
	if(argc != 6)
	{
		DBG("input error, you should use this program like that: program xxxx.yuv width height.");
		exit(-1);
	}
 
	width  = atoi(argv[2]);
	height = atoi(argv[3]);
	input_width  = atoi(argv[4]);
	input_height = atoi(argv[5]);
 
	DBG("scale to width %d, height %d.", width, height);
	
	file = fopen(argv[1], "rb");
	if(file == NULL)
	{
		DBG("fatal error, open file %s failure, please check the file status.", argv[1]);
		exit(-1);
	}
 
	fseek(file, 0, SEEK_END);
	int filelen = ftell(file);
	
	DBG("file %s len %d byets.", argv[1], filelen);
 
	unsigned char *p = malloc(filelen);
	if(p == NULL)
	{
		DBG("malloc buffer failure for %s len %d.", argv[1], filelen);
		exit(-1);
	}
 
	memset(p, 0x00, filelen);
	fseek(file, 0, SEEK_SET);
 
	if(fread(p, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}
 
    fclose(file);
 
	dump_memory(p, 32);
	dump_memory(p + filelen - 32, 32);
 
    image orig_Y = make_image(input_width,input_height, 1);
    image orig_U = make_image(input_width/2,input_height/2, 1);
    image orig_V = make_image(input_width/2,input_height/2, 1);
    memcpy(orig_Y.data, p + 0*input_width*input_height,input_width*input_height);
    /*memcpy(orig_U.data, p + 1*input_width*input_height,input_width*input_height/4);*/
    /*memcpy(orig_V.data, p + input_width*input_height *5/4,input_width*input_height/4);*/

	int i;
    int j = 0, k = 0;
	for(i = input_width * input_height; i < input_width * input_height * 3 /2 ; i ++)
	{
       if(i % 2 == 0) 
           orig_U.data[j++] = p[i];
	   else
           orig_V.data[k++] = p[i];
	}
 
    image outputy = resize_image(orig_Y, width,height);
    image outputu = resize_image(orig_U, width/2,height/2);
    image outputv = resize_image(orig_V, width/2,height/2);

	int ksize = width * height / 2;
	unsigned char *uv = malloc(ksize);

	memset(uv, 0x00, ksize);
	j = k = 0;
	for(i = 0; i < ksize; i ++)
	{
       if(i % 2 == 0) 
           uv[i] = outputu.data[j++];
	   else
           uv[i] = outputv.data[k++];
	}

 
	file = fopen("./output.yuv", "wb+");
	if(file == NULL)
	{
		DBG("fatal error, open output file failure, please check the file status.");
		exit(-1);
	}
    
	unsigned char *o = malloc(width * height);
	if(o == NULL)
	{
		DBG("malloc output buffer failure.");
		exit(-1);
	}
 
	memset(o, 0x00, width * height);
	memcpy(o, outputy.data, width * height);
   
	filelen = width * height;
	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}

	filelen = ksize;
	memset(o, 0xb0, filelen);
	memcpy(o, uv,  filelen);
 
	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}
 
#if 0
	memset(o, 0xb0, filelen);
	memcpy(o, outputv.data, filelen);
 
	if(fwrite(o, 1, filelen, file) != filelen)
	{
		DBG("read file failure, size wrong.");
		exit(-1);
	}
 
#endif
	fflush(file);
	fsync(fileno(file));
	fclose(file);
 
    return 0;
}

基于G2D硬件加速的SUNXI平台缩放实现代码:

下面代码已经应用在人脸检测模型算法中。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <memoryAdapter.h>
#include <ion_memmanager.h>
#include <plat_math.h>
#include <plat_log.h>
#include <utils/PIXEL_FORMAT_E_g2d_format_convert.h>
#include <linux/g2d_driver.h>
#include "hw_scale.h"

typedef struct
{
    unsigned long *p_virtaddr_y;
    unsigned long *p_virtaddr_uv;
    unsigned long *p_physaddr_y;
    unsigned long *p_physaddr_uv;
}ion_img_buff_t;

int g2d_mem_open(void)
{
    return ion_memOpen();
}

int g2d_mem_close(void)
{
    return ion_memClose();
}

static unsigned char* g2d_alloc_mem(unsigned int size)
{
    IonAllocAttr alloc_attr;
    memset(&alloc_attr, 0, sizeof(IonAllocAttr));

    alloc_attr.mLen           = size;
    alloc_attr.mAlign         = 0;
    alloc_attr.mIonHeapType   = IonHeapType_IOMMU;
    alloc_attr.mbSupportCache = 0;
    return ion_allocMem_extend(&alloc_attr);
}

static int g2d_free_mem(void *vir_ptr)
{
    return ion_freeMem(vir_ptr);
}

static unsigned int g2d_getphyaddr_by_viraddr(void *vir_ptr)
{
    return ion_getMemPhyAddr(vir_ptr);
}

static int g2d_flush_cache(void *vir_ptr, unsigned int size)
{
    return ion_flushCache(vir_ptr, size);
}

static ion_img_buff_t src;
static ion_img_buff_t dst;
int scale_picture_nv12_to_nv12_byg2d(const unsigned char *srcpic, int src_width, int src_height, unsigned char *dstpic, int dst_width, int dst_height, int g2d_fd)
{
    int ret = 0;
    static int mem_inited = 0;
    int size;
    g2d_blt_h blit;
    g2d_fmt_enh src_fmt, dst_fmt;

    if(mem_inited == 0)
    {
        size = ALIGN(src_width, 16) * ALIGN(src_height, 16);
        src.p_virtaddr_y  = (void*)g2d_alloc_mem(size);
        src.p_virtaddr_uv = (void*)g2d_alloc_mem(size/2);

        if(!src.p_virtaddr_y || !src.p_virtaddr_uv )
        {
            aloge("fatal error, ion malloc for src image failure.");
            goto EXIT;
        }

        src.p_physaddr_y  = (void *)g2d_getphyaddr_by_viraddr(src.p_virtaddr_y);
        src.p_physaddr_uv = (void *)g2d_getphyaddr_by_viraddr(src.p_virtaddr_uv);

        size = ALIGN(dst_width, 16) * ALIGN(dst_height, 16);
        dst.p_virtaddr_y  = (void*)g2d_alloc_mem(size);
        dst.p_virtaddr_uv = (void*)g2d_alloc_mem(size/2);

        if(!dst.p_virtaddr_y || !dst.p_virtaddr_uv )
        {
            aloge("fatal error, ion malloc for dst image failure.");
            goto EXIT;
        }

        dst.p_physaddr_y  = (void *)g2d_getphyaddr_by_viraddr(dst.p_virtaddr_y);
        dst.p_physaddr_uv = (void *)g2d_getphyaddr_by_viraddr(dst.p_virtaddr_uv);
        mem_inited = 1;
    }

    if(!src.p_virtaddr_y || !src.p_virtaddr_uv || !dst.p_virtaddr_y || !dst.p_virtaddr_uv)
    {
        aloge("src or dst buffer addr corrupted?");
        goto EXIT;
    }

    size = src_width*src_height;
    memcpy(src.p_virtaddr_y, srcpic, size);
    memcpy(src.p_virtaddr_uv, srcpic + size , size / 2);
    g2d_flush_cache(src.p_virtaddr_y, size);
    g2d_flush_cache(src.p_virtaddr_uv, size / 2);

    // MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420. nv12 format.
    ret = convert_PIXEL_FORMAT_E_to_g2d_fmt_enh(MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420 , &src_fmt);
    if(ret != SUCCESS)
    {
        aloge("fatal error, convert pixel fmt from video to g2d failure.");
        goto EXIT;
    }

    ret = convert_PIXEL_FORMAT_E_to_g2d_fmt_enh(MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420, &dst_fmt);
    if(ret != SUCCESS)
    {
        aloge("fatal error, convert pixel fmt from video to g2d failure.");
        goto EXIT;
    }

    memset(&blit, 0, sizeof(g2d_blt_h));
    blit.flag_h = G2D_BLT_NONE_H;

    blit.src_image_h.format      = src_fmt;
    blit.src_image_h.laddr[0]    = (unsigned long)src.p_physaddr_y;
    blit.src_image_h.laddr[1]    = (unsigned long)src.p_physaddr_uv;
    blit.src_image_h.laddr[2]    = (unsigned long)0;

    blit.src_image_h.width       = src_width;
    blit.src_image_h.height      = src_height;
    blit.src_image_h.align[0]    = 0;
    blit.src_image_h.align[1]    = 0;
    blit.src_image_h.align[2]    = 0;
    blit.src_image_h.clip_rect.x = 0;
    blit.src_image_h.clip_rect.y = 0;
    blit.src_image_h.clip_rect.w = src_width;
    blit.src_image_h.clip_rect.h = src_height;
    blit.src_image_h.gamut       = G2D_BT601;
    blit.src_image_h.bpremul     = 0;

    blit.src_image_h.mode         = G2D_PIXEL_ALPHA;
    blit.src_image_h.fd           = -1;
    blit.src_image_h.use_phy_addr = 1;

    blit.dst_image_h.format       = dst_fmt;
    blit.dst_image_h.laddr[0]     = (unsigned long)dst.p_physaddr_y;
    blit.dst_image_h.laddr[1]     = (unsigned long)dst.p_physaddr_uv;
    blit.dst_image_h.laddr[2]     = (unsigned long)0;

    blit.dst_image_h.width        = dst_width;
    blit.dst_image_h.height       = dst_height;
    blit.dst_image_h.align[0]     = 0;
    blit.dst_image_h.align[1]     = 0;
    blit.dst_image_h.align[2]     = 0;
    blit.dst_image_h.clip_rect.x  = 0;
    blit.dst_image_h.clip_rect.y  = 0;
    blit.dst_image_h.clip_rect.w  = dst_width;
    blit.dst_image_h.clip_rect.h  = dst_height;
    blit.dst_image_h.gamut        = G2D_BT601;
    blit.dst_image_h.bpremul      = 0;

    blit.dst_image_h.mode         = G2D_PIXEL_ALPHA;
    blit.dst_image_h.fd           = -1;
    blit.dst_image_h.use_phy_addr = 1;

    ret = ioctl(g2d_fd, G2D_CMD_BITBLT_H, (unsigned long)&blit);
    if(ret < 0)
    {
        aloge("fatal error! bit-block(image) transfer failed[%d]", ret);
        goto EXIT;
    }

    size = dst_width*dst_height;

    g2d_flush_cache(dst.p_virtaddr_y, size);
    g2d_flush_cache(dst.p_virtaddr_uv, size / 2);

    memcpy(dstpic, dst.p_virtaddr_y,  size);
    memcpy(dstpic + size, dst.p_virtaddr_uv, size / 2);

    return 0;

EXIT:
    if(src.p_virtaddr_y)
    {
        g2d_free_mem(src.p_virtaddr_y);
    }
    if(src.p_virtaddr_uv)
    {
        g2d_free_mem(src.p_virtaddr_uv);
    }
    if(dst.p_virtaddr_y)
    {
        g2d_free_mem(dst.p_virtaddr_y);
    }
    if(dst.p_virtaddr_uv)
    {
        g2d_free_mem(dst.p_virtaddr_uv);
    }

    memset(&src, 0x00, sizeof(src));
    memset(&dst, 0x00, sizeof(dst));

    return -1;
}

// dummy function,nothing need todo.
void scale_create_buffer(void)
{
    return;
}

void scale_destory_buffer(void)
{
    if(src.p_virtaddr_y)
    {
        g2d_free_mem(src.p_virtaddr_y);
    }
    if(src.p_virtaddr_uv)
    {
        g2d_free_mem(src.p_virtaddr_uv);
    }
    if(dst.p_virtaddr_y)
    {
        g2d_free_mem(dst.p_virtaddr_y);
    }
    if(dst.p_virtaddr_uv)
    {
        g2d_free_mem(dst.p_virtaddr_uv);
    }

    memset(&src, 0x00, sizeof(src));
    memset(&dst, 0x00, sizeof(dst));
    return;
}

名词释义:

像素格式中看到很多格式后面紧跟着字母P,SP,它们是什么意思呢?P代表planer,也就是平面,SP就是Semi Planer,翻译过来就是半平面。具体代表什么呢?

以YUV444P为例,P的意思是Y,U,V三个元素个占用一个平面,也就是三个平面,几何布局和内存中布局就是如下这个样子的:

而SP代表的半平面,顾名思义,就是平面不到3个,但也不能是1个,1个,因为YUV毕竟存在不同元,所以实际上就是2个平面,Y一个,UV合起来站占用一个.

YUV420SP格式的图像阵列,首先是所有Y值,然后是UV或者VU交替存储,NV12和NV21属于YUV420SP格式,是一种two-plane模式,即Y和UV分为两个plane,但是UV(CbCr)为交错存储,而不是分为三个平面,我们常用的NV12或者NV21都属于YUV420SP。

布局如下图所示:

我们最常见的YUV420P和YUV420SP都是基于4:2:0采样的,所以如果图片的宽为width,高为heigth,在内存中占的空间为width * height * 3 / 2。

YUV420P又叫plane平面模式Y , U , V分别在不同平面,也就是有三个平面,它是YUV标准格式4:2:0,主要分为:YU12和YV12, YUV420P其中前width * height的空间存放Y分量,接着width * height / 4存放U或者V分量,最后width * height / 4存放V或者U分量,根据UV顺序的不同,YUV420P又可以分为YV12和YU12

神经网络的输入一般是RGB24格式,而非ARGB格式,这点要注意。

参考:

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别_handy周的博客-优快云博客_yv12


结束!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值