Q:我想將I幀的預測圖像和原始圖像的平均絕對誤差給輸出來,請問這個在JM86中需要在哪一點改動呢?謝謝 A: 差值保存在diffy中: diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i] - pred[j][i]; 分析MAD不知道程序中在哪求可以直接搜索"MAD“ 結果中有一個函數: img->MADofMB[img->current_mb_nr] = calc_MAD(); 就是這個了,進去看一下: //calculate MAD for the current macroblock double calc_MAD() { int k,l; int s = 0; double MAD; for (k = 0; k < 16; k++) for (l = 0; l < 16; l++) s+= abs(diffy[k][l]); MAD=s*1.0/256; return MAD; } 剛好是根據diffy求MAD Q:看了很多的文獻,不論是經典的二次R-Q模型,還是其它什么模型,其中總有一個用于表示編碼復雜度的變量,如二次R-Q模型中是MAD,有的模型中是SATD等,根據二次R-Q模型的源出文獻《Scalable Rate Control for MPEG-4 Video》,MAD的引入是為了使模型scalable with video content,但是為什么有這種效果卻沒有講。請教各位,MAD的引入的原因是為了什么,有什么數據來證明或文獻支持?謝謝高手賜教! A:就是為了根據前一幀的復雜度來預測當前幀的復雜度啊。 我說的是R-Q模型中,引入了MAD,不是使用MAD的線性預測模型 A:《Scalable Rate Control for MPEG-4 Video》中最初得到的二次模型是一個碼率和QP之間的關系,但是實際中并不是QP越高,碼率就越小,不同的圖像復雜度不同,對得到的碼率也會有影響,因此,需要對原先的二次模型做一個修正,加入圖像復雜度這個因素。而對于為什么MAD可以近似代表圖像復雜度,我想不用我解釋了吧,自己好好想下就知道了。 Q:道理確實是如此,從二次模型的公式來看,對某個圖像,給定QP時,BIts/MAD就是一個常數,這意味著Bits和MAD就是線性關系,但從《Scalable Rate Control for MPEG-4 Video》中,并沒有看到相關的證明! A:率失真模型中,一方面關心的是比特率與QP值(或量化步長)的關系,另外一方面關心的是比特率與圖像編碼復雜度之間的關系。 假定QP值如果和編碼復雜度相互獨立的話,那么率失真模型應當相當優雅。但是實際的情況并非如此,特別是在H.264中。 在MPEG-4及以前版本中,計算MAD的方法是用運動估值后的殘差信息。這樣MAD值與比特之間確實存在一種線性關系(注意是線性,而不是正比),雖然在樓主提到的文獻Scalable Rate Control for MPEG-4 Video 中并沒有給出圖。為了方便,或者為了避免一些無法解決的問題,該文獻將MAD直接寫入了二次率失真模型中,作為正比項存在,并一直主導著視頻圖像編碼的碼率控制算法。 在下通過大量的實驗數據,繪制出了H.264中比特率與MAD的關系,甚至是預測MAD(JVT-G012線性預測方法)的關系圖。從圖中可以看到,在H.264中比特率與MAD的線性關系存在,但不明顯,而且線性截距很大,不可忽略。比特率與預測MAD的關系可以用不相關三個字來形容。個中特點,各自揣摩。 談一點我個人的看法: MAD如果統計的是運動估值后的殘差信息,確實可以直接理解為圖像的編碼復雜度。因為這個時候的MAD已經帶有雙重特性:其一運動估值,其二殘差。這個時候的MAD的表征對象就是馬上用于變換編碼和量化的基礎。很多早期的文獻對此都有評論,推導或改進。但是如果MAD不能直接取到的話,再用MAD的任何預測形式來做圖像復雜度都是自欺欺人的做法。 “從二次模型的公式來看,對某個圖像,給定QP時,BIts/MAD就是一個常數” 從在下的若干實驗看來,BIts/MAD不會是個常數。原因很簡單,BIts/(MAD+b)才是常數,b表示截距。我想 Scalable Rate Control for MPEG-4 Video 的作者是知道的,但是他不愿這樣做,所以沒有給出圖。 另外特別注意,MAD和QP不獨立,在H.264中。 十年放羊 寫的“BIts/(MAD+b)才是常數”才是常數,這個很早就有文獻,就是在二次模型中那個常數項是不能省掉的,我也做了這方面的實驗,MAD確實與QP有關系,而且關系應該能用模型表示出來,應該可以進行理論推導 Q:JM86中關了RDO后 原始圖像和運動預測補償后的MAD怎么突然變的很大?是什么原因,我覺得應該變的小一點才是正確的 為什么差別那么大,RDO開著的時候是1點多 關掉的時候是 6點多, 不一定RDO最準確,RDO只是選擇使代價最小的點作為匹配點,不一定是最匹配的位置,應該是開著RDO好一點,因為可以進行模式選擇,對宏塊進行細分 A:你說的對。RDO 最小并不是 MAD 最小。所以 RDO 跟 MAD 之間沒有規律性。 Q:在編碼中,P幀中也有使用幀內預測模式來進行預測編碼的,那么在計算該P幀的MAD時,是否計算幀內預測模式下編碼宏塊的MAD值?在JM配置文件中有沒有選項使編碼P幀時只使用幀間編碼模式,將幀內編碼模式關掉,如果有是哪個參數呢?謝謝~~~~~ A:配置文件中沒有,JM86 可以強制修改 encode_one_macroblock 函數中的 valid 變量 Q:JSVM9.17中,jsvmCalcMAD好像不是計算的MAD,是SAD啊,程序如下 unsigned int MbEncoder::jsvmCalcMAD( IntMbTempData*& rpcMbBestData, MbDataAccess& rcMbDataAccess ) { UInt uiDist = 0; UInt uiDelta = 1; Int n, m; IntMbTempData *rpcMbTempData = new IntMbTempData; rpcMbTempData->init( rcMbDataAccess ); rpcMbTempData->loadLuma ( *m_pcIntOrgMbPelData ); rpcMbTempData->loadChroma ( *m_pcIntOrgMbPelData ); XPel* pucDst = rpcMbBestData->getMbLumAddr(); XPel* pucSrc = rpcMbTempData->getMbLumAddr(); Int iStride = rpcMbTempData->getLStride(); Int iDeltaXStride = uiDelta * iStride; AOF( iStride == rpcMbBestData->getLStride() ); for( n = 0; n < 16; n += uiDelta ) { for( m = 0; m < 16; m += uiDelta ) { uiDist += abs( pucSrc[m] - pucDst[m] ); } pucSrc += iDeltaXStride; pucDst += iDeltaXStride; } delete rpcMbTempData; return uiDist; } 最后的uiDist應該再除以16*16才對吧 A:MAD,SAD都是衡量失真的準則,其作用就是用來做比較 如果每個塊的sad都要除以16x16以后再互相比大小,不覺得這很多余么 SAD足矣,這里的確是計算的SAD而不是MAD Q:在264的碼率控制中要用到MAD值,請問對于幀間和幀內編碼的宏塊其MAD值分別是怎么計算的?我在JM代碼中看不太明白,有知道的朋友能給說說?謝謝了! A: I幀和第一個P幀用固定的Qp,不進行MAD值的預測,從第二個P幀開始,利用前一幀相同位置basic unit的MAD值線性預測當前basic unit的MAD值 Q: 我的意思是實際MAD值是怎樣計算的? 對于幀間編碼宏塊 MAD=(原宏塊像素值-運動補償后的預測宏塊像素值)/256; 對于幀內編碼宏塊 MAD=(原宏塊像素值-幀內預測宏塊像素值)/256; 我這樣理解對嗎? A: 對,在JM86代碼的calc_MAD() 函數中 Q:都知道在二次模型中有MAD。但是為什么這里要用MAD。有沒有文獻或者數據的支持呢。為什么可以引入。無論是MAD還是SSD,有具體推導的過程嗎 A:為某幀編碼后大小也即Rate可以用MAD與QP的函數表達, 即 RATE=function(MAD,QP)q Q:在計算QP的時候,有RD的二次關系。但是RD二次模型的基礎是圖像復雜度相似的情況。D可以由QP表達。引入MAD是為了讓圖像scalable。 我想知道MAD引入有沒有嚴格的理論證明。 A:是針對 R=X1*Q^(-1)+X2*Q^(-2)這個式子對吧. X1,X2表征和圖像復雜度有關的變量, 實際操作中通過MAD計算, 我沒有記錯吧? 嗯....那個X1X2的部分我是有點記錯了, 不過幸好不是錯得很離譜, 式子應該是R/MAD_predicted=X1*Q^(-1)+X2*Q^(-2) MAD是用來近似描述圖像復雜度的一個參數 (scalable這個詞在這里怪怪的, 我不是很確定你用這個詞在這里的意思), 實際編碼不可能存在輸入任何源固定一個Q的情況下編出來的比特數都一樣嘛. 當然是和源的復雜度有關的. 至于描述復雜度也可以用其他參數, 如上面說的SSD. Q:Q:在JM的碼率控制中,函數calc_mad()是用來計算一個宏塊的MAD,而且這個函數encode_one_macroblock()中調用。我想使用前面已經計算過的相鄰宏塊的MAD,那怎么得到它的值呢?可有數組儲存已經計算出來的MAD的值?還有,在JVT-G012中,MAD線性模型是用來預測基本單元的MAD的,那它能和一個宏塊的MAD相加嗎? A:當然有存儲mad的數組了,自己跟蹤代碼,就能找到了。mad的和,本來就是為了計算每個bu的mad以及每幀的mad,當然要把每個mad加起來了。不過單純的一個bu的mad加上一個不屬于該bu的宏塊的mad沒有什么意義。 Q:請教各位大俠,在碼率控制中有一部分要預測當前基本單元的MAD。一開始我以為是整個BasicUnit 總的MAD,但我看了代碼后覺得好像是BasicUnit 中宏塊的MAD。 請問到底怎么理解基本單元的MAD呢? A:是整個 BasicUnit 的平均 MAD。也就是 BasicUnit 中所有 MB 的 MAD 求和再平均。提案里就是這么提的,就這么做就可以了。 (第二人解釋)最終得到的值,表示的是當前恢復圖像的basic unit 與原始圖像中對應的部分,平均每個像素值的差別. Q:在jvt-o12,jvt-h017提到的碼率控制算法中,幀層碼率控制和basic unit的碼率控制時都要由前一幀的mad來預測 當前的mad,提案中采用的是線性預測,即: pred_mad = C0xprev_mad + C1 pred_mad:預測的當前幀mad; prev_mad:為前一幀的實際mad C0,C1為預測系數; 每次幀編碼完成后,得到當前幀的實際mad,更新C0,C1; 我的問題是更新C0,C1具體是如何進行的. A:經過研究,還是不知道具體采用的了理論是什么,不過看明白了代碼的做法.代碼做法是對于每個線性預測關系 pred_mad = C0xprev_mad + C1; 兩端乘以prev_mad ,得到 pred_madxpred_mad = C0xprev_madxpred_mad + C1xpred_mad; 以上兩式連立,寫成矩陣形式: B = AC; 其中 B為1x2,B0 = pred_mad,B1 = pred_madxpred_mad; A為2x2,A00 = 1,A01 = A10 = prev_mad,A11 = prev_madxprev_mad; C就是由待更新的C0,C1組成的1x2矩陣. 假設有n個A - B 的對應關系,則可以得到n個Bi = AiC(i = 1,2,,,n),將這些等式相加,得到總的SUM(B) = SUM(A)C; 再由克來母公式計算出C. Q&A說過無數次了,跟代碼最接近的是 JVT-H017r3