1. 程式人生 > >插值---雙線性,三線性,四線性 及非線性

插值---雙線性,三線性,四線性 及非線性

網上有很多這方面的資料,介紹的也算明白。但是,這些文章只介紹了演算法,並沒有具體說怎麼實現以及怎麼實現最好,舉個例子,你可以按照網上文章的演算法自己寫一個雙線性插值程式,用它對一張圖片進行處理,然後再用matlab或者openCV的resize函式對同一張圖片進行處理,得到的結果是不一樣的,如果源圖片較小,效果差距就更大。以下是對於雙線性插值的講解以及上述現象的解釋:

假設源影象大小為mxn,目標影象為axb。那麼兩幅影象的邊長比分別為:m/a和n/b。注意,通常這個比例不是整數,程式設計儲存的時候要用浮點型。目標影象的第(i,j)個畫素點(i行j列)可以通過邊長比對應回源影象。其對應座標為(i*m/a,j*n/b)。

顯然,這個對應座標一般來說不是整數,而非整數的座標是無法在影象這種離散資料上使用的。雙線性插值通過尋找距離這個對應座標最近的四個畫素點,來計算該點的值(灰度值或者RGB值)。如果你的對應座標是(2.5,4.5),那麼最近的四個畫素是(2,4)、(2,5)、(3,4),(3,5)。

若影象為灰度影象,那麼(i,j)點的灰度值可以通過一下公式計算:

f(i,j)=w1*p1+w2*p2+w3*p3+w4*p4;

其中,pi(i=1,2,3,4)為最近的四個畫素點,wi(i=1,2,3,4)為各點相應權值。關於權值的計算,在維基百科和百度百科上寫的很明白。

2.存在的問題

這部分的前提是,你已經明白什麼是雙線性插值並且在給定源影象和目標影象尺寸的情況下,可以用筆計算出目標影象某個畫素點的值。當然,最好的情況是你已經用某種語言實現了網上一大堆部落格上原創或轉載的雙線性插值演算法,然後發現計算出來的結果和matlab、openCV對應的resize()函式得到的結果完全不一樣。

那這個究竟是怎麼回事呢?

其實答案很簡單,就是座標系的選擇問題,或者說源影象和目標影象之間的對應問題。

按照網上一些部落格上寫的,源影象和目標影象的原點(0,0)均選擇左上角,然後根據插值公式計算目標影象每點畫素,假設你需要將一幅5x5的影象縮小成3x3,那麼源影象和目標影象各個畫素之間的對應關係如下:

只畫了一行,用做示意,從圖中可以很明顯的看到,如果選擇右上角為原點(0,0),那麼最右邊和最下邊的畫素實際上並沒有參與計算,而且目標影象的每個畫素點計算出的灰度值也相對於源影象偏左偏上。

那麼,讓座標加1或者選擇右下角為原點怎麼樣呢?很不幸,還是一樣的效果,不過這次得到的影象將偏右偏下。

最好的方法就是,兩個影象的幾何中心重合,並且目標影象的每個畫素之間都是等間隔的,並且都和兩邊有一定的邊距,這也是matlab和openCV的做法。如下圖:

如果你不懂我上面說的什麼,沒關係,只要在計算對應座標的時候改為以下公式即可,

int x=(i+0.5)*m/a-0.5

int y=(j+0.5)*n/b-0.5 ,instead of 

int x=i*m/a

int y=j*n/b

利用上述公式,將得到正確的雙線性插值結果

總結:

總結一下,我得到的教訓有這麼幾條。

1.網上的一些資料有的時候並不靠譜,自己還是要多做實驗。

2.不要小瞧一些簡單的、基本的演算法,讓你寫你未必會寫,而且其中可能還藏著一些玄妙。

3.要多動手程式設計,多體會演算法,多看大牛寫的原始碼(雖然有的時候很吃力,但是要堅持看)。

 在影象處理中,雙線性插值演算法的使用頻率相當高,比如在影象的縮放中,在所有的扭曲演算法中,都可以利用該演算法改進處理的視覺效果。

     用一個簡單的數學表示式可以表示如下:

     f(x,y)=f(0,0)(1-x)(1-y)+f(1,0)x(1-y)+f(0,1)(1-x)y+f(1,1)xy

     合併有關項,可寫為: f(x,y)=(  f(0,0)(1-x)+ f(1,0) x  ) (1-y)  +  (  f(0,1)(1-x)  +  f(1,1)x  )  y

     由上式可以看出,這個過程存在著大量的浮點數運算,對於影象這樣大的計算使用者來說,是一個較為耗時的過程。

     考慮到影象的特殊性,他的畫素值的計算結果需要落在0到255之間,最多隻有256種結果,由上式可以看出,一般情況下,計算出的f(x,y)是個浮點數,我們還需要對該浮點數進行取整。因此,我們可以考慮將該過程中的所有類似於1-x、1-y的變數放大合適的倍數,得到對應的整數,最後再除以一個合適的整數作為插值的結果。

      如何取這個合適的放大倍數呢,要從三個方面考慮,第一:精度問題,如果這個數取得過小,那麼經過計算後可能會導致結果出現較大的誤差。第二,這個數不能太大,太大會導致計算過程超過長整形所能表達的範圍。第三:速度考慮。假如放大倍數取為12,那麼算式在最後的結果中應該需要除以12*12=144,但是如果取為16,則最後的除數為16*16=256,這個數字好,我們可以用右移來實現,而右移要比普通的整除快多了。 

      綜合考慮上述三條,我們選擇2048這個數比較合適。

      下面我們假定某個演算法得到了我們要取樣的座標分別PosX以及PosY,其中PosX=25.489,PosY=58.698。則這個過程的類似程式碼片段如下:

