如何将仿射变换应用于图像的一部分?

huangapple go评论54阅读模式
英文:

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应用于具有矩阵Mroi

代码示例:

不同的假设:

假设“大图像”的变换矩阵已知。
假设我们希望将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(&#39;input_image.png&#39;);

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 matrix T:

<!-- 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" with roiM 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(&#39;input_image.png&#39;);

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 - &quot;shifts&quot; 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(&#39;roi&#39;, roi)
cv2.imshow(&#39;rotated_roi&#39;, rotated_roi)
cv2.imshow(&#39;rotated_roi_ref&#39;, rotated_roi_ref)
cv2.waitKey()
cv2.destroyAllWindows()

rotated_roi:
如何将仿射变换应用于图像的一部分?

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(&#39;input_image.png&#39;);

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 &quot;large image&quot;

# 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 &quot;large image&quot;).
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 &quot;original warp&quot;.
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 &quot;shift&quot; (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(&#39;rotated_roi.png&#39;, rotated_roi)  # Save for testing.

rotated_roi:
如何将仿射变换应用于图像的一部分?

答案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.)

huangapple
  • 本文由 发表于 2023年6月5日 18:01:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76405308.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定