Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏

20.7. PIL(Python Imaging Library)Python 图像处理库

20.7.1. 安装

		
pip install pillow		
		
		

20.7.2. 缩放图像与尺寸修改

自定义宽度和高度,会出现拉伸

		
image = image.resize((w, h))		
		
		

放大图像会出现画质损失,设置图像差值可以提高画质

		
image = image.resize((w, h), Image.ANTIALIAS)		
		
		

20.7.2.1. 图像插值

		
from PIL import Image
 
img = Image.open('netkiller.jpg')
 
width, height = img.size
 
# 默认模式是NEARESET(最近邻插值)
img_NEARESET = img.resize((width//2, height//2))  
# BILINEAR 2x2区域的双线性插值
img_BILINEAR = img.resize((width//2, height//2), Image.BILINEAR)
# BICUBIC 4x4区域的双三次插值 
img_BICUBIC = img.resize((width//2, height//2), Image.BICUBIC)  
# ANTIALIAS 高质量下采样滤波
img_ANTIALIAS = img.resize((width//2, height//2), Image.ANTIALIAS)  

		
			

20.7.2.2. 基于长边放大

			
width = 800
height = 600
print(width,height)

w = 400
ratio = width / w
print(ratio)

width = w
height = height / ratio
print(width,height)			
			
			

self.args.imgsz 是希望修改的长边

			
from PIL import Image
# 加载图像
image = Image.open('path_to_your_image.jpg')
# 计算缩放因子
width, height = image.size
# print(width, height)
if max(width,height)> self.args.imgsz:
    if width > height :
        ratio = width / self.args.imgsz
        width = self.args.imgsz
        height = int(height / ratio)
    else:
        ratio = height / self.args.imgsz
        width = int(width / ratio)
        height = self.args.imgsz

    # print(ratio)
    # print(width, height)

    image.resize((width, height))

			
			

20.7.2.3. 解决 resize 后图片自动翻转问题

image = ImageOps.exif_transpose(image)

			
    def resize(self,image):
        # from PIL import Image
        # 加载图像
        # image = Image.open('path_to_your_image.jpg')
        # 计算缩放因子
        width, height = image.size
        # print(width, height)
        if max(width,height)> self.args.imgsz:
            if width > height :
                ratio = width / self.args.imgsz
                width = self.args.imgsz
                height = int(height / ratio)
            else:
                ratio = height / self.args.imgsz
                width = int(width / ratio)
                height = self.args.imgsz

            # print(ratio)
            # print(width, height)
            image = image.resize((width, height))
            image = ImageOps.exif_transpose(image)
            return image
        return image			
			
			

20.7.3. 叠加图像

		
from PIL import Image

a = Image.new('RGB', (300, 300), (255, 0, 0))  # 生成一张300*300的红色图片
b = Image.new('RGB', (200, 200), (0, 255, 0))  # 生成一张200*200的绿色图片
c = Image.new('RGB', (100, 100), (0, 0, 255))  # 生成一张200*200的红色图片
b.paste(c, (50, 50)) # 将c贴到b的坐标为(50,50)的位置
a.paste(b, (50, 50)) # 将b贴到a的坐标为(50,50)的位置
a.show() # 显示最终实现三个图像叠加效果		
		
		

超出范围部分会被裁切掉

		
from PIL import Image

a = Image.new('RGB', (300, 300), (255, 0, 0))  # 生成一张300*300的红色图片
b = Image.new('RGB', (100, 600), (0, 255, 0))  # 生成一张100*600的绿色图片
a.paste(b, (100, 150))  # 将b贴到a的坐标为(100,150)的位置
a.show()  # 显示效果表明,超出部分会被裁切掉
		
		

负坐标测试,同样也会被裁剪

		
from PIL import Image

a = Image.new('RGB', (200, 200), (255, 0, 0))  # 生成一张200*200的红色图片
b = Image.new('RGB', (150, 150), (0, 255, 0))  # 生成一张150*150的绿色图片
a.paste(b, (-50, -50))  # 将b贴到a的坐标为(-50,-50)的位置
a.show()		
		
		

20.7.3.1. 画布调整

		
from PIL import Image
 
img = Image.open('netkiller.png')
 
width, height = img.size
channel_mode = img.mode
 
img_full = Image.new(channel_mode, (width*2, height))
img_part = Image.new(channel_mode, (width+100, height))
 
# 图像水平扩展整个图像
img_full.paste(img, (0, 0, width, height))
img_full.paste(img, (width, 0, width*2, height))
 
# left, top, width, height
box = (width-100, 0, width, height)
region = img.crop(box)
 
# 图像水平右侧扩展一个ROI
img_part.paste(img, (0, 0, width, height))
img_part.paste(region, (width, 0, width+100, height))
img_part.show()
img_full.show()
		
		
			

20.7.4. 图像旋转

		
image = image.rotate(90)		
		
		
	
import PIL.Image as img
import os
 
# 图片地址
imgfile = 'Neo.jpg'  

# 用PIL打开一个图片
im = img.open(imgfile)  

# 剪切图片的位置,格式为:xmin ymin xmax ymax
box = (50, 50, 200, 50)

# 对im进行裁剪
new = im.crop(box)  

# 进行向左旋转20度 向右为负数
new = ng.rotate(20)  

#保存选取
new.save('copy.jpg')

# 粘贴选取
im.paste(ng, (150, 150)) 
#保存
im.save('new.jpg')
	
		

20.7.5. 获取图片信息

		
from PIL import Image
import numpy as np
 
img = Image.open('netkiller.jpg')
 
# 宽度,高度
width, height = img.size
# 通道
channel_mode = img.mode
# 平均值
mean_value = np.mean(img)
 
print(width)
print(height)
print(channel_mode)
print(mean_value)
		
		

20.7.6. 创建空图像

		
from PIL import Image
 
width = 200
height = 100
 
img_white = Image.new('RGB', (width,height), (255,255,255))
img_black = Image.new('RGB', (width,height), (0,0,0))
img_L = Image.new('L', (width, height), (255))
 
img_white.show()
img_black.show()
img_L.show()
		
		
		

20.7.7. 裁剪

		
from PIL import Image
 
img = Image.open('netkiller.jpg') 
width, height = img.size
 
# 前两个坐标点是左上角坐标,后两个坐标点是右下角坐标(width,height)
box = (100, 100, 600, 800)
 
region = img.crop(box) 
region.save('neo.jpg')		
		
		

20.7.8. 彩色转灰度

		
from PIL import Image
 
img = Image.open('netkiller.jpg')
imgGrey = img.convert('L')
 
img.show()
imgGrey.show()
 
img.save('neo.jpg')
imgGrey.save('gray.jpg')
		
		
		

20.7.9. RGB 通道操作

		
from PIL import Image
 
img = Image.open('netkiller.jpg')
 
# 分离通道
R, G, B = img.split()
 
R.show)
G.show()
B.show()
 
# 合并通道
img_RGB = Image.merge('RGB', (R, G, B))
img_BGR = Image.merge('RGB', (B, G, R))

# 显示图像
img_RGB.show()
img_BGR.show()
		
		
		

20.7.10. 像素操作

		
from PIL import Image
 
img = Image.open('netkiller.jpg')
 
width, height = img.size
 
# 获取指定坐标位置像素值
pixel_value = img.getpixel((width/2, height/2))
print(pixel_value)
 
# 使用load方法获取指定坐标位置像素值
pim = img.load()
pixel_value1 = pim[width/2, height/2]
print(pixel_value1)
 
# 设置指定坐标位置像素的值
pim[width/2, height/2] = (0, 0, 0)
 
# 使用putpixel方法设置指定坐标位置像素的值
img.putpixel((w//2, h//2), (255,255,255))
 
# 设置指定区域像素的值
for w in range(int(width/2) - 50, int(width/2) + 50):
    for h in range(int(height/2) - 50, int(height/2) + 50):
        pim[w, h] = (255, 0, 0)
        # img.putpixel((w, h), (255,255,255))
img.show()
		
		
		

20.7.11. 图像上加文字

		
from PIL import Image, ImageDraw, ImageFont
 
img = Image.open('netkiller.jpg')
 
# 创建Draw对象:
draw = ImageDraw.Draw(img)
# 字体颜色
fillColor = (255, 0, 0)
 
text = 'https://www.netkiller.cn'
position = (100,100)
 
draw.text(position, text, fill=fillColor)
img.show()
		
		
		

20.7.12. 明暗调整

		
image = image.point(lambda p: p * 1.3)		
		
		

20.7.13. PIL 与 Numpy 相互转换

20.7.13.1. Image 转 numpy

		
from PIL import Image
import numpy as np
 
img = Image.open('netkiller.jpg')
 
# PIL.Image 转 numpy
array = np.array(img)  
 
# numpy转 PIL.Image
img1 = Image.fromarray(array)  
img1 = Image.fromarray(array.astype('uint8'))
img1.save('from_array.jpg')
		
			
		
from PIL import Image  
import numpy as np
im = Image.open("netkiller.jpg")
im.show() 
img = np.array(im)      # image类 转 numpy
img = img[:,:,0]        #第1通道
im=Image.fromarray(img) # numpy 转 image类
im.show() 
		
		
			

20.7.13.2. Numpy 转换为 PIL Image

		
from PIL import Image
PIL_img = Image.fromarray(array)
		
			

20.7.14. 比较两张图片

	
from PIL import Image
from PIL import ImageChops 
def compare_images(one, two, diff):
  image_one = Image.open(one)
  image_two = Image.open(two)
  try: 
    diff = ImageChops.difference(image_one, image_two)
    if diff.getbbox() is None:
      print("【+】We are the same!")
    else:
      diff.save(diff)
  except ValueError as e:
    text = ("Pastes another image into this image."
        "The box argument is either a 2-tuple giving the upper left corner, a 4-tuple defining the left, upper, "
        "right, and lower pixel coordinate, or None (same as (0, 0)). If a 4-tuple is given, the size of the pasted "
        "image must match the size of the region.")
    print("【{0}】{1}".format(e,text))
if __name__ == '__main__':
  compare_images('1.png', '2.png', '我们不一样.png')