YUV 任意尺寸缩放2011-11-20 16:52最近项目中遇到jpeg 图片缩放问题,libjpeg 只支持 1/8, 1/4, 1/2, 1/1 的缩小。而 ffplay 对 Jpeg, 视频的缩放貌似不支持。
于是经过断断续续的编码和思考,“基本上” 解决了YUV420P格式的缩放问题。
这里的“基本上”指的是:
1)它解决了视频全屏缩小问题,没有产生颜色偏移等问题;
2)YUV 按某一特定比例对静态图缩放后,颜色可能会变;
代码:
/*file:sdl_yuv.c
direct access yuv color space
author: ludi
gcc sdl_yuv.c rgb2yuv.c -g -DGEN_SDL_YUV_EXE `sdl-config --cflags --libs`
quick and dirty, but it is correct:
void drawHLine_(SDL_Overlay *yuv, int sx, int sy, int len)
{
int w = yuv->pitches[0];
memset(yuv->pixels[0]+sy*w + sx, 255, len*1);
memset(yuv->pixels[1]+(sy*w + 2*sx)/4, 255, (len+1)/2);
memset(yuv->pixels[2]+(sy*w + 2*sx)/4, 255, (len+1)/2);
}
todo: add scalability for blitSurface2YUV (really need this??).
history: 2011.11.05 initial startup.
*/
#include<string.h>
#include<SDL.h>
/*
双线性内插值算法描述如下:
对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v)
(其中i、j均为浮点坐标的整数部分,u、v为浮点坐标的小数部分,是取值[0,1)区间的浮点数),
则这个像素的值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1) 公式1
其中f(i,j)表示源图像(i,j)处的的像素值,以此类推。
例子:
假如目标图的象素坐标为(1,1),那么反推得到的对应于源图的坐标是(0.75 , 0.75),
这其实只是一个概念上的虚拟象素,实际在源图中并不存在这样一个象素,
那么目标图的象素(1,1)的取值不能够由这个虚拟象素来决定,
而只能由源图的这四个象素共同决定:(0,0)(0,1)(1,0)(1,1),
而由于(0.75,0.75)离(1,1)要更近一些,那么(1,1)所起的决定作用更大一些,
这从公式1中的系数uv=0.75×0.75就可以体现出来,
而(0.75,0.75)离(0,0)最远,所以(0,0)所起的决定作用就要小一些,
公式中系数为(1-u)(1-v)=0.25×0.25也体现出了这一特点;
浮点运算的优化:
反向变换
(x, y) --> (i+u, j+v) = (sw/dw * x, sh/dh * y)
u = (sw*x % dw)/dw
v = (sh*y % dh)/dh
1 - u = (dw - sw*x % dw)/dw
1 - v = (dh - sh*y % dh)/dh
公式1
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
两边同时乘以 dw*dh,得到
dw*dh*f(i+u, j+v) = (dw - sw*x % dw)*(dh - sh*y %dh)*f(i,j) + ... + (sw*x % dw)(sh*y % dh)f(i+1,j+1)
* */
#define yf(i,j) (*((Uint8*)src->pixels[0] + ((j) + srcrect->y)*src->pitches[0] + ((i) + srcrect->x) ))
#define vf(i,j) (*((Uint8*)src->pixels[1] + ((j)/2 + srcrect->y/2)*src->pitches[1] + ((i)/2 + srcrect->x/2) ))
#define uf(i,j) (*((Uint8*)src->pixels[2] + ((j)/2 + srcrect->y/2)*src->pitches[2] + ((i)/2 + srcrect->x/2) ))
int blitYUV2YUVScale(SDL_Overlay *src, SDL_Rect *srcrect, SDL_Overlay *dst, SDL_Rect *dstrect)
{
unsigned int x,y, i,j, tu,tv,tu1,tv1,tf;
unsigned int y1,v1,u1;
int dw,dh, sw,sh;
//check args
if(src->format != dst->format)return 1;
dw = dstrect->x + dstrect->w < dst->w ? dstrect->w : dst->w - dstrect->x;
dh = dstrect->y + dstrect->h < dst->h ? dstrect->h : dst->h - dstrect->y;
sw = srcrect->x + srcrect->w < src->w ? srcrect->w : src->w - srcrect->x;
sh = srcrect->y + srcrect->h < src->h ? srcrect->h : src->h - srcrect->y;
if(dw <= 0 || dh <= 0 || sw <= 0 || sh <= 0)
return 1;
for(y = 0; y < dh; ++y)
{
for(x = 0; x < dw; ++x)
{
i = sw*x / dw;
j = sh*y / dh;
tu = sw*x % dw;
tv = sh*y % dh;
tu1 = dw - tu;
tv1 = dh - tv;
tf =
tu1 * tv1 * yf(i,j) + tu1 * tv * yf(i,j+1) +
tu * tv1 * yf(i+1,j) + tu * tv * yf(i+1,j+1);
y1 = tf/(dw*dh);
*(dst->pixels[0] + (dstrect->y + y) * dst->pitches[0] + (dstrect->x + x)) = y1;
if((x%2 == 0 ) && (y%2 == 0 ))
{
tf =
tu1 * tv1 * vf(i,j) + tu1 * tv * vf(i,j+1) +
tu * tv1 * vf(i+1,j) + tu * tv * vf(i+1,j+1);
v1 = tf/(dw*dh);
tf =
tu1 * tv1 * uf(i,j) + tu1 * tv * uf(i,j+1) +
tu * tv1 * uf(i+1,j) + tu * tv * uf(i+1,j+1);
u1 = tf/(dw*dh);
*(dst->pixels[1] + (y/2 + dstrect->y /2) * dst->pitches[1] + (dstrect->x/2 + x/2)) = v1;
*(dst->pixels[2] + (y/2 + dstrect->y /2) * dst->pitches[2] + (dstrect->x/2 + x/2)) = u1;
}
}
}
return 0;
}
extern void rgb2yuv(int r, int g, int b, int *y, int *u, int *v);
extern void yuv2rgb(int y, int u, int v, int *r, int *g, int *b);
void fillRect(SDL_Overlay *yuv, SDL_Rect *rect, int y0, int u, int v)
{
int y;
int size = rect->w;
int uv_size = (size-1)/2+1;
int uv_off = 0;
for(y = 0; y< rect->h; ++y)
{
memset(yuv->pixels[0] + (rect->y + y) * yuv->pitches[0] + rect->x,
y0, size);
if(y%2 == 0)
{
memset(yuv->pixels[1] + (uv_off + rect->y /2) * yuv->pitches[1] + rect->x/2,
v, uv_size);
memset(yuv->pixels[2] + (uv_off + rect->y /2) * yuv->pitches[2] + rect->x/2,
u, uv_size);
++uv_off;
}
}
}
int blitYUV2YUV(SDL_Overlay *src, int srcx, int srcy, SDL_Overlay *dst, SDL_Rect *dstrect)
{
int min_size, uv_size, min_h, line, uv_off;
min_size = (src->pitches[0] - srcx < dst->pitches[0] - dstrect->x)?
src->pitches[0] - srcx : dst->pitches[0] - dstrect->x;
min_h = (src->h - srcy < dst->h - dstrect->y)?
src->h - srcy : dst->h - dstrect->y;
if(min_size > dstrect->w ) min_size = dstrect->w;
if(min_h > dstrect->h)min_h = dstrect->h;
if(min_size <= 0 || min_h <= 0)return 0;
if(src->format != dst->format)return 1;
for(uv_off = 0, line = 0; line < min_h; line++)
{
memcpy(dst->pixels[0] + (line + dstrect->y) * dst->pitches[0] + dstrect->x,
src->pixels[0] + (line + srcy) * src->pitches[0] + srcx, min_size);
if(line%2 == 0)
{
uv_size = (min_size+1)/2;
memcpy(dst->pixels[1] + (uv_off + dstrect->y /2) * dst->pitches[1] + dstrect->x /2,
src->pixels[1] + (uv_off + srcy /2) * src->pitches[1] + srcx /2, uv_size);
memcpy(dst->pixels[2] + (uv_off + dstrect->y /2) * dst->pitches[2] + dstrect->x /2,
src->pixels[2] + (uv_off + srcy /2) * src->pitches[2] + srcx /2, uv_size);
++uv_off;
}
}
return 0;
}
int blitSurface2YUV(SDL_Surface *src, SDL_Overlay *dst, SDL_Rect *dstrect)
{
Uint8 r, g, b;
int y1,u1,v1;
int y,x;
int height = src->h < dstrect->h ? src->h: dstrect->h;
int width = src->w < dstrect->w ? src->w: dstrect->w;
int uv_off = 0;
Uint32 pixel;
if(dst->format != SDL_YV12_OVERLAY)return 1;
for(y = 0; y < height; ++y)
{
for(x = 0; x < width; ++x)
{
switch(src->format->BitsPerPixel)
{
case 8:
pixel = *((Uint8*)src->pixels + y*src->pitch + x);
break;
case 16:
pixel = *((Uint16*)src->pixels + y*src->pitch/2 + x);
break;
case 32:
pixel = *((Uint32*)src->pixels + y*src->pitch/4 + x);
break;
default:
return -1;
}
SDL_GetRGB(pixel, src->format, &r, &g, &b);
rgb2yuv(r, g, b, &y1, &u1, &v1);
memset(dst->pixels[0] + (dstrect->y + y) * dst->pitches[0] + (dstrect->x + x),
(Uint8)y1, 1);
if((x%2 == 0 ) && (y%2 == 0 ))
{
memset(dst->pixels[1] + (uv_off + dstrect->y /2) * dst->pitches[1] + (dstrect->x/2 + x/2),
(Uint8)v1, 1);
memset(dst->pixels[2] + (uv_off + dstrect->y /2) * dst->pitches[2] + (dstrect->x/2 + x/2),
(Uint8)u1, 1);
}
}
if(y%2 == 0)++uv_off;
}
retu
寒泊
- 粉丝: 86
- 资源: 1万+
最新资源
- 【华为】AI Ready的数据基础设施参考架构白皮书.pdf
- 基于Springboot+Vue智慧校园之家长子系统-毕业源码案例设计(高分毕业设计).zip
- 基于Springboot+Vue智能物流管理系统毕业源码案例设计(高分项目).zip
- 基于Springboot+Vue智能推荐的卫生健康系统毕业源码案例设计(源码+项目说明+演示视频).zip
- 基于Springboot+Vue中小企业设备管理系统-毕业源码案例设计(高分项目).zip
- 基于Springboot+Vue中小企业人事管理系统代码-毕业源码案例设计(源码+项目说明+演示视频).zip
- 以实战为核心,逐步深入 Spring Cloud Alibaba 微服务架构的各个环节,掌握微服务注册与发现、配置管理、限流熔断、分布式事务等核心技术 构建完整的服务治理和网关解决方案,优化系统性能
- 基于Springboot+Vue智能学习平台系统-毕业源码案例设计(源码+论文).zip
- 基于Springboot+Vue卓越导师双选系统设计与实现-毕业源码案例设计(源码+项目说明+演示视频).zip
- 基于Springboot+Vue中药实验管理系统设计与实现-毕业源码案例设计(高分毕业设计).zip
- 基于Springboot+Vue在线商城系统设计与开发毕业源码案例设计(95分以上).zip
- 基于Springboot+Vue在线远程考试系统的设计与实现-毕业源码案例设计(高分项目).zip
- 基于Springboot+Vue在线课程管理系统的设计与实现-毕业源码案例设计(源码+项目说明+演示视频).zip
- 金融经济领域基于缺失数据替换的强化鲁棒过滤与预测方法研究
- 基于Springboot+Vue政府管理会议室预约信访系统设计-毕业源码案例设计(95分以上).zip
- 基于Springboot+Vue知识管理系统毕业源码案例设计(源码+项目说明+演示视频).zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
评论0