简 介: 本文中,你了解了了如何通过OpenCV完成对于图像的旋转和平移。我们首先通过 getRotationMatrix2D() 获取2D旋转矩阵,然后完成了对于图像的旋转。具体是通过warpAffine() 将旋转拒转施加在图像上完成对图像绕着中心旋转所需的角度。接着通过明确定义了转换矩阵,包含有想要图像沿着xy轴移动的信息。同样利用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执行图像的旋转。在后面我们将会对于代码的每一行伴随着对于图片的转换进行解释。最后,我们就会对下面的代码有了充分的理解。

  • Python
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)
  • C++
#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的库和图片导入。

  • Python
import cv2# Reading the image
image = cv2.imread('image.jpg')
  • C++
#include "opencv2/opencv.hpp"
using namespace cv;# Reading the image
Mat image = imread("image.jpg");

  接着,计算旋转点,在这个例子中就是图像的中心。所以只要简单的吧图像的宽和高除以二就可以了。

  • Python
# Dividing height and width by 2 to get the center of the image
height, width = image.shape[:2]
center = (width/2, height/2)
  • C++
// 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-旋转拒转,下面就是用该矩阵对图像进行旋转。

  • Python
# 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)
  • C++
// create the rotation matrix using the image center
Mat rotation_matix = getRotationMatrix2D(center, angle=45, 1.0);

  现在,通过函数 warpAffine()将旋转拒转作用在图像上,这个函数需要三个输入:
  1. 原始图像;
  2. 旋转拒转;
  3. 输出图像的尺寸;

  旋转结果存储在 rotated_image中,下面我们会展示出来。

  • Python
# Rotate the image using cv2.warpAffine
rotated_image = cv2.warpAffine(src=image, M=rotate_matrix, dsize=(width, height))
  • C++
// 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() 函数。

  • Python
# 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)
  • C++
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=[10​01​tx​ty​​​]

  在将图像平移 tx,tyt_x ,t_ytx​,ty​ 时你需要注意:

  • txt_xtx​ 为正表示将图像往右平移,负值表示将图像往左平移;
  • 类似, tyt_yty​ 为正,表示图像往下平移,负值则图像网上平移;

  安装一下三个步骤使用OpenCV完成图像的平移:
  1. 首先读入图像,获得图像的宽、高;
  2. 截止,就像前面在旋转图像那样,你需要创建一个变换矩阵,也是一个2D的矩阵。这个矩阵包含了平移图像所需要的参数,也就是沿着x、y轴移动的距离;
  3. 有一次使用 warpAffine() 函数,就像前面旋转图像那样, 将变换矩阵作用在图像上。

  下面的代码你可以自行阅读分析,比较简单:

  • Python
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]
  • C++
#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;

  上面的代码你读入图像获得它的尺寸;

  接着你创建转换矩阵:

  • Python
# 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)
  • C++
// 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() 函数将转换矩阵作用在图像上,就像前面旋转图像那样:

  • Python
# apply the translation to the image
translated_image = cv2.warpAffine(src=image, M=translation_matrix, dsize=(width, height))
  • C++
// 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 定义好就行了。

  最后一扩代码就是将转换后的图像进行显示,并存储在磁盘上。 到此为止,你完成了所有的工作。

  • Python
# 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)
  • C++
//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() 将旋转拒转施加在图像上完成对图像绕着中心旋转所需的角度。

  接着通过明确定义了转换矩阵,包含有想要图像沿着xy轴移动的信息。同样利用warpAffine()函数对图像进行变换。

  旋转和平移图像是我们学习利用OpenCV完成对图像进行其它变化的良好的基础。鼓励你在此基础上测试其它的输入查看一下变化的效果。

  你是否还想构建一个应用来获得鸟眼中的图片景象?这需要了解更多OpenCV中的透视变换信息。加上现在你已经了解的旋转和平移就可以构建上述应用了。

  在这个 链接 中你可以尝试一下我们使用StreamLit够贱的Web应用程序,来帮助你旋转和平移图像。

▲ 图3.1 StreamLit演示程序


■ 相关文献链接:

  • 链接

● 相关图表链接:

  • 图1.1 用于后面实验的图片样例
  • 图1.1 使用OpenCV旋转后的图像
  • 图2.1 通过OpenCV平移图像
  • 图3.1 StreamLit演示程序