複製程式碼 複製程式碼  1 NewX = Int(PosX)                        '向下取整,NewX=25 2 NewY = Int(PosY)                        '向下取整,NewY=58 3 PartX = (PosX - NewX) * 2048            '對應表示式中的X 4 PartY = (PosY - NewY) * 2048            '對應表示式中的Y 5 InvX = 2048 - PartX                     '對應表示式中的1-X 6 InvY = 2048 - PartY                     '對應表示式中的1-Y 7 
 8 Index1 = SamStride * NewY + NewX * 3    '計算取樣點左上角鄰近的那個畫素點的記憶體地址 9 Index2 = Index1 + SamStride          '左下角畫素點地址
10 ImageData(Speed + 2) = ((Sample(Index1 + 2) * InvX + Sample(Index1 + 5) * PartX) * InvY + (Sample(Index2 + 2) * InvX +                            Sample(Index2 + 5) * PartX) * PartY) \ 4194304       '處理紅色分量 11 ImageData(Speed + 1) = ((Sample(Index1 + 1) * InvX + Sample(Index1 + 4) * PartX) * InvY + (Sample(Index2 + 1) * InvX +                           Sample(Index2 + 4) * PartX) * PartY) \ 4194304       '處理綠色分量
12 ImageData(Speed) = ((Sample(Index1) * InvX + Sample(Index1 + 3) * PartX) * InvY + (Sample(Index2) * InvX +                       Sample(Index2 + 3) * PartX) * PartY) \ 4194304           '處理藍色分量 複製程式碼 複製程式碼

      以上程式碼中涉及到的變數都為整型(PosX及PosY當然為浮點型)。

      程式碼中Sample陣列儲存了從中取樣的影象資料,SamStride為該影象的掃描行大小。

      觀察上述程式碼,除了有2句涉及到了浮點計算,其他都是整數之間的運算。

      在Basic語言中,編譯時如果勾選所有的高階優化,則\ 4194304會被編譯為>>22,即右移22位,如果使用的是C語言,則直接寫為>>22。

      需要注意的是,在進行這代程式碼前,需要保證PosX以及PosY在合理的範圍內,即不能超出取樣影象的寬度和高度範圍。

      通過這樣的改進,速度較直接用浮點型別快至少100%以上,而處理後的效果基本沒有什麼區別。

相關推薦

---線性線性線性 非線性

網上有很多這方面的資料,介紹的也算明白。但是,這些文章只介紹了演算法,並沒有具體說怎麼實現以及怎麼實現最好,舉個例子,你可以按照網上文章的演算法自己寫一個雙線性插值程式,用它對一張圖片進行處理,然後再用matlab或者openCV的resize函式對同一張圖片進行處理,得到的結果是不一樣的,如果源圖片較小

影象-線性

在現實生活中,我們經常會遇到把影象進行放大、幾何空間變換的情況等等,這些操作都需要在源影象和目標影象之間建立一個對映規則,使得兩影象畫素座標之間建立起一種對應關係,從而為目標影象的每一個畫素賦值。 從源影象到目標影象的對映叫前向對映,但是這種對映方法可能會出現這樣的兩個問題

影象演算法-最近鄰 線性

影象插值演算法包括向上插值和向下插值,向上插值就是對影象進行放大,向下插值就是對影象進行縮小,插值演算法在影象預處理過程中經常被使用,通過插值演算法,可以將影象尺寸變換為任意尺寸,下面以舉例子的方式來說明兩種常見的插值演算法: 假設影象原始尺寸為wi,hi,縮

day 27 網際網路TCP與UDP協議 次握手次揮手

一 . OSI七層模型(網際網路核心協議,從下往上的順序是物理層<資料鏈路層<網路層<傳輸層<會話層<表示層<應用層)         也瞭解下五層通訊的流程: 二 . socket      

北京少兒程式設計分鐘為孩子的未來開啟一扇新的大門

  麻省理工學院媒體實驗室的教授米切爾·雷斯尼克的觀點:“當孩子學會程式設計,就會開始思考世界上的一切過程。”他是一位兒童程式設計的倡導者。     喬布斯在生前接受的一次採訪中,曾說過這樣一句話:“這個國家的每一個人都應該學習程式設計,因為它教你

