文章目录
-
-
- 26. 双线性插值(Bilinear Interpolation)
- 27. 双三次插值 (Bicubic Interpolation)
- 28. 仿射变换(Afine Transformations) - 平移移动
- 29. 仿射变换(Affine Transformations) - 放大缩小
- 30. 仿射变换(Affine Transformations - 旋转)
-
26. 双线性插值(Bilinear Interpolation)
使用双线插值放大图像1.5倍吧! 双线插值检查4邻域的像素点,并根据距离设置权值.虽然计算量的增加会延长处理时间,但可以有效抑制画质的劣化.
放大图像坐标(x',y除以放大率a,获得相应原始图像的坐标 floor(x'/a,y'/a). '
图像的坐标(x'/a,y'/a)四个邻域的坐标 I(x,y), I(x 1,y), I(x,y 1),I(x 1,y 1)
I(x,y) I(x 1,y) (x'/a,y'/a) I(x,y 1) I(x 1,y 1)
-
分别要求这四点和(x’/a,y’/a)权重根据距离设定: w = d / sum d
-
根据下公式放大后图像(x’,y)像素值:
dx = x'/a - x dy = y'/y - y I'(x',y') = (1-dx)(1-dy)I(x,y) dx(1-dy)I(x 1,y) (1-dx)dyI(x,y 1) dxdyI(x 1,y 1)
代码实现:
# @Time : 2022/6/11 16:59 # @Author : Fioman # @Phone : 13149920693 # @Tips : Talk is Cheap,Show me the code! ^_^^_^ from settings import * def linear_interpolate(image, ax=1.1, ay=1.):
H, W = image.shape[:2]
aH = int(ay * H)
aW = int(ax * H)
# get position of original position
y = np.arange(aH).repeat(aW).reshape(aH, -1)
x = np.tile(np.arange(aW), (aH, 1))
# get position of original position
y = (y / ay)
x = (x / ax)
ix = np.floor(x).astype(np.int0)
iy = np.floor(y).astype(np.int0)
ix = np.minimum(ix, W - 2)
iy = np.minimum(iy, H - 2)
# get distance
dx = x - ix
dy = y - iy
dx = np.repeat(np.expand_dims(dx, axis=-1), 3, axis=-1)
dy = np.repeat(np.expand_dims(dy, axis=-1), 3, axis=-1)
# interpolation
out = (1 - dx) * (1 - dy) * image[iy, ix] + dx * (1 - dy) * image[iy, ix + 1] + \
(1 - dx) * dy * image[iy + 1, ix] + dx * dy * image[iy + 1, ix + 1]
out = np.clip(out, 0, 255)
out = out.astype(np.uint8)
return out
if __name__ == '__main__':
imagePath = os.path.join(OPENCV_100_Q_PATH,"color_02.bmp")
imageOriginal = cv.imread(imagePath,cv.IMREAD_COLOR)
out = linear_interpolate(imageOriginal,ax=1.5,ay=1.5)
cv.imshow("Original",imageOriginal)
cv.imshow("Out",out)
cv.waitKey(0)
27. 双三次插值 (Bicubic Interpolation)
双三次插值是双线性插值的扩展,它使用的是邻域的16个像素进行插值.
I(x-1,y-1) I(x,y-1) I(x+1,y-1) I(x+2,y-1)
I(x-1,y) I(x,y) I(x+1,y) I(x+2,y)
I(x-1,y+1) I(x,y+1) I(x+1,y+1) I(x+2,y+1)
I(x-1,y+2) I(x,y+2) I(x+1,y+2) I(x+2,y+2)
各像素间的距离由下式决定:
dx1 = x'/a - (x-1) , dx2 = x'/a - x , dx3 = (x+1) - x'/a , dx4 = (x+2) - x'/a
dy1 = y'/a - (y-1) , dy2 = y'/a - y , dy3 = (y+1) - y'/a , dy4 = (y+2) - y'/a
由于距离的权重函数由以下函数取得,a在大部分时候取-1:
h(t) = {
(a+2)|t|^3 - (a+3)|t|^2 + 1 (when |t|<=1)
a|t|^3 - 5a|t|^2 + 8a|t| - 4a (when 1<|t|<=2)
0 (when 2<|t|)
利用上面得到的权重,通过下面的式子扩大图像.将每个像素和权重的乘积之和除以权重的和.
I'(x', y') = (Sum{
i=-1:2}{
j=-1:2} I(x+i,y+j) * wxi * wyj) / Sum{
i=-1:2}{
j=-1:2} wxi * wyj
实现代码如下:
# @Time : 2022/6/13 10:48
# @Author : Fioman
# @Phone : 13149920693
# @Tips : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
# Bicubic Interpolation (双三次插值算法)
def bicubic_interpolation(image,ax=1.,ay=1.):
H,W,C = image.shape
aH = int(ay * H)
aW = int(ax * W)
# get positions of resized image
y = np.arange(aH).repeat(aW).reshape(aH,-1)
x = np.tile(np.arange(aW),(aH,1))
y = (y / ay)
x = (x / ax)
# get positions of original image
ix = np.floor(x).astype(np.int0)
iy = np.floor(y).astype(np.int0)
ix = np.minimum(ix,W-1)
iy = np.minimum(iy,H-1)
# get distance of each postion of original image
dx2 = x- ix
dy2 = y - iy
dx1 = dx2 + 1
dy1 = dy2 +1
dx3 = 1 - dx2
dy3 = 1 - dy2
dx4 = 1 +dx3
dy4 = 1 + dy3
dxs = [dx1,dx2,dx3,dx4]
dys = [dy1,dy2,dy3,dy4]
# bi-cubic weight
def weight(t):
a = -1
at = np.abs(t)
w = np.zeros_like(t)
ind = np.where(at <= 1)
w[ind] = ((a+2) * np.power(at,3) - (a +3) * np.power(at,2) + 1)[ind]
ind = np.where((at > 1) & (at <= 2))
w[ind] = (a * np.power(at,3) - 5 * a * np.power(at,2) +8*a*at - 4 * a)[ind]
return w
wSum = np.zeros((aH,aW,C),dtype=np.float32)
out = np.zeros((aH,aW,C),dtype=np.float32)
# interpolation
for j in range(-1,3):
for i in range(-1,3):
indX = np.minimum(np.maximum(ix + i,0),W-1)
indY = np.minimum(np.maximum(iy+j,0),H-1)
wx = weight(dxs[i+1])
wy = weight(dys[j+1])
wx = np.repeat(np.expand_dims(wx,axis=-1),3,axis=-1)
wy = np.repeat(np.expand_dims(wy,axis=-1),3,axis=-1)
wSum += wx * wy
out += wx*wy*image[indY,indX]
out /= wSum
out = np.clip(out,0,255)
out = out.astype(np.uint8)
return out
if __name__ == '__main__':
imagePath = os.path.join(OPENCV_100_Q_PATH,"color_02.bmp")
imageOriginal = cv.imread(imagePath,cv.IMREAD_COLOR)
out = bicubic_interpolation(imageOriginal,1.5,1.5)
cv.imshow("Original",imageOriginal)
cv.imshow("BicubicRes",out)
cv.waitKey(0)
28. 仿射变换(Afine Transformations) - 平移移动
平移操作可以这么去看待:
原图记为(x,y),变换后的图像记为(x’,y’).图像放大缩小的矩阵为下式: 另一方面,平行移动按照下面的式子去计算: 上面的两个式子合成一个: 但是在实际的操作的过程中,如果一个一个地去计算原图像的像素的话,处理后的像素可能没有在原图像中有对应的坐标. 因此,我们有必要对处理后的图像中各个像素进行仿射变换逆变换,取得变换后图像中的像素在原图像中的坐标.仿射变换的逆变换如下:
实现代码:
# @Time : 2022/6/13 13:55
# @Author : Fioman
# @Phone : 13149920693
# @Tips : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
def affine(image, a, b, c, d, tx, ty):
H, W, C = image.shape
# temporary image,这个临时图像的宽和高都加了两个像素,然后中间赋值为原图像.
imageTemp = np.zeros((H + 2, W + 2, C), dtype=np.float32)
imageTemp[1:H + 1, 1:W + 1] = image
# get new image shape,这里也有缩放的那个意思,不只是平移.
newH = np.round(H * d).astype(np.int0)
newW = np.round(W * a).astype(np.int0)
out = np.zeros((newH + 1, newW + 1, C), dtype=np.float32)
# get position of new image
newX = np.tile(np.arange(newW), (newH, 1))
newY = np.arange(newH).repeat(newW).reshape(newH, -1)
# get position of original image by affine
adbc = a * d - b * c
x = np.round((d * newX - b * newY) / adbc).astype(np.int0) - tx + 1
y = np.round((-c * newX + a * newY) / adbc).astype(np.int0) - ty + 1
x = np.minimum(np.maximum(x, 0), W + 1).astype(np.int0)
y = np.minimum(np.maximum(y, 0), H + 1).astype(np.int0)
# assgin pixcel to new image
out[newY, newX] = image[y, x]
out = out[:newH, :newW]
out = out.astype(np.uint8)
return out
if __name__ == '__main__':
imagePath = os.path.join(OPENCV_100_Q_PATH, "color_02.bmp")
imageOriginal = cv.imread(imagePath, cv.IMREAD_COLOR)
out = affine(imageOriginal, a=1, b=0, c=0, d=1, tx=30, ty=30)
cv.imshow("Original", imageOriginal)
cv.imshow("MoveAffine", out)
cv.waitKey(0)
29. 仿射变换(Affine Transformations) - 放大缩小
- 使用仿射变换,将图片在x方向上放大1.3倍,在y方向上缩小至原来的0.8.
- 在上面的条件下,同时在x方向上向右平移30(+30),在y方向上向上平移30(-30).
代码实现:
from settings import * def affine(image, a, b, c, d, tx, ty): H, W, C = image.shape # temporary image newImage = np.zeros((H + 2, W + 2, C), dtype=np.float32) newImage[1:H + 1, 1:W + 1] = image # get new image shape newH = np.round(H * d).astype(np.int0) newW = np.round(W * a).astype(np.int0) out = np.zeros((newH + 1, newW + 1, C), dtype=np.float32) # get position of new image newX = np.tile(np.arange(newW), (newH, 1)) newY = np.arange(newH).repeat(newW).reshape(newH, -1) # get position of original image by affine adbc = a * d - b * c x = np.round((d * newX - b * newY) / adbc).astype(np.int0) - tx + 1 y = np.round((-c * newX + a * newY) / adbc).astype(np.int0) - ty + 1 x = np.minimum(np.maximum(x, 0), W + 1).astype(np.int0) y = np.minimum(np.maximum(y, 0), H + 1).astype(np.int0) out[newY, newX] = image[y, x] out = out[:newH, :newW] out = out.astype(np.uint8) return out if __name__ == '__main__': imagePath = os.path.join(OPENCV_100_Q_PATH,"color_02.bmp") imageOriginal = cv.imread(imagePath,cv.IMREAD_COLOR) out = affine(imageOriginal,a = 1.3,b = 0,c = 0, d = 0.8,tx=30,ty =