目录
需求
需要对一些图片做图像处理,但是原数据图像太大了(2700x2500左右),实际的处理过程中并不需要这么高的分辨率,所以需要对数据进行预处理。
图像的读取
比较熟悉的图像读取方式有2种:
- img = cv2.imread(imgpath) opencv中处理图片的函数,需要import cv2
- img = Image.open(imgpath) PIL中处理图片的函数,需要from PIL import Image
imgpath = "D:\\xxx\\xxx\\xxx.png"
img1 = Image.open(imgpath)
print("im1的类型是",type(img1)) #<class 'PIL.PngImagePlugin.PngImageFile'>
w,h = img1.size
print("w,h",w,h) #2754 2426
img = cv2.imread(imgpath)
print("img.shape",img.shape) #(2426, 2754, 3)
print("type",type(img)) #<class 'numpy.ndarray'>
可以看到cv2.imread读取图像后返回值是numpy格式的,并且它读取的是图片的真实数据。而Image.open读取图像类型是Image对象,不是数组,且只是保持图象被读取的状态。所以如果要操作具体某个元素,比如输出某个像素点的RGB值时,需要先img = img.load()读取数据。 然后print(img[0,0]) 就可以看到(0,0)坐标像素点的RGB值。
两者区别
一个就是上面写到的,返回值及读取是否是真实数据
另一个就是,Image.open函数默认彩色图像读取通道的顺序是RGB的,而cv2.imread读取通道是BGR的。同时,如果图像格式是RGBA时,Image.open读取格式是RGBA,是四通道,cv2.imread是BGR,只有三通道。
写这篇博客主要就是因为,处理的图片数据其实是RGBA四通道的,而我需要用改变分辨率后,还只需要三通道的numpy返回值
两者相互转换
#1、Image对象 --> np.adarray
img = Image.open(imgpath)
img_array = np.array(img)
#2、np.adarry --> Image对象
img = cv2.imread(imgpath)
img_Image = Image.fromarray(np.uint8(img))
这样就可以实现两者的简单转换了。那放在我这个需求中应该怎么具体处理呢
具体需求代码
首先,明确步骤: 读取图片,改变分辨率,转换通道,输出图片
一开始,我仅考虑了改变分辨率的问题,代码如下
imgpath = "D:\\T18.png"
img1 = Image.open(imgpath) #通过Image打开,进行resize操作
print("img1的类型是",type(img1)) #<class 'PIL.PngImagePlugin.PngImageFile'>
w,h = img1.size
print("w,h",w,h) #2754 2426
img1 = img1.resize((1000,1000))
print("resize,w,h:",img1.size) #(1000,1000)
img = np.asarray(img1)
print("img的类型是", type(img)) #<class 'numpy.ndarray'>
plt.imshow(img)
plt.show()
首先,用Image读取,使用resize函数进行分辨率改变,将原本2754 2426的图片缩小到1000 1000上去,然后将Image对象转换为numpy进行展示,发现居然可以!
就在我以为已经大功告成的时候,接下去的图像处理,就出现问题了
比如就以 给图像的某一个像素点涂色 这个小功能来说,其实就是 img[i][j] = (255,0,0) ,但是出现了问题,报错为
img[up][j] = (255,0,0)
ValueError: could not broadcast input array from shape (3,) into shape (4,)
意思是,它的通道其实是四通道!还有一个通道似乎是alpha,所以它的通道顺序是RGBA!
所以需要找到它对应的通道,并重新组合
imgpath = "D:\\T18.png"
img1 = Image.open(imgpath) #通过Image打开,进行resize操作
print("img1的类型是",type(img1)) #<class 'PIL.PngImagePlugin.PngImageFile'>
w,h = img1.size
print("w,h",w,h) #2754 2426
img1 = img1.resize((1000,1000))
print("resize,w,h:",img1.size) #(1000,1000)
img = np.asarray(img1)
r,g,b,a = cv2.split(img)
img = cv2.merge([b,g,r])
print("img的类型是", type(img)) #<class 'numpy.ndarray'>
print("img.shape", img.shape) #img.shape (1000, 1000, 3)
plt.imshow(img)
plt.show()
split找到它的四个通道,分别是rgba,cv2.merge将通道重新排序,因为cv2.imread读取图片就是以BGR的顺序,所以干脆也以b,g,r的顺序组合,这样也方便后面用。
最后,整个功能需求就实现了。