1. 程式人生 > >雙線性插值演算法進行影象縮放及效能效果優化

雙線性插值演算法進行影象縮放及效能效果優化

一)轉自http://handspeaker.iteye.com/blog/1545126

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

1.雙線性插值

假設源影象大小為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.要多動手程式設計,多體會演算法,多看大牛寫的原始碼(雖然有的時候很吃力,但是要堅持看)。

二)轉自http://www.cnblogs.com/Imageshop/archive/2011/11/12/2246808.html

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

     在數學上,雙線性插值演算法可以看成是兩個變數間的線性插值的延伸。執行該過程的關鍵思路是先在一個方向上執行線性插值,然後再在另外一個方向上插值。下圖示意出這個過程的大概意思。

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

     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%以上,而處理後的效果基本沒有什麼區別。

相關推薦

線性演算法進行影象效能效果優化

一)轉自http://handspeaker.iteye.com/blog/1545126 最近在程式設計時用到了雙線性插值演算法,對影象進行縮放。網上有很多這方面的資料,介紹的也算明白。但是,這些文章只介紹了演算法,並沒有具體說怎麼實現以及怎麼實現最好,舉個例子,你可以按照網上文章的演算法自己寫一個雙線性

線性演算法實現影象

  為了方便理解,先考慮一維情況下的線性插值  對於一個數列c,我們假設c[a]到c[a+1]之間是線性變化的  那麼對於浮點數x(a<=x<a+1),c(x)=c[a+1]*(x-a)+c[a]*(1+a-x);  這個好理解吧? 把這種插值方式擴充套件到二維情況  對於一個二維陣列c,我們假

影象——線性演算法

在數學上,雙線性插值是有兩個變數的插值函式的線性插值擴充套件,其核心思想是在兩個方向分別進行一次線性插值。如果選擇一個座標系統使得  的四個已知點座標分別為 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那麼插值公式就可以化簡為: 用矩陣運算來表示的話就

opencv 學習--- 線性演算法原理簡述

***好記性不如爛筆頭*** 轉自: https://www.cnblogs.com/yssongest/p/5303151.html 1,原理   在影象的仿射變換中,很多地方需要用到插值運算,常見的插值運算包括最鄰近插值,雙線性插值,雙三次插值,蘭索思插值等方法,Op

線性演算法的詳細總結

       最近在做視訊拼接的專案,裡面用到了影象的單應性矩陣變換,在最後的影象重對映,由於目標影象的座標是非整數的,所以需要用到插值的方法,用的就是雙線性插值,下面的博文主要是查看了前輩的部落格對雙線性插值演算法原理進行了一個總結,在這裡也感謝一些大牛的博文。

線性演算法詳解並用matlab實現

雙線性插值演算法 介紹 雙線性插值法又稱為二次線性插值法。在傳統的插值演算法中,它的插值效果比nearest插值法要好的多,但是速度上也必然會慢很多,比bicubic(二次立方法)效果要差, 但速度上要優於bicubic。 它主要思想就是利用某

線性影象演算法的研究與實現

Opencv學堂 http://mp.weixin.qq.com/s?__biz=MzA4MDExMDEyMw==&mid=100000109&idx=1&sn=7540b49e869c3e27f87c84f6f3dfe9a8&chksm

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

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

線性影象問題

       初次開始寫部落格,想記錄下自己在公司實習所做過的事情以及學習到的東西,雖然還是有很多東西不瞭解也還沒做出來,但是也希望這是一種體驗。        我於2018.9.3入職進行實習,到現在也快過去兩個月了,我在公司

OpenCV---如何對影象進行線性運算(7)

附程式碼如下: import cv2 as cv import numpy as np def resize(): src = cv.imread("D:/matplotlib/0.jpg") cv.imshow("input",src) h, w = src.shape

影象演算法-最近鄰 線性

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

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

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

影象中最近鄰線性的基本原理

影象的縮放很好理解,就是影象的放大和縮小。傳統的繪畫工具中,有一種叫做“放大尺”的繪畫工具,畫家常用它來放大圖畫。當然,在計算機上,我們不再需要用放大尺去放大或縮小影象了,把這個工作交給程式來完成就可以了。下面就來講講計算機怎麼來放大縮小圖象;在本文中,我們所說的影象都是指

影象線性

IplImage *img = cvLoadImage("C:\\Users\\Administrator\\Desktop\\3838.jpg"); int nw = img->width; int nh = img->height; void Ctry::OnTryTyr1() { //T

線性影象示例

演算法原理簡介 雙線性插值是一階插值,常用於影象的旋轉、縮放處理。 它利用原圖中對應的四個點的畫素值來確定目標影象中的畫素值。 為了便於理解,我們來看兩張尺寸不一樣的圖片: 原圖 變換圖 假設原圖圖片的寬度為yw,高度為xh 變換圖的寬

圖像——線性算法

val 位置 單位 sso 數學 圖像 取值 利用 等待   在數學上,雙線性插值是有兩個變量的插值函數的線性插值擴展,其核心思想是在兩個方向分別進行一次線性插值。如果選擇一個坐標系統使得 的四個已知點坐標分別為 (0, 0)、(0, 1)、(1, 0) 和 (1, 1)

最近鄰線性的基本原理 以及OpenCV中resize函式的用法改變影象的大小

最近鄰插值和雙線性插值的基本原理 影象的縮放很好理解,就是影象的放大和縮小。傳統的繪畫工具中,有一種叫做“放大尺”的繪畫工具,畫家常用它來放大圖畫。當然,在計算機上,我們不再需要用放大尺去放大或縮小影象了,把這個工作交給程式來完成就可以了。下面就來講講計算機怎麼來放大縮小圖象;在本文中,

線性線性Bilinear Interpolation演算法

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

影象-線性三次

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

影象的放大與縮小(2)——線性放大與均值縮小

概述 基於上一節“等距取樣法”實現圖片放大與縮小的缺點。要對其進行改進,對影象的縮小則可以用“區域性均值法”,對於影象的放大則可以用“雙線性插值法”。 效果如下:                           2048*1536縮小為10