应用OpenCV进行图像旋转和平移相关推荐

  1. Opencv 基础(四):使用OpenCV进行图像旋转和平移

    如今,图像编辑变得越来越流行,因为手机有内置的功能,可以让你裁剪.旋转和更多的操作你的图像. 这篇文章中,我们将探索和学习这些图像编辑技术.具体来说,我们将学习如何: 旋转图像 移动图像 基本图像变换 ...

  2. OpenCV 图像旋转、平移、缩放

    本文是 OpenCV图像视觉入门之路的第7篇文章,本文详细的进行了图像的缩放 cv2.resize().旋转 cv2.flip().平移 cv2.warpAffine()等操作. OpenCV 图像旋 ...

  3. Opencv:图像旋转,cv2.getRotationMatrix2D 和 cv2.warpAffine 函数

    学习记录如何使用opencv实现对图像的旋转操作. 1 cv2.getRotationMatrix2D(center, angle, scale) 图像的旋转矩阵一般为: 但是单纯的这个矩阵是在原点处 ...

  4. opencv之图像翻转、平移、缩放、旋转、仿射学习笔记

    opencv版本:opencv3.4.1 目录 1. 图像翻转(坐标映射) 2.  平移 3. 缩放 4. 旋转 1. 图像翻转(坐标映射) int main() {cv::Mat srcImage ...

  5. opencv warpAffine()函数详解 -- 图像旋转与平移

    简述 仿射变换是二维坐标间的线性变换,故而变换后的图像仍然具有原图的一些性质,包括"平直性"以及"平行性",常用于图像翻转(Flip).旋转(Rotations ...

  6. OpenCV中图像旋转(warpAffine)算法的实现过程

    在OpenCV中,目前并没有现成的函数直接用来实现图像旋转,它是用仿射变换函数cv::warpAffine来实现的,此函数目前支持4种插值算法,最近邻.双线性.双三次.兰索斯插值,如果传进去的参数为基 ...

  7. 【OpenCV3】图像旋转与平移——cv::warpAffine()详解

    图像旋转和平移是图像处理中常用的一种操作,opencv2和opencv3中对图像的旋转和平移都是通过仿射变换函数cv::warpAffine()来实现的. 1.图像的旋转 图像的旋转具体实现分为两步: ...

  8. 【OpenCV】图像旋转详解,边缘用黑色填充

    项目要用到图像旋转,OpenCV里面居然没有专门封装好的函数,只好自己写了.根据<learnning OpenCV>发现效果不是很理想,旋转后图像大小不变,可是图像却被裁减了. 例子如下: ...

  9. 基于OpenCV做图像数据增强(平移、镜像、缩放、旋转、仿射)

    前言: 基于OpenCV的基本使用,对图像的数据量进行数据增强,使得框架对神经网络进行训练,提高模型的鲁棒性以及准确性. 原图: 1.平移 平移通过自定义平移矩阵以及函数warpAffine实现: 代 ...

最新文章

  1. 基于FCN,U-Net的深度学习医学影像分割算法(细胞分割算法)以及传统算法分析
  2. helm部署hadoop并指定namespace和名称的命令
  3. 最新综述:作为体现具体化自然语言环境的文本世界
  4. 第八次ScrumMeeting博客
  5. intellij idea 中去除 @Autowired 注入对象带来的红色下划线报错提示
  6. 网友评论:Struts漏洞为什么来势凶猛
  7. Oracle数据库DBA必备基本技能
  8. SQLite 不能加密?
  9. 大数据技术 - MapReduce 作业的运行机制
  10. Codeforces Round 1384
  11. 微软洪小文全面解读智能层级:目前的智能都是AI+HI
  12. 什么是OEM、ODM、OBM
  13. 正点原子 任天堂_任天堂20年前,任天堂用纸Mario改变了RPG风格
  14. 基于Java 生产者消费者模式(详细分析)
  15. python中pandas.DataFrame如何对行与列求和以及如何添加新行与列的示例
  16. 【思考】Docker到底解决了什么问题
  17. 酷派S1android版本,酷派S1太烂了?NO!阉割降频版骁龙821依旧给力
  18. 计算机管理usb出现问号,USB设备全部都是问号,求助?
  19. 不用找,你想要的酒店餐饮su模型素材都在这里
  20. SVD(奇异值矩阵分解) 转载(+师兄ppt)

热门文章

  1. weblogic反序列化漏洞
  2. xmake新增对WDK驱动编译环境支持
  3. asp.net core 教程(七)-异常处理、静态文件
  4. CentOS 6.6安装Xtrabackup RPM提示缺少libev.so.4()
  5. ubuntu 突然不能 sudo成功,报错su: Authentication failure
  6. curl 命令行下载工具使用方法小结
  7. Vuex源码学习(五)加工后的module
  8. kafka的一些常用命令
  9. maven搭建ssm框架
  10. C# Email邮件发送,功能是密码找回或者重置功能。