前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CV基础教程:图像上的几何变换

CV基础教程:图像上的几何变换

作者头像
deephub
发布2020-05-09 16:31:35
1.1K0
发布2020-05-09 16:31:35
举报
文章被收录于专栏:DeepHub IMBADeepHub IMBA

作者:Akula Hemanth Kumar deephub翻译组:孟翔杰

目录

1.缩放

2.平移

3.旋转

4.仿射变换

5.透视变换

缩放

  • 图像缩放是指调整图像的大小
  • magnification称为放大
  • downsizing称为缩小
  • 理想目标-图片无损转换
  • 图像分辨率-高度(以像素为单位)*宽度(以像素为单位)

使用 numpy 模块调整图像大小

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("imgs/chapter4/tessellate.jpg", -1)
print("Input image shape - {}".format(img.shape))
plt.imshow(img[:,:,::-1])
plt.show()

输出

Input image shape - (240, 320, 3)

缩小图像宽度

height, width, channels = img.shape

# create blank image of half the width
resized_img_width = np.zeros((height, width//2, channels), dtype=np.int32)for r in range(height):
    for c in range(width//2):
        resized_img_width[r][c] += (img[r][2*c])
        
print("Width resized image shape - {}".format(resized_img_width.shape))
plt.imshow(resized_img_width[:,:,::-1])
plt.show()

输出

Width resized image shape - (240, 160, 3)

将图像的高度和宽度均缩小到原来的一半

resized_img = np.zeros((height//2, width//2, channels), dtype=np.int32)for r in range(height//2):
    for c in range(width//2):
        resized_img[r][c] += (resized_img_width[r*2][c])
print("Complete resized image shape - {}".format(resized_img.shape))
plt.imshow(resized_img[:,:,::-1])
plt.show()

输出

Complete resized image shape - (120, 160, 3)

放大图像高度

half_upsclaled_img = np.zeros((height, width//2, channels), dtype=np.int32)half_upsclaled_img[0:height:2, :, :] = resized_img[:, :, :]
half_upsclaled_img[1:height:2, :, :] = resized_img[:, :, :]
print("Height upscaled image shape - {}".format(half_upsclaled_img.shape))
plt.imshow(half_upsclaled_img[:,:,::-1])
plt.show()

输出

Height upscaled image shape - (240, 160, 3)

放大图像宽度

upsclaled_img = np.zeros((height, width, channels), dtype=np.int32)# Expand rows by replicating every consecutive row
upsclaled_img[:, 0:width:2, :] = half_upsclaled_img[:, :, :]
upsclaled_img[:, 1:width:2, :] = half_upsclaled_img[:, :, :]
print("Fully upscaled image shape - {}".format(upsclaled_img.shape))
upscaled_img_manual = upsclaled_img
plt.imshow(upsclaled_img[:,:,::-1])
plt.show()

输出

Fully upscaled image shape - (240, 320, 3)

比较原始版本和更改后的版本

f = plt.figure(figsize=(15,15))
f.add_subplot(1, 2, 1).set_title('Original Image')
plt.imshow(img[:, :, ::-1])
f.add_subplot(1, 2, 2).set_title('Upscaled image post downscaling')
plt.imshow(upsclaled_img[:, :, ::-1])
plt.show()

注意:用这种方式调整图像大小会损失很多信息

使用OpenCV模块调整图像大小

  • 通过使用cv2.resize()缩小图像
  • 通过使用cv2.resize()放大图像

将图像的高度和宽度均缩小到原来的一半

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("imgs/chapter4/tessellate.jpg", -1)height, width, channels = img.shape

# create blank image of half the width
resized_img = cv2.resize(img, (width//2, height//2))
print("Downscaled image shape - {}".format(resized_img.shape))
plt.imshow(resized_img[:,:,::-1])
plt.show()

将操作后的图像放大至其原本的高度和宽度

height, width, channels = img.shape

# create blank image of half the widthupscaled_img = cv2.resize(resized_img, (width, height));
print("Upscaled image shape - {}".format(upscaled_img.shape))
upscaled_img_opencv = upscaled_img
plt.imshow(upscaled_img[:,:,::-1])
plt.show()

输出

Upscaled image shape - (240, 320, 3)

比较原始图片,手动缩放的图片和使用opencv缩放的图片

f = plt.figure(figsize=(15,15))
f.add_subplot(3, 1, 1).set_title('Original Image');
plt.imshow(img[:, :, ::-1])
f.add_subplot(3, 1, 2).set_title('Manually Upscaled post downscaling');
plt.imshow(upscaled_img_manual[:, :, ::-1])
f.add_subplot(3, 1, 3).set_title('Upscaled using opencv post downscaling');
plt.imshow(upscaled_img[:, :, ::-1])
plt.show()

使用Pillow模块调整图像大小

将图像的高度和宽度均缩小到原来的一半```

import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
img_p = Image.open("imgs/chapter4/tessellate.jpg")width, height = img_p.size

# create blank image of half the width
resized_img = img_p.resize((width//2, height//2))
print("Downscaled image shape - {}".format(resized_img.size))
plt.imshow(resized_img);
plt.show()

输出

Downscaled image shape - (160, 120)

将操作后的图像放大至其原本的高度和宽度

width, height = img_p.size

# create blank image of half the width
upscaled_img = resized_img.resize((width, height))
print("Upscaled image shape - {}".format(upscaled_img.size))
plt.imshow(resized_img)
plt.show()

输出

Upscaled image shape - (320, 240)

比较原始图片,手动缩放的图片,使用OpenCV缩放的图片和使用Pillow缩放的图片

f = plt.figure(figsize=(15,15))
f.add_subplot(2, 2, 1).set_title('Original Image')
plt.imshow(img[:, :, ::-1])
f.add_subplot(2, 2, 2).set_title('Manually Upscaled post downscaling')
plt.imshow(upscaled_img_manual[:, :, ::-1])
f.add_subplot(2, 2, 3).set_title('Upscaled using opencv post downscaling')
plt.imshow(upscaled_img_opencv[:, :, ::-1])
f.add_subplot(2, 2, 4).set_title('Upscaled using PIL post downscaling')
plt.imshow(upscaled_img)
plt.show()

图片缩放的算法

什么是插值

  • 插值是一种在一组已知的离散数据点范围内构造新数据点的方法。
  • 也就是说,已知自变量的中间值估算该函数的值。
  • 也称为曲线拟合或近似值。

使用OpenCV进行插值

最近邻插值

  • 分配最接近当前像素的值。
  • 这种方法是最基础的一种方法
  • 在所有插值算法中,它的处理时间最短,因为它仅考虑一个像素-最接近插值点的像素。

双线性插值

  • 双线性插值法考虑了未知像素值周围的已知像素值的2 * 2邻域。
  • 然后,对这4个像素进行加权平均,以得出其最终插值。

双三次插值

LancZos插值

  • 高阶插值。
  • 因为在高阶中操作所以难以可视化。
  • 是一种更高维度的过滤和特征提取方法。

应该用哪种插值方法呢?

  • 默认情况下使用cv2.INTER_LINEAR。
  • cv2.INTER_AREA用于缩小。
  • cv2.INTER_CUBIC也是用于缩小,效果更好但速度较慢。
  • cv.INTER_LINEAR用于图片缩放缩放。
  • 当不考虑计算速度时可以运用其他方法。

OpenCV的算法

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("imgs/chapter4/tessellate.jpg", -1)
h, w, c = img.shape

# Downscaling and upscaling using nearest neighbor interpolation
img_n = cv2.resize(img, (w//2, h//2), interpolation = cv2.INTER_NEAREST)
img_n = cv2.resize(img_n, (w, h), interpolation = cv2.INTER_NEAREST)

# Downscaling and upscaling using Bilinear interpolation
img_b = cv2.resize(img, (w//2, h//2), interpolation = cv2.INTER_LINEAR)
img_b = cv2.resize(img_b, (w, h), interpolation = cv2.INTER_LINEAR)

# Downscaling and upscaling using matrix area interpolation
img_a = cv2.resize(img, (w//2, h//2), interpolation = cv2.INTER_AREA)
img_a = cv2.resize(img_a, (w, h), interpolation = cv2.INTER_AREA)

# Downscaling and upscaling using cubic interpolation
img_c = cv2.resize(img, (w//2, h//2), interpolation = cv2.INTER_CUBIC)
img_c = cv2.resize(img_c, (w, h), interpolation = cv2.INTER_CUBIC)


# Downscaling and upscaling using lanczos interpolation
img_l = cv2.resize(img, (w//2, h//2), interpolation = cv2.INTER_LANCZOS4)
img_l = cv2.resize(img_l, (w, h), interpolation = cv2.INTER_LANCZOS4)f = plt.figure(figsize=(15,15))
f.add_subplot(3, 2, 1).set_title('Original Image')
plt.imshow(img[:, :, ::-1])
f.add_subplot(3, 2, 2).set_title('Nearest neighbour Interpolation')
plt.imshow(img_n[:, :, ::-1])
f.add_subplot(3, 2, 3).set_title('Bilinear Interpolation')
plt.imshow(img_b[:, :, ::-1])
f.add_subplot(3, 2, 4).set_title('Area matrix Interpolation')
plt.imshow(img_a[:, :, ::-1])
f.add_subplot(3, 2, 5).set_title('Cubic Interpolation')
plt.imshow(img_c[:, :, ::-1])
f.add_subplot(3, 2, 6).set_title('Lanczos Interpolation')
plt.imshow(img_l[:, :, ::-1])
plt.show()

Pillow的算法

import PIL
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
img_p = Image.open("imgs/chapter4/tessellate.jpg")
width, height = img_p.size


# Downscaling and upscaling using nearest neighbor interpolation
img_n = img_p.resize((width//2, height//2), resample=PIL.Image.NEAREST)
img_n = img_n.resize((width, height), resample=PIL.Image.NEAREST)

# Downscaling and upscaling using nearest box filtering
img_f = img_p.resize((width//2, height//2), resample=PIL.Image.BOX) 
img_f = img_f.resize((width, height), resample=PIL.Image.BOX)


# Downscaling and upscaling using nearest Bilinear interpolation
img_b = img_p.resize((width//2, height//2), resample=PIL.Image.BILINEAR)
img_b = img_b.resize((width, height), resample=PIL.Image.BILINEAR)


# Downscaling and upscaling using nearest Hamming interpolation
img_h = img_p.resize((width//2, height//2), resample=PIL.Image.HAMMING)
img_h = img_h.resize((width, height), resample=PIL.Image.HAMMING)# Downscaling and upscaling using nearest Bicubic interpolation
img_c = img_p.resize((width//2, height//2), resample=PIL.Image.BICUBIC); 
img_c = img_c.resize((width, height), resample=PIL.Image.BICUBIC)


# Downscaling and upscaling using nearest Lanczos interpolation
img_l = img_p.resize((width//2, height//2), resample=PIL.Image.LANCZOS)
img_l = img_l.resize((width, height), resample=PIL.Image.LANCZOS)



f = plt.figure(figsize=(15,20))
f.add_subplot(4, 2, 1).set_title('Original Image')
plt.imshow(img_p)
f.add_subplot(4, 2, 2).set_title('Nearest neighbour Interpolation')
plt.imshow(img_n)
f.add_subplot(4, 2, 3).set_title('Box Interpolation')
plt.imshow(img_f)
f.add_subplot(4, 2, 4).set_title('Bilinear Interpolation')
plt.imshow(img_b)
f.add_subplot(4, 2, 5).set_title('Hamming Interpolation')
plt.imshow(img_h)
f.add_subplot(4, 2, 6).set_title('Bi-Cubic Interpolation')
plt.imshow(img_c)
f.add_subplot(4, 2, 7).set_title('Lanczos Interpolation')
plt.imshow(img_l)
plt.show()

平移

  • 在四个方向中的任何一个方向上将图像移动一定像素。

为什么要这么做?

  • 用于数据增强

使用numpy进行图像平移

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("imgs/chapter4/dog.jpg",-1)
plt.imshow(img[:,:,::-1])
plt.show()


图像向右平移50像素值

h, w, c = img.shape;
img_new = np.zeros((h, w, c), dtype=np.uint8);

f = plt.figure(figsize=(15,15))
f.add_subplot(3, 1, 1).set_title('Original Image');
plt.imshow(img[:, :, ::-1])
f.add_subplot(3, 1, 2).set_title('New Blank Image');
plt.imshow(img_new[:, :, ::-1])
plt.show()


img_new[:, 50:, :] = img[:, :w-50, :]

plt.imshow(img_new[:,:,::-1])
plt.show()


向左平移50像素值

h, w, c = img.shape
img_new = np.zeros((h, w, c), dtype=np.uint8)

img_new[:, :w-50, :] = img[:, 50:, :]
plt.imshow(img_new[:,:,::-1])
plt.show()


向下平移50像素值

h, w, c = img.shape;
img_new = np.zeros((h, w, c), dtype=np.uint8)

img_new[:h-50, :, :] = img[50:, :, :]
plt.imshow(img_new[:,:,::-1])
plt.show()


旋转

使用PIL模块旋转图像

import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
img_p = Image.open("imgs/chapter4/triangle.jpg")
plt.imshow(img_p)
plt.show()


以枢纽为中心顺时针旋转30度

img_p_new = img_p.rotate(-30)
plt.imshow(img_p_new)
plt.show()


以枢纽为中心逆时针旋转30度

img_p_new = img_p.rotate(30)
plt.imshow(img_p_new)
plt.show()


仿射变换

  • 涉及图像平移和旋转的变换。
  • 但是,变换的方式遵循图像中的直线永远不会弯曲。

使用OpenCV进行仿射变换

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("imgs/chapter4/tessellate.jpg", -1)
plt.imshow(img[:,:,::-1])
plt.show()


保持两个点不变的情况下进行变换

img = cv2.imread("imgs/chapter4/tessellate.jpg", -1)
rows,cols,ch = img.shape


# Read as x, y
pts1 = np.float32([[50,50],[200,50], [50,200]])
pts2 = np.float32([[80,50],[200,50], [50,200]])


cv2.circle(img,(int(pts1[0][0]),int(pts1[0][1])),5,(0,255,0),-1)
cv2.circle(img,(int(pts1[1][0]),int(pts1[1][1])),5,(0,0,255),-1)
cv2.circle(img,(int(pts1[2][0]),int(pts1[2][1])),5,(255,0,0), -1)M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(cols,rows))

f = plt.figure(figsize=(15,15))
f.add_subplot(1, 2, 1).set_title('Input')
plt.imshow(img[:, :, ::-1])
f.add_subplot(1, 2, 2).set_title('Transformed')
plt.imshow(dst[:, :, ::-1])
plt.show()


将一个点作为铰链进行变换

img = cv2.imread("imgs/chapter4/tessellate.jpg", -1)
rows,cols,ch = img.shape

pts1 = np.float32([[50,50],[200,50], [50,200]])
#pts2 = np.float32([[60,50],[190,50], [50,200]])
# Works as translation + shrinking
pts2 = np.float32([[60,50],[200,50], [50,175]])


cv2.circle(img,(int(pts1[0][0]), int(pts1[0][1])), 5, (0,255,0), -1)
cv2.circle(img,(int(pts1[1][0]), int(pts1[1][1])), 5, (0,0,255), -1)
cv2.circle(img,(int(pts1[2][0]), int(pts1[2][1])), 5, (255,0,0), -1)

M = cv2.getAffineTransform(pts1,pts2)

dst = cv2.warpAffine(img,M,(cols,rows))

f = plt.figure(figsize=(15,15))
f.add_subplot(1, 2, 1).set_title('Input')
plt.imshow(img[:, :, ::-1])
f.add_subplot(1, 2, 2).set_title('Transformed')
plt.imshow(dst[:, :, ::-1])
plt.show()


对三个点均进行平移-->平移

img = cv2.imread("imgs/chapter4/tessellate.jpg", -1)
rows,cols,ch = img.shape

pts1 = np.float32([[50,50],[200,50], [50,200]])
pts2 = np.float32([[60,50],[210,50], [60,200]])


cv2.circle(img,(int(pts1[0][0]), int(pts1[0][1])), 5, (0,255,0), -1)
cv2.circle(img,(int(pts1[1][0]), int(pts1[1][1])), 5, (0,0,255), -1)
cv2.circle(img,(int(pts1[2][0]), int(pts1[2][1])), 5, (255,0,0), -1)

M = cv2.getAffineTransform(pts1,pts2)

dst = cv2.warpAffine(img,M,(cols,rows))

f = plt.figure(figsize=(15,15))
f.add_subplot(1, 2, 1).set_title('Input')
plt.imshow(img[:, :, ::-1])
f.add_subplot(1, 2, 2).set_title('Transformed')
plt.imshow(dst[:, :, ::-1])
plt.show()


透视变换

使用OpenCV进行透视变换

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("imgs/chapter4/cube.png", 1)
plt.imshow(img[:,:,::-1])
plt.show()


放大视图

img = cv2.imread("imgs/chapter4/cube.png", 1)
img = cv2.resize(img, (400, 400))
rows,cols,ch = img.shape

# Counter clock wise
pts1 = np.float32([[130,130],[390,75],[360,320],[140, 390]])
pts2 = np.float32([[0,0],[0, 200],[200,200],[200,0]])


# uncomment each and see
cv2.circle(img,(int(pts1[0][0]),int(pts1[0][1])),5,(255,255,255), -1)
cv2.circle(img,(int(pts1[1][0]), int(pts1[1][1])), 5, (255,255,255), -1)
cv2.circle(img,(int(pts1[2][0]), int(pts1[2][1])), 5, (255,255,255), -1)
cv2.circle(img,(int(pts1[3][0]), int(pts1[3][1])), 5, (255,255,255), -1)

M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(img,M,(cols,rows))

f = plt.figure(figsize=(15,15))
f.add_subplot(1, 2, 1).set_title('Input');
plt.imshow(img[:, :, ::-1])
f.add_subplot(1, 2, 2).set_title('Transformed');
plt.imshow(dst[:, :, ::-1])
plt.show()


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DeepHub IMBA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 缩放
    • 使用 numpy 模块调整图像大小
      • 使用OpenCV模块调整图像大小
        • 使用Pillow模块调整图像大小
          • 图片缩放的算法
            • 什么是插值
              • 使用OpenCV进行插值
              • 平移
                • 使用numpy进行图像平移
                • 旋转
                  • 使用PIL模块旋转图像
                  • 仿射变换
                    • 使用OpenCV进行仿射变换
                    • 透视变换
                      • 使用OpenCV进行透视变换
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档