NMM视频技术(旧)

 找回密码
 成为会员
搜索
查看: 6685|回复: 16

[求助] 关于LanczosResize的问题。

[复制链接]
发表于 2007-11-16 15:11 | 显示全部楼层 |阅读模式
今天我在做DVDRIP时发现了这样一个问题:
NTSC 16:9的动画片DVD,色彩空间是YV12。做完IVTC后使用711切边法,在一个颜色比较昏暗的场景里,用以下不同的代码出现了不同的效果。
  1. MPEG2source("test.d2v")
  2. ConvertToRGB()
  3. Crop(5,0,-4,0)
  4. LanczosResize(864,480)
  5. ConvertToYV12()
复制代码
使用这段代码写成avs,送入megui压缩x264,设置是AE-Goodquality的默认设置,画面出现非常严重的马赛克现象。
  1. MPEG2source("test.d2v")
  2. LanczosResize(864,480,5,0,-4,0)
复制代码
不转换颜色空间,直接用LanczosResize的切边,使用同样的设置进行压缩,马赛克现象消失,但还有少量色块。
  1. MPEG2source("test.d2v")
  2. LanczosResize(864,480)
复制代码
不转换颜色空间,也不做任何切边,直接resize,效果同上
  1. MPEG2source("test.d2v")
复制代码
除了IVTC以外什么都不做,导入后就直接输出,效果同上。


这样,是不是说明Lanczos有可能是在YUV444的颜色空间内进行resize的,或者说Lanczos的色彩转换比ConvertToRGB更准确?请高手们帮我分析下这个问题,谢谢!

评分

1

查看全部评分

发表于 2007-11-16 21:11 | 显示全部楼层
Resize内部切边是2.56新添加的功能,就目前查到的资料,没有任何关于Resize内部颜色空间转换的记载,包括英文和日文的资料到目前为止都没有提到。
但是就我实验结果来看,内部切边确实比外部颜色转换再切边效果好很多,速度也提高不少。如果不求甚解的话,可以先姑且这么用着。我看了半天源代码也没看出个所以然来,所以等我再研究两天说不定就能看出来为什么。
 楼主| 发表于 2007-11-17 13:03 | 显示全部楼层
谢谢您的答复,期待您的研究结果!

另外还想向您请教一个问题:
今天我看到一个和AVS有关的叫AAA的函数,功能是柔化动画片的画面。您肯定知道这个函数吧。我看了源代码,这个函数是将画面横纵都放大两倍,然后向左转动90度做一个SangNom(我不清楚SangNom是做什么的),然后转回来再SangNom一遍,还原回原本的尺寸,再做一次锐化。请问,这样做会不会对原始画面造成很严重的破坏?

好象有点偏离这个主题了,抱歉。
发表于 2007-11-17 14:42 | 显示全部楼层
回答您的问题。
先说简单的AAA的问题。AAA是从一个叫做AA的Script(毕竟是用AVS脚本写的,还算不上Plugin^^)演化而来的,所以如果您知道AA的全称,就知道怎么回事了。AA的全称是Anti Aliasing,即抗锯齿。而AAA则是Animation Anti Aliasing,用于动画的抗锯齿。就像名字说的一样,这个Script的作用是去除画面中的锯齿,不过代价就是画面大幅度模糊。当然,其对Deinterlace所产生的锯齿也有一定的修复作用,不过个人感觉效果不是那么明显罢了(Deinterlace所产生的锯齿通常比那种“天然锯齿”更为严重一些)。不过想想也是,边缘锯齿和边缘模糊本来就是一对矛盾,取哪边好,看您欣赏习惯了。

之后是LanczosResize的问题。AVS中与Resize有关的部分,都在resample.cpp和resample_functions.cpp里面。
我们首先看resample.cpp中CreateResizeH()这个函数(负责水平方向处理)。
  1. PClip CreateResizeH(PClip clip, double subrange_left, double subrange_width, int target_width, ResamplingFunction* func, IScriptEnvironment* env)
  2. {
  3.   const VideoInfo& vi = clip->GetVideoInfo();
  4.   //...略
  5.   if (subrange_left == int(subrange_left) && subrange_width == target_width && subrange_left >= 0 && subrange_left + subrange_width <= vi.width) {
  6.         if (vi.IsRGB() || ((int(subrange_left) | int(subrange_width)) & 1) == 0) {
  7.           return new Crop(int(subrange_left), 0, int(subrange_width), vi.height, 0, clip, env);
  8.         }
  9.   }
  10.   return new FilteredResizeH(clip, subrange_left, subrange_width, target_width, func, env);
  11. }
