在Python中旋转图像,并获取在旋转后的图像中的像素的原始位置。

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

Rotate an image in Python, and get the original position of a pixel which is in the rotated image

问题

  1. 旋转图像并保留图像的全部内容(允许填充)需要使用指定的角度(比如θ)。
  2. 如果原始图像中有一个像素位于x,y处,则需要找到旋转后图像中的x_r,y_r,即该像素所在位置。
  3. 如果旋转后图像中有一个像素位于x_r, y_r处,则需要找到它在原始图像中的位置x,y。

我尝试使用PIL的image.rotate函数进行旋转,并保持expand=True

我开发了一个像素反转函数,对于90度的旋转工作正常,但对于0到90之间的角度,它无法正常工作。

下面是我迄今为止编写的代码。

  1. import math
  2. from PIL import Image, ImageDraw
  3. from icecream import ic
  4. def draw_circle(img, x, y, title):
  5. # 创建一个ImageDraw对象来在图像上绘制
  6. draw = ImageDraw.Draw(img)
  7. # 设置点的中心坐标
  8. point_x, point_y = x, y
  9. # 设置点的大小(宽度和高度)(使其更大)
  10. point_size = 50 # 您可以调整此值以更改点的大小
  11. # 设置点的颜色(在此示例中为红色,表示为RGB)
  12. point_color = (255, 0, 0)
  13. # 计算椭圆的边界框(表示点)
  14. point_bbox = (
  15. point_x - point_size // 2,
  16. point_y - point_size // 2,
  17. point_x + point_size // 2,
  18. point_y + point_size // 2,
  19. )
  20. # 在图像上绘制椭圆(表示点)
  21. draw.ellipse(point_bbox, fill=point_color, outline=point_color)
  22. img.show(title=title)
  23. # 关闭ImageDraw对象
  24. del draw
  25. def rotate_pixel(x, y, theta, rotated_img):
  26. """
  27. 给定此函数,原始图像旋转的X、Y位置,原始图像旋转的角度,
  28. 和旋转后的图像本身。
  29. 返回:旋转后图像中该像素的X、Y坐标
  30. 要反转旋转,请提供结果X、Y坐标以及-theta,以及原始图像
  31. """
  32. rotated_img_width, rotated_img_height = rotated_img.size
  33. # 将theta转换为弧度
  34. theta_rad = math.radians(theta)
  35. # 计算旋转后的新X和Y坐标
  36. new_x = round(x * math.cos(theta_rad) - y * math.sin(theta_rad))
  37. new_y = round(x * math.sin(theta_rad) + y * math.cos(theta_rad))
  38. if new_y < 0:
  39. new_y = rotated_img_height + new_y
  40. elif new_x < 0:
  41. new_x = rotated_img_width + new_x
  42. return new_x, new_y
  43. strip_image_path = '../../dumb_data/perfect_strip.png'
  44. angle = 90
  45. img = Image.open(strip_image_path)
  46. rot_img = img.rotate(angle, expand=True)
  47. width, height = img.size
  48. rot_width, rot_height = rot_img.size
  49. original_x, original_y = 500, 100
  50. rotated_x, rotated_y = rotate_pixel(original_x, original_y, -angle, rotated_img=rot_img) # 旋转坐标(img, +angle, original_x, original_y)
  51. reverse_x, reverse_y = rotate_pixel(rotated_x, rotated_y, angle, rotated_img=img) # 旋转坐标(img, -angle, rotated_x, rotated_y)
  52. # 定义图像尺寸
  53. image_width, image_height = img.size
  54. print()
  55. ic(img.size)
  56. ic(rot_img.size)
  57. ic(original_x, original_y)
  58. ic(rotated_x, rotated_y)
  59. ic(reverse_x, reverse_y)
  60. draw_circle(img, original_x, original_y, title="original")
  61. draw_circle(rot_img, rotated_x, rotated_y, title="rotated")

欢迎任何能够实现上述目标的解决方案。

英文:

