图像的平移
- 假定图像中初始坐标为(x,y),经过平移得到新坐标(x',y'),即我们可以得到变换因子
- x方向上为dx=x'-x
- y方向上为dy=y‘-y
- 我们又知道,矩阵同时也代表着运动,上述描述,可以写为
=*
- 即可以得到反变换公式
- x=x'-dx
- y=y'-dy
- 同样地,图像旋转和图像缩放也可以用这个矩阵来表示了
- 即每个原图像上的像素点均可以通过这样的一一映射关系得到,则代码就很容易实现咯
def bl_interpolate(img, dx=1, dy=1):
H, W, C = img.shape # 首先取得原图像的尺寸大小
out = np.zeros((H, W, C), dtype=np.float) # 重建图像
for y in range(H):
for x in range(W):
for c in range(C):
y1 = y - dy#取得原图像坐标
x1 = x - dx#取得原图像坐标
if ((y1 > H-1 or y1 < 0 or x1 > W-1 or x1 < 0)):
pass
else:
out[y, x, c] = img[y1, x1, c] # 根据上述推导的公式进行变换
return out.astype(np.uint8)
平移伸缩
- 如果想为图像加上放大缩小然后再平移,上面的变换矩阵就变为了tx与ty即对应着x方向和y方向上的伸缩变换,同时dx与dy对应着x和y方向上的平移变换,让我们来看一下反变换公式即
- x方向上变为x=(x'-dx)/tx
- y方向上变为x=(y'-dy)/ty
def bl_interpolate(img, tx=1, ty=1, dx=1, dy=1):
H, W, C = img.shape # 首先取得原图像的尺寸大小
aH = int(ty * H) # 计算插值后的图像尺寸
aW = int(tx * W) # 计算插值后的图像尺寸
out = np.zeros((aH, aW, C), dtype=np.float) # 重建图像
for y in range(aH):
for x in range(aW):
for c in range(C):
y1 = int((y - dy) // ty)
x1 = int((x - dx) // tx)
if ((y1 > H - 1 or y1 < 0 or x1 > W - 1 or x1 < 0)):
pass
else:
print(y, x, c)
print(y1, x1, c)
out[y, x, c] = img[y1, x1, c] # 根据上述推导的公式进行变换
return out.astype(np.uint8)
旋转操作
- 旋转操作同样可以用一个矩阵来说明,举个最简单的例子,直角坐标系中有一点(x,y),当期沿着原点逆时针旋转时,我们可以轻松地写出变换之后的坐标(x',y')即
- x'=xcos-ysin
- y'=xsin+ycos
矩阵形式即
- 反变换公式即为
- x=x'cos+y'sin
- y=y'cos-x'sin
- 如果再把旋转中心加上的话,情况会稍稍复杂一点,但仍然可以通过简单的画图将式子推导出来,即假设旋转中心为(a,b),即根据简单变换即可得到
- x'-a=(x-a)cos-(y-b)sin
- y'-b=(x-a)sin+(y-b)cos
- 此时矩阵可以表示为
- 反变换公式即为
- x-a=(x'-a)cos+(y'-b)sin
- y-b=(y'-b)cos-(x'-a)sin
def affine(_img, a, b, c, d, tx, ty):
H, W, C = _img.shape
# temporary image
img = np.zeros((H + 2, W + 2, C), dtype=np.float32)
img[1:H + 1, 1:W + 1] = _img
# get shape of new image
H_new = np.round(H).astype(np.int)
W_new = np.round(W).astype(np.int)
out = np.zeros((H_new, W_new, C), dtype=np.float32)
# get position of new image
x_new = np.tile(np.arange(W_new), (H_new, 1))
y_new = np.arange(H_new).repeat(W_new).reshape(H_new, -1)
# get position of original image by affine
adbc = a * d - b * c
x = np.round((d * x_new - b * y_new) / adbc).astype(np.int) - tx + 1
y = np.round((-c * x_new + a * y_new) / adbc).astype(np.int) - ty + 1
# adjust center by affine
dcx = (x.max() + x.min()) // 2 - W // 2
dcy = (y.max() + y.min()) // 2 - H // 2
x -= dcx
y -= dcy
x = np.clip(x, 0, W + 1)
y = np.clip(y, 0, H + 1)
# assign pixcel
out[y_new, x_new] = img[y, x]
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread(r"C:\Users\root\Desktop\123.jpg")
# Affine
A = 30.
theta = - np.pi * A / 180.
out = affine(img, a=np.cos(theta), b=-np.sin(theta), c=np.sin(theta), d=np.cos(theta),
tx=0, ty=0)
图像仿射变换使图像倾斜
- 本质相当于在x方向或y方向单独施加一个力,让图像发生x方向或y方向上的形变,即当只在x方向上作用时,y坐标范围不发生变化,而x坐标由于受到力的作用,范围变大,x坐标随y坐标的变化而产生变化,变换矩阵为在此不做过多叙述,原理与上述平移旋转原理一致
def affine(img, dx=30, dy=30):
# get shape
H, W, C = img.shape
# Affine hyper parameters
a = 1.
b = dx / H
c = dy / W
d = 1.
tx = 0.
ty = 0.
# prepare temporary
_img = np.zeros((H+2, W+2, C), dtype=np.float32)
# insert image to center of temporary
_img[1:H+1, 1:W+1] = img
# prepare affine image temporary
H_new = np.ceil(dy + H).astype(np.int)
W_new = np.ceil(dx + W).astype(np.int)
out = np.zeros((H_new, W_new, C), dtype=np.float32)
# preprare assigned index
x_new = np.tile(np.arange(W_new), (H_new, 1))
y_new = np.arange(H_new).repeat(W_new).reshape(H_new, -1)
# prepare inverse matrix for affine
adbc = a * d - b * c
x = np.round((d * x_new - b * y_new) / adbc).astype(np.int) - tx + 1
y = np.round((-c * x_new + a * y_new) / adbc).astype(np.int) - ty + 1
x = np.minimum(np.maximum(x, 0), W+1).astype(np.int)
y = np.minimum(np.maximum(y, 0), H+1).astype(np.int)
# assign value from original to affine image
out[y_new, x_new] = _img[y, x]
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread(r"C:\Users\root\Desktop\123.jpg")
# Affine
out = affine(img, dx=0, dy=30)
网友评论