复制代码
最外面一层if说的是,当subrange_left(左边切的像素数,在你的例子里是5)为整数subrange_width(切到右边为止的像素,这里是711)与target_width(resize的目标宽度,这里是864)相等subrange_left不为负数subrange_left与subrange_width相加小于vi.width(片源的宽度,这里是720),这么多条件同时满足的时候才会继续下面一个if的判断。
下一个if,当片源是RGBsubrange_left、subrange_width为奇数的时候,会继续向下走。
下面新建了一个crop类的实体,把subrange_left和subrange_width输入进去,切边。
其实我们只要看第一个if就知道,这个crop在我们的例子中压根没用到。首先就是第一个if里面的第二个且条件subrange_width == target_width(我们这里是711 vs 864,不相等)没有满足,不会执行这个crop。

那么既然没有进crop,程序直接转入下一步,FilteredResizeH()。
  1. FilteredResizeH::FilteredResizeH( PClip _child, double subrange_left, double subrange_width, int target_width, ResamplingFunction* func, IScriptEnvironment* env ) : GenericVideoFilter(_child), tempY(0), tempUV(0),pattern_luma(0),pattern_chroma(0)
  2. {
  3.   pattern_luma = pattern_chroma = (int *)0;
  4.   tempUV = tempY = 0;
  5.   original_width = _child->GetVideoInfo().width;
  6.   //...略
  7.   if (vi.IsYUV())
  8.   {
  9.     //...略
  10.     if (vi.IsYV12()) {
  11.       pattern_chroma = GetResamplingPatternYUV( vi.width>>1, subrange_left/2.0, subrange_width/2.0, target_width>>1, func, true, tempY, env );
  12.     } else {
  13.       //...略
  14.     }
  15.     pattern_luma = GetResamplingPatternYUV(vi.width, subrange_left, subrange_width, target_width, func, true, tempY, env);
  16.   }
  17.   else
  18.   //...略
  19. }
复制代码
在这里,已经把chroma和luma分开进行处理。我只留下了与YV12颜色空间下相关的代码。因为YV12的色度信号横向采样只有亮度信号的一半,所以就将vi.width、subrange_left、subrange_width、target_width全部除以2(xx>>1是除以2的一种更加高效的写法,因为subrange_left和subrange_width都是double类型的变量要除以2.0而不是2,所以不能像vi.width和target_width一样使用二进制方法来计算)。
接下来,它又将这些东西交给了一个叫做GetResamplingPatternYUV()的函数(源代码在resample_functions.cpp)。我看了一眼这个函数,似乎也没什么跟切边有关系的内容。
所以基本上可以推测:
  • 在resize内部没有经过任何颜色空间转换。
  • 当切边像素是奇数的时候,这些像素并非被切掉了,而是在resize的时候被无视了。因为Y和C被分开处理,所以并不受奇数偶数的限制。

我不是AVS作者,C也不是很好,以上纯推断。
在阅读代码过程中,得到了joshyu的帮助,大感谢!
(本来不想写代码分析的,还是写了 囧)
发表于 2007-11-17 15:55 | 显示全部楼层
楼主第一个为啥要先转换成rgb
再crop resize呢
不解
发表于 2007-11-17 16:58 | 显示全部楼层
在YV12颜色空间下,不能进行奇数像素的切边。目前为止只有RGB和YUV444可以。

AVS3.0就会增加对YUV444的支持了。只不过都好几年了,AVS3依然是只闻其声,不见其形。
 楼主| 发表于 2007-11-17 17:16 | 显示全部楼层
谢谢dgwxx的分析!

一开始我还以为内部切边是Lanczos的特性,看了您的分析才明白,原来所有的变形滤镜都可以这么做的。

看了代码以后我还是有个疑问:在您贴出的第2段代码中,subrange_left/2.0和subrange_width/2.0都不是整数(5.0/2.0和711.0/2.0),那么GetResamplingPatternYUV要怎么处理半个象素呢?
发表于 2007-11-17 18:31 | 显示全部楼层
不会出现半个像素的啊,只是计算的时候会出现小数而已,实际上计算resize开始的像素和结束的像素的时候,都使用整数的。
所以最多只是出现奇数像素,而不会出现半个像素
 楼主| 发表于 2007-11-17 21:12 | 显示全部楼层
