几何变换

几何变换是指将一幅图像映射到另一副图像内的操作,根据映射关系的不同,有缩放、翻转、仿射变换、透视、重映射等。

1.缩放

在OpenCV中使用函数cv2.resize()实现对图像的缩放:

cv2.resize(src, dsize[,fx[,fy[, interpolation]]])

src  :代表要缩放的原始图像;

dsize : 代表输出图像大小,第一个值为目标图像的宽度,第二个值为目标图像的高度

fx  : 代表水平方向的缩放比

fy  : 代表垂直方向的缩放比

interpolation: 代表插值方式。插值是指在对图像进行几何处理时,给无法直接通过映射得到值的像素点赋值。当缩小图像时,使用区域插值方式( INTER_AREA)能够得到最好的效果;当放大图像时,使用三次样条插值(INTER_CUBIC)方式和双线性插值(INTER_LINEAR)方式都能得到较好的效果。三次样条插值方式速度较慢,双线性插值方式速度相对较快且效果并不逊色。

【注】:fx、fy只要当dsize=None时才起作用。

import cv2

import numpyas np

img = cv2.imread('wasser_2.jpg')

shape_img = img.shape

print(shape_img)

biger_img = cv2.resize(img,(720,480),interpolation=cv2.INTER_LINEAR)

smaller_img = cv2.resize(img,None,fx=0.8,fy=0.8,interpolation=cv2.INTER_AREA)

cv2.imshow('img',img)

cv2.imshow('biger_img',biger_img)

cv2.imshow('smaller_img',smaller_img)

return_value = cv2.waitKey(0)

cv2.destroyAllWindows()

2. 翻转

在OpenCV中,图像的翻转采用函数cv2.flip()实现,该函数能实现水平方向、垂直方向、两个方向同时翻转。

dst = cv2.flip(src, flipCode)

src : 表示要处理的图像;

flipCode : 表示旋转类型,为0时,表示绕X轴旋转;为正数,表示绕y轴旋转;为负数,表示绕x、y轴同时旋转。

dst: 返回和原图像有相同大小和类型的目标图像。

img = cv2.imread('wasser_2.jpg')

shape_img = img.shape

print(shape_img)

x_img = cv2.flip(img,1)

xy_img = cv2.flip(img,-1)

cv2.imshow('img',img)

cv2.imshow('x_img',x_img)

cv2.imshow('xy_img',xy_img)

return_value = cv2.waitKey(0)

cv2.destroyAllWindows()

3.仿射

仿射是指图像可以经过一系列的几何变换来实现平移、旋转等多种操作。该变换能够保持图像的平直性(变换前后,直线仍是直线)和平行性(变换前后,平行线仍是平行线)。

OpenCV中的仿射函数是cv2.warpAffine(),其通过一个变换矩阵M实现变换,具体为:

dst(x,y) = src(M_{11}x+M_{12}y+M_{13},M_{21}x+M_{22}y+M_{23} )

dst = cv2.warpAffine(src,M,dsize[,flags[,borderMode[,borderValue]]])

dst: 表示输出图像,它和原始图像有相同的类型,大小由dsize决定;

src: 表示原始图像;

M: 代表一个2X3的变换矩阵。

dsize: 输出图像的尺寸大小;

flags : 代表插值方法,默认为INTER_LINEAR。当该值是WARP_INVERSE_MAP时,意味着M是逆变换矩阵,实现从目标图像dst到原始图像src的逆变换。

borderModer : 代表边类型,默认为BORDER_CONSTANT.当该值为BORDER_TRANSPARENT时,意味着目标图像内的值不做改变,这些值对应原始图像内的异常值。

borderValue : 代表边界值,默认是0.

1)平移

平移的矩阵M:

M = [[1,0,x],[0,1,y]]

将图像水平向右移动100像素,垂直向下平移150像素。

import cv2

import numpyas np

img = cv2.imread('wasser_2.jpg')

shape_img = img.shape

print(shape_img)

M = np.float32([[1,0,100],[0,1,150]])

warp_img = cv2.warpAffine(img,M,(shape_img[1],shape_img[0]))

rut_warp_img = cv2.warpAffine(img,M,(shape_img[1],shape_img[0]),borderMode=cv2.BORDER_TRANSPARENT)

cv2.imshow('img',img)

cv2.imshow('warp_img',warp_img)

cv2.imshow('rut_warp_img',rut_warp_img)

return_value = cv2.waitKey(0)

cv2.destroyAllWindows()

2)旋转

在使用wrapAffine()对图像进行旋转时,可以通过函数cv2.getRotationMatrix2D(center,angle,scale)获取转换矩阵。其中:

center为旋转中心;

angle为旋转角度;

scale为变换尺度。

例如:以图像中心点为旋转中心,顺时针旋转45°,图像缩小到原来的0.6倍。