軟工-軟體工程(過程特性步驟要素目標)

軟體工程過程 軟體規格說明(Plan):規定軟體的功能及其執行的限制 軟體開發(Do):產生滿足規格說明的軟體 軟體確認(Check):確認軟體能夠完成客戶提出的要求 軟體維護 軟體工程過程的特性 ·易理解性 ·可見性 ·可支援性 ·可接受性 ·可靠性 ·健壯性 ·可維護性 ·速度

從java 理解http互動過程次握手次揮手

ip 網絡卡地址 本機 192.168.8.50 C8-5B-76-03-AC-5B 伺服器 192.168

TCP/UDP通訊協議基礎全集(區別次握手次揮手)

在本篇部落格你將瞭解到: 什麼是TCP/IP和UDP協議 TCP協議中的三次握手和四次揮手過程 為什麼連線的時候是三次握手,關閉的時候卻是四次握手 為什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態 TCP與UDP的

(code)驗證數字黑洞位數位數-python

#!/usr/bin/python import urllib.request import urllib.parse import urllib.response import os import sys import bs4 response = urllib.reque

TCP/IP次握手次揮手TCP/UDP , HTTP/HTTPS

規則 什麽 會話層 file 三次 報文 分享圖片 iso 數據鏈路 internet:通用名詞,由多個計算機網絡組成的網絡,網絡間的通信協議是任意的 Internet:專用名詞,當前全球最大的開放計算機網絡,采用TCP/IP協議族作為通信的規則。www萬維網是廣泛應用其

影象演算法(一):最近鄰線性

最近在複習影象演算法,對於一些簡單的影象演算法進行一個程式碼實現,由於找工作比較忙,具體原理後期補上,先上程式碼。今天先給出最近鄰插值,雙線性插值,三次插值。 1.最近鄰插值 原始圖中影響點數為1 (1)程式碼 # include<iostream>

Lanczos最鄰近線性二次

本文為轉載,原部落格地址:http://blog.csdn.net/trent1985/article/details/45150677 [研究內容] 目前比較常用的幾種插值演算法 [正文] 目前比較常用的插值演算法有這麼幾種:最鄰近插值,雙線性二次插值,三次插值, Lan

matlab做線性擬合(多元線性迴歸準確來說不叫

matlab三維擬合(多元線性迴歸) 問題描述 今天同學問了我一個問題,大概意思是給了你三列輸入資料,一列輸出資料,想用一個線性超平面做一個最小二乘擬合(注意這裡不能叫插值)。 一點思考 剛聽到這個問題,同學說的是做插值,說想要做一個插值,這種說法不準確的,不想說迴歸的話

影象演算法的基礎知識(線性協方差矩陣矩陣的特徵值、特徵向量)

0. 前言 MATLAB或者OpenCV裡有很多封裝好的函式,我們可以使用一行程式碼直接呼叫並得到處理結果。然而當問到具體是怎麼實現的時候,卻總是一臉懵逼,答不上來。前兩天參加一個演算法工程師的筆試題,其中就考到了這幾點,感到非常汗顏!趕緊補習! 1. 雙線性插值 在影象處

線性線性Bilinear Interpolation演算法

線性插值 先講一下線性插值:已知資料 (x0, y0) 與 (x1, y1),要計算 [x0, x1] 區間內某一位置 x 在直線上的y值(反過來也是一樣,略): y−y0x−x0=y1−y0x1−x0y−y0

線性最鄰近法 處理圖片的旋轉放大

對於一張圖片旋轉某個角度,其實就是把每個畫素計算好它的位置,再對對應的位置設定畫素值即可,以順時針為例,如下圖,由P點旋轉到P', x=rcos(a) y=rsin(a) x'=rcos(a+b)=rcos(a)cos(b)-rsin(a)sin(b) y'=rsi

最臨近 線性 次卷積(影象放縮)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

最臨近、線性次卷積演算法比較

 //原文:http://blog.csdn.net/google0802/article/details/8938849 【我只是想把最近鄰這個弄過來╮(╯-╰)╭ 】 插值演算法對於縮放比例較小的情況是完全可以接受的,令人信服的。一般的,縮小0.5倍以上或放大3.

Matlab 演算法(最鄰近、線性

1、最鄰近元法 這是最簡單的一種插值方法,不需要計算,在待求象素的四鄰象素中,將距離待求象素最近的鄰象素灰度賦給待求象素。設i+u, j+v(i, j為正整數, u, v為大於零小於1的小數,下同)為待求象素座標,則待求象素灰度的值 f(i+u, j+v) 如下圖所示:

線性

線性插值先講一下線性插值:已知資料 (x0, y0) 與 (x1, y1),要計算 [x0, x1] 區間內某一位置 x 在直線上的y值(反過來也是一樣,略):y−y0x−x0=y1−y0x1−x0y=x1−xx1−x0y0+x−x0x1−x0y1上面比較好理解吧,仔細看就是