深度學習之雙線性插值(Bilinear interpolation)

1. 什么是插值

Interpolation is a method of constructing new data points within the range of a discrete set of known data points. Image interpolation refers to the“guess”of intensity values at missing locations.

圖片放大是圖像處理中的一個特別基礎的操作。在幾乎每一個圖片相關的項目中,從傳統圖像處理到深度學習,都有應用。生活里,和朋友通過微信傳張圖片,從圖片發出,到朋友收到圖片,查看圖片,都會數次的的改變圖像的尺寸,從而用到這個算法。但是很少關注這個算法的實現細節:插值算法是如何工作的。
簡單來說,插值指利用已知的點來“猜”未知的點,圖像領域插值常用在修改圖像尺寸的過程,由舊的圖像矩陣中的點計算新圖像矩陣中的點并插入,不同的計算過程就是不同的插值算法。

2.常用的插值算法

插值算法有很多種,常見的插值運算包括:

  • 最近鄰法(Nearest Interpolation):計算速度最快,但是效果最差。
  • 雙線性插值(Bilinear Interpolation):雙線性插值是用原圖像中4(2*2)個點計算新圖像中1個點,效果略遜于雙三次插值,速度比雙三次插值快,屬于一種平衡美,在很多框架中屬于默認算法。由于折中的插值效果和運算速度,運用比較廣泛。
  • 雙三次插值(Bicubic interpolation):雙三次插值是用原圖像中16(4*4)個點計算新圖像中1個點,效果比較好,但是計算代價過大。

3.最近鄰法(Nearest Interpolation)

越是簡單的模型越適合用來舉例子,我們就舉個簡單的圖像:3?33*33?3 的256級灰度圖。假如圖像的象素矩陣如下圖所示(這個原始圖把它叫做源圖,Source):

       234	38 	22  67 	44 	12  89 	65	63  

這個矩陣中,元素坐標(x,y)是這樣確定的,x從左到右,從0開始,y從上到下,也是從零開始,這是圖象處理中最常用的坐標系。

如果想把這副圖放大為 4?44*44?4 大小的圖像,那么該怎么做呢?那么第一步肯定想到的是先把 4?44*44?4 的矩陣先畫出來再說,好了矩陣畫出來了,如下所示,當然,矩陣的每個像素都是未知數,等待著我們去填充(這個將要被填充的圖的叫做目標圖,Destination):

  ? ? ? ?  ? ? ? ?  ? ? ? ?  ? ? ? ?  

然后要往這個空的矩陣里面填值了,要填的值從哪里來來呢?是從源圖中來,好,先填寫目標圖最左上角的象素,坐標為(0,0),那么該坐標對應源圖中的坐標可以由如下公式得出

srcX=dstX?(srcWidth/dstWidth),srcY=dstY?(srcHeight/dstHeight)srcX=dstX* (srcWidth/dstWidth) ,srcY = dstY * (srcHeight/dstHeight)srcX=dstX?(srcWidth/dstWidth),srcY=dstY?(srcHeight/dstHeight)

好了,套用公式,就可以找到對應的原圖的坐標了 (0?(3/4),0?(3/4))=>(0?0.75,0?0.75)=>(0,0)(0*(3/4),0*(3/4))=>(0*0.75,0*0.75)=>(0,0)(0?(3/4),0?(3/4))=>(0?0.75,0?0.75)=>(0,0),找到了源圖的對應坐標,就可以把源圖中坐標為(0,0)處的234象素值填進去目標圖的(0,0)這個位置了。

