我意识到 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)
结果是: