手写数字图像平移至质心时缩小的问题排查与解决
手写数字图像平移至质心时图像缩小的问题排查
我尝试将手写数字图像平移至其像素质心,同时保留图像尺寸并将空白区域填充为白色,为此编写了如下函数:
import numpy as np def shift(image : np.ndarray, x : int = 0, y : int = 0, output_shape : tuple = (28, 28), fill_value : float = 255.0, dtype : str = "float32"): image_shape = image.shape[:2] res = image col = np.array([[fill_value]]*image_shape[0]) row = np.array([fill_value]*image_shape[1]) if x > 0: for i in range(x): res = np.hstack((col, res)) res = np.delete(res, len(res[0]) - 1 - i, 1) elif x < 0: for i in range(np.abs(x)): res = np.hstack((res, col)) res = np.delete(res, i, 1) if y > 0: for i in range(y): res = np.vstack((row, res)) res = np.delete(res, len(res) - 1 - i, 0) elif y < 0: for i in range(np.abs(y)): res = np.vstack((res, row)) res = np.delete(res, i, 0) return res.reshape(output_shape).astype(dtype)
但运行后发现图像在平移的同时被缩小,测试代码如下:
from keras.util import load_img, img_to_array import scipy.ndimage as ndi import matplotlib.pyplot as plt fig, ax = plt.subplots(2,1) ax = ax.ravel() img = load_img("7.png", color_mode="grayscale") img = img_to_array(img).reshape(28, 28).astype("float32") x, y = ndi.center_of_mass(img) ax[0].imshow(img, cmap="gray") ax[0].plot(x, y, "ro") new_img = shift(img, -int(x), int(y)) ax[1].imshow(new_img, cmap="gray") ax[1].plot(x, y, "ro") plt.show()
错误效果:图像被缩小,数字出现变形,不符合保留原尺寸的要求。我期望的效果是保留图像形状与像素值,数字平移至质心位置,空白区域填充为白色。
我也曾尝试使用cv2.warpAffine结合skimage.transform.resize,但会留下黑色背景且分辨率较差。
更新1:使用NumPy数组切片修复问题
我通过移除np.delete并改用NumPy数组切片解决了问题:
def shift(image : np.ndarray, x : int = 0, y : int = 0, output_shape : tuple = (28, 28), fill_value : float = 255.0, dtype : str = "float32"): image_shape = image.shape[:2] res = image col = np.array([[fill_value]]*image_shape[0]) row = np.array([fill_value]*image_shape[1]) if x > 0: for _ in range(x): res = np.hstack((col, res)) res = res[:, :-1] elif x < 0: for _ in range(np.abs(x)): res = np.hstack((res, col)) res = res[:, 1:] if y > 0: for _ in range(y): res = np.vstack((row, res)) res = res[:-1, :] elif y < 0: for _ in range(np.abs(y)): res = np.vstack((res, row)) res = res[1:, :] return res.reshape(output_shape).astype(dtype)
修复后效果:图像尺寸保持28×28不变,数字成功平移至质心位置,空白区域填充为白色,符合预期。不过我当时不确定np.delete为何会导致图像缩小。
更新2:np.delete本身无问题,是索引错误
后来发现我搞错了,np.delete并没有问题!错误原因是之前的删除索引计算错误,修正索引后代码同样可以正常运行:
def shift(image : np.ndarray, x : int = 0, y : int = 0, output_shape : tuple = (28, 28), fill_value : float = 255.0, dtype : str = "float32"): image_shape = image.shape[:2] res = image col = np.array([[fill_value]]*image_shape[0]) row = np.array([fill_value]*image_shape[1]) if x > 0: for _ in range(x): res = np.hstack((col, res)) res = np.delete(res, len(res[0]) - 1, 1) elif x < 0: for _ in range(np.abs(x)): res = np.hstack((res, col)) res = np.delete(res, 0, 1) if y > 0: for _ in range(y): res = np.vstack((row, res)) res = np.delete(res, len(res) - 1, 0) elif y < 0: for _ in range(np.abs(y)): res = np.vstack((res, row)) res = np.delete(res, 0, 0) return res.reshape(output_shape).astype(dtype)
内容的提问来源于stack exchange,提问作者Leah
相关产品推荐
相关产品推荐

