【问题标题】:How to rotate an image to get not-null pixels?如何旋转图像以获得非空像素?
【发布时间】:2021-11-20 17:45:09
【问题描述】:

在我下面链接的图像中,我需要获取这个旋转矩形中的所有黄色/绿色像素并去除蓝色背景,以便矩形的轴与 x 和 y 轴对齐。

我正在使用 numpy,但不知道我应该做什么。

我在drive 中上传了数组,以防有人想使用实际数组

提前感谢您的帮助。

【问题讨论】:

  • 如果我理解正确,您不能在轴对齐的框架中显示旋转图像,因为框架只会使用图像的最小和最大 x ,y 坐标作为其轴范围。如果您希望旋转黄色/绿色像素,则可以使用旋转矩阵
  • 你会如何找到旋转的角度?
  • 对于特定类型的图像,我会将其二值化,然后使用导数找到对角线最底端的线。这条线有一个你想旋转的角度(在相反的方向)
  • @HadarSharvit 虽然至少他需要在开始时检查列/行的对齐情况,否则 OP 可能会遇到例如col0 的高度为 10,col1 的高度为 11,通过旋转或者通过截断像素来截断数据,或者通过使用抗锯齿来破坏数据,或者在边框周围仍然有一些蓝色像素。

标签: python numpy image-processing


【解决方案1】:

我使用与 user2640045 相同的图像,但方法不同。

import numpy as np
import cv2

# load and convert image to grayscale
img = cv2.imread('image.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# binarize image
threshold, binarized_img = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# find the largest contour
contours, hierarchy = cv2.findContours(binarized_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
c = max(contours, key = cv2.contourArea)

# get size of the rotated rectangle
center, size, angle = cv2.minAreaRect(c)

# get size of the image
h, w, *_ = img.shape

# create a rotation matrix and rotate the image
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated_img = cv2.warpAffine(img, M, (w, h))

# crop the image
pad_x = int((w - size[0]) / 2)
pad_y = int((h - size[1]) / 2)

cropped_img = rotated_img[pad_y : pad_y + int(size[1]), pad_x : pad_x + int(size[0]), :]

结果:

【讨论】:

  • 那是完美的@dlt_w!它也非常快。我忘了指出我的图像不完全是 RGB:前 2 个波段的值范围从 -1 到 1,因此 opencv 很难处理实际图像,而不是屏幕截图。我设法使其工作的方法是将单个波段转换为 0-255 并将其称为“灰色”。之后,一切顺利。
【解决方案2】:

我意识到 numpys 加载方法中有一个 allow_pickle=False 选项,但我对从互联网上解压/使用数据感到不舒服,所以我使用了小图像。删除坐标系和我拥有的东西后

我定义了两个辅助方法。一个到稍后旋转从另一个堆栈溢出线程获取的图像。请参阅下面的链接。一个得到一个掩码,一个指定颜色的掩码,否则为零。

import numpy as np
import matplotlib.pyplot as plt
import sympy
import cv2
import functools

color = arr[150,50]

def similar_to_boundary_color(arr, color=tuple(color)):
    mask = functools.reduce(np.logical_and, [np.isclose(arr[:,:,i], color[i]) for i in range(4)])
    return mask

#https://stackoverflow.com/a/9042907/2640045
def rotate_image(image, angle):
    image_center = tuple(np.array(image.shape[1::-1]) / 2)
    rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
    result = cv2.warpAffine(image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR)
    return result

接下来我计算旋转的角度。我通过找到宽度为 50 和 300 的最低像素来做到这一点。我选择了这些像素,因为它们离边界足够远,不会受到缺少角等的影响。

i,j = np.where(~similar_to_boundary_color(arr))

slope = (max(i[j == 50])-max(i[j == 300]))/(50-300)
angle = np.arctan(slope)
arr = rotate_image(arr, np.rad2deg(angle))
plt.imshow(arr)

.

进行裁剪的一种方法如下。您计算高度和宽度的中间值。然后你在中间取两个切片,比如在一个方向上 20 像素,直到另一个方向的中间。像素为白色/背景色的最大/最小索引是合理的切割点。

i,j = np.where(~(~similar_to_boundary_color(arr) & ~similar_to_boundary_color(arr, (0,0,0,0)))) 

imid, jmid = np.array(arr.shape)[:2]/2
imin = max(i[(i < imid) & (jmid - 10 < j) & (j < jmid + 10)])
imax = min(i[(i > imid) & (jmid - 10 < j) & (j < jmid + 10)])
jmax = min(j[(j > jmid) & (imid - 10 < i) & (i < imid + 10)])
jmin = max(j[(j < jmid) & (imid - 10 < i) & (i < imid + 10)])

arr = arr[imin:imax,jmin:jmax]
plt.imshow(arr)

结果是:

【讨论】:

  • 感谢@user2640045!这很有帮助。我设法按照您的代码到达倒数第二张图片,但没有按照您最终获得最后一张图片的方式进行操作。你是手工剪的吗?我不太担心在边框上剪掉一点图像,以免最终出现蓝色区域。您将如何自动化裁剪过程(这对于应用程序的目的很重要)?
  • @BernardReznik 好吧,我对它不是 100% 满意,但我添加了裁剪。
  • 哦,我明白了。这是做填充的好方法。我最终使用了@dlt_w 的方法,但非常感谢您的回答!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
  • 2012-06-09
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
相关资源
最近更新 更多