如何保存PIL、skimage处理后的图像 解决save/imwrite报错问题
报错核心原因
两个输出对象的类型和保存接口的要求不匹配:
img_edge是sobel算子输出的numpy数组,值范围为[0,1]的浮点类型,不是PIL的Image实例,直接调用.save()方法必然触发属性错误;cv2.imwrite默认要求输入为0-255取值范围的uint8类型数组,传入0-1范围的浮点数组时,无法匹配对应图像格式的写入器,会抛出参数错误。canny是measure.find_contours()返回的轮廓坐标列表,列表内每个元素是单条轮廓的坐标点numpy数组,本身不是图像矩阵,既没有PIL对象的save方法,也不符合cv2.imwrite要求的数组/UMat输入类型,直接调用两个保存接口都会报错。
正确保存方案
保存img_edge边缘图
先将数组值范围从[0,1]映射到图像通用的0-255区间,转换为uint8类型后再调用对应保存接口即可。
- 用OpenCV保存:
import numpy as np # 格式转换 img_edge_uint8 = (img_edge * 255).astype(np.uint8) # 文件名必须带.png/.jpg等合法图像后缀 cv2.imwrite("sobel_edge_result.png", img_edge_uint8)
- 用PIL保存:
from PIL import Image import numpy as np img_edge_uint8 = (img_edge * 255).astype(np.uint8) # 转成PIL Image对象后再保存 pil_img = Image.fromarray(img_edge_uint8) pil_img.save("sobel_edge_result.jpg")
保存canny轮廓结果
canny存储的是轮廓坐标点,不是渲染完成的图像,根据需求选择存可视化图像或者存原始坐标数据即可。
- 存为可视化轮廓图(适配查看需求)
用matplotlib渲染后保存是最简便的方式,适配skimage轮廓的坐标格式:
import matplotlib.pyplot as plt # 创建画布绘制底图和轮廓 fig, ax = plt.subplots() ax.imshow(gray, cmap="gray") for single_contour in canny: # 注意轮廓坐标是(行,列),对应绘图的(y,x),x传列索引、y传行索引 ax.plot(single_contour[:, 1], single_contour[:, 0], linewidth=2, color="red") ax.axis("off") # 保存为无白边的图像 plt.savefig("contour_visual.png", bbox_inches="tight", pad_inches=0) plt.close()
如果需要用OpenCV绘制保存,注意转换坐标顺序:
import numpy as np h, w = gray.shape # 创建纯黑画布 canvas = np.zeros((h, w), dtype=np.uint8) for single_contour in canny: # 坐标转整数,调整顺序为cv2要求的(x,y)格式 cnt_points = single_contour[:, [1, 0]].astype(np.int32).reshape((-1, 1, 2)) cv2.polylines(canvas, [cnt_points], isClosed=True, color=255, thickness=1) cv2.imwrite("contour_opencv.png", canvas)
- 存为原始坐标数据(适配后续计算需求)
如果不需要可视化,只是留存轮廓坐标供后续代码调用,直接存为numpy序列化文件即可:
import numpy as np # 存为npy格式 np.save("contour_coords.npy", np.array(canny, dtype=object), allow_pickle=True) # 后续读取方式 # loaded_contours = np.load("contour_coords.npy", allow_pickle=True).tolist()
内容的提问来源于stack exchange,提问作者Anefu
相关产品推荐
相关产品推荐