接下來,如法炮制,尋找目標圖中坐標為(1,0)的象素對應源圖中的坐標,套用公式:
(1?0.75,0?0.75)=>(0.75,0)(1*0.75,0*0.75)=>(0.75,0)(1?0.75,0?0.75)=>(0.75,0) 結果發現,得到的坐標里面竟然有小數,這可怎么辦?計算機里的圖像可是數字圖像,象素就是最小單位了,象素的坐標都是整數,從來沒有小數坐標。這時候采用的一種策略就是采用四舍五入的方法(也可以采用直接舍掉小數位的方法),把非整數坐標轉換成整數,好,那么按照四舍五入的方法就得到坐標(1,0),完整的運算過程就是這樣的:(1?0.75,0?0.75)=>(0.75,0)=>(1,0)(1*0.75,0*0.75)=>(0.75,0)=>(1,0)(1?0.75,0?0.75)=>(0.75,0)=>(1,0) 那么就可以再填一個象素到目標矩陣中了,同樣是把源圖中坐標為(1,0)處的像素值38填入目標圖中的坐標。

依次填完每個象素,一幅放大后的圖像就誕生了,像素矩陣如下所示:

  234 38 22 22  67 44 12 12  89 65 63 63  89 65 63 63  

這種放大圖像的方法叫做最臨近插值算法,這是一種最基本、最簡單的圖像縮放算法,效果也是最不好的,放大后的圖像有很嚴重的馬賽克,縮小后的圖像有很嚴重的失真;效果不好的根源就是其簡單的最臨近插值方法引入了嚴重的圖像失真,比如,當由目標圖的坐標反推得到的源圖的的坐標是一個浮點數的時候,采用了四舍五入的方法,直接采用了和這個浮點數最接近的象素的值,這種方法是很不科學的,當推得坐標值為 0.75的時候,不應該就簡單的取為1,既然是0.75,比1要小0.25 ,比0要大0.75 ,那么目標象素值其實應該根據這個源圖中虛擬的點四周的四個真實的點來按照一定的規律計算出來的,這樣才能達到更好的縮放效果。

4 雙線性插值

雙線型內插值算法就是一種比較好的圖像縮放算法,它充分的利用了源圖中虛擬點四周的四個真實存在的像素值來共同決定目標圖中的一個像素值,因此縮放效果比簡單的最鄰近插值要好很多。 雙線性內插值算法描述如下:

對于一個目的像素,設置坐標通過反向變換得到的浮點坐標為(i+u,j+v) (其中i、j均為浮點坐標的整數部分,u、v為浮點坐標的小數部分,是取值[0,1)區間的浮點數),則這個像素得值 f(i+u,j+v) 可由原圖像中坐標為 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所對應的周圍四個像素的值決定,即:f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
其中f(i,j)表示源圖像(i,j)處的的像素值,以此類推。

比如,象剛才的例子,現在假如目標圖的象素坐標為(1,1),那么反推得到的對應于源圖的坐標是(0.75,0.75), 這其實只是一個概念上的虛擬象素,實際在源圖中并不存在這樣一個象素,那么目標圖的象素(1,1)的取值不能夠由這個虛擬象素來決定,而只能由源圖的這四個象素共同決定:(0,0)(0,1)(1,0)(1,1),而由于(0.75,0.75)離(1,1)要更近一些,那么(1,1)所起的決定作用更大一些,這從公式1中的系數uv=0.75×0.75就可以體現出來,而(0.75,0.75)離(0,0)最遠,所以(0,0)所起的決定作用就要小一些,公式中系數為(1-u)(1-v)=0.25×0.25也體現出了這一特點。

計算方法
在這里插入圖片描述

首先,在X方向上進行兩次線性插值計算,然后在Y方向上進行一次插值計算。
  在這里插入圖片描述
在這里插入圖片描述

在圖像處理的時候,我們先根據
  
srcX=dstX?(srcWidth/dstWidth),srcX=dstX* (srcWidth/dstWidth) ,srcX=dstX?(srcWidth/dstWidth),
srcY=dstY?(srcHeight/dstHeight)srcY = dstY * (srcHeight/dstHeight) srcY=dstY?(srcHeight/dstHeight)

來計算目標像素在源圖像中的位置,這里計算的srcX和srcY一般都是浮點數,比如f(1.2, 3.4)這個像素點是虛擬存在的,先找到與它臨近的四個實際存在的像素點 (1,3) (2,3) (1,4) (2,4) 寫成f(i+u,j+v)的形式,則u=0.2,v=0.4, i=1, j=3 在沿著X方向差插值時,f(R1)=u(f(Q21)-f(Q11))+f(Q11) 沿著Y方向同理計算。 或者,直接整理一步計算,f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1) 。

5. 加速以及優化策略

單純按照上文實現的插值算法只能勉強完成插值的功能,速度和效果都不會理想,在具體代碼實現的時候有些小技巧。參考OpenCV源碼以及網上博客整理如下兩點:

  • 源圖像和目標圖像幾何中心的對齊。
  • 將浮點運算轉換成整數運算

5.1 源圖像和目標圖像幾何中心的對齊

方法:在計算源圖像的虛擬浮點坐標的時候,一般情況:

srcX=dstX?(srcWidth/dstWidth),srcY=dstY?(srcHeight/dstHeight)srcX=dstX* (srcWidth/dstWidth) ,srcY = dstY * (srcHeight/dstHeight) srcX=dstX?(srcWidth/dstWidth),srcY=dstY?(srcHeight/dstHeight)

中心對齊(OpenCV也是如此):

SrcX=(dstX+0.5)?(srcWidth/dstWidth)?0.5,SrcY=(dstY+0.5)?(srcHeight/dstHeight)?0.5SrcX=(dstX+0.5)* (srcWidth/dstWidth) -0.5,SrcY=(dstY+0.5) * (srcHeight/dstHeight)-0.5SrcX=(dstX+0.5)?(srcWidth/dstWidth)?0.5,SrcY=(dstY+0.5)?(srcHeight/dstHeight)?0.5

問題

下面這張圖是以右上角為坐標系原點,我們可以發現最右面的點都會有概率直接復制到目標圖像中(至少原點肯定是這樣),而且就算不不和原圖像中的點重合,也相當于進行了1次單線性插值。這樣如果我們采用不用的坐標系產生的結果是不一樣的,而且無論我們采用什么坐標系,最左側和最右側(最上側和最下側)的點是不“公平的”,這是第一個問題。

在這里插入圖片描述

整體的圖像相對位置會發生變化看下面這張圖,左側是原圖像(33),右側是目標圖像(55),原圖像的幾何中心點是(1, 1),目標圖像的幾何中心點是(2, 2),根據對應關系,目標圖像的幾何中心點對應的原圖像的位置是(1.2, 1.2),如圖所示,那么問題來了,目標圖像的原點(0, 0)點和原始圖像的原點是重合的,但是目標圖像的幾何中心點相對于原始圖像的幾何中心點偏右下,那么整體圖像的位置會發生偏移,為什么這樣說,其實圖像是由1個個的像素點組成,單純說1個像素點是沒有太大的意義的,1個像素點跟相鄰像素點的值的漸變或者突變形成圖像顏色的漸變或者邊界,所以參與計算的點相對都往右下偏移會產生相對的位置信息損失。這是第二個問題。

在這里插入圖片描述
解決
  
將公式變形,srcX=dstX?(srcWidth/dstWidth)+0.5?(srcWidth/dstWidth?1)srcX=dstX* (srcWidth/dstWidth)+0.5*(srcWidth/dstWidth-1)srcX=dstX?(srcWidth/dstWidth)+0.5?(srcWidth/dstWidth?1) 相當于我們在原始的浮點坐標上加上了 0.5?(srcWidth/dstWidth?1)0.5*(srcWidth/dstWidth-1)0.5?(srcWidth/dstWidth?1) 這樣一個控制因子,這項的符號可正可負,與 srcWidth/dstWidthsrcWidth/dstWidthsrcWidth/dstWidth 的比值也就是當前插值是擴大還是縮小圖像有關,有什么作用呢?看一個例子:假設源圖像是 3?33*33?3,中心點坐標(1,1)目標圖像是 9?99*99?9,中心點坐標(4,4),我們在進行插值映射的時候,盡可能希望均勻的用到源圖像的像素信息,最直觀的就是(4,4)映射到(1,1)現在直接計算 srcX=4?3/9=1.3333!=1srcX=4*3/9=1.3333!=1srcX=4?3/9=1.3333=1,也就是我們在插值的時候所利用的像素集中在圖像的右下方,而不是均勻分布整個圖像。現在考慮中心點對齊,srcX=(4+0.5)*3/9-0.5=1,剛好滿足我們的要求。

5.2 將浮點運算轉換成整數運算

參考圖像處理界雙線性插值算法的優化

直接進行計算的話,由于計算的srcX和srcY 都是浮點數,后續會進行大量的乘法,而圖像數據量又大,速度不會理想,解決思路是:浮點運算→→整數運算→→”<<左右移按位運算”

放大的主要對象是u,v這些浮點數,OpenCV選擇的放大倍數是2048“如何取這個合適的放大倍數呢,要從三個方面考慮,第一:精度問題,如果這個數取得過小,那么經過計算后可能會導致結果出現較大的誤差。第二,這個數不能太大,太大會導致計算過程超過長整形所能表達的范圍。第三:速度考慮。假如放大倍數取為12,那么算式在最后的結果中應該需要除以12*12=144,但是如果取為16,則最后的除數為16*16=256,這個數字好,我們可以用右移來實現,而右移要比普通的整除快多了。”我們利用左移11位操作就可以達到放大目的。

6. 代碼

    uchar* dataDst = matDst1.data;int stepDst = matDst1.step;uchar* dataSrc = matSrc.data;int stepSrc = matSrc.step;int iWidthSrc = matSrc.cols;int iHiehgtSrc = matSrc.rows;for (int j = 0; j < matDst1.rows; ++j){float fy = (float)((j + 0.5) * scale_y - 0.5);int sy = cvFloor(fy);fy -= sy;sy = std::min(sy, iHiehgtSrc - 2);sy = std::max(0, sy);short cbufy[2];cbufy[0] = cv::saturate_cast<short>((1.f - fy) * 2048);cbufy[1] = 2048 - cbufy[0];for (int i = 0; i < matDst1.cols; ++i){float fx = (float)((i + 0.5) * scale_x - 0.5);int sx = cvFloor(fx);fx -= sx;if (sx < 0) {fx = 0, sx = 0;}if (sx >= iWidthSrc - 1) {fx = 0, sx = iWidthSrc - 2;}short cbufx[2];cbufx[0] = cv::saturate_cast<short>((1.f - fx) * 2048);cbufx[1] = 2048 - cbufx[0];for (int k = 0; k < matSrc.channels(); ++k){*(dataDst+ j*stepDst + 3*i + k) = (*(dataSrc + sy*stepSrc + 3*sx + k) * cbufx[0] * cbufy[0] + *(dataSrc + (sy+1)*stepSrc + 3*sx + k) * cbufx[0] * cbufy[1] + *(dataSrc + sy*stepSrc + 3*(sx+1) + k) * cbufx[1] * cbufy[0] + *(dataSrc + (sy+1)*stepSrc + 3*(sx+1) + k) * cbufx[1] * cbufy[1]) >> 22;}}}cv::imwrite("linear_1.jpg", matDst1);cv::resize(matSrc, matDst2, matDst1.size(), 0, 0, 1);cv::imwrite("linear_2.jpg", matDst2);

參考:

  • OpenCV ——雙線性插值(Bilinear interpolation)
  • https://blog.csdn.net/qq_37577735/article/details/80041586

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/453713.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/453713.shtml
英文地址,請注明出處:http://en.pswp.cn/news/453713.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

div table 超出了_div包裹的table,table的寬度超出了的寬度,出現的滾動條的在windows下無法拖動...

1.父級div是否設置了寬度&#xff0c;只有設置了寬度且滾動條在div內才是你想要控制的滾動2.僅憑你說的這些屬性不知道滾動條怎么不能動&#xff0c;可以貼一下代碼&#xff1f;3.橫向需要滾動條的話必須設置table的確定寬度做了一個demo:.table{table-layout:fixed; width:…

第二階段站立會議7

昨天&#xff1a;美化頁面 今天&#xff1a;進行項目上傳 問題&#xff1a;阿里云服務器上的mysql出現連接問題轉載于:https://www.cnblogs.com/sdysyhj/p/8301489.html

深度學習之 OHEM (Online Hard Example Mining)

論文 《Training Region-based Object Detectors with Online Hard Example Mining》鏈接 https://arxiv.org/pdf/1604.03540.pdf Astract 摘要主要講了四點&#xff1a; (1) 訓練過程需要進行參數的空間搜索(2) 簡單樣本與難分辨樣本之間的類別不平衡是亟需解決的問題(3) 自…

音視頻 詳解

avi文件格式詳解 AVI是音頻視頻交錯(Audio Video Interleaved)的英文縮寫&#xff0c;它是Microsoft公司開發的一種符合RIFF文件規范的數字音頻與視頻文件格式&#xff0c;原先用于Microsoft Video for Windows (簡稱VFW)環境&#xff0c;現在已被Windows 95/98、OS/2等多數操…

c6011取消對null指針的引用_C++| 函數的指針參數如何傳遞內存?

函數的參數是一個一級指針&#xff0c;可以傳遞內存嗎&#xff1f;如果函數的參數是一個一級指針&#xff0c;不要指望用該指針去申請動態內存。看下面的實例&#xff1a;#include using namespace std;void GetMemory(char *p, int num){p (char *)malloc(sizeof(char) * num…

Servlet執行時要實現的方法

Servlet執行時要實現的方法 public void init(ServletConfig config) public ServletConfig getServletConfig() public String getServletInfo() public void service(ServletRequest request,ServletResponse response) public void destroy() 本文轉自sucre03 5…

axios 設置攔截器 全局設置帶默認參數(發送 token 等)

應用場景&#xff1a;1&#xff0c;每個請求都帶上的參數&#xff0c;比如token&#xff0c;時間戳等。2&#xff0c;對返回的狀態進行判斷&#xff0c;比如token是否過期代碼如下&#xff1a;[javascript] view plain copyaxios.interceptors.request.use( config &g…

深度學習目標檢測之 YOLO v2

論文名&#xff1a;《YOLO9000: Better, Faster, Stronger》原文&#xff1a;https://arxiv.org/pdf/1612.08242v1.pdf代碼&#xff1a;http://pjreddie.com/darknet/yolo/ YOLO v2 斬獲了CVPR 2017 Best Paper Honorable Mention。在這篇文章中&#xff0c;作者首先在YOLOv1的…

tcpmp 編譯 源代碼分析

TCPMP源代碼分析 TCPMP源代碼分析 播放器主要由核心框架模塊&#xff08;common工程&#xff09;和解碼器、分離器插件組成。TCPMP的插件非常多&#xff0c;其中主要的插件有&#xff1a;interface插件實現了TCPMP的界面&#xff0c;ffmpeg是系統主要的音視頻解碼模塊&#xff…

使用zerorpc踩的第一個坑:

Server端代碼&#xff1a;注意s.run() 和 s.run的區別&#xff0c;一個括號搞死我了.如果不加括號&#xff0c;服務端服務是不會啟動的&#xff0c;客戶端就會報連接超時的錯誤 Server端在本機所有IP上監聽4242端口的tcp協議 import zerorpcclass HelloRPC(object):   def __…

django存入mysql數據庫_django如何存數據到一個mysql數據表里面

讓我們聊聊這個話題&#xff0c; django如何存數據至mysql數據表里面&#xff0c;你會用什么方法&#xff1f;正常情況下&#xff0c;我們form邏輯處理后&#xff0c;直接form.save()&#xff0c;是&#xff0c;這個方法沒毛病&#xff1b;但有沒有其他的方法呢&#xff1f;假如…