One part of the project I am currently working on, requires me to achieve the following:

  1. Rotate an image by any specified angle (theta let's say), without cropping out any portion of the image (padding is allowed)
  2. If I have a pixel at x,y in the original image, find the x_r,y_r in the rotated image, where the pixel lies.
  3. If I have a pixel at x_r, y_r in the rotated image, find the x,y where this pixel lies in the original image.

I tried using PIL's image.rotate function for rotation and kept expand=True.

I developed a pixel reversal function which works fine for 90 degree rotation , but on using angles between 0 and 90, it doesn't work properly.

Here's a couple of images showing the rotation and it's results, with the red dot indicating the two pixels that are supposed to be identical. The image on the left is the original, whereas the one on the right is the rotated one

θ=90
θ=45

Here's the code I wrote so far.

  1. import math
  2. from PIL import Image, ImageDraw
  3. from icecream import ic
  4. def draw_circle(img, x, y,title):
  5. # Create an ImageDraw object to draw on the image
  6. draw = ImageDraw.Draw(img)
  7. # Set the coordinates for the center of the point
  8. point_x, point_y = x, y
  9. # Set the size (width and height) of the point (making it bigger)
  10. point_size = 50 # You can adjust this value to change the size of the point
  11. # Set the color of the point (red in this example, represented as RGB)
  12. point_color = (255, 0, 0)
  13. # Calculate the bounding box for the ellipse
  14. point_bbox = (
  15. point_x - point_size // 2,
  16. point_y - point_size // 2,
  17. point_x + point_size // 2,
  18. point_y + point_size // 2,
  19. )
  20. # Draw the ellipse (representing the point) on the image
  21. draw.ellipse(point_bbox, fill=point_color, outline=point_color)
  22. img.show(title=title)
  23. # Close the ImageDraw object
  24. del draw
  25. def rotate_pixel(x, y, theta,rotated_img):
  26. &quot;&quot;&quot;
  27. Give this function, the X,Y positions from the original image, the angle by which the original image is rotated,
  28. and the rotated image itself.
  29. Returns: The X,Y coordinates of that exact pixel in the rotated image
  30. To reverse the rotation, give the resulting X,Y coordinates, along with -theta, and the original image
  31. &quot;&quot;&quot;
  32. rotated_img_width, rotated_img_height = rotated_img.size
  33. # Convert theta to radians
  34. theta_rad = math.radians(theta)
  35. # Calculate the new x and y coordinates after rotation
  36. new_x = round(x * math.cos(theta_rad) - y * math.sin(theta_rad))
  37. new_y = round(x * math.sin(theta_rad) + y * math.cos(theta_rad))
  38. if new_y &lt; 0:
  39. new_y = rotated_img_height + new_y
  40. elif new_x &lt; 0:
  41. new_x = rotated_img_width + new_x
  42. return new_x, new_y
  43. strip_image_path = &#39;../../dumb_data/perfect_strip.png&#39;
  44. angle = 90
  45. img = Image.open(strip_image_path)
  46. rot_img = img.rotate(angle, expand=True)
  47. width,height = img.size
  48. rot_width,rot_height = rot_img.size
  49. original_x, original_y = 500, 100
  50. rotated_x, rotated_y = rotate_pixel(original_x,original_y,-angle,rotated_img=rot_img) # rotation_coordinates(img, +angle, original_x, original_y)
  51. reverse_x, reverse_y = rotate_pixel(rotated_x,rotated_y,angle,rotated_img=img) #rotation_coordinates(img, -angle, rotated_x, rotated_y)
  52. # Define the image dimensions
  53. image_width, image_height = img.size
  54. print()
  55. ic(img.size)
  56. ic(rot_img.size)
  57. ic(original_x, original_y)
  58. ic(rotated_x, rotated_y)
  59. ic(reverse_x, reverse_y)
  60. draw_circle(img, original_x, original_y,title=&quot;original&quot;)
  61. draw_circle(rot_img, rotated_x, rotated_y,title=&quot;rotated&quot;)

Any solutions which achieve the general above mentioned goal are welcome

答案1

得分: 1

这是一个使用PIL(Python Imaging Library)的解决方案,带有类型提示和文档字符串。

图像被上传并旋转,但不进行裁剪,使用PIL库本身提供的方法。然后,只需在平面上应用简单的旋转。

如果这不是您要找的,请让我知道,我将尝试改进它。

  1. from pathlib import Path
  2. from typing import Tuple
  3. import numpy as np
  4. from PIL import Image
  5. from matplotlib import pyplot as plt
  6. def main(image_path_: Path, angle: float, pixel_coordinates: Tuple[int, int]) -> None:
  7. """
  8. 入口点。
  9. Parameters
  10. ----------
  11. image_path_ : Path
  12. angle : float
  13. pixel_coordinates : Tuple[int, int]
  14. """
  15. image = Image.open(image_path_)
  16. rotated_image = rotate_image(image, angle)
  17. transformed_pixel_coordinates = transform_pixel_coordinates(
  18. pixel_coordinates, angle, image, rotated_image
  19. )
  20. draw_images(image, rotated_image, pixel_coordinates, transformed_pixel_coordinates)
  21. def rotate_image(image: Image, angle: float) -> Image:
  22. """
  23. 旋转图像。
  24. Parameters
  25. ----------
  26. image : Image
  27. angle : float
  28. Returns
  29. -------
  30. Image
  31. """
  32. return image.rotate(angle, expand=True)
  33. def transform_pixel_coordinates(
  34. pixel_coordinates: Tuple[int, int],
  35. angle: float,
  36. image: Image,
  37. rotated_image: Image,
  38. ) -> Tuple[int, int]:
  39. """
  40. 转换像素坐标。
  41. Parameters
  42. ----------
  43. pixel_coordinates : Tuple[int, int]
  44. angle : float
  45. image : Image
  46. rotated_image : Image
  47. Returns
  48. -------
  49. Tuple[int, int]
  50. """
  51. x, y = pixel_coordinates
  52. center = (image.width / 2, image.height / 2)
  53. transformed_center = (rotated_image.width / 2, rotated_image.height / 2)
  54. angle_radians = -np.deg2rad(angle)
  55. x -= center[0]
  56. y -= center[1]
  57. x_transformed = x * np.cos(angle_radians) - y * np.sin(angle_radians)
  58. y_transformed = x * np.sin(angle_radians) + y * np.cos(angle_radians)
  59. x_transformed += transformed_center[0]
  60. y_transformed += transformed_center[1]
  61. return int(x_transformed), int(y_transformed)
  62. def draw_images(
  63. image, rotated_image, pixel_coordinates, transformed_pixel_coordinates
  64. ) -> None:
  65. """
  66. 绘制图像和像素。
  67. Parameters
  68. ----------
  69. image : Image
  70. rotated_image : Image
  71. pixel_coordinates : Tuple[int, int]
  72. transformed_pixel_coordinates : Tuple[int, int]
  73. """
  74. fig, axes = plt.subplots(1, 2, figsize=(12, 6))
  75. axes[0].imshow(image)
  76. axes[0].scatter(*pixel_coordinates, color="y", s=50)
  77. axes[0].set_title("Image")
  78. axes[0].axis("off")
  79. axes[1].imshow(rotated_image)
  80. axes[1].scatter(*transformed_pixel_coordinates, color="y", s=50)
  81. axes[1].set_title("Rotated Image")
  82. axes[1].axis("off")
  83. plt.show()
  84. if __name__ == "__main__":
  85. image_path = Path("test.png")
  86. angle = 30
  87. pixel_coordinates = (100, 200)
  88. main(image_path, angle, pixel_coordinates)

在Python中旋转图像,并获取在旋转后的图像中的像素的原始位置。

英文:

Here is a solution using PIL with type hints and docstrings.

The image is uploaded and rotated, but without cropping, using the method provided by the PIL library itself. Then, it's just about applying a simple rotation on the plane.

If it's not what you are looking for, I will try to make it better.

  1. from pathlib import Path
  2. from typing import Tuple
  3. import numpy as np
  4. from PIL import Image
  5. from matplotlib import pyplot as plt
  6. def main(image_path_: Path, angle: float, pixel_coordinates: Tuple[int, int]) -&gt; None:
  7. &quot;&quot;&quot;
  8. Entry point.
  9. Parameters
  10. ----------
  11. image_path_ : Path
  12. angle : float
  13. pixel_coordinates : Tuple[int, int]
  14. &quot;&quot;&quot;
  15. image = Image.open(image_path_)
  16. rotated_image = rotate_image(image, angle_)
  17. transformed_pixel_coordinates = transform_pixel_coordinates(
  18. pixel_coordinates, angle, image, rotated_image
  19. )
  20. draw_images(image, rotated_image, pixel_coordinates_, transformed_pixel_coordinates)
  21. def rotate_image(image: Image, angle: float) -&gt; Image:
  22. &quot;&quot;&quot;
  23. Rotate image.
  24. Parameters
  25. ----------
  26. image : Image
  27. angle : float
  28. Returns
  29. -------
  30. Image
  31. &quot;&quot;&quot;
  32. return image.rotate(angle, expand=True)
  33. def transform_pixel_coordinates(
  34. pixel_coordinates: Tuple[int, int],
  35. angle: float,
  36. image: Image,
  37. rotated_image: Image,
  38. ) -&gt; Tuple[int, int]:
  39. &quot;&quot;&quot;
  40. Transform pixel coordinates.
  41. Parameters
  42. ----------
  43. pixel_coordinates : Tuple[int, int]
  44. angle : float
  45. image : Image
  46. rotated_image : Image
  47. Returns
  48. -------
  49. Tuple[int, int]
  50. &quot;&quot;&quot;
  51. x, y = pixel_coordinates
  52. center = (image.width / 2, image.height / 2)
  53. transformed_center = (rotated_image.width / 2, rotated_image.height / 2)
  54. angle_radians = -np.deg2rad(angle)
  55. x -= center[0]
  56. y -= center[1]
  57. x_transformed = x * np.cos(angle_radians) - y * np.sin(angle_radians)
  58. y_transformed = x * np.sin(angle_radians) + y * np.cos(angle_radians)
  59. x_transformed += transformed_center[0]
  60. y_transformed += transformed_center[1]
  61. return int(x_transformed), int(y_transformed)
  62. def draw_images(
  63. image, rotated_image, pixel_coordinates, transformed_pixel_coordinates
  64. ) -&gt; None:
  65. &quot;&quot;&quot;
  66. Draw images and pixel.
  67. Parameters
  68. ----------
  69. image : Image
  70. rotated_image : Image
  71. pixel_coordinates : Tuple[int, int]
  72. transformed_pixel_coordinates : Tuple[int, int]
  73. &quot;&quot;&quot;
  74. fig, axes = plt.subplots(1, 2, figsize=(12, 6))
  75. axes[0].imshow(image)
  76. axes[0].scatter(*pixel_coordinates, color=&quot;y&quot;, s=50)
  77. axes[0].set_title(&quot;Image&quot;)
  78. axes[0].axis(&quot;off&quot;)
  79. axes[1].imshow(rotated_image)
  80. axes[1].scatter(*transformed_pixel_coordinates, color=&quot;y&quot;, s=50)
  81. axes[1].set_title(&quot;Rotated Image&quot;)
  82. axes[1].axis(&quot;off&quot;)
  83. plt.show()
  84. if __name__ == &quot;__main__&quot;:
  85. image_path = Path(&quot;test.png&quot;)
  86. angle_ = 30
  87. pixel_coordinates_ = (100, 200)
  88. main(image_path, angle_, pixel_coordinates_)

在Python中旋转图像,并获取在旋转后的图像中的像素的原始位置。

huangapple
  • 本文由 发表于 2023年7月24日 19:39:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76754112.html
匿名

发表评论

匿名网友

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

确定