古老的视频去噪算法(FLT_GradualNoise)解析并优化,可实现1920*1080 YUV数据400fps的处理能力
本篇博文來(lái)自博主Imageshop,打賞或想要查閱更多內(nèi)容可以移步至Imageshop。
轉(zhuǎn)載自:https://www.cnblogs.com/Imageshop/p/14224965.html? 侵刪
這個(gè)好像沒(méi)有啥對(duì)應(yīng)的論文可以找到,在百度上搜索也能找到一些相關(guān)的資料,不過(guò)就直接是代碼,可以看到其實(shí)來(lái)自于一個(gè)叫做DScaler的項(xiàng)目,在github上目前還能找到該項(xiàng)目的完整資料。
詳見:https://github.com/JohnAdders/DScaler/tree/f7d92b76678e24422c48d4a956c0486ee042786d
其中含有FLT_GradualNoise.c文件,我們復(fù)制以下代碼的注釋部分對(duì)算法的解釋:
? ? ? ? This algorithm is very similar to what Andrew Dowsey came up with in his "Adaptive?Temporal Averaging" for his DirectShow filter.? The algorithms differ in 1) their?block size, 2) their motion estimation(sum of absolute differences versus mean?squared error), 3) The addition of a "high tail," in which areas which have changed?a lot(but not too much) still cause a small amount of averaging with the previous?rame, and 4) rounding.
? ? ? ?The algorithm :
? ? ? ?This filter gets the sum of absolute differences between a four pixel?horizontal block in the current image and the same block in the preceding?frame.This isn't the best local motion measure, but it's very fast due to?the psadbw SSE instruction.
? ? ? ? This difference measure is used to determine the kind of averaging which will be?conducted.If it's more than the "noise reduction" parameter, motion is?inferred.In that case, we just use the new pixel values.If it's less than the?noise reduction, we use the ratio of(difference / noise reduction) to determine the?weighting of the old and new values.
? ? ? ?Somewhat more formally :
? ? ? ? ? N = Sum_block(| oldByte - newByte | )
? ? ? ? ? R = Noise Reduction parameter
? ? ? ? ? ?M = (motion evidence) = 1? ? ?if N / R >= 1.2
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0.999? ?if 1.2 > N / R >= 1
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? N / R? ?otherwise
? ? ? ? ?Result pixel = (bytewise)oldPixel * (1 - M) + newPixel * M
? ? ? ? Rounding has a very significant effect on the algorithm.In general, for?computational reasons, values are rounded down.An important exception?occurs when? ? ? ? ? ?M > 0 and oldPixel != newPixel??
?but
? ? ? ? ? oldPixel * (1 - M) + newPixel * M
? ? ? ?rounds to oldPixel.In that case, the Result pixel is rounded to one toward?the newPixel value.This makes sure that very gradual variation is maintained.
? ? ? 針對(duì)這個(gè)算法,作者提供了相關(guān)的匯編代碼,而且進(jìn)行了非常詳細(xì)的注釋,但是這個(gè)匯編還不是普通的匯編,而是用的SIMD指令,因此,對(duì)于閱讀來(lái)說(shuō)就非常的困難了,我大概花了10天左右,理解其思路,并用更加容易東的Intrinsic進(jìn)行了重寫和優(yōu)化。下面是一些編寫時(shí)的疑惑和解讀,共享下。
// 疑點(diǎn)1: 對(duì)于YUV數(shù)據(jù),這個(gè)程序是如何處理的? // 答復(fù): 從原始的匯編代碼看,他對(duì)YUV分量是同步處理的,并沒(méi)有做特別的區(qū)分,前面說(shuō)的四個(gè)像素,指的意思就是Y0 U0 Y1 V0 Y2 U1 Y3 V1這4個(gè)像素,不管是MMX指令還是SSE指令 // 他們的psadbw指令都是一次性執(zhí)行八個(gè)字節(jié)數(shù)據(jù)的絕對(duì)值累加(SSE指令一次性執(zhí)行2個(gè)8個(gè)字節(jié)的累加而已)。如果把這個(gè)算法換成RGB格式的數(shù)據(jù),那范圍要麻煩了,要拆分RGB到各個(gè)獨(dú)立的分量了。 // 疑點(diǎn)2: 上面提及默認(rèn)的Rounding是向下的,但是一般要求只要Src和Prev有差異,就至少要向新像素有1個(gè)像素的偏移,以保證視頻的連續(xù)性,如何實(shí)現(xiàn)的。 // 答復(fù): 程序里對(duì)數(shù)據(jù)進(jìn)行了判斷,如果Src和Prev不同,則設(shè)置偏移量至少是1(正1和負(fù)1都可以),相同的話偏移量當(dāng)然為0了。 // 另外,如果定點(diǎn)化后的偏移量大于65535,則設(shè)置偏移量為AbsDiff值,因?yàn)檫@個(gè)時(shí)候的由于程序移位計(jì)算的原因,直接算的值還會(huì)少1的。 (X * 65535) >> 16結(jié)果會(huì)為X - 1 // 疑點(diǎn)3: 程序是如何進(jìn)行優(yōu)化的? // 答復(fù): (1) 在原始的代碼中,有這個(gè)0.999 if 1.2 > N / R >= 1,在作者提供的匯編代碼中,對(duì)這部分做了處理,他是通過(guò)一些比較和移位來(lái)實(shí)現(xiàn)的,把NoiseMultiplier更改為65534了(N/R>=1,就已經(jīng)設(shè)為65535了) // 在本代碼中,個(gè)人覺(jué)得這個(gè)判斷毫無(wú)必要,0.999對(duì)結(jié)果的影響太小了,因此舍棄了,在作者提供的SSE和MMX代碼中,這個(gè)也舍棄了。 // (2) 定點(diǎn)化,程序中N/R涉及到除法運(yùn)算,為了減少這個(gè),我們將整體擴(kuò)大65536倍,然后再乘以AbsDiff,這個(gè)時(shí)候需要除以65536,這樣可以利用_mm_mulhi_epu16來(lái)快速實(shí)現(xiàn)(不需要特別的移位指令了,也不需要轉(zhuǎn)換到32位) // 但是實(shí)際上,這里是有誤差的,因?yàn)檫@個(gè)函數(shù)不能做到四舍五入,建議使用_mm_mulhrs_epi16代替。同時(shí)注意如果N/R * 65536如果大于65535了,就對(duì)于了原始算式中的M=1了 ,這個(gè)時(shí)候就把他直接限定為65535了(不需要轉(zhuǎn)換到32位了) // 舉個(gè)例子,如果AbsDiff_Sum = 24,NoiseValue取值64,此時(shí)Multiplier的值為1024,則如果某個(gè)像素的newPixel - oldPixel = 10,則結(jié)果為 (24 * 1024 * 10) >> 16 = 3,但是實(shí)際的浮點(diǎn)為3.75,理論上應(yīng)該取4更為合適。 // (3) oldPixel * (1 - M) + newPixel * M經(jīng)過(guò)整理可以變?yōu)? oldPixel + (newPixel - oldPixel) * M, 此時(shí)配合newPixel - oldPixel的符號(hào)特性,可以使用_mm_adds_epu8和_mm_subs_epu8來(lái)實(shí)現(xiàn)最后的結(jié)果計(jì)算總的來(lái)說(shuō)這個(gè)算法,還是利用歷史幀的數(shù)據(jù)不斷的來(lái)平均誤差,減少視頻的噪音的,但是其可以充分利用快速計(jì)算8個(gè)字節(jié)數(shù)據(jù)的累加值的指令_mm_sad_epu8,可以達(dá)到非常恐怖的計(jì)算效率和速度。
測(cè)試1280*720大小視頻,去噪平均一幀約0.8ms,1920*1080視頻一幀需要約1.8ms(均位YUV422格式視頻)。
? ? ? ?由于這里上傳不了視頻,有需要了解該算法效果的,可以單獨(dú)聯(lián)系我,我可以提供個(gè)測(cè)試DEMO(DEMO太大,無(wú)法上傳),下面截兩張圖可以稍微看到區(qū)別。
??
總結(jié)
以上是生活随笔為你收集整理的古老的视频去噪算法(FLT_GradualNoise)解析并优化,可实现1920*1080 YUV数据400fps的处理能力的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 关于音视频的一些知识(demux、fil
- 下一篇: java制作《石头迷阵》游戏。