我感觉奇怪的是:假设图象尺寸是711x480的话,那么在YV12下亮度信息应该是711x480,色度信息应该是355.5x240,这样就会出来半个象素。

我注意到代码中这样的一个现象:

==================================================
pattern_chroma = GetResamplingPatternYUV( vi.width>>1, subrange_left/2.0, subrange_width/2.0, target_width>>1, func, true, tempY, env );
pattern_luma = GetResamplingPatternYUV(vi.width, subrange_left, subrange_width, target_width, func, true, tempY, env);

==================================================

在GetResamplingPatternYUV函数里,上面标记为红色部分的形参是luma,上面程序两次调用GetResamplingPatternYUV函数时的参数都是TRUE,在GetResamplingPatternYUV函数里有很多次类似于这样的判断:
  1. *result = luma ? fir_fs_mmx : fir_filter_size;
复制代码
这样是否就可以理解为,程序把chroma用luma的方法来处理了?换句话说,就是把UV的数量变的和Y一边多,变相的转换成YUV444了呢?
如果不转换颜色空间就可以随便切出奇数边,还不会出现错误的话,总觉得不太现实。

[ 本帖最后由 diseac 于 2007-11-17 21:18 编辑 ]
发表于 2007-11-17 21:44 | 显示全部楼层
本来想在上一帖就说一下这个问题的,看您没问,我就犯懒了,结果还是问题。
首先是第一个问题。就算是切边,也不可以通过切边后的像素来计算C的数量。
我这样解释您说不定就会明白了。切边的时候,Y和C应该分开来计算,不然就会陷入“半像素”的怪圈之中。首先明确720*480的画面中,一共有720*480个Y和360*240个C,四个Y共享一个C。我们左边切5,就是说左边切掉了5个Y、3个C,右边切掉4,相当于切掉了4个Y和2个C。所以切边之后,一共还剩下711个Y和355个C。(我只是通过这种方式来打个比方,具体程序中,左边切5时,到底是切掉2个C还是3个C我没看代码也不知道怎么处理的。)

第二个问题我也说不好,不过目前没有证据表明是在是用YUV444颜色空间。我使用文本搜索工具在所有源代码中搜索,出现涉及转换到YUV444空间的只后overlay相关的函数。这点在AVS手册中也得到了证实。
Input for overlay is any colorspace, and colorspaces of different clip doesn't matter! The input clips are internally converted to a general YUV (with no chroma subsampling) format, so it is possible for the filter to output another colorspace than the input. It is also possible to input video in different colorspaces, as they will be converted seamlessly. It is however not recommended to use overlay ''only'' for colorspace conversions, as it is both slower and with slightly worse quality.

目前不知道的事情太多,关于这几个切边的描述,日语wiki里面这样写道:
v2.56から、すべてのリサイズフィルタに対して、(Crop と同様に)オフセットを使用することができますすべてのリサイズに対して、リサイズの前にクロップする拡張されたシンタックスを使用することができます。リサイズの前に Crop を置くと同じ演算が実行されますが、両者にはわずかなスピードの違いがあります。
重要: AviSynth は、完全に独立した垂直と水平のリサイザを持っています。もし 1 つの軸に関して入力が出力と同じなら、リサイザはスキップされるでしょう。どちらが最初に呼び出されるかは、どちらが最も小さい縮小率を持っているかによって決定されます。これは、最大限の品質を保持するために行われます。このため、2 番目のリサイザは、処理するべき、考えられる最良のピクチャを得ます。データの格納方法*1は、リサイズとクロップをするときのサイズに関して、どの倍数が使われるべきかに影響を与える。

几乎是英文手册的翻译,比起英文手册没多出什么信息。虽然写着跟外置crop效果相同,但无论从实际还是从代码都证明了处理方式实际上是不同的。不知道手册为什么要这么写。

所以,咱们只要知道这样切边比转换到RGB效果好,就可以了。如果楼主有兴趣,可以试试跟AU的711法做出来的图像进行一下比较,就知道孰优孰劣了。
发表于 2007-11-17 22:06 | 显示全部楼层
分别用下面方法试验:
1.AVS
  1. loadplugin("D:\gk\dgmpgdec\DGDecode.dll")
  2. mpeg2source("jin-roh.d2v",upconv=1)
  3. trim(0,1)
  4. LanczosResize(864,480,5,0,-4,0)
