简 介: 本文中,你了解了了如何通过OpenCV
完成对于图像的旋转和平移。我们首先通过 getRotationMatrix2D()
获取2D
旋转矩阵,然后完成了对于图像的旋转。具体是通过warpAffine()
将旋转拒转施加在图像上完成对图像绕着中心旋转所需的角度。接着通过明确定义了转换矩阵,包含有想要图像沿着x
,y
轴移动的信息。同样利用warpAffine()
函数对图像进行变换。旋转和平移图像是我们学习利用OpenCV
完成对图像进行其它变化的良好的基础。鼓励你在此基础上测试其它的输入查看一下变化的效果。
关键词
: 图像旋转,图像平移
#mermaid-svg-chZXXJo5R7087MnQ .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-chZXXJo5R7087MnQ .label text{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .node rect,#mermaid-svg-chZXXJo5R7087MnQ .node circle,#mermaid-svg-chZXXJo5R7087MnQ .node ellipse,#mermaid-svg-chZXXJo5R7087MnQ .node polygon,#mermaid-svg-chZXXJo5R7087MnQ .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-chZXXJo5R7087MnQ .node .label{text-align:center;fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .node.clickable{cursor:pointer}#mermaid-svg-chZXXJo5R7087MnQ .arrowheadPath{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-chZXXJo5R7087MnQ .flowchart-link{stroke:#333;fill:none}#mermaid-svg-chZXXJo5R7087MnQ .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-chZXXJo5R7087MnQ .edgeLabel rect{opacity:0.9}#mermaid-svg-chZXXJo5R7087MnQ .edgeLabel span{color:#333}#mermaid-svg-chZXXJo5R7087MnQ .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-chZXXJo5R7087MnQ .cluster text{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-chZXXJo5R7087MnQ .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-chZXXJo5R7087MnQ text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-chZXXJo5R7087MnQ .actor-line{stroke:grey}#mermaid-svg-chZXXJo5R7087MnQ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-chZXXJo5R7087MnQ .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-chZXXJo5R7087MnQ #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-chZXXJo5R7087MnQ .sequenceNumber{fill:#fff}#mermaid-svg-chZXXJo5R7087MnQ #sequencenumber{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ #crosshead path{fill:#333;stroke:#333}#mermaid-svg-chZXXJo5R7087MnQ .messageText{fill:#333;stroke:#333}#mermaid-svg-chZXXJo5R7087MnQ .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-chZXXJo5R7087MnQ .labelText,#mermaid-svg-chZXXJo5R7087MnQ .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-chZXXJo5R7087MnQ .loopText,#mermaid-svg-chZXXJo5R7087MnQ .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-chZXXJo5R7087MnQ .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-chZXXJo5R7087MnQ .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-chZXXJo5R7087MnQ .noteText,#mermaid-svg-chZXXJo5R7087MnQ .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-chZXXJo5R7087MnQ .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-chZXXJo5R7087MnQ .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-chZXXJo5R7087MnQ .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-chZXXJo5R7087MnQ .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ .section{stroke:none;opacity:0.2}#mermaid-svg-chZXXJo5R7087MnQ .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-chZXXJo5R7087MnQ .section2{fill:#fff400}#mermaid-svg-chZXXJo5R7087MnQ .section1,#mermaid-svg-chZXXJo5R7087MnQ .section3{fill:#fff;opacity:0.2}#mermaid-svg-chZXXJo5R7087MnQ .sectionTitle0{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .sectionTitle1{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .sectionTitle2{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .sectionTitle3{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-chZXXJo5R7087MnQ .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ .grid path{stroke-width:0}#mermaid-svg-chZXXJo5R7087MnQ .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-chZXXJo5R7087MnQ .task{stroke-width:2}#mermaid-svg-chZXXJo5R7087MnQ .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ .taskText:not([font-size]){font-size:11px}#mermaid-svg-chZXXJo5R7087MnQ .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-chZXXJo5R7087MnQ .task.clickable{cursor:pointer}#mermaid-svg-chZXXJo5R7087MnQ .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-chZXXJo5R7087MnQ .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-chZXXJo5R7087MnQ .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-chZXXJo5R7087MnQ .taskText0,#mermaid-svg-chZXXJo5R7087MnQ .taskText1,#mermaid-svg-chZXXJo5R7087MnQ .taskText2,#mermaid-svg-chZXXJo5R7087MnQ .taskText3{fill:#fff}#mermaid-svg-chZXXJo5R7087MnQ .task0,#mermaid-svg-chZXXJo5R7087MnQ .task1,#mermaid-svg-chZXXJo5R7087MnQ .task2,#mermaid-svg-chZXXJo5R7087MnQ .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-chZXXJo5R7087MnQ .taskTextOutside0,#mermaid-svg-chZXXJo5R7087MnQ .taskTextOutside2{fill:#000}#mermaid-svg-chZXXJo5R7087MnQ .taskTextOutside1,#mermaid-svg-chZXXJo5R7087MnQ .taskTextOutside3{fill:#000}#mermaid-svg-chZXXJo5R7087MnQ .active0,#mermaid-svg-chZXXJo5R7087MnQ .active1,#mermaid-svg-chZXXJo5R7087MnQ .active2,#mermaid-svg-chZXXJo5R7087MnQ .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-chZXXJo5R7087MnQ .activeText0,#mermaid-svg-chZXXJo5R7087MnQ .activeText1,#mermaid-svg-chZXXJo5R7087MnQ .activeText2,#mermaid-svg-chZXXJo5R7087MnQ .activeText3{fill:#000 !important}#mermaid-svg-chZXXJo5R7087MnQ .done0,#mermaid-svg-chZXXJo5R7087MnQ .done1,#mermaid-svg-chZXXJo5R7087MnQ .done2,#mermaid-svg-chZXXJo5R7087MnQ .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-chZXXJo5R7087MnQ .doneText0,#mermaid-svg-chZXXJo5R7087MnQ .doneText1,#mermaid-svg-chZXXJo5R7087MnQ .doneText2,#mermaid-svg-chZXXJo5R7087MnQ .doneText3{fill:#000 !important}#mermaid-svg-chZXXJo5R7087MnQ .crit0,#mermaid-svg-chZXXJo5R7087MnQ .crit1,#mermaid-svg-chZXXJo5R7087MnQ .crit2,#mermaid-svg-chZXXJo5R7087MnQ .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-chZXXJo5R7087MnQ .activeCrit0,#mermaid-svg-chZXXJo5R7087MnQ .activeCrit1,#mermaid-svg-chZXXJo5R7087MnQ .activeCrit2,#mermaid-svg-chZXXJo5R7087MnQ .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-chZXXJo5R7087MnQ .doneCrit0,#mermaid-svg-chZXXJo5R7087MnQ .doneCrit1,#mermaid-svg-chZXXJo5R7087MnQ .doneCrit2,#mermaid-svg-chZXXJo5R7087MnQ .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-chZXXJo5R7087MnQ .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-chZXXJo5R7087MnQ .milestoneText{font-style:italic}#mermaid-svg-chZXXJo5R7087MnQ .doneCritText0,#mermaid-svg-chZXXJo5R7087MnQ .doneCritText1,#mermaid-svg-chZXXJo5R7087MnQ .doneCritText2,#mermaid-svg-chZXXJo5R7087MnQ .doneCritText3{fill:#000 !important}#mermaid-svg-chZXXJo5R7087MnQ .activeCritText0,#mermaid-svg-chZXXJo5R7087MnQ .activeCritText1,#mermaid-svg-chZXXJo5R7087MnQ .activeCritText2,#mermaid-svg-chZXXJo5R7087MnQ .activeCritText3{fill:#000 !important}#mermaid-svg-chZXXJo5R7087MnQ .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-chZXXJo5R7087MnQ g.classGroup text .title{font-weight:bolder}#mermaid-svg-chZXXJo5R7087MnQ g.clickable{cursor:pointer}#mermaid-svg-chZXXJo5R7087MnQ g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-chZXXJo5R7087MnQ g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-chZXXJo5R7087MnQ .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-chZXXJo5R7087MnQ .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-chZXXJo5R7087MnQ .dashed-line{stroke-dasharray:3}#mermaid-svg-chZXXJo5R7087MnQ #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ .commit-id,#mermaid-svg-chZXXJo5R7087MnQ .commit-msg,#mermaid-svg-chZXXJo5R7087MnQ .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-chZXXJo5R7087MnQ g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-chZXXJo5R7087MnQ g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-chZXXJo5R7087MnQ g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-chZXXJo5R7087MnQ .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-chZXXJo5R7087MnQ .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-chZXXJo5R7087MnQ .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-chZXXJo5R7087MnQ .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-chZXXJo5R7087MnQ .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-chZXXJo5R7087MnQ .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-chZXXJo5R7087MnQ .edgeLabel text{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-chZXXJo5R7087MnQ .node circle.state-start{fill:black;stroke:black}#mermaid-svg-chZXXJo5R7087MnQ .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-chZXXJo5R7087MnQ #statediagram-barbEnd{fill:#9370db}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-state .divider{stroke:#9370db}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-chZXXJo5R7087MnQ .note-edge{stroke-dasharray:5}#mermaid-svg-chZXXJo5R7087MnQ .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-chZXXJo5R7087MnQ .error-icon{fill:#522}#mermaid-svg-chZXXJo5R7087MnQ .error-text{fill:#522;stroke:#522}#mermaid-svg-chZXXJo5R7087MnQ .edge-thickness-normal{stroke-width:2px}#mermaid-svg-chZXXJo5R7087MnQ .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-chZXXJo5R7087MnQ .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-chZXXJo5R7087MnQ .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-chZXXJo5R7087MnQ .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-chZXXJo5R7087MnQ .marker{fill:#333}#mermaid-svg-chZXXJo5R7087MnQ .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}#mermaid-svg-chZXXJo5R7087MnQ {color: rgba(0, 0, 0, 0.75);font: ;}
前 言
目 录
Contents
图像的基本变换
图像旋转
图像平移
转换总结
§00 前 言
本文是对 Image Rotation and Translation Using OpenCV 中介绍的关于OpenCV进行图像旋转和平移内容进行总结。
自从手机内的内置的APP都考可以让你随心所欲对你拍摄的图像进行剪裁、旋转的时候,对于图像进行编辑变得越来越流行。
本文中,我们将会探讨这些图像班级的技术。特别对于:
0.1 图像的基本变换
在图像编辑中,对于图像进行旋转和平移是最基本的操作,他们都归于“仿射变换”(Affine Tranformations)这一大类。在学习更复杂的变换之前,对于基本的旋转和平移需要掌握,这些都可以通过OpenCV来实现。
下面这张图将会在后面的软件测试中使用。
▲ 图1.1 用于后面实验的图片样例
上面这张图我们后面将会使用到。
在开始前可以先看看下面的代码,他们通过OpenCV执行图像的旋转。在后面我们将会对于代码的每一行伴随着对于图片的转换进行解释。最后,我们就会对下面的代码有了充分的理解。
import cv2# Reading the image
image = cv2.imread('image.jpg')# dividing height and width by 2 to get the center of the image
height, width = image.shape[:2]
# get the center coordinates of the image to create the 2D rotation matrix
center = (width/2, height/2)# using cv2.getRotationMatrix2D() to get the rotation matrix
rotate_matrix = cv2.getRotationMatrix2D(center=center, angle=45, scale=1)# rotate the image using cv2.warpAffine
rotated_image = cv2.warpAffine(src=image, M=rotate_matrix, dsize=(width, height))cv2.imshow('Original image', image)
cv2.imshow('Rotated image', rotated_image)
# wait indefinitely, press any key on keyboard to exit
cv2.waitKey(0)
# save the rotated image to disk
cv2.imwrite('rotated_image.jpg', rotated_image)
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace cv;int main(int, char**)
{Mat image = imread("image.jpg");imshow("image", image);waitKey(0);double angle = 45;// get the center coordinates of the image to create the 2D rotation matrixPoint2f center((image.cols - 1) / 2.0, (image.rows - 1) / 2.0);// using getRotationMatrix2D() to get the rotation matrixMat rotation_matix = getRotationMatrix2D(center, angle, 1.0);// we will save the resulting image in rotated_image matrixMat rotated_image;// rotate the image using warpAffinewarpAffine(image, rotated_image, rotation_matix, image.size());imshow("Rotated image", rotated_image);// wait indefinitely, press any key on keyboard to exitwaitKey(0);// save the rotated image to diskimwrite("rotated_im.jpg", rotated_image);return 0;
}
§01 图像旋转
可以通过定出 一个旋转矩阵 MMM 完成对图像 任意角度 θ\thetaθ 的旋转。这个旋转矩阵通常具有如下形式:
M=[cosθ−sinθsinθcosθ]M = \begin{bmatrix} \begin{matrix} {\cos \theta } & { - \sin \theta }\\{\sin \theta } & {\cos \theta }\\\end{matrix} \end{bmatrix}M=[cosθsinθ−sinθcosθ]
OpenCV可以定义图像的旋转中心点,以及比例因子来缩放图像,在这些因素作用下,这个转换矩阵的形式变成如下的形式:
[απ(1−α)⋅cx−β⋅cy−βαβ⋅cx+(1−α)⋅cy]\begin{bmatrix} \begin{matrix} \alpha & \pi & {\left( {1 - \alpha } \right) \cdot c_x - \beta \cdot c_y }\\{ - \beta } & \alpha & {\beta \cdot c_x + \left( {1 - \alpha } \right) \cdot c_y }\\\end{matrix} \end{bmatrix}[α−βπα(1−α)⋅cx−β⋅cyβ⋅cx+(1−α)⋅cy]
在上面的矩阵中:α=scale⋅cosθ\alpha = scale \cdot \cos \thetaα=scale⋅cosθβ=scale⋅sinθ\beta = scale \cdot \sin \thetaβ=scale⋅sinθ
其中 cx,cyc_x ,c_ycx,cy 就是图片的旋转中心点坐标。
OpenCV提供getRotationMatrix2D()
函数来创建上述转换矩阵。
下面就是创建2D旋转矩阵的函数调用方式:
getRotationMatrix2D(center, angle, scale)
函数 getRotationMatrix2D()
有以下三个输入变量:
- center: the center of rotation for the input image
- angle: the angle of rotation in degrees
- cale: an isotropic scale factor which scales the image up or down according to the value provided
通过三个步骤完成旋转:
1. 首先,你需要得到旋转的中心,也就是你用于旋转图像所围绕的中心点;
2. 接着,创建 2D-旋转拒转。 OpenCV提供了上面讨论的 getRotationMatrix2D()
函数。
3. 最后,使用前面你创建的旋转矩阵对图像进行仿射变换。利用 OpenCV
中的warpAffine()
函数完成。
函数 warpAffine()
对图像施加仿射变换。在仿射变换后,所有的原始图像中的平行线在变换后仍然是平行线。
函数 warpAffine()
的复杂调用语法在下面给出:
- rc: the source mage
- M: the transformation matrix
- dsize: size of the output image
- dst: the output image
- flags: combination of interpolation methods such as INTER_LINEAR or INTER_NEAREST
- borderMode: the pixel extrapolation method
- borderValue: the value to be used in case of a constant border, has a default value of 0
请注意:在此你可以学习OpenCV 仿射变换更多的内容。
好了,现在你已经了解了相关的代码和函数,下面采用一个具体的OpenCV例子测试一下。首先你需要吧OpenCV的库和图片导入。
import cv2# Reading the image
image = cv2.imread('image.jpg')
#include "opencv2/opencv.hpp"
using namespace cv;# Reading the image
Mat image = imread("image.jpg");
接着,计算旋转点,在这个例子中就是图像的中心。所以只要简单的吧图像的宽和高除以二就可以了。
# Dividing height and width by 2 to get the center of the image
height, width = image.shape[:2]
center = (width/2, height/2)
// get the center coordinates of the image to create the 2D rotation matrix
Point2f center((image.cols - 1) / 2.0, (image.rows - 1) / 2.0);
一旦你获得图像旋转中心,就可以计算出旋转矩阵。利用函数 getRotationMatrix2D() 完成,看下面所示,这个函数需要的输入包括:
- 旋转中心点;
- 旋转角度,单位°(注意,不是弧度),正值表示逆时针旋转,负值表示顺时针旋转;
- 各向同性的图片缩放比例因子。这个可以使一个浮点数字。比如,1.0表示保持输出图像与输入图像的尺寸一致。 2.0表示输出图像的尺寸比输入图像大了一倍。
函数返回一个2D-旋转拒转,下面就是用该矩阵对图像进行旋转。
# the above center is the center of rotation axis
# use cv2.getRotationMatrix2D() to get the rotation matrix
rotate_matrix = cv2.getRotationMatrix2D(center=center, angle=45, scale=1)
// create the rotation matrix using the image center
Mat rotation_matix = getRotationMatrix2D(center, angle=45, 1.0);
现在,通过函数 warpAffine()将旋转拒转作用在图像上,这个函数需要三个输入:
1. 原始图像;
2. 旋转拒转;
3. 输出图像的尺寸;
旋转结果存储在 rotated_image中,下面我们会展示出来。
# Rotate the image using cv2.warpAffine
rotated_image = cv2.warpAffine(src=image, M=rotate_matrix, dsize=(width, height))
// we will save the resulting image in rotated_image matrix
Mat rotated_image;
// apply affine transformation to the original image using the 2D rotation matrix
warpAffine(image, rotated_image, rotation_matix, image.size());
下面我们现实旋转后的图像,仍然使用 imshow() 函数。
# visualize the original and the rotated image
cv2.imshow('Original image', image)
cv2.imshow('Rotated image', rotated_image)
# wait indefinitely, press any key on keyboard to exit
cv2.waitKey(0)
# write the output, the rotated image to disk
cv2.imwrite('rotated_image.jpg', rotated_image)
imshow("Rotated image", rotated_image);
waitKey(0);
// save the rotated image to disk
imwrite("rotated_im.jpg", rotated_image);
▲ 图1.1 使用OpenCV旋转后的图像
上面就是使用OpenCV旋转后的图像。
§02 图像平移
在计算机视觉中, 平移一个图像意味着将图像沿着x轴,或者y轴移动指定的像素个数。将图像平移的像素数个数记为 txtxtx 和 tytyty 。此时你可以定义转换拒转 MMM 为:
M=[10tx01ty]M = \begin{bmatrix} \begin{matrix} 1 & 0 & {t_x }\\0 & 1 & {t_y }\\\end{matrix} \end{bmatrix}M=[1001txty]
在将图像平移 tx,tyt_x ,t_ytx,ty 时你需要注意:
- txt_xtx 为正表示将图像往右平移,负值表示将图像往左平移;
- 类似, tyt_yty 为正,表示图像往下平移,负值则图像网上平移;
安装一下三个步骤使用OpenCV完成图像的平移:
1. 首先读入图像,获得图像的宽、高;
2. 截止,就像前面在旋转图像那样,你需要创建一个变换矩阵,也是一个2D的矩阵。这个矩阵包含了平移图像所需要的参数,也就是沿着x、y轴移动的距离;
3. 有一次使用 warpAffine() 函数,就像前面旋转图像那样, 将变换矩阵作用在图像上。
下面的代码你可以自行阅读分析,比较简单:
import cv2
import numpy as np# read the image
image = cv2.imread('image.jpg')
# get the width and height of the image
height, width = image.shape[:2]
#include "opencv2/opencv.hpp"
using namespace cv
// read the image
Mat image = imread("image.jpg");
// get the height and width of the image
int height = image.cols;
int width = image.rows;
上面的代码你读入图像获得它的尺寸;
接着你创建转换矩阵:
# get tx and ty values for translation
# you can specify any value of your choice
tx, ty = width / 4, height / 4# create the translation matrix using tx and ty, it is a NumPy array
translation_matrix = np.array([[1, 0, tx],[0, 1, ty]
], dtype=np.float32)
// get tx and ty values for translation
float tx = float(width) / 4;
float ty = float(height) / 4;
// create the translation matrix using tx and ty
float warp_values[] = { 1.0, 0.0, tx, 0.0, 1.0, ty };
Mat translation_matrix = Mat(2, 3, CV_32F, warp_values);
就像前面讨论的那样,你需要首先确定平移参数 tx,tyt_x ,t_ytx,ty ,才能够确定转换矩阵。这个例子中使用图像的宽、高的四分之一作为转换数值。建议你使用其它的数值进行测试。
现在,调用 warpAffine() 函数将转换矩阵作用在图像上,就像前面旋转图像那样:
# apply the translation to the image
translated_image = cv2.warpAffine(src=image, M=translation_matrix, dsize=(width, height))
// save the resulting image in translated_image matrix
Mat translated_image;
// apply affine transformation to the original image using the translation matrix
warpAffine(image, translated_image, translation_matrix, image.size());
注意: warpAffine() 函数是一个通用函数,它可以将任何仿射变换都作用在图像上。 你所做的就是将转换矩阵 MMM 定义好就行了。
最后一扩代码就是将转换后的图像进行显示,并存储在磁盘上。 到此为止,你完成了所有的工作。
# display the original and the Translated images
cv2.imshow('Translated image', translated_image)
cv2.imshow('Original image', image)
cv2.waitKey(0)
# save the translated image to disk
cv2.imwrite('translated_image.jpg', translated_image)
//display the original and the Translated images
imshow("Translated image", translated_image);
imshow("Original image", image);
waitKey(0);
// save the translated image to disk
imwrite("translated_image.jpg", translated_image);
下面的图像显示了图片平移后的结果。
▲ 图2.1 通过OpenCV平移图像
※ 转换总结 ※
本文中,你了解了了如何通过OpenCV
完成对于图像的旋转和平移。我们首先通过 getRotationMatrix2D()
获取2D
旋转矩阵,然后完成了对于图像的旋转。具体是通过warpAffine()
将旋转拒转施加在图像上完成对图像绕着中心旋转所需的角度。
接着通过明确定义了转换矩阵,包含有想要图像沿着x
,y
轴移动的信息。同样利用warpAffine()
函数对图像进行变换。
旋转和平移图像是我们学习利用OpenCV
完成对图像进行其它变化的良好的基础。鼓励你在此基础上测试其它的输入查看一下变化的效果。
你是否还想构建一个应用来获得鸟眼中的图片景象?这需要了解更多OpenCV
中的透视变换信息。加上现在你已经了解的旋转和平移就可以构建上述应用了。
在这个 链接 中你可以尝试一下我们使用StreamLit
够贱的Web
应用程序,来帮助你旋转和平移图像。
▲ 图3.1 StreamLit演示程序
■ 相关文献链接:
● 相关图表链接:
- 图1.1 用于后面实验的图片样例
- 图1.1 使用OpenCV旋转后的图像
- 图2.1 通过OpenCV平移图像
- 图3.1 StreamLit演示程序
应用OpenCV进行图像旋转和平移相关推荐
- Opencv 基础(四):使用OpenCV进行图像旋转和平移
如今,图像编辑变得越来越流行,因为手机有内置的功能,可以让你裁剪.旋转和更多的操作你的图像. 这篇文章中,我们将探索和学习这些图像编辑技术.具体来说,我们将学习如何: 旋转图像 移动图像 基本图像变换 ...
- OpenCV 图像旋转、平移、缩放
本文是 OpenCV图像视觉入门之路的第7篇文章,本文详细的进行了图像的缩放 cv2.resize().旋转 cv2.flip().平移 cv2.warpAffine()等操作. OpenCV 图像旋 ...
- Opencv:图像旋转,cv2.getRotationMatrix2D 和 cv2.warpAffine 函数
学习记录如何使用opencv实现对图像的旋转操作. 1 cv2.getRotationMatrix2D(center, angle, scale) 图像的旋转矩阵一般为: 但是单纯的这个矩阵是在原点处 ...
- opencv之图像翻转、平移、缩放、旋转、仿射学习笔记
opencv版本:opencv3.4.1 目录 1. 图像翻转(坐标映射) 2. 平移 3. 缩放 4. 旋转 1. 图像翻转(坐标映射) int main() {cv::Mat srcImage ...
- opencv warpAffine()函数详解 -- 图像旋转与平移
简述 仿射变换是二维坐标间的线性变换,故而变换后的图像仍然具有原图的一些性质,包括"平直性"以及"平行性",常用于图像翻转(Flip).旋转(Rotations ...
- OpenCV中图像旋转(warpAffine)算法的实现过程
在OpenCV中,目前并没有现成的函数直接用来实现图像旋转,它是用仿射变换函数cv::warpAffine来实现的,此函数目前支持4种插值算法,最近邻.双线性.双三次.兰索斯插值,如果传进去的参数为基 ...
- 【OpenCV3】图像旋转与平移——cv::warpAffine()详解
图像旋转和平移是图像处理中常用的一种操作,opencv2和opencv3中对图像的旋转和平移都是通过仿射变换函数cv::warpAffine()来实现的. 1.图像的旋转 图像的旋转具体实现分为两步: ...
- 【OpenCV】图像旋转详解,边缘用黑色填充
项目要用到图像旋转,OpenCV里面居然没有专门封装好的函数,只好自己写了.根据<learnning OpenCV>发现效果不是很理想,旋转后图像大小不变,可是图像却被裁减了. 例子如下: ...
- 基于OpenCV做图像数据增强(平移、镜像、缩放、旋转、仿射)
前言: 基于OpenCV的基本使用,对图像的数据量进行数据增强,使得框架对神经网络进行训练,提高模型的鲁棒性以及准确性. 原图: 1.平移 平移通过自定义平移矩阵以及函数warpAffine实现: 代 ...
最新文章
- 基于FCN,U-Net的深度学习医学影像分割算法(细胞分割算法)以及传统算法分析
- helm部署hadoop并指定namespace和名称的命令
- 最新综述:作为体现具体化自然语言环境的文本世界
- 第八次ScrumMeeting博客
- intellij idea 中去除 @Autowired 注入对象带来的红色下划线报错提示
- 网友评论:Struts漏洞为什么来势凶猛
- Oracle数据库DBA必备基本技能
- SQLite 不能加密?
- 大数据技术 - MapReduce 作业的运行机制
- Codeforces Round 1384
- 微软洪小文全面解读智能层级:目前的智能都是AI+HI
- 什么是OEM、ODM、OBM
- 正点原子 任天堂_任天堂20年前,任天堂用纸Mario改变了RPG风格
- 基于Java 生产者消费者模式(详细分析)
- python中pandas.DataFrame如何对行与列求和以及如何添加新行与列的示例
- 【思考】Docker到底解决了什么问题
- 酷派S1android版本,酷派S1太烂了?NO!阉割降频版骁龙821依旧给力
- 计算机管理usb出现问号,USB设备全部都是问号,求助?
- 不用找,你想要的酒店餐饮su模型素材都在这里
- SVD(奇异值矩阵分解) 转载(+师兄ppt)
热门文章
- weblogic反序列化漏洞
- xmake新增对WDK驱动编译环境支持
- asp.net core 教程(七)-异常处理、静态文件
- CentOS 6.6安装Xtrabackup RPM提示缺少libev.so.4()
- ubuntu 突然不能 sudo成功,报错su: Authentication failure
- curl 命令行下载工具使用方法小结
- Vuex源码学习(五)加工后的module
- kafka的一些常用命令
- maven搭建ssm框架
- C# Email邮件发送,功能是密码找回或者重置功能。