何為插值?
插值是離散函數逼近的重要方法,利用它可通過函數在有限個點處的取值狀況,估算出函數在其他點處的近似值。
何為圖像插值?
從低解析度圖像生成高解析度圖像的過程(放大),用以恢復圖像中所丟失的信息。
APIpublic static void resize(Mat src, Mat dst, Size dsize, double fx, double fy, int interpolation)public static final int
INTER_NEAREST = 0, // 最近鄰插值法
INTER_LINEAR = 1, // 雙線性插值法
INTER_CUBIC = 2, // 雙三次插值法
INTER_AREA = 3, // 使用像素區域關係進行重採樣
INTER_LANCZOS4 = 4, // 8x8像素鄰域的Lanczos插值
插值方法最近鄰插值(INTER_NEAREST)最近鄰插值法, 找到與之距離最相近的鄰居(原來就存在的像素點, 黑點), 賦值與其相同。
最近鄰插值雙線性插值 (INTER_LINEAR)雙線性插值,又稱為雙線性內插。在數學上,雙線性插值是有兩個變量的插值函數的線性插值擴展,其核心思想是在兩個方向分別進行一次線性插值。
雙線性插值計算過程雙三次插值(INTER_CUBIC)雙三次插值是一種更加複雜的插值方式,它能創造出比雙線性插值更平滑的圖像邊緣。在這種方法中,函數 f 在點 (x, y) 的值可以通過矩形網格中最近的十六個採樣點的加權平均得到,在這裡需要使用兩個多項式插值三次函數,每個方向使用一個。
雙立方插值如上,P點就是目標圖像B在(X,Y)處對應於源圖像A中的位置, 假設P的坐標為(i+u,j+v),其中i,j分別表示整數部分,u,v分別表示小數部分。找到距離p最近的16個像素的位置,在這裡用a(m,n)(m,n=0,1,2,3)來表示。雙立方插值的目的就是通過找到一種關係,或者說係數,可以把這16個像素對於P處像素值得影響因子找出來,從而根據這個影響因子來獲得目標圖像對應點的像素值,達到圖像縮放的目的。基於BiCubic基函數的雙三次插值法使用如下函數:
計算公式通過16個最近的點到P點的距離,求取權重係數。然後通過行列權重與各點的像素值乘積求和,獲取目標圖像對應位置的像素值。
區域插值(INTER_AREA )區域插值共分三種情況,圖像放大時類似於雙線性插值,圖像縮小(x軸、y軸同時縮小)又分兩種情況,此情況下可以避免波紋出現。因此對圖像進行縮小時,為了避免出現波紋現象,推薦採用區域插值方法。
Lanczos插值(INTER_LANCZOS4)蘭索斯插值,由相鄰的8*8像素計算得出,公式類似於雙線性。操作方式和雙三次插值類似,計算距離,計算權重,計算行列乘積,求和。
Lanczos插值計算操作/**
* 圖像插值
* author: yidong
* 2020/12/27
*/
class ResizeActivity : AppCompatActivity() {
private val mList = mutableListOf<ImageTextObject>()
private val mAdapter by lazy { ImageTextAdapter(this, mList) }
private val mBinding: ActivityResizeBinding by lazy {
ActivityResizeBinding.inflate(layoutInflater)
}
private val mFlags = mapOf(
Imgproc.INTER_NEAREST to "INTER_NEAREST",
Imgproc.INTER_LINEAR to "INTER_LINEAR",
Imgproc.INTER_CUBIC to "INTER_CUBIC",
Imgproc.INTER_AREA to "INTER_AREA",
Imgproc.INTER_LANCZOS4 to "INTER_LANCZOS4"
)
private val rgb: Mat by lazy {
val bgr = getBgrFromResId(R.drawable.tiny_lena)
bgr.toRgb()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
mBinding.container.adapter = mAdapter
wrapCoroutine({ before() }, { doResize() }, { after() })
}
override fun onDestroy() {
super.onDestroy()
rgb.release()
}
private fun doResize() {
val w = rgb.rows()
val h = rgb.cols()
for (i in mFlags) {
val dst = Mat()
Imgproc.resize(
rgb,
dst,
Size((w * 100).toDouble(), (h * 100).toDouble()),
0.0,
0.0,
i.key
)
mList.add(ImageTextObject(dst, mFlags.getOrElse(i.key) { "" }))
}
}
private fun before() {
mBinding.isLoading = true
}
private fun after() {
mBinding.isLoading = false
mAdapter.notifyDataSetChanged()
}
}
效果INTER_NEARESTINTER_LINEARINTER_CUBICINTER_AREAINTER_LANSZOS4源碼https://github.com/onlyloveyd/LearningAndroidOpenCV
推薦閱讀:
Android OpenCV(五十):圖像翻轉
Android OpenCV(四十九):圖像積分圖
Android OpenCV(四十八):Poisson圖像編輯
Android OpenCV(四十七):脫色