img = cv2.imread('wasser_2.jpg')

height,width = img.shape[:2]

M = cv2.getRotationMatrix2D((width/2,height/2),45,0.6)

rota_img = cv2.warpAffine(img,M,(width,height))

cv2.imshow('img',img)

cv2.imshow('rota_img',rota_img)

3)更复杂的仿射

对于更复杂的仿射变换,Opencv提供了函数cv2.getAffineTransform()来生成仿射函数所需要的转换矩阵M.

cv2.getAffineTransform(src,dst)

src 代表输入图像的三个点坐标

dst 代表输出图像的三个点坐标

该函数定义了两个平行四边形,src和dst中的三个点分别对应平行四边形的左上角、右上角、左下角。它确定了原图像到目标图像的映射关系。

img = cv2.imread('wasser_2.jpg')

height,width = img.shape[:2]

# 确定两个平行四边形

p1 = np.float32([[0,0],[width-1,0],[0,height-1]])

p2 = np.float32([[0,height*0.33],[width*0.85,height*0.25],[height*0.2,height*0.7]])

M = cv2.getRotationMatrix2D((width/2,height/2),45,0.6)

retval = cv2.getAffineTransform(p1,p2)

rota_img = cv2.warpAffine(img,M,(width,height))

dst_img = cv2.warpAffine(img,retval,(width,height))

cv2.imshow('img',img)

cv2.imshow('rota_img',rota_img)

cv2.imshow('dst_img',dst_img)

4.透视

仿射变换可以将矩形变成任意平行四边形,透视变换可以将矩形映射到任意四边形。

透视变换通过cv2.warpPerspective()实现:

dst = cv2.warpPerspective(src, M, dsize[,flags[,borderMode[,borderValue]]])

dsize  :决定输出图像的大小

M  :代表一个3X3的变换矩阵

flags: 代表差值方法,默认为INTER_LINEAR。当该值是WARP_INVERSE_MAP时,意味着M是逆变换类型

borderValue  :代表边界值,默认是0

与仿射变换一样,同样可以使用一个函数来生成M:

cv2.getPerspectiveTransform(src,dst)

src,dst 都是一个包含四个坐标点的数组。

例如:

img = cv2.imread('wasser_2.jpg')

height,width = img.shape[:2]

# 确定两个平行四边形

p1 = np.float32([[0,0],[100,0],[0,50],[100,50]])

p2 = np.float32([[20,20],[50,30],[30,70],[70,60]])

retval = cv2.getPerspectiveTransform(p1,p2)

dst_img = cv2.warpPerspective(img, retval, (width,height))

cv2.imshow('img',img)

cv2.imshow('dst_img',dst_img)

5.重映射

把一幅图像的像素点放到另一幅图像的指定范围,这个过程称为图映射。OpenCV提供了多种重映射方式,其中dst = cv2.remap(src, map1, map2, interpolation[,borderMode[,borderValue]])

dst 和src有相同的大小和类型。

map1 参数都有两种可能的值:

1)表示(x,y)点的一个映射

2)表示CV_16SC2,CV_32FC1,CV_32FC2类型(x,y)点的x值

map1 参数同样有两种可能的值:

1)当map1表示(x,y)时,该值为空

2)当map1表示(x,y)点的x值时,该值是CV_16UC1,CV_32FC1类型(x,y)点的y值。

Interpolation代表插值方式,这里不支持INTER_AREA方法。

重映射通过修改像素点的位置得到一幅新图像。在构造新图像时,需要确定新图像中每一个像素点在原始图像中的位置,因此映射函数的作用是查找新图像在原始图像中的位置,该过程是将新图像映射到原始图像的过程,因此被称为反向映射。

在函数cv2.remap()中,参数map1和map2用来说明反向映射,map1针对的是坐标x,指代像素所在位置的列号,map2针对的是坐标y,指代像素所在位置的行号。map1和map2的值都是浮点数。因此目标函数可以映射回一个非整数的值,这意味着可以将目标图像“反向映射”到原始图像中两个像素之间的位置(这样的位置是不存在的)。这是采用不同的方法来插值处理。

(1)复制

\bullet 将map1的值设为对应位置上的x轴坐标值

\bullet 将map2的值设为对应位置上的y轴坐标值

remap()实现复制图像

(2)绕X轴 、Y轴翻转

假如想让图片绕X轴翻转,则图像x坐标不变,y坐标变为总行数-1-当前行号;

如果想让它绕y轴翻转,也同理:总列数-1-当前列号

(3)x轴、y轴互换

将x轴的值调整为所在行的行号;将y轴的值调整为所在列的列号

注:如果行数和列数不等,可能出现存在值不能映射的情况。默认情况下,无法完成的值会被处理为0.

(4)图像的缩放

将图像缩小为原来的两倍,并居中处理:

结果如下:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350