新人学习opencv图像处理的笔记,一:c++操作图像放大
新人學習opencv圖像處理的筆記,一:c++操作圖像放大
筆者最近開始接觸opencv,并且上學期學了一點數值計算,所以覺得計算機圖像挺有意思的,故而誕生了寫筆記的想法
好了,廢話不多說,由于筆者水平有有限,如有錯誤,敬請指正(!^ _ ^!)
一些入門基礎點
首先,在實踐操作前,我們得了解下,什么是計算機圖像,對通常的彩色圖像而言,計算機圖像就是一個個緊密排列的像素點組成,這些像素點呈現不同的顏色,共同組成了一個完整的畫面如下圖所示
值得注意的是,圖像在計算機內,是以矩陣的方式保存的,矩陣的行列代表圖像的長寬,其中每個元素代表一個像素點,而每一個元素的組成,則代表了該像素點的顏色(三通道RGB的矩陣分別有紅綠藍三個顏色的通道,每個通道上的數值又代表了該顏色的深淺。例如:(255,255,255)代表的是黑色,(0,0,0)代表的是白色)。
實現圖像放大需要面臨的問題
這個問題其實筆者大一就想過,但是當時覺得圖像既然是像素點保存的,那么就應該是一個離散的數據,當時了解的不多也就不了了之,直到上學期,筆者上了數值計算這門課,才有了思路
問題1:在我們眼中的圖像顏色是連續的,漸變的, 這個漸變可以用導數的思維來思考,正是因為導數的存在,使得圖像的局部色差不會太大,從而有漸變連續的視覺效果。但正如前面所說,計算機圖像是以離散的數據保存下來的,所以我們需要想一個辦法,來給離散的數據求導------插值擬合,通過給離散的數據點擬合一個連續的函數,從而可以求導,使得像素是連續的。
問題2:圖像放大后,新圖會比原圖多出很多像素點,我們該如何去定位和確定像素值?比如,上圖中,是4x4,而在放大兩倍后,會變成8x8的圖像,這么多的像素點,我們該如何去確定呢?
解決方法
1:怎么解決第一個問題,那就是插值擬合函數,幾種擬合方法,會在后文介紹。
2:怎么解決第二個問題,那我們就需要定義一個映射含函數。把新圖中的點和原途中的點,通過一個函數 : f(x) 聯系起來。然后通過擬合出的函數來確定像素值。
三種擬合辦法
雙線性插值法
雙線性插值的思想是分別在 x 和 y方向做一次插值,從而實現像素值的填充。這里筆者提供一種簡單的方法。
假設原圖矩陣 R行 C列,即 RXC,在放大 m 倍數后變成 Rm * Cm,即 r * c 。首先創建一個 r * c的矩陣,然后把原途中的像素均勻有間隔的平鋪在新途中,那我需要尋找的像素點就只有 r * c - R * C個了。
然后通過構造一次函數,來計算空白點的值。上圖中,從橫坐標方向上看,綠色點的值和紅色點的值可以通過 像素值Pixle 和 橫坐標x來構造一個一次函數。而兩點中間空白點的值,則通過這個一次函數來確定。
比如紅綠點,構造一次函數。以綠點為起點,有 P = (PR - PG)/(XR - XG) * (X - XG) + PG。公式的意思是,用已知的兩點確定一條直線,在直線中確定未知點的值(邊界點可以自己設置一個較合適的數值進行處理)。通過第一次循環遍歷后,我們處理了有顏色橫向像素如圖
接下來的工作就是處理縱向像素,操作方法同上
這是筆者的結果圖,很明顯,數值插值公式的選擇的問題,導致像素點間變化生硬,效果不行。
最鄰近插值法
先上效果圖
這個方法就比雙線性插值更粗暴,更簡單,但是筆者的效果圖比雙線性更好,這里是為什么,筆者也沒找到答案??赡苁菍懙碾p線性的程序有點問題,這里先存疑。
這個方法的操作,把新圖上的點,重新映射到原圖上。通過公式計算
其中i,j是新圖中的坐標,XY是原圖中對應的整數坐標,R是小數部分。這里解釋一下,為什么會有小數和整數之分,因為放大的關系,新的像素點比原圖多,那么兩者之間的映射就不一定是一一對應的,新圖中的整數坐標點不一定對應原圖中整數坐標點,所以會有小數部分的存在。
如圖,紅圈點在原圖中對應的不是整數(正中心), 而是有偏差R的。有了這個偏差就好辦了。用整數部分去對應原圖中的整數點,然后根據這個偏差,看這個還原在原圖中的映射靠哪個點近,就把這個鄰近點的值賦給新點。(注意,不要看上圖來理解,要根據R大小來確定,R>0.5,就取下一個點,否則取這個整數點。)
二次插值(存疑)
由于有雙線性插值,筆者就在想,會不會二次插值效果更好一點,結果并非如此。
筆者同樣采用多點構造的方法,只不過使用的擬合函數是用三個點確定的二次函數,用二次拉格朗日插值公式得到??雌饋砗侠?#xff0c;但是得到效果圖慘不忍睹。
下面是效果圖,我寫報告時心血來潮的產物,結果不忍直視。
雙三插值法
這個插值法筆者也說不清楚是怎么回事,也是在老師提示下,查了這個方法
由于筆者水平有限所以只給了一個公式截圖,具體詳情請看下方超鏈接。
參考資料
總結和思考
筆者也是初次寫博客,如果有什么不對,還請多多指教。
筆者覺得,對于圖像的resize,主要是對于離散數據的操作,要通過一些比較好的插值方法還原函數,盡可能地在導數上做一些優化,使得局部像素變化平滑。對于那些突變地像素點,則可以使用梯度來算法來進行邊緣檢測(筆者用了一個很笨的方法實現了輪廓檢測,感覺自己好蠢,(* ^ _ ^ * ))。一個risize的好壞取決于函數的否平滑,而函數的平滑取決于導數和梯度,所以筆者在想,除開突變點,如果一個函數在滿足所有離散點的情況下,且變化平穩,那一定就是最好的辦法了。
總之,還是感謝大家看了我的博客。
總結
以上是生活随笔為你收集整理的新人学习opencv图像处理的笔记,一:c++操作图像放大的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python读取mac地址_python
- 下一篇: 【C++】队列优先队列详解——deque