[原始碼] C / C++ 線性插補 bilinear 與注意事項
https://www.wikiwand.com/en/Bilinear_interpolation
就是依照比例取因為比較靠近A所以分到的A比較多,離B比較遠分到的就比較少
AB = A*dx2 + B*dx1
然後再把AB跟CD這兩個點在做一次運算就可以算出中間那個點了
float AB = A*dx2 + B*dx1;
float CD = C*dx2 + D*dx1;
float X = AB*dy2 + CD*dy1;
實作代碼
獲取鄰點
使用 ceil() 這樣就可以正確獲得了
獲取比例
/*****************************************************************
Name :
Date : 2017/11/16
By : CharlotteHonG
Final: 2017/11/16
*****************************************************************/
#include <iostream>
#include <cmath>
using namespace std;
float linear(int* arr, float pos){
// 獲取鄰點(不能用 1+)
size_t c0 = floor(pos);
size_t c1 = ceil(pos);
// 獲取比例(只能用 1-)
float dx1 = pos - c0;
float dx2 = 1 - dx1;
// 乘出比例(要交叉)
float X = arr[c0]*dx2 + arr[c1]*dx1;
return X;
}
float bilinear(int* arr, size_t w, float y, float x){
// 獲取鄰點(不能用 1+, 選中結尾時 x0=x1=W-1 才是對的)
size_t x0 = floor(x);
size_t x1 = ceil(x);
size_t y0 = floor(y);
size_t y1 = ceil(y);
// 獲取比例(只能用 1-, 選中結尾時 1:0 才是對的)
float dx1 = x - x0;
float dx2 = 1 - dx1;
float dy1 = y - y0;
float dy2 = 1 - dy1;
// 獲取點
const float& A = arr[y0*w + x0];
const float& B = arr[y0*w + x1];
const float& C = arr[y1*w + x0];
const float& D = arr[y1*w + x1];
// 乘出比例(要交叉)
float AB = A*dx2 + B*dx1;
float CD = C*dx2 + D*dx1;
float X = AB*dy2 + CD*dy1;
return X;
}
//================================================================
int main(int argc, char const *argv[]){
int arr[] = {0, 10};
cout << linear(arr, 0.1f) << endl;
int arr2[] = {0, 0, 10, 10};
cout << bilinear(arr2, 2, 0.1f, 0.1f) << endl;
return 0;
}
//================================================================
縮放比例
// 縮小向中間對齊
r=srcW/dstW;
double srcX = (dstX+r) * ((double)srcW/dstW) - r;
double srcY = (dstY+r) * ((double)srcH/dstH) - r;
原理其實就是原本會向左上角也就是原點對齊,然後再加上偏差值讓他向中間對齊。
// 縮小的倍率
double r1W = ((double)src.width )/(dst.width );
double r1H = ((double)src.height)/(dst.height);
// 縮小時候的誤差
double deviW = ((src.width-1.0) - (dst.width -1.0)*(r1W)) /dst.width;
double deviH = ((src.height-1.0) - (dst.height-1.0)*(r1H)) /dst.height;
// 縮小保持邊緣對齊
srcX = i*(r1W+deviW);
srcY = j*(r1H+deviH);
公式從原本的向原點對齊,會產生一定誤差,把這個誤差分攤給每個位置。
// 放大保持邊緣對齊
double srcX = (dstX)* ((width-1.0) / (newW-1.0));
double srcY = (dstY)* ((height-1.0) / (newH-1.0));
另外上述算是為了表達沒有加上(double)轉型修飾,是因為有 +1.0 會自動隱式轉型,所以不用補。但是如果是 (int)/(double) 就要補,這個是後面的會隱式轉型成 (int)。