• PIL(Python Imaging Library)图像处理库教程


    PIL(Python Imaging Library)图像处理库教程

    • open()函数,该库根据文件的内容自动确定格式,除非确实需要,否则库不会解码或加载栅格数据。
      open()将读取文件头以确定文件格式并提取解码文件所需的模式、大小和其他属性等内容,但文件的其余部分直到稍后才会处理。
      即open()打开图像文件是一项快速操作,它与文件大小和压缩类型无关。
    • save()方法,保存文件时,名称很重要。除非指定格式,否则库将使用文件扩展名来发现要使用的文件存储格式
    • show()的标准版本不是很有效,因为它将图像保存到临时文件并调用实用程序来显示图像,依赖于已经安装的其他图片查看工具
    • convert()在不同像素表示之间转换图像,图片格式转换,B,G,R,L通道等转换 split merge 通道分离及合并
    • thumbnails创建缩略图
    • crop(), paste()剪切粘贴合并图像
    • transpose()翻转图像
    • roll()翻转 图像滚动拼接
    • 图像类包含resize()和rotate(),前者采用元组给出新大小,后者采用逆时针方向的角度(以度为单位);
    • transpose()翻转平移
    • 创建MASK imout = im.point(lambda i: expression and
      255)
    • ImageEnhance调整对比度,亮度,色彩平衡和清晰度( contrast, brightness, color
      balance and sharpness)。
    • PIL包含对图像序列(也称为动画格式)的一些基本支持。支持的序列格式包括 FLI/FLC、GIF 和一些实验格式。TIFF文件还可以包含多个帧;
      当打开序列文件时,PIL会自动加载序列中的第一帧。可以使用seek和tell不同帧之间移动;
      读取动图并遍历每一帧展示,seek,tell或者ImageSequence.Iterator(im)
    • 图像文本图形等绘制
    • draft()方法操作已打开但尚未加载的图像,使其尽可能接近给定的模式和大小。这是通过重新配置图像解码器来完成的
      draft()草稿模式下的阅读仅适用于 JPEG 和 MPO 文件
      draft()生成的图像可能与请求的模式和大小不完全匹配。若要确保图像不大于给定大小,请改用缩略图thumbnails方法;

    源码

    # Python Image Library(PIL)库学习记录 
    # pil.py
    
    import os
    import sys
    from pathlib import Path
    from urllib.request import urlopen
    
    from PIL import Image, TarIO
    from PIL import ImageEnhance  # 图像增强:调整对比度,亮度,色彩平衡和清晰度(像素级操作)
    from PIL import ImageFilter  # 图像过滤:高斯平滑,边缘
    from PIL import ImageSequence  # 图像读取保存展示,gif等读取,一帧一帧,帧跳转获取等;
    from PIL import PSDraw  # 图像文本图形图像等绘制
    
    
    # open()函数,该库根据文件的内容自动确定格式
    # save()方法,保存文件时,名称很重要。除非指定格式,否则库将使用文件扩展名来发现要使用的文件存储格式
    # 读取保存图片,获取图片属性
    def readSave():
        # 从文件加载图片
        im = Image.open("ml.jpg")
    
        # 以上下文对象方式读取
        # with Image.open("hopper.ppm") as im:
        #     im.show()
    
        # 从打开的文件读取
        # with open(’ml.jpg‘, "rb") as fp:
        #     im = Image.open(fp)
    
        # 从二进制文件读取
        # im = Image.open(io.BytesIO(buffer))
    
        # 从url读取
        url = "https://python-pillow.org/images/pillow-logo.png"
        img = Image.open(urlopen(url))
    
        # 或者使用ContainerIO or TarIO从压缩文件/大文件读取
        fp = TarIO.TarIO("Tests/images/hopper.tar", "hopper.jpg")
        im = Image.open(fp)
    
        # 像素类型和深度。常见的模式是灰度图像的“L”(亮度),真彩色图像的“RGB”和印前图像的“CMYK”。
        print(im.format, im.size, im.mode)
        # JPEG (512, 512) RGB
    
        # show()的标准版本不是很有效,因为它将图像保存到临时文件并调用实用程序来显示图像,依赖于已经安装的其他图片查看工具
        im.show()
    
    
    # 图片格式转换
    def convert(infile):
        # for infile in sys.argv[1:]:
        f, e = os.path.splitext(infile)
        outfile = f + ".jpg"
        if infile != outfile:
            try:
                with Image.open(infile) as im:
                    im.save(outfile)
            except OSError:
                print("cannot convert", infile)
    
    
    # 创建JPEG缩略图(thumbnails)
    def thumbnails(infile):
        size = (128, 128)
    
        # for infile in sys.argv[1:]:
        outfile = os.path.splitext(infile)[0] + ".thumbnail"
        if infile != outfile:
            try:
                # 请务必注意,除非确实需要,否则库不会解码或加载栅格数据。
                # 打开文件时,将读取文件头以确定文件格式并提取解码文件所需的模式、大小和其他属性等内容,但文件的其余部分直到稍后才会处理。
                # 即open()打开图像文件是一项快速操作,它与文件大小和压缩类型无关。
                with Image.open(infile) as im:
                    im.thumbnail(size)
                    # im.thumbnail((200, 200), Image.ANTIALIAS)
                    print("thumbnail =", im.mode, im.size)
                    im.save(outfile, "JPEG")
                    im.show()
            except OSError:
                print("cannot create thumbnail for", infile)
    
    
    # 下面是一个简单的脚本,用于快速识别一组图像文件:
    def identify():
        print(sys.argv)
        print(sys.argv[1:])
        for infile in sys.argv[1:]:
            try:
                with Image.open(infile) as im:
                    print(infile, im.format, f"{im.size}x{im.mode}")
            except OSError:
                pass
    
    
    # 剪切、粘贴、合并图像
    def crop(infile):
        im = Image.open(infile)
        # 该区域由 4 元组定义,其中坐标为(左、上、右、下)。Python 成像库使用左上角为 (0, 0) 的坐标系。
        # 坐标是指像素之间的位置,因此上例中的区域正好为 300x300 像素
        box = (100, 100, 400, 400)
        # 提取子矩形
        region = im.crop(box)
        region.show()
    
        # 将区域旋转180°,再粘贴回去
        region = region.transpose(Image.ROTATE_180)
        im.paste(region, box)
    
        im.show()
    
    
    def roll(im, delta):
        """横向滚动图像"""
        xsize, ysize = im.size
        print(xsize, ysize)
    
        delta = delta % xsize
        print(delta)
        if delta == 0:
            return im
    
        part1 = im.crop((0, 0, delta, ysize))
        part2 = im.crop((delta, 0, xsize, ysize))
        im.paste(part1, (xsize - delta, 0, xsize, ysize))
        im.paste(part2, (0, 0, xsize - delta, ysize))
        im.show()
    
    
    # 合并图像
    def merge(im1, im2):
        w = im1.size[0] + im2.size[0]
        h = max(im1.size[1], im2.size[1])
        # paste方法还可以将透明度掩码作为可选参数。值255表示粘贴的图像在该位置是不透明的(即,粘贴的图像应按原样使用)。
        # 值 0 表示粘贴的图像是完全透明的。介于两者之间的值表示不同的透明度级别。
        # 例如,粘贴 RGBA图像并将其用作蒙版将粘贴图像的不透明部分,但不粘贴其透明背景。
        im = Image.new("RGBA", (w, h))
    
        im.paste(im1)
        im.paste(im2, (im1.size[0], 0))
    
        im.show()
    
    
    # 分离和合并通道
    def mergeSplit(im):
        # 单通道图像的话,split方法只返回自身
        r, g, b = im.split()
        r.show()
        g.show()
        b.show()
    
        # Image是rgb格式
        # im = Image.merge("BGR", (b, g, r))
        # im.show()
    
        im = Image.merge("RGB", (r, g, b))
        im.show()
    
    
    # 几何变换
    # 图像类包含resize()和rotate()的方法。前者采用元组给出新大小,后者采用逆时针方向的角度(以度为单位)。
    # transpose()翻转平移
    # convert()在不同像素表示之间转换图像。
    def geometricalTransform(im):
        out = im.resize((128, 128))
        out.show()
    
        # out = im.rotate(45)  # degrees counter-clockwise
        # out.show()
    
        # out = im.transpose(Image.FLIP_LEFT_RIGHT)
        # out.show()
        # out = im.transpose(Image.FLIP_TOP_BOTTOM)
        # out.show()
        # out = im.transpose(Image.ROTATE_90)
        # out.show()
        # out = im.transpose(Image.ROTATE_180)
        # out.show()
        out = im.transpose(Image.ROTATE_270)
        out.show()
    
        l = im.convert("L")
        l.show()
    
    
    # 图像增强模式 PIL提供了许多可用于增强图像的方法和模块。
    # 图像筛选器模块包含许多预定义的增强过滤器,可与 filter()方法一起使用。
    def fil(im):
        out = im.filter(ImageFilter.DETAIL)
        out.show()
    
        # multiply each pixel by 1.2
        out = im.point(lambda i: i * 1.2)
        out.show()
    
    
    # 创建MASK
    # imout = im.point(lambda i: expression and 255)
    def createMask(im):
        # 分离图像通道
        source = im.split()
    
        R, G, B = 0, 1, 2
    
        # 选择红色区域 < 100
        mask = source[R].point(lambda i: i < 100 and 255)
        mask.show()
    
        # 处理绿色通道 * 0.7
        out = source[G].point(lambda i: i * 0.7)
        out.show()
    
        # 粘贴绿色通道到 红色<100的模板
        source[G].paste(out, None, mask)
    
        # 构建新的图像
        im = Image.merge(im.mode, source)
        im.show()
    
    
    # 对于更高级的图像增强,可以使用“ImageEnhance”模块中的类。从图像创建后,可以使用增强对象快速尝试不同的设置。
    # 可以通过这种方式调整对比度,亮度,色彩平衡和清晰度( contrast, brightness, color balance and sharpness)。
    def enhancement(im):
        enh = ImageEnhance.Contrast(im)
        enh.enhance(1.3).show("30% more contrast")
    
    
    # PIL包含对图像序列(也称为动画格式)的一些基本支持。支持的序列格式包括 FLI/FLC、GIF 和一些实验格式。TIFF文件还可以包含多个帧。
    # 当打开序列文件时,PIL会自动加载序列中的第一帧。可以使用seek和tell不同帧之间移动:
    def imageSequence(infile):
        with Image.open(infile) as im:
            im.seek(1)  # skip to the second frame
        # im.show()
    
        try:
            while 1:
                print('--: ', im.tell() + 1)
                im.seek(im.tell() + 1)
                im.show()
                # do something to im
        except EOFError:
            pass  # end of sequence
    
    
    # 读取动图并遍历每一帧展示
    def readGif(infile):
        im = Image.open(infile)
    
        for i, frame in enumerate(ImageSequence.Iterator(im)):
            print(i)
            frame.show()
    
    
    # 图像文本图形等绘制
    def drawPostScript(infile):
        with Image.open(infile) as im:
            title = "hopper"
            box = (1 * 72, 2 * 72, 7 * 72, 10 * 72)  # in points
    
            ps = PSDraw.PSDraw()  # default is sys.stdout or sys.stdout.buffer
            ps.begin_document(title)
    
            # draw the image (75 dpi)
            ps.image(box, im, 75)
            ps.rectangle(box)
    
            # draw title
            ps.setfont("HelveticaNarrow-Bold", 36)
            ps.text((3 * 72, 4 * 72), title)
    
            ps.end_document()
            im.show()
        im.show()
    
    
    def compress_image(source_path, dest_path):
        with Image.open(source_path) as img:
            if img.mode != "RGB":
                img = img.convert("RGB")
            img.save(dest_path, "JPEG", optimize=True, quality=80)
    
    
    def batchProcess():
        paths = Path(".").glob("*.png")
        for path in paths:
            compress_image(path, path.stem + ".jpg")
    
    
    # draft()方法操作已打开但尚未加载的图像,使其尽可能接近给定的模式和大小。这是通过重新配置图像解码器来完成的
    # 草稿模式下的阅读仅适用于 JPEG 和 MPO 文件
    # 请注意: draft()生成的图像可能与请求的模式和大小不完全匹配。若要确保图像不大于给定大小,请改用缩略图thumbnails方法。
    def draft(file):
        print(file)
        with Image.open(file) as im:
            print("original =", im.mode, im.size)
    
        im.draft("L", (100, 100))
        print("draft =", im.mode, im.size)
    
    
    infile = '0_viz_float64.png'
    infile = 'ml.jpg'
    # infile = 'ym.jpeg'
    # infile = 'n_100.jpg'
    # infile = 'rb.jpeg'
    im = Image.open(infile)
    im2 = Image.open('ml.jpg')
    convert(infile)
    thumbnails(infile)
    identify()
    crop(infile)
    roll(im, 540)
    merge(im, im2)
    mergeSplit(im)
    geometricalTransform(im)
    fil(im)
    createMask(im)
    enhancement(im)
    gif = 'detect_bright_spots.gif'
    imageSequence(gif)
    readGif(gif)
    drawPostScript(infile)
    # batchProcess()
    draft(infile)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325

    参考

  • 相关阅读:
    excel功能区(ribbonx)编程笔记--3 editbox与状态按钮togglebutton控件
    自助点餐系统微信小程序,支持外卖、到店等
    git你学“废”了吗?——git撤销操作指令详解
    java毕业生设计疫情防控医用品管理计算机源码+系统+mysql+调试部署+lw
    【Java进阶】多线程(一)
    MyBatis-Plus快速开发
    报错:Unknown at rule @apply
    Spring MVC 的使用
    上海数字经济 “十四五” | 原生信仰者听见的历史潮流轰鸣声
    Spring之环境变量配置
  • 原文地址:https://blog.csdn.net/qq_40985985/article/details/127512692