复制代码
在VDM中选择Direct Stream Copy输出YUY2无压缩AVI。

2.AU(用的刚出的0.99a)
用M2V插件直接加载MPEG。在AU里只做crop和resize,切边像素数和resize分辨率与AVS脚本里相同。同样选取前两帧之后保存成为无压缩YUY2 AVI。

为了避免YV12 Decoder的干扰,使用了YUY2颜色空间的AVI。

对这两个AVI放大到400%进行观感对比,发现AVS保存出来的AVI无论是细节还是颜色都要胜过AU。
照理说,AVS里的Lanczos3Resize是AU移植过去的,效果应该基本相同,差别估计就差在了颜色空间转换上。在AU中,m2v.aui递给AU的是YUY2数据,AU内部处理要先提升到YUV444,保存时又要降低到YUY2。尽管AU的计算精度比AVS高许多,但经过这两折腾,数据损失还是避免不了。尽管差别只有放大到400%才能显示出来,但是丢失了终究是丢失了。在实验中,AVS毕竟还是经过了一次颜色空间转换,如果不经过颜色空间转换,全程YV12的话,一定会更好。
 楼主| 发表于 2007-11-18 00:14 | 显示全部楼层
感谢您的讲解和测试!
看了您的帖子,我基本明白了。
如果只是多切一个C,或者少切一个C的话,对画面的影响应该不是很大吧。我觉得至少应该比转换一次颜色空间更值得。
发表于 2007-11-28 17:26 | 显示全部楼层
原帖由 dgwxx 于 2007-11-17 22:06 发表
2.AU(用的刚出的0.99a)
用M2V插件直接加载MPEG。在AU里只做crop和resize,切边像素数和resize分辨率与AVS脚本里相同。同样选取前两帧之后保存成为无压缩YUY2 AVI。

为了避免YV12 Decoder的干扰,使用了YUY2颜色空间的AVI。

对这两个AVI放大到400%进行观感对比,发现AVS保存出来的AVI无论是细节还是颜色都要胜过AU。
照理说,AVS里的Lanczos3Resize是AU移植过去的,效果应该基本相同,差别估计就差在了颜色空间转换上。在AU中,m2v.aui递给AU的是YUY2数据,AU内部处理要先提升到YUV444,保存时又要降低到YUY2。尽管AU的计算精度比AVS高许多,但经过这两折腾,数据损失还是避免不了。尽管差别只有放大到400%才能显示出来,但是丢失了终究是丢失了。在实验中,AVS毕竟还是经过了一次颜色空间转换,如果不经过颜色空间转换,全程YV12的话,一定会更好。

請問你是用那種Lanczos-3的選項? 不同的選項會得出不同的畫質, 好像是SSE2 Real Number的畫質最高。
另外, 你現在是做400%原圖的AB Test......這個測試可能受心理影響而得出不準確的結果, 加上兩種的畫質差距應該很小, 很容易受心理因素影響。能否做一次ABX Test, 看結果跟現在的會不會一樣.....
发表于 2007-11-28 18:49 | 显示全部楼层
是我没说清楚。AU中我用的是“SSE实数”选项。上面说的“画质好”的标准,是细节保留量,可以看出差别,因此我觉得不像是心里作用的影响。
如果方便的话,ss大也可以做一下实验,看看是否得出同样的结果。
发表于 2007-11-28 23:53 | 显示全部楼层
剛剛看了一下AVISynch的LanczosResize.......
它與AVIUTL的Lanczos3分別是:
AVS:
-用的是Floating Point演算法, 失真比較細, 速度會慢一點
-用取樣方法是Y和UV分開取樣, 如果是從720->864, Y是用720->864的算式, UV是用360->432的算式, 色彩取樣範圍會比AU的大。因為是取畫面的7/360, AU只作畫面的7/720來取樣。
发表于 2007-11-29 09:59 | 显示全部楼层
有传言说AVS的LR是AU的LR3移植过去的,这个说法是真的?
发表于 2007-11-29 10:50 | 显示全部楼层

回复 16# 的帖子

又不算是, 因為現在AVS的寫法是能變換Filter Function, 它的幾種Resize方法也是用同一個Function來達成的, 這跟AU內的Lanczos-3不一樣
您需要登录后才可以回帖 登录 | 成为会员

本版积分规则

小黑屋|手机版|NMM视频技术

GMT+8, 2019-10-15 09:12 , Processed in 0.091130 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表