An introduction to affine transformations
What is a radiative transformation
An affine transformation on an image, which is essentially a pixel in the image, moves to another place through some transformation.
Mathematically, it’s a linear transformation from one vector space to another by adding a translation vector.
Vector space m: m=(x,y)
Vector space n: n=(x ‘,y ‘)
The transformation from m to n of the vector space n=A∗m+b
Sorted out:
You combine A and B to form the affine matrix M. The dimension is 2∗3
Using different matrix M, different 2D affine transformation effects are obtained.
In OpencV, the realization of 2D affine transformation needs the help of warpAffine function.
cv2.warpAffine(image, M, (image.shape[1], image.shape[0])
Copy the code
Next, I will take you to analyze the transformation matrix of a specific 2D affine transformation.
Image translation
The formulas
Translation is kind of the simplest kind of space transformation. Its expression is:
Where (b0,b1) is the offset.
routine
If the shift is 10 pixels to the right and 30 pixels to the bottom, then the transformation matrix M can be written as:
Demo code
Pan it 10 pixels to the right and 30 pixels to the bottom:
Import cv2 import numpy as np img = cv2.imread('lena1.jpg') height,width,channel = img.shape = np.float32([[1, 0, 10], [0, 1, 30]]) # move 2D affine transform = cv2.warpAffine(img, M, (width, 0); height)) cv2.imwrite('shift_right_10_down_30.jpg', shifted)Copy the code
Original image:
Move the image 10 pixels to the right and 30 pixels down:
Shift 10 pixels to the left and 30 pixels up:
Shift the transformation matrix 10 pixels to the left, M = np.float32([[1, 0, -10], [0, 1, -30]]) # move 2D affine transform = cv2.warpAffine(img, M, (width, 0); height)) cv2.imwrite('shift_right_-10_down_-30.jpg', shifted)Copy the code
Affine transformation image:
Image translation v2
We can encapsulate this operation with the translate function:
def translate(image, x, y):
M = np.float32([[1, 0, x], [0, 1, y]])
shifted = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
return shifted
Copy the code
Complete some code:
import cv2
import numpy as np
img = cv2.imread('cat.png')
def translate(image, x, y):
M = np.float32([[1, 0, x], [0, 1, y]])
shifted = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
return shifted
shifted = translate(img, 10, 30)
cv2.imwrite('shift_right_10_down_30.png', shifted)
Copy the code
The processing results are the same as above…
The image rotation
Use getRotationMatrix2D to implement rotation
The getRotationMatrix2D function in OpencV can generate M directly for us without requiring us to calculate trig functions in the program:
getRotationMatrix2D(center, angle, scale)
Copy the code
Argument parsing
center
Center of rotation(cx, cy)
You can specify whatever you wantangle
The unit of rotation is Angle. The counterclockwise direction is positive, and the positive Angle represents counterclockwisescale
The scaling factor is equal to1.0
Represents constant size
This function returns the affine transformation matrix M
The sample code
RotateMatrix = cv2.getRotationMatrix2D((100, 200), 90, Np. set_printoptions(precision=2,suppress=True) print(rotateMatrix) OUTPUT [[0\.1 \.-100.] [-1\. 0 \. 300.]]Copy the code
You can also encapsulate the rotation process for ease of use
Def rotate(image, Angle, center = None, scale = 1.0): (h, w) = image.shape[:2] def rotate(image, Angle, center = None, scale = 1.0): (h, w) = image.shape[:2] if center is None: center = (w / 2, h / 2) M = cv2.getRotationMatrix2D(center, angle, scale) rotated = cv2.warpAffine(image, M, (w, h)) return rotatedCopy the code
Demo code
# -*- coding: Utf-8 -*- "" Rotate around the origin (upper left corner of image) in a positive direction counterclockwise generate the affine matrix" "import numpy as NP import cv2 from math import using the getRotationMatrix2D function cos,sin,radians from matplotlib import pyplot as plt img = cv2.imread('lena1.jpg') height, width, Channel = img.shape # Cx = int(width / 2) cy = int(height / 2) # M = cv2. GetRotationMatrix2D (center=center, Angle =30, Scale =1.0) rotated_30 = cv2.warpAffine(img, M, M = cv2.getRotationMatrix2D(center=center, Angle =45, Scale =1.0) rotated_45 = cv2.warpAffine(img, M, M = cv2.getRotationMatrix2D(center=center, Angle =60, Scale =1.0) rotated_60 = cv2.warpAffine(img, M, new_dim) plt.subplot(221) plt.title("Src Image") plt.imshow(img[:,:,::-1]) plt.subplot(222) plt.title("Rotated 30 Degree") plt.imshow(rotated_30[:,:,::-1]) plt.subplot(223) plt.title("Rotated 45 Degree") plt.imshow(rotated_45[:,:,::-1]) plt.subplot(224) plt.title("Rotated 60 Degree") plt.imshow(rotated_60[:,:,::-1]) plt.show()Copy the code
Original graphics:
Image rotation image (counterclockwise 30 degrees, 45 degrees, 60 degrees) :
Use wrapAffine for scaling
Mathematical principle derivation
We rotate around the origin
From this we conclude that
So the corresponding transformation matrix is zero
Notice that when we do the derivation here, the origin is in the lower left corner, whereas in OpenCV the origin is in the upper left corner of the image, so we’re going to invert theta in our code.
We can use trigonometry in the Math package. One thing to note, however, is that the trigonometric input is in radians, not angles.
We need to use the radians(x) function to convert the Angle to radians.
The import math math. Radians (180) 3.141592653589793Copy the code
Code demo
# -*- coding: Utf-8 -*- "" rotate around the origin (upper left corner of the image) counterclockwise" "import numpy as NP import cv2 import math from matplotlib import Pyplot as PLT img = cv2.imread('lena1.jpg') height, width, channel = img.shape def getRotationMatrix2D(theta): Radians (-1*theta) M = NP.float32 ([[math.cos(theta), -math.sin(theta), 0], [math.sin(theta), math.cos(theta), M = getRotationMatrix2D(30) rotated_30 = cv2.warpaffine (img, M, (width, M = getRotationMatrix2D(45) rotated_45 = cv2.warpAffine(img, M, (width, M = getRotationMatrix2D(60) rotated_60 = cv2.warpAffine(img, M, (width, height)) plt.subplot(221) plt.title("Src Image") plt.imshow(img[:,:,::-1]) plt.subplot(222) plt.title("Rotated 30 Degree") plt.imshow(rotated_30[:,:,::-1]) plt.subplot(223) plt.title("Rotated 45 Degree") plt.imshow(rotated_45[:,:,::-1]) plt.subplot(224) plt.title("Rotated 60 Degree") plt.imshow(rotated_60[:,:,::-1]) plt.show()Copy the code
Original image:
Illustration after rotation:
I rotate around any point
Mathematical principle derivation
So how do you rotate around any point?
You can shift the current center of rotation to the origin, rotate at the origin and then shift it back again.
Suppose the center of rotation is zero(cx,cy)
Among them
so
Code demo
# -*- coding: Utf-8 -*- "" rotate around any point in the screen import numpy as NP import cv2 from math import cos,sin,radians from matplotlib import pyplot as plt img = cv2.imread('lena1.jpg') height, width, channel = img.shape theta = 45 def getRotationMatrix2D(theta, cx=0, cy=0): Because the top left corner of the image is the origin, we need ×-1 theta = radians(-1 * theta) M = NP.Float32 ([[cos(theta), -sin(theta), (1-cos(theta))*cx + sin(theta)*cy], [sin(theta), cos(theta) *cx + (1-cos(theta))*cy]]) As the axis of rotation cx= int(width / 2) cy = int(height / 2) # Perform 2D affine transformation # Rotate 30 degrees counterclockwise around the origin M = getRotationMatrix2D(30, cx=cx, Rotated_30 = cv2. WarpAffine (img, M, (width, height)) # rotated_30 = cv2. Rotated_45 = cv2.warpAffine(img, M, (width, height)) # rotated_45 = cv2.warpAffine(img, M, (width, height)) # cy=cy) rotated_60 = cv2.warpAffine(img, M, (width, height)) plt.subplot(221) plt.title("Src Image") plt.imshow(img[:,:,::-1]) plt.subplot(222) plt.title("Rotated 30 Degree") plt.imshow(rotated_30[:,:,::-1]) plt.subplot(223) plt.title("Rotated 45 Degree") plt.imshow(rotated_45[:,:,::-1]) plt.subplot(224) plt.title("Rotated 60 Degree") plt.imshow(rotated_60[:,:,::-1]) plt.show()Copy the code
Rotation effect:
Rotate 30 degrees to 60 degrees around the center of the image
Image zooming
Use the resize function for scaling
Opencv actually has a function called resize for image scaling.
resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) -> dst
Copy the code
Argument parsing
src
The input imagedsize
Output the size of the picturedst
The output imagefx
The scaling factor for the x axisfy
The scaling factor for the y axisinterpolation
The interpolation methodINTER_NEAREST
– Nearest neighbor interpolationINTER_LINEAR
– Linear interpolation (default)INTER_AREA
– Region interpolationINTER_CUBIC
– Cubic spline interpolationINTER_LANCZOS4
– Lanczos interpolation
When used, we can pass in the specified image size dsize
Import cv2 import numpy as NP img = cv2.imread('lena1.jpg') height,width,channel = img.shape # New_dimension = (400, 400) # Specifies dimension and interpolation algorithm (Interpolation) resized = cv2.resize(img, new_dimension) cv2.imwrite('lena_resize_400_400.png', resized)Copy the code
Original image:
Zoomed image:
Or specify a scaling factorfx,fy
Set dsize to None, and specify FX fy
import cv2 import numpy as np img = cv2.imread('lena1.jpg') height,width,channel = img.shape # Resized = cv2.resize(img, None, fx=1.5, fy=2) cv2.imwrite('lena_resize_fx_fy.jpg', resized)Copy the code
The running results are as follows:
Or specify the output image and pass in the size of the output image:
Import cv2 import numpy as NP img = cv2.imread('lena1.jpg') height,width,channel = img.shape # Zeros ((100, 100, 3), dtype='uint8') # Dsize =(dst.shape[1], dst.shape[0]), fx=1.5, fy=2) cv2.imwrite('lena_resize_from_dst.jpg', DST)Copy the code
The running results are as follows:
See the Opencv-resize documentation for more detailed instructions
We can also wrap it as a function for ease of use
def resize(image, width = None, height = None, inter = cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
if width is None and height is None:
return image
if width is None:
r = height / float(h)
dim = (int(w * r), height)
if height is None:
r = width / float(w)
dim = (width, int(h * r))
if width and height:
dim = (width, height)
resized = cv2.resize(image, dim, interpolation = inter)
return resized
Copy the code
The resolution is enlarged from 5 * 5 to 1000 * 1000, and different interpolation algorithms are selected. The corresponding demonstration effect is as follows:
Import cv2 import numpy as NP from matplotlib import pyplot as PLT img = Uint8 (np.random. Randint (0,255,size=(5,5))) height,width= img.shape 1000) plt.subplot(231) plt.title("SRC Image") plt.imshow(img,cmap='seismic') plt.subplot(232) resized = cv2.resize(img, new_dimension, interpolation = cv2.INTER_NEAREST) plt.title("INTER_NEAREST") plt.imshow(resized,cmap='seismic') plt.subplot(233) resized = cv2.resize(img, new_dimension, interpolation = cv2.INTER_LINEAR) plt.title("INTER_LINEAR") plt.imshow(resized,cmap='seismic') plt.subplot(234) resized = cv2.resize(img, new_dimension, interpolation = cv2.INTER_AREA) plt.title("INTER_AREA") plt.imshow(resized,cmap='seismic') plt.subplot(235) resized = cv2.resize(img, new_dimension, interpolation = cv2.INTER_CUBIC) plt.title("INTER_CUBIC") plt.imshow(resized,cmap='seismic') plt.subplot(236) resized = cv2.resize(img, new_dimension, interpolation = cv2.INTER_LANCZOS4) plt.title("INTER_LANCZOS4") plt.imshow(resized,cmap='seismic') plt.show()Copy the code
Use wrapAffine for scaling
Mathematical principles
The transformation matrix M of the expansion transformation of the image is
Among them,
fx
: represents the focal length of the x axis (scaling factor)
fy
: represents the focal length of the Y-axis (scaling factor)
The following formula can be obtained:
Concrete code demo
The source code:
Import numpy as np import cv2 img = cv2.imread('lena1.jpg') height,width,channel = img.shape # x axis focal length 1.5 x fx = 1.5 # y focal length 2 x fy = 2 # Declare the transformation matrix shifted 10 pixels to the right, Zoom down 30 pixels M = Np.float32 ([[fx, 0, 0], [0, fy, 0]]) # Re-sized 2D affine transform = cv2.warpaffine (img, M, (int(width*fx), int(height*fy))) cv2.imwrite('resize_raw.jpg', resized)Copy the code
Operation effect:
Original image:
weRandom module is used to generate a 5×5 random matrix.
Img = np.random. Randint (0,255,size=(5,5))Copy the code
The source code:
The affine matrix implements scaling fx,fy "import numpy as NP import cv2 from matplotlib import Pyplot as PLT # generates a random noise img = Uint8 (np.random. Randint (0,255,size=(5,5))) height,width = img.shape # x axis focal length 1.5 x fx = 1.5 y axis focal length 2 x fy = 2 Shift it 10 pixels to the right, Zoom down 30 pixels M = Np.float32 ([[fx, 0, 0], [0, fy, 0]]) # Re-sized 2D affine transform = cv2.warpaffine (img, M, (int(width*fx), Int (height*fy)) print(img) print(resized) # plt.subplot(121) plt.imshow(img, cmap="gray") plt.subplot(122) plt.imshow(resized,cmap="gray") plt.show()Copy the code
The original:
[[224 25 25 165 16] [37 170 114 16 101] [181 5 7 94 41] [206 167 23 133 115] [217 115 154 97 65]Copy the code
After the scale:
[[224 93 25 25 117 114 16] [131 109 88 70 83 80 59] [37 124 151 114 50 45 101] [109 95 78 61 57 61 71] [181 66 6 7 64 76 41] [194 123 62 15 80 101 78] [206 180 118 23 95 127 115] [212 165 123 89 106 106 90] [217 150 128 154 117 86 65] [109 75 64 77 58 43 33]Copy the code
For a more intuitive feeling, we can perform data visualization.
We use thematplotlib
Image before and after resize.
Image rollovers
Flip using the flip function
Flip function prototype
flip(src, flipCode[, dst]) -> dst
Copy the code
Argument parsing
src
The input imageflipCode
Flip the code1
Flip Horizontally Horizontally (the second dimension of the image is column)0
Vertically invert *Vertically *- 1
Horizontally and Vertically inverting Horizontally & Vertically
You can also encapsulate the following functions for ease of use
def flip(image, direction):
if direction == "h":
flipped = cv2.flip(image, 1)
elif direction == "v":
flipped = cv2.flip(image, 0)
else:
# both horizontally and vertically
flipped = cv2.flip(image, -1)
Copy the code
Specific source code and effect display
Import numpy as np import cv2 from matplotlib import pyplot as PLT img = cv2.imread('lena1.jpg') def bgr2rbg(img): Flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip flip Flip_hv = cv2.flip(img, -1) plt.subplot(221) plt.title('SRC') plt.imshow(bgr2rbg(img)) plt.subplot(222) plt.title('Horizontally') plt.imshow(bgr2rbg(flip_h)) plt.subplot(223) plt.title('Vertically') plt.imshow(bgr2rbg(flip_v)) plt.subplot(224) plt.title('Horizontally & Vertically') plt.imshow(bgr2rbg(flip_hv)) plt.show()Copy the code
Use numpy’s index for flipping
Using the nDARray index in NUMpy, we can easily achieve image flipping.
# flip horizontal flip_h = img [: : : 1] # flip vertical flip_v = img] [: : - 1 # levels at the same time flip vertical flip_hv = img [: : 1, : : 1]Copy the code
Specific source code and effect display
Import cv2 import numpy as NP from matplotlib import pyplot as PLT img = Flip_h = img[:,::-1] # flip flip_v = img[::-1] # flip flip_v = img[::-1] # Flip_hv = img[::-1, ::-1] def bgr2rbg(img): Return img[:,:,::-1] plt.subplot(221) plt.title('SRC') plt.imshow(bgr2rbg(img)) plt.subplot(222) plt.title('Horizontally') plt.imshow(bgr2rbg(flip_h)) plt.subplot(223) plt.title('Vertically') plt.imshow(bgr2rbg(flip_v)) plt.subplot(224) plt.title('Horizontally & Vertically') plt.imshow(bgr2rbg(flip_hv)) plt.show() 12345678910111213141516171819202122232425262728293031323334353637383940414243Copy the code
Use wrapAffine for rollover
Mathematical principles of image flipping
Note: width represents the width of the image; Height represents the height of the image
The transformation matrix of the horizontal flip
The vertically flipped transformation matrix
Flip horizontally and vertically simultaneously
Specific source code and effect display
Import cv2 import numpy as NP from matplotlib import pyplot as PLT img = cv2.imread('lena1.jpg') Float32 ([[-1, 0, width], [0, 1, 0]]) flip_h = cv2.warpAffine(img, M1, 1, 0) Float = np.float32([[1, 0, 0], [0, -1, height]]) flip_v = cv2.warpAffine(img, M2, (width, 0, 0)) Float ([[-1, 0, width], [0, -1, height]]) flip_hv = cv2.warpAffine(img, M3, (width, 0, -1, height) height)) def bgr2rbg(img): Return img[:,:,::-1] plt.subplot(221) plt.title('SRC') plt.imshow(bgr2rbg(img)) plt.subplot(222) plt.title('Horizontally') plt.imshow(bgr2rbg(flip_h)) plt.subplot(223) plt.title('Vertically') plt.imshow(bgr2rbg(flip_v)) plt.subplot(224) plt.title('Horizontally & Vertically') plt.imshow(bgr2rbg(flip_hv)) plt.show()Copy the code
Resource portal
- Pay attention to [be a gentle program ape] public account
- In [do a tender program ape] public account background reply [Python information] [2020 autumn recruit] can get the corresponding surprise oh!
“❤️ thank you.”
- Click “like” to support it, so that more people can see this content.
- Share your thoughts with me in the comments section, and record your thought process in the comments section.
- Excel/Word/CSV with Python (160 +)
- The average programmer likes to browse 40 websites, so many years, I will not hide private, personally strongly recommend (230+)
- Image Encryption and Restoration Based on Chaotic Logistic Encryption Algorithm
- Draw dynamic fireworks in Python
- Error: AttributeError: ‘Module’ object has no attribute ‘XXXXX’
- How to parse XML and PDF easily in Python (300 +)