【Luogu】P3343地震后的幻想鄉(對積分概率進行DP)

題目鏈接 神難qwq。配合rqy的博客食用。 首先我們學到有一個概率函數$p(x)$表示某事件發生概率取值小于x的函數。這個函數有什么特點呢&#xff1f; 那就是$\int_{-∞}^{∞}p(x)dx1$ 這個是顯然的 然后我們令p(x)為首次聯通的時間的概率分布函數 這其實等價于生成樹的最大權邊等…

深度學習目標檢測之 YOLO v3

論文名&#xff1a;《YOLOv3: An Incremental Improvement》論文地址 https://pjreddie.com/media/files/papers/YOLOv3.pdfhttps://arxiv.org/abs/1804.02767v1 論文代碼 https://github.com/yjh0410/yolov2-yolov3_PyTorchkeras&#xff1a;https://github.com/qqwweee/keras…

30本pdf完整版的經典Linux學習和開發教程和資料下載 android arm java 資料大全

史上最牛的Linux內核學習方法論 點擊下載我的arm_linux移植筆記 點擊下載S3C2440完全開發流程 點擊下載Linux系統命令及其使用詳解完整版 點擊下載Linux主要shell命令詳解 點擊下載深入理解Linux內核(第三版 pdf英文版) 點擊下載深入分析Linux內核源代碼教程pdf完整版 點擊下…

Fedex Ship Manager Software安裝

本文出自Simmy的個人blog&#xff1a;西米在線 http://simmyonline.com/archives/552.html 這個軟件的安裝頗費了我一番周章&#xff0c;特地Log之。下載&#xff1a;http://www.fedex.com/apac_english/fsmsoftware/ 安裝完后&#xff0c;接著輸入用戶信息&#xff0c;然后連…

mysql5.7.11解壓版安裝_Mysql5.7.11在windows10上的安裝與配置(解壓版)

第一步my-default.ini 添加配置&#xff1a;#綁定IPv4和3306端bind-address 127.0.0.1port 3306# 設置mysql的安裝目basedir E:\mysql# 設置mysql數據庫的數據的存放目datadirE:\mysql\data# 允許最大連接數max_connections200#設置默認字符集為utf8default-character-setutf…

【轉】博客美化(3)為博客添加一個漂亮的分享按鈕

閱讀目錄 1.社會化分享2.選擇一個分享按鈕3.添加到博客園博客博客園美化相關文章目錄&#xff1a;博客園博客美化相關文章目錄 在前2篇博客“博客美化(1)基本后臺設置與樣式設置”與"博客美化(2)自定義博客樣式細節"中詳細介紹了博客樣式設置的相關問題&#xff0c;當…

深度學習目標檢測之 YOLO v4

論文原文&#xff1a;https://arxiv.org/abs/2004.10934代碼 原版c&#xff1a; https://github.com/AlexeyAB/darknetkeras:https&#xff1a;//github.com/Ma-Dan/keras-yolo4pytorch&#xff1a;https://github.com/Tianxiaomo/pytorch-YOLOv4 前言 2020年YOLO系列的作者…

[Android] 年年有魚手機主題

自制的年年有魚手機主題&#xff0c;希望大家喜歡&#xff01;~ 下載地址&#xff1a;https://yunpan.cn/cqauQbiM97idd &#xff08;提取碼&#xff1a;d272&#xff09; 本文轉自haiyang45751CTO博客&#xff0c;原文鏈接&#xff1a; http://blog.51cto.com/haiyang457/1…

mysql 小數做索引_10 分鐘掌握 MySQL 的索引查詢優化技巧

本文的內容是總結一些MySQL的常見使用技巧&#xff0c;以供沒有DBA的團隊參考。如無特殊說明&#xff0c;存儲引擎以InnoDB為準。MySQL的特點了解MySQL的特點有助于更好的使用MySQL&#xff0c;MySQL和其它常見數據庫最大的不同在于存在存儲引擎這個概念&#xff0c;存儲引擎負…