英文:
How to apply affine transform to part of the image?
问题
有一个带有3个锚点(黑色矩形)的图像。可以从这些点生成一个仿射变换矩阵。
使用生成的矩阵来转换整个图像很容易,但如果我想要转换图像的一部分(绿色矩形),该怎么办?
我知道的唯一方法是将绿色矩形扩展到完整尺寸的图像,进行变换,然后再次裁剪它。
更新以使问题更清晰。
如果我有上面的图像和一个变换器,变换后的图像如下:
因为图像很大,完成变换需要很长时间,所以我只想要变换图像的一部分(绿色矩形)。
我期望的是裁剪绿色矩形并对其进行一些变换,以获得相同的结果。
英文:
There is an image with 3 anchor points (black rectangle). An affine transformation can be generated from these points.
It's easy to transform the whole image with the generated matrix, but if I want to transform a part of the image (green rectangle), how to do it?
The only way I know is to extend the green rectangle to full size image, transform, then crop it again.
Update to make it more clear.
If I have the image above and a transformer, the transformed image is like:
Because the image is big and takes long time to complete the transformation, so I only want to transform part of the image (the green rectangle)
what I expect is crop the green rectangle and perform some transformation to it, to get the same result.
答案1
得分: 3
基本上,我们可以将“ROI大小的图像”的变换矩阵与平移矩阵链接起来,将ROI移到“大图像”的左上角。
假设我们有一个尺寸为ROI的图像(称为roi
):
假设我们知道给定ROI图像的变换矩阵M
:
以下是计算变换矩阵M
的示例:
构建要应用于给定ROI的“大图像”的变换矩阵:
- 准备应用平移的变换矩阵。
平移将“大图像”中的每个像素移动,以将ROI移到图像的左上角。
平移矩阵:
将行[0, 0, 1]添加到M
的底部。
OpenCV对仿射变换的约定是省略底部行,即[0, 0, 1]
。我们必须添加省略的行以使M的大小为3x3。
链接变换 - 将M
与平移矩阵T
相乘:
删除roiM
的最后一行,以匹配OpenCV的2x3仿射变换约定:
将warpAffine
应用于具有roiM
变换矩阵的“大图像”:
用于测试,我们可以将warpAffine
应用于具有矩阵M
的roi
:
代码示例:
不同的假设:
假设“大图像”的变换矩阵已知。
假设我们希望将ROI的中心在“大图像”中的中心变换为所需目标图像的中心。
代码示例(请阅读注释):
rotated_roi
:
rotated_roi_ref
(用于测试的参考):
更新:不同的假设:
英文:
Basically we may chain the transformation matrix of a "ROI sized image" with translation matrix that "shifts" the ROI to the top-left corner of the "large image".
Assume we have an image in the size of the ROI (name it roi
):
Assume we know the transformation matrix M
for that given ROI image:
<!-- language: lang-python -->
M = np.array([[ 1.03366188, 0.37622216, 50],
[-0.37622216, 1.03366188, 100]])
Here is an example for computing the transformation matrix M
:
<!-- language: lang-python -->
import cv2
import numpy as np
img = cv2.imread('input_image.png');
x0, y0 = 770, 491 # Top left corner of the ROI in the image.
roi = img[y0:685, x0:1129, :]
M = cv2.getRotationMatrix2D((roi.shape[1]/2, roi.shape[0]/2), 20, 1.1) # Rotation and scale
M[0:2, 2] = (50, 100) # Add translation
print(M)
Building transformation matrix be applied on the "large image" with the given ROI:
- Prepare transformation matrix that applies translation.
The translation "shifts" each pixel in the "large image" to bring the ROI to the top-left corner of the image.
Translation matrix:
<!-- language: lang-python -->
T = np.array([[1, 0, -x0],
[0, 1, -y0],
[0, 0, 1]])
- Add row [0, 0, 1] to the bottom of
M
.
OpenCV convention for affine transformation is omitting the bottom row that equals[0, 0, 1]
.
We have to add the omitted row for making M size 3x3.
<!-- language: lang-python -->
M = np.vstack((M, np.array([0, 0, 1])))
- Chain transformation - multiply
M
by the translation matrixT
:
<!-- language: lang-python -->
roiM = M @ T
- Remove the last row of
roiM
for matching OpenCV 2x3 affine transformation conventions:
<!-- language: lang-python -->
roiM = roiM[0:2, :]
- Apply
warpAffine
to the "large image" withroiM
transformation matrix:
<!-- language: lang-python -->
rotated_roi = cv2.warpAffine(img, roiM, (dst_width, dst_height))
For testing, we may apply warpAffine
to roi
with matrix M
:
<!-- language: lang-python -->
rotated_roi_ref = cv2.warpAffine(roi, M, (dst_width, dst_height))
Code sample:
<!-- language: lang-python -->
import cv2
import numpy as np
img = cv2.imread('input_image.png');
x0, y0 = 770, 491 # Top left corner of the ROI in the image.
#roi = img[y0:685, x0:1129, :]
#M = cv2.getRotationMatrix2D((roi.shape[1]/2, roi.shape[0]/2), 20, 1.1) # Rotation and scale
#M[0:2, 2] = (50, 100) # Add translation
#print(M)
M = np.array([[ 1.03366188, 0.37622216, 50],
[-0.37622216, 1.03366188, 100]])
dst_width = 538 # int(roi.shape[1]*1.5)
dst_height = 291 # int(roi.shape[0]*1.5)
# Translation matrix - "shifts" the ROI to the top-left corner of img
T = np.array([[1, 0, -x0],
[0, 1, -y0],
[0, 0, 1]])
M = np.vstack((M, np.array([0, 0, 1]))) # Add row [0, 0, 1] to the bottom of M (we need M to be 3x3 before matrix multiplication).
roiM = M @ T # Chain transformations - each source pixel is translated by x=-770 and y=-491 and warped with M after the translation.
roiM = roiM[0:2, :] # Keep only the two upper rows (warpAffine input is 2x3 matrix).
rotated_roi = cv2.warpAffine(img, roiM, (dst_width, dst_height))
# Reference for testing: apply warp to roi
################################################################################
roi = img[y0:685, x0:1129, :]
M = cv2.getRotationMatrix2D((roi.shape[1]/2, roi.shape[0]/2), 20, 1.1) # Rotation and scale
M[0:2, 2] = (50, 100) # Add translation
rotated_roi_ref = cv2.warpAffine(roi, M, (dst_width, dst_height))
################################################################################
# Show output images for testing:
#cv2.imshow('roi', roi)
cv2.imshow('rotated_roi', rotated_roi)
cv2.imshow('rotated_roi_ref', rotated_roi_ref)
cv2.waitKey()
cv2.destroyAllWindows()
rotated_roi_ref
(reference for testing):
Update:
Different assumptions:
- Assume the transformation matrix of the "large image" is given.
- Assume we want the center of the ROI is the "large image" to be transformed to the center of the desired destination image.
Code sample (please read the comments):
<!-- language: lang-python -->
import cv2
import numpy as np
img = cv2.imread('input_image.png');
x0, y0 = 770, 491 # Top left corner of the ROI in the image.
x1, y1 = 1128, 684 # Bottom left corner of the ROI
# Size of destination image (output of Warp)
dst_width = 538
dst_height = 291
# Assume the following transformation matrix M is given:
M = cv2.getRotationMatrix2D((img.shape[1]/2, img.shape[0]/2), 15, 1.05) # Transformation matrix that applies the "large image"
# Center coordinate of the ROI:
roi_cx = (x1 + x0) / 2
roi_cy = (y1 + y0) / 2
# Transform the center coordinate of the ROI and get the center coordinate after the transformation (after the transformation of the "large image").
transformed_roi_cx, transformed_roi_cy = cv2.transform(np.array([[[roi_cx, roi_cy]]], np.float64), M)[0][0]
# Center coordinate of the destination image (output of Warp).
dst_cx = (dst_width - 1) / 2
dst_cy = (dst_height - 1) / 2
# Compute the horizontal and vertical translation - how much to shift the center after the "original warp".
tx = dst_cx - transformed_roi_cx
ty = dst_cy - transformed_roi_cy
# Translation matrix:
T = np.array([[1, 0, tx],
[0, 1, ty],
[0, 0, 1]])
M = np.vstack((M, np.array([0, 0, 1]))) # Add row [0, 0, 1] to the bottom of M (we need M to be 3x3 before matrix multiplication).
# T is multiplied from the left side - assume warp with M and than "shift" (translation comes after the warp).
roiM = T @ M # Chain transformations
roiM = roiM[0:2, :] # Keep only the two upper rows (warpAffine input is 2x3 matrix).
rotated_roi = cv2.warpAffine(img, roiM, (dst_width, dst_height))
cv2.imwrite('rotated_roi.png', rotated_roi) # Save for testing.
答案2
得分: 2
创建提取兴趣矩形区域的图像。
在此ROI图像中,像素位置之间的转换与原始图像中的像素位置之间的转换是简单的平移。
因此,为此坐标变换添加平移,并将其应用于ROI图像。
在这里,转换后的图像缓冲区的大小是原始图像的大小。
例如,考虑从原始点到结果点的变形。
“Result_Position = AffineTrans(Original_Point)”
如果ROI是原始图像中的(Left=100,Top=200, Width=any,Height=any)矩形,
提取的ROI图像中的点(0,0)对应于原始图像中的(100,200)。
由于函数“AffineTrans()”的参数是“原始图像中的点”,要将此函数用于ROI图像,必须通过将ROI图像中的位置转换为原始图像中的位置来获取参数值。
即
“Result_Position = AffineTrans(Point_in_ROI_Image +(100,200))”
(当然,在现实中,必要的变形方向是相反的,但要做的事情是相同的。)
英文:
Create an image that extracts only the interest rectangular region.
The transformation between pixel positions in this ROI image and pixel positions in the original image is a simple translation.
So, add the translation for this coordinate transformation to the affine transformation and apply it to the ROI image.
Here, the size of the transformed image buffer is the size of the original image.
e.g. consider about the warp from original point to result point.
Result_Position = AffineTrans( Original_Point )
If ROI is (Left=100,Top=200, Width=any,Height=any) rectangle in the original image,
Point(0,0) in the extracted ROI image corresponds to (100,200) in the original image.
Since the argument of the function AffineTrans()
is "Point in the Original Image", to use this function for the ROI image, you have to obtain ther argument value by translating the position in the ROI image to in the Original image.
i.e.
Result_Position = AffineTrans( Point_in_ROI_Image + (100,200) )
(Of cause, in real, necessary warp direction is the opposite, but what to do is same.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论