• PIL:处理图像的好模块


    介绍

    PIL是一个专门用来处理图像的模块,可以对图象进行各种各样的变换
    

    打开一张图片

    from PIL import Image
    
    # 调用Image下的open方法,即可打开一张图片
    # 得到的im便是图片的字节流
    # 我们便可以对im进行操作
    im = Image.open("古明地觉.jpg")
    

    查看图片的相关信息

    • 显示图片

      im.show()
      

    • 获取图片的信息

      print(im.format)  # JPEG
      
    • 获取大小

      print(im.size)  # (960, 626)
      """
      关于图片的大小,我要说两句
      
      首先图片的结构是一个三维数组,第一维表示行,第二维表示列,第三位表示rgb或者灰度值
      我们平常说一张图片是1920*1080,指的是这张图片每一行有1920个像素,每一列有1080个像素,想成一个长方形的话,就是长为1920,宽为1080
      每一个像素点,是一个rgb或者灰度值,所有的像素组合,成为一张图片
      
      1920 * 1080相当于是有1080行,1920列
      一般我们对数组进行操作时,比如numpy,通过指定在哪一行、以及哪一列来获取对应的元素。都是先确定行,然后再确定列
      
      比如对于这样一张1920*1080的图片,假设转为了一个numpy里面的数组。我如果要获取图片最右下角的那一个点的像素值的话,我要怎么获取呢?
      是arr[1080, 1920],还是[1920, 1080]呢?
      答案显然是前者,因为数组会先确定行,然后再确定列
      
      1920*1080表示有1080行,1920列,所以是arr[1080, 1920]。
      如果是arr[1920, 1080]的话,显然长度越界了
      
      这里的图片size是(960, 626),表示图片的长是960个像素,宽626个像素。对应数组则是,626行,960列
      """
      
    • 查看图片的直方图

      print(im.histogram())
      """
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 2, 4, 5, 5, 5, 5, 5, 9, 15, 27, 25, 24, 
      30, 30, 47, 67, 78, 96, 130, 133, 164, 182, 178, 205, 260, 281, 275, 250, 252, 238, 268, 258, 259, 265, 294, 
      286, 277, 307, 333, 316, 360, 317, 393, 376, 453, 441, 449, 467, 503, 526, 529, 642, 589, 611, 624, 729, 827, 
      975, 2728, 1204, 984, 993, 933, 1072, 769, 679, 629, 680, 655, 631, 607, 543, 562, 587, 561, 576, 577, 572, 576, 
      563, 579, 550, 547, 530, 564, 554, 530, 505, 560, 581, 581, 569, 552, 554, 572, 579, 583, 578, 555, 580, 590, 579, 
      566, 635, 604, 641, 611, 632, 673, 609, 608, 642, 630, 652, 594, 651, 685, 632, 688, 721, 696, 708, 720, 738, 682, 
      722, 742, 694, 762, 753, 797, 813, 777, 814, 1039, 1134, 1336, 1149, 1395, 1469, 1252, 1276, 1190, 1114, 1234, 1178, 
      1249, 1200, 1188, 1231, 1305, 1177, 1234, 1336, 1436, 1481, 1444, 1470, 1445, 1548, 1440, 1480, 1362, 1492, 1482, 
      1487, 1458, 1503, 1493, 1591, 1380, 1417, 1547, 1549, 1532, 1480, 1629, 1685, 1650, 1576, 1693, 1736, 1849, 2003, 
      2013, 2240, 2443, 2911, 4315, 3522, 17555, 3966, 2752, 2639, 2498, 2492, 2525, 2649, 2691, 2686, 3173, 3578, 3950, 
      3769, 3993, 4172, 4318, 4135, 4503, 4561, 4732, 5195, 5465, 5763, 6722, 8012, 7917, 9095, 9090, 9263, 10565, 17944, 
      15564, 33561, 14438, 18056, 14119, 10557, 8824, 8699, 11656, 24911, 102089, 37, 10, 16, 17, 20, 29, 39, 30, 55, 53, 
      69, 84, 97, 95, 129, 156, 184, 225, 251, 310, 336, 390, 392, 441, 496, 543, 611, 678, 634, 517, 556, 526, 492, 520, 
      571, 561, 618, 554, 582, 603, 609, 591, 627, 651, 643, 709, 652, 693, 644, 679, 676, 694, 636, 663, 732, 687, 774, 
      858, 928, 1130, 2931, 1386, 1231, 1123, 1075, 1201, 931, 805, 713, 704, 691, 666, 654, 625, 624, 618, 617, 693, 612, 
      587, 583, 574, 574, 538, 525, 576, 590, 616, 585, 583, 580, 595, 625, 636, 633, 588, 647, 663, 647, 652, 666, 696, 725, 
      710, 720, 784, 795, 810, 845, 815, 864, 882, 895, 850, 810, 828, 807, 864, 794, 798, 811, 824, 773, 850, 847, 848, 861, 
      947, 980, 988, 939, 1031, 1005, 1059, 1022, 1155, 1159, 1167, 1240, 1293, 1282, 1212, 1293, 1295, 1402, 1351, 1430, 
      1376, 1422, 1412, 1544, 1493, 1376, 1459, 1401, 1458, 1360, 1468, 1497, 1544, 1695, 1815, 1824, 1789, 1837, 1830, 1822, 
      1993, 2035, 2089, 1977, 2045, 2068, 2208, 2347, 2436, 2372, 2407, 2331, 2644, 2881, 2796, 2746, 2870, 2757, 2658, 2650, 
      2829, 2937, 2806, 2939, 3343, 3467, 3558, 3596, 3741, 3821, 5841, 4104, 3709, 3868, 3707, 4067, 4130, 4181, 4412, 4429, 
      4207, 4193, 4245, 4349, 5025, 5866, 8310, 23939, 6447, 5139, 4911, 4898, 5203, 5157, 6506, 6787, 6445, 7493, 14253, 
      8702, 8904, 6328, 7212, 6623, 7041, 5137, 3894, 4669, 4247, 4305, 10851, 7108, 13967, 15077, 23766, 17083, 5750, 8382, 
      18893, 3736, 3179, 8640, 3894, 890, 511, 345, 303, 238, 373, 24, 3, 3, 6, 13, 7, 9, 14, 12, 24, 28, 28, 35, 40, 40, 53, 
      67, 75, 87, 104, 122, 134, 208, 225, 269, 286, 303, 349, 351, 391, 404, 453, 486, 524, 583, 505, 601, 544, 587, 615, 
      533, 554, 485, 522, 570, 560, 586, 579, 568, 639, 636, 622, 638, 746, 754, 948, 962, 2379, 1296, 1546, 1255, 1210, 
      1318, 913, 809, 750, 797, 707, 663, 671, 639, 616, 599, 650, 655, 643, 647, 616, 619, 657, 679, 646, 585, 686, 626, 
      630, 659, 626, 642, 603, 634, 643, 645, 589, 633, 601, 691, 627, 626, 665, 641, 656, 664, 668, 644, 615, 696, 690, 
      705, 743, 782, 813, 731, 798, 834, 817, 826, 831, 842, 881, 924, 884, 977, 996, 997, 1002, 1015, 1015, 960, 1062, 1061, 
      1019, 1028, 990, 1065, 1002, 1043, 1071, 1013, 1059, 1047, 1046, 1108, 1118, 1102, 1064, 1170, 1140, 1265, 1355, 1394, 
      1388, 1361, 1456, 1433, 1597, 1616, 1787, 1779, 1909, 1967, 1904, 2134, 2437, 2444, 2982, 2686, 2675, 2575, 2609, 2597, 
      2667, 2536, 2445, 2588, 2651, 2943, 2946, 2885, 2726, 2733, 2807, 2994, 3399, 3602, 3712, 3730, 3513, 3914, 3909, 4060, 
      4119, 4199, 4356, 4291, 4224, 4264, 4537, 4651, 4894, 5129, 5498, 5929, 6614, 9097, 7885, 8448, 8050, 8585, 9255, 12108, 
      15453, 10869, 16029, 10879, 13984, 16131, 36720, 8793, 10447, 9403, 4410, 14121, 8540, 14786, 11199, 2803, 2821, 1814, 
      1805, 1879, 1461, 1457, 1504, 1420, 1673, 1515, 1541, 1616, 1852, 2186, 2468, 5031, 7030, 15774, 2499, 2253, 1463, 922,
      738, 611, 487, 323, 417, 214, 616]
      
      """
      

    im(图片字节流)的一些操作

    • 获取某一个像素

      # 之前我们说先按照行,再按照列获取像素点。
      # 但是在im.getpixel里面是按照列和行来的,因为这样符合我们的日常思维,但是有的就不是
      # 所以有时候是按照行和列,还是列和行,容易混淆,就很烦
      # 这里则是获取长度为第850、宽为第300个像素,以元组的形式传入。我们这里是彩色图片,所以会返回一个三元组
      print(im.getpixel((850, 300)))  # (246, 214, 215)
      # 此外获取还有一种办法
      pixel = im.load()
      print(pixel[850, 300])  # (246, 214, 215)
      # 并且下面的方法会更快一些
      
    • 修改某个像素的颜色

      # 这里第一个参数是像素的位置,依旧是列和行的顺序
      # 第二个参数是rgb三元组
      for i in range(im.size[1]):
          im.putpixel((i, i), (100, 100, 100))
      
      im.show()
      # 或者
      """
      pixel = im.load()
      for i in range(im.size[1]):
          pixel[i, i] = (100, 100, 100)
      im.show()
      """
      # 下面这种方式会更快一些
      

      注意到图片上有一个斜线,就是我们对像素进行修改的结果。因此修改像素是在本地进行操作的,直接影响im,进而影响im.show()所显示的图片

      另外值得一提的是,我这里的代码省略了一部分,不是一次性执行的,而是反复执行了。为了简洁,我把如下代码省略了

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      

      因此每次执行都会重新加载图片,重新得到一个im对象

    • 图片缩放

      # 缩放为原来的1/2
      im1 = im.resize((im.size[0] // 2, im.size[1] // 2))
      im1.show()
      

      此外还有一种缩放图片的方式,im.thumbnail,这个和resize不同,resize是返回一个新的对象,thumbnail则是在原来对象的基础上进行修改,所以可以先copy一下

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      im1 = im.copy()
      # 缩放为原来的1/2
      im1.thumbnail((im.size[0] // 2, im.size[1] // 2))
      im1.show()
      
      

    • 图像翻转

      # 填入角度,按照逆时针进行翻转
      im1 = im.rotate(90)
      im1.show()
      

    • 图像的裁剪与粘贴

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      # 先获取一个矩形区域,传入矩形的左上顶点和右下顶点两个坐标
      # 这样就能定位一个矩形
      box = (120, 194, 220, 294)
      
      # 裁剪,然后旋转九十度,得到的仍是一个Image对象
      region = im.crop(box).rotate(90)
      
      # 粘贴,传入两个参数,Image对象,位置
      im.paste(region, box)
      
      # 这个不会返回新的对象,直接在本地修改
      im.show()
      

    • 图像通道的分离

      彩色图像有三个通道,可以对通道进行分离,得到三个通道分别对应的图像,此时每个图像只有一个分量。注意:分离的之后,得到的仍是Image对象

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      r, g, b = im.split()
      print(r)  # <PIL.Image.Image image mode=L size=960x626 at 0x1EB4768B048>
      print(g)  # <PIL.Image.Image image mode=L size=960x626 at 0x1EB4768BF60>
      print(b)  # <PIL.Image.Image image mode=L size=960x626 at 0x1EB47697320>
      
      r.show()
      g.show()
      b.show()
      

    • 图像的点运算

      可以实现整体变亮或者变暗的效果

      im1 = im.point(lambda x: x * 1.8)
      im1.show()
      
      im2 = im.point(lambda x: x * 0.6)
      im2.show()
      
      

    • 将图片转化为灰度图片

      im1 = im.convert("L")
      im1.show()
      
      

      这和im.split转化为单通道有点像



    图像过滤

    可以使用ImageFilter来对图像进行细节上的增强、变换等等,当然还是对im进行操作,但是参数主要是ImageFilter这个模块提供的。这个模块提供很多的过滤器,通过指定不同的过滤器参数,来对图片进行不同的变换

    from PIL import Image
    from PIL import ImageFilter
    
    im = Image.open("古明地觉.jpg")
    
    • 图像模糊

      # 图像模糊
      im1 = im.filter(ImageFilter.BLUR)
      im1.show()
      

    • 图像增强(细节突出)

      im1 = im.filter(ImageFilter.DETAIL)
      im1.show()
      
      

    • 图像边缘提取

      im1 = im.filter(ImageFilter.FIND_EDGES)
      im1.show()
      

    • 图像轮廓

      im1 = im.filter(ImageFilter.CONTOUR)
      im1.show()
      

    • 边缘增强滤波

      增强不同灰度之间的边界和轮廓

      im1 = im.filter(ImageFilter.EDGE_ENHANCE)
      im1.show()
      
      # 从名字也能看出来,作用一样,但是效果增强了
      im2 = im.filter(ImageFilter.EDGE_ENHANCE_MORE)
      im2.show()
      
      

    • 浮雕效果

      im1 = im.filter(ImageFilter.EMBOSS)
      im1.show()
      

    • 平滑滤波

      突出图像的主干部分,减少突变

      im1 = im.filter(ImageFilter.SMOOTH)
      im1.show()
      
      im2 = im.filter(ImageFilter.SMOOTH_MORE)
      im2.show()
      

    • 锐化

      im1 = im.filter(ImageFilter.SHARPEN)
      im1.show()
      
      


    图像过滤(高级用法)

    • ImageFilter.Kernel(size, kernel, scale=None, offset=0)

      有点类似于TensorFlow里的卷积神经网络
      size:卷积核的尺寸,比如为(3, 3)或者(5, 5)
      kernel:size为(3, 3),那么kernel必须为由9个int或者float组成的元组。如果size为(5, 5),那么kernel为25个
      scale:如果设置了,那么卷积核作用每个像素之后都要除以scale,默认是卷积核的权重之和
      offset:卷积核作用于每个像素之后要加上offset再除以scale,默认是0
      
      
      im1 = im.filter(ImageFilter.Kernel((3, 3), (1, 1, 1, 0, 1, 0, 1, 0, 1), scale=None, offset=0))
      im1.show()
      
      

    • ImageFilter.RankFilter(size, rank)

      生成等级滤波器,对于每一个像素点,等级滤波器根据像素值,在(size, size)的区域中对所有像素点进行排序,然后将对应等级的值拷贝到图像中。rank∈[0, size * size -1],size * size * 0.5为中等
      
      # 表示在每个像素点为中心的3*3区域组成的9个像素中,选择第7位的像素作为新值
      im1 = im.filter(ImageFilter.RankFilter(3, 7))
      im1.show()
      

      感觉有点类似模糊的效果

    • ImageFilter.MinFilter(size)

      和RankFilter类似,不过只需要指定一个size即可,会自动选择最小的,相当于rank=0

      im1 = im.filter(ImageFilter.MinFilter(3))
      im1.show()
      
      

    • ImageFilter.MaxFilter(size)

      和上一次一样,只不过是选取最大的

      im1 = im.filter(ImageFilter.MaxFilter(3))
      im1.show()
      
      

    • ImageFilter.MedianFilter(size)

      选取中间的

      im1 = im.filter(ImageFilter.MedianFilter(3))
      im1.show()
      

    • ImageFilter.ModeFilter(size)

      选择(size, size)中出现次数最多的像素值,如果没有出现两次或者两次以上的,就用原始的像素值

      im1 = im.filter(ImageFilter.ModeFilter(3))
      im1.show()
      
      im2 = im.filter(ImageFilter.ModeFilter(6))
      im2.show()
      

      size=3还可以,等于6就有点



    Image模块下的api


    • Image.eval

      类似于im.point,这个函数会有一个返回值,不会在原来的图像上进行操作

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      # 接收两个参数,Image对象,和函数
      im1 = Image.eval(im, lambda x: x * 0.5)
      im1.show()
      
      

    • Image.blend

      图像融合,使用两张图像和一个透明度,融合成一张新的图像。注意:融合的时候,两张图像的尺寸必须要相同

      from PIL import Image
      
      im1 = Image.open("古明地觉.jpg").resize((600, 400))
      im2 = Image.open("古明地恋.jpg").resize((600, 400))
      
      im1.show()
      im2.show()
      
      

      from PIL import Image
      
      im1 = Image.open("古明地觉.jpg").resize((600, 400))
      im2 = Image.open("古明地恋.jpg").resize((600, 400))
      
      """
      参数1:图像1
      参数2:图像2
      参数3:透明度alpha
      合成公式:图像1 * (1 - alpha) + 图像2 * alpha
      可以看出,如果alpha=0,那么结果就是图像1,alpha=1,结果就是图像2 
      """
      im = Image.blend(im1=im1, im2=im2, alpha=0.6)
      im.show()
      

    • Image.composite

      将两张图片进行合成,和blend类似

      from PIL import Image
      
      im1 = Image.open("古明地觉.jpg").resize((600, 400))
      im2 = Image.open("古明地恋.jpg").resize((600, 400))
      
      """
      参数1:图像1
      参数2:图像2
      参数3:mask,图像的一个通道。这是不再是透明度alpha
      """
      im = Image.composite(image1=im1, image2=im2, mask=im1.split()[1])
      im.show()
      
      

    • Image.merge

      这个方法和split是对应的,split是将图片的三个通道进行分解,而merge是将三个通道进行融合,类似于pandas里面的merge

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      r, g, b = im.split()
      
      # 得到的r、g、b均是Image对象,所以可以使用对象的所有方法
      r = r.point(lambda x: x * 1.3)  # r通道变为原来的1.3倍
      g = g.point(lambda x: x * 0.9)  # g通道变为原来的0.9倍
      b = b.point(lambda x: 0)  # g通道变为0
      
      # 融合
      # 接收两个参数
      # 参数一:模式,这里直接使用原图的模式
      # 参数二:三通道,要以元组的方式传入
      print(im.mode)  # RGB
      im1 = Image.merge(im.mode, (r, g, b))
      
      im1.show()
      
      

      得到了一个暖色调的图像

    • 读取gif格式的图片

      # 此外,Image.open()还可以读取gif格式
      '''
      im = Image.open("xxx.gif")
      # 从序列中查找指定的帧,如果越界会抛出一个EOFError异常
      # 当文件序列被打开,自动获取第零帧
      # 这里显示第二帧
      im.seek(2).show()
       
      # 获取当前帧所处的位置,从0开始计算
      im.tell()
      '''
      


    图片的变换

    这里的方法是通过im对象调用的

    im.transform

    图像可以有大小或者形状上的变化。
    主要是用im.transform(size, method, data, filter)
    size:新图像的尺寸
    method:有EXTENT(裁剪一个矩形区域),AFFINE(仿射变换),QUAD等等,下面举例介绍
    data:裁剪的区域,传入矩形的左上顶点和右下顶点
    filter:滤波器,有NEAREST,BILINEAR,BICUBIC,ANTIALIAS。中间两个不常用,NEAREST速度最快,ANTIALIAS质量最高
    
    • ENTENT

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      """
      表示将im的(0, 0, 600, 600)这块区域裁剪出来,并且尺寸变为(300, 300)
      我们裁剪的区域的宽和高为600和600,那么在变换的时候也要符合比例,不然会有拉伸和压缩
      至于滤波器我们不用管,默认的就好
      
      这种方法类似于im.crop但是速度上没有crop块,速度上类似于resize
      这个方法是有返回值的
      """
      im1 = im.transform((300, 300), Image.EXTENT, (0, 0, 600, 600))
      im1.show()
      

    • AFFINE

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      """
      前两个参数不用说,关键是第三个参数
      传入一个元组(a, b, c, d, e, f)那么原来的(x, y)就会被映射成(ax+by+c, dx+ey+f)
      """
      im1 = im.transform((300, 300), Image.AFFINE, (1, 2, 1, 2, 1, 3))
      im1.show()
      
      

    • QUAD

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      """
      这个简单,就是输出图像的一个四边形
      这里是图像的截取部分,需要传入左上、左下、右下、右上四个位置,个人觉得只需要传两个就可以了
      """
      im1 = im.transform((300, 300), Image.QUAD, (0, 0, 0, 400, 500, 400, 500, 0))
      im1.show()
      
      

    • PERSPECTIVE

      from PIL import Image
      
      im = Image.open("古明地觉.jpg")
      
      """
      透视变化
      和仿射类似,只不过最后一个元组需要传入8个值
      (a, b, c, d, e, f, g, h),然后(x, y)会映射成( (ax+by+c)//(gx+hy+1), (dx+ey+f)//(gx+hy+1) )
      """
      im1 = im.transform((300, 300), Image.PERSPECTIVE, (1, 1, 1, 1, 0, 0, 0, 0))
      im1.show()
      
      

    im.transpose

    可以对图像进行翻转

    from PIL import Image
    
    im = Image.open("古明地觉.jpg")
    
    
    im1 = im.transpose(Image.FLIP_LEFT_RIGHT)  # 左右翻转
    im2 = im.transpose(Image.FLIP_TOP_BOTTOM)  # 上下翻转
    im1.show()
    im2.show()
    
    



    图像增强

    PIL还提供了了一个专门用来增强图像的模块,叫ImageEnhance

    操作也很简单
    调用ImageEnhance下的某个方法,传入Image对象,也就是im,得到一个增强图像的对象,比如叫enh
    然后调用enh.enhance方法,传入增强或者减弱的数值,变得到一个新的Image对象,可以直接调用show方法,或者Image.open()得到的对象的其他方法 
    
    
    from PIL import Image, ImageEnhance
    
    im = Image.open("古明地觉.jpg")
    
    # 传入Image对象im,得到可以操作亮度的对象
    enh = ImageEnhance.Brightness(im)
    
    # 增强或者减弱亮度
    enh.enhance(1.5).show()  # 增强为原来的1.5倍
    enh.enhance(0.3).show()  # 减弱为原来的0.3倍
    
    

    from PIL import Image, ImageEnhance
    
    im = Image.open("古明地觉.jpg")
    
    # 传入Image对象im,得到可以操作对比度的对象
    enh = ImageEnhance.Contrast(im)
    
    # 增强或者减弱对比度
    enh.enhance(1.5).show()  # 增强为原来的1.5倍
    enh.enhance(0.3).show()  # 减弱为原来的0.3倍
    

    from PIL import Image, ImageEnhance
    
    im = Image.open("古明地觉.jpg")
    
    # 传入Image对象im,得到可以操作锐化的对象
    enh = ImageEnhance.Sharpness(im)
    
    # 增强或者减弱锐化
    enh.enhance(20).show()  # 增强为原来的20倍
    enh.enhance(0.5).show()  # 减弱为原来的0.5倍
    

    from PIL import Image, ImageEnhance
    
    im = Image.open("古明地觉.jpg")
    
    # 传入Image对象im,得到可以操作颜色均衡的对象
    enh = ImageEnhance.Color(im)
    
    # 增强或者减弱颜色均衡
    enh.enhance(5).show()  # 增强为原来的5倍
    enh.enhance(0.5).show()  # 减弱为原来的0.5倍
    
    



    图像加特技

    PIL还为我们提供了ImageChops模块(channel operations),可以对图像进行一些特效上的操作。

    • ImageChops.constant(image, value)

      返回一个和image大小一样,像素值为value的层

      from PIL import Image, ImageChops
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageChops.constant(im, 200)
      im1.show()
      

    • ImageChops.dupicate(image)

      返回给定图像的拷贝,类似于im.copy()

      from PIL import Image, ImageChops
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageChops.duplicate(im)
      im1.show()
      

    • ImageChops.invert(image)

      返回一个新图像,新图像的每一个像素等于255-原像素

      from PIL import Image, ImageChops
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageChops.invert(im)
      im1.show()
      

    • ImageChops.lighter(image1, image2)

      将两个图片的像素逐个比较,选取较大的作为新图片的像素,两者尺寸可以不一样,尺寸相当于会取两者共有的部分。如果是600*400和700*300,那么得到结果会是600*300

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg")
      im2 = Image.open("古明地恋.jpg")
      
      im = ImageChops.lighter(im1, im2)
      im1.show()
      im2.show()
      im.show()
      

    • ImageChops.darker(image1, image2)

      从名字也能看出,选取较小的作为新像素

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg")
      im2 = Image.open("古明地恋.jpg")
      
      im = ImageChops.darker(im1, im2)
      im.show()
      

    • ImageChops.difference(image1, image2)

      返回两个图片像素的绝对差值作为新图片的像素

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg")
      im2 = Image.open("古明地恋.jpg")
      
      im = ImageChops.difference(im1, im2)
      im.show()
      

    • ImageChops.mutiply(image1, image2)

      两张图片进行融合,image1 * image2 / MAX,对应像素相乘,然后除以较大的像素

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg")
      im2 = Image.open("古明地恋.jpg")
      
      im = ImageChops.multiply(im1, im2)
      im.show()
      

    • ImageChops.screen(image1, image2)

      将两张图片进行融合,这几个api比较类似,无非是像素的算法不一样,result = MAX -((MAX - image1) * (MAX - image2) / MAX)

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg")
      im2 = Image.open("古明地恋.jpg")
      
      im = ImageChops.screen(im1, im2)
      im.show()
      

    • ImageChops.add(image1, image2, scale, offset)

      result = (image1 + image2)/scale + offset

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg")
      im2 = Image.open("古明地恋.jpg")
      
      im = ImageChops.add(im1, im2)
      im.show()
      
      im = ImageChops.add(im1, im2, 5)
      im.show()
      

    • ImageChops.subtract(image1, image2, scale, offset)

      result = (image1 - image2) / scale + offset

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg")
      im2 = Image.open("古明地恋.jpg")
      
      im = ImageChops.subtract(im1, im2)
      im.show()
      
      im = ImageChops.subtract(im1, im2, 5)
      im.show()
      

    • ImageChops.blend(image1, image2, alpha)

      和Iamge模块的blend用法一样,将两张图像合并为一张,注意:此时要求图片尺寸一致

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg").resize((600, 400))
      im2 = Image.open("古明地恋.jpg").resize((600, 400))
      
      im = ImageChops.blend(im1, im2, 0.5)
      im.show()
      

    • ImageChops.composite(image1, image2, mask)

      根据mask合成两张图像,mask可以是一个通道,和Image下的composite是一样的。同理,要求两张图片尺寸一致

      from PIL import Image, ImageChops
      
      im1 = Image.open("古明地觉.jpg").resize((600, 400))
      im2 = Image.open("古明地恋.jpg").resize((600, 400))
      
      im = ImageChops.composite(im1, im2, im1.split()[0])
      im.show()
      
      im = ImageChops.composite(im1, im2, im1.split()[1])
      im.show()
      

    • ImageChops.offset(image, xoffset, yoffset)

      原图像(x,y)--》新图像(x+xoffset, y+yoffset)

      from PIL import Image, ImageChops
      
      im = Image.open("古明地觉.jpg")
      im1 = ImageChops.offset(im, 100, 200)
      im1.show()
      



    图像处理

    PIL还提供了一个ImageOps模块,包含一些图像处理操作

    • ImageOps.autocontrast(image, cutoff=0)

      最大图像对比度。计算一个输入图像的直方图,image.histogram(),除去最亮和最暗的百分之cutoff,重新映射图像

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      im1 = ImageOps.autocontrast(im, 15)
      im1.show()
      

    • ImageOps.colorize(image, black, white)

      使得灰色图像变为彩色图像,变量black和white应该是RGB元组或者颜色名称。这个函数会使得原图像的所有黑色变成black,所有白色变成white,前提是变量image的模式必须为L,使用im.split()会获取三个通道,那么每个通道的模式便为L

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg").convert("L")
      
      im1 = ImageOps.colorize(im, "pink", "green")
      im1.show()
      

    • ImageOps.crop(image, border=0)

      类似于im.crop(),但是参数不太一样,那个border依旧是一个元组,包含四个int。但不是矩形的左上和右下顶点,而是表示左上右下分别去掉多少行/列

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      # 表示左边去掉200列,上边去掉100行,右边去掉300列,下边去掉200行
      im1 = ImageOps.crop(im, border=(200, 100, 300, 200))
      im1.show()
      

    • ImageOps.equalize(image)

      产生一个灰色值均匀分布的图像

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.equalize(im)
      im1.show()
      

    • ImageOps.expand(image, border=0, fill=0)

      和crop相反,expand表示扩充行/列,用fill指定的颜色填充

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.expand(im, border=(100, 100, 100, 100), fill="pink")
      im1.show()
      

    • ImageOps.fit(image, size, method, bleed, centering)

      size:输出的尺寸
      method:采样的方法,默认是NEARST,速度最快
      bleed:去除边界(四个),需要传入一个百分比,如0.01,去除百分之一的边界。默认是0
      centering:裁剪位置,(0.5,0.5)表示中心,(0, 0),左上角,(1.0, 0)左下角。(1.0, 1.0)右下角
                 (0.5,0.5),裁剪宽度,从右边开始,裁剪高度,从底部开始
                 (0,0),裁剪宽度,从右边开始,裁剪高度,从底部开始
                 (1.0,0),裁剪宽度,从左边开始,裁剪高度,从底部开始
      
      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.fit(im, (400, 400), Image.NEAREST, 0.3, (1.0, 0))
      im1.show()
      

    • ImageOps.flip(image)

      输出image在垂直方向的景象

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.flip(im)
      im1.show()
      

    • ImageOps.mirror(image)

      既然有垂直方向的景象,那就肯定有水平方向上的

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.mirror(im)
      im1.show()
      

    • ImageOps.grayscale(image)

      将彩色图像转化为灰度图像

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.grayscale(im)
      im1.show()
      

    • ImageOps.invert(image)

      每一个像素都用255去减,和ImageChops.invert()功能一样

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.invert(im)
      im1.show()
      

    • ImageOps.posterize(image,bits)

      将每个颜色通道值的低bits个位设置为0

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.posterize(im, 10)
      im1.show()
      

    • ImageOps.solarize(image,threshold=128)

      在指定的阈值范围内,翻转所有的像素点

      from PIL import Image, ImageOps
      
      im = Image.open("古明地觉.jpg")
      
      im1 = ImageOps.solarize(im, threshold=128)
      im1.show()
      



    ImageDraw

    ImageDraw是PIL里面的一个画笔,我们可以导入图像,也可以绘制图像。既然要绘制图像,那么肯定要有画笔啊。调用ImageDraw模块下的Draw方法,draw=ImageDraw(im),传入的im也就是Image对象,就可以生成一个画笔,那么画笔所画的内容就会显示在im(画板)上。那么这个画板可以是image.open创建的Image对象,也可以是自己创建的Image对象。下面我们就来自己创建


    创建一个画板

    from PIL import Image
    
    """
    三个参数:
    第一个参数:模式
    第二个参数:画板的长和宽
    第三个参数:画板的颜色,是一个三元组
    """
    im = Image.new("RGB", (200, 80), (150, 155, 180))
    im.show()
    

    创建画笔

    from PIL import Image
    from PIL import ImageDraw
    
    im = Image.new("RGB", (200, 80), (150, 155, 180))
    # 此时变得到一个画笔,画笔所画的内容都会显示在im上面
    draw = ImageDraw.Draw(im)
    

    绘制直线

    from PIL import Image
    from PIL import ImageDraw
    
    im = Image.new("RGB", (200, 80), (150, 155, 180))
    draw = ImageDraw.Draw(im)
    """
    line方法表示画一条直线,参数如下:
    参数一:起点和终点位置,[x1, y1, x2, y2]
    参数二:fill,用什么颜色填充,是一个rgb三元组
    参数三:width:线条宽度
    """
    draw.line([10, 10, 150, 80], fill=(150, 140, 255), width=2)
    draw.line([20, 10, 50, 180], fill=(250, 40, 155), width=2)
    
    im.show()
    

    绘制曲线

    from PIL import Image
    from PIL import ImageDraw
    
    im = Image.new("RGB", (800, 600), (100, 100, 100))
    draw = ImageDraw.Draw(im)
    """
    和绘制直线类似,但是坐标的意义不一样
    
    参数一:起点和终点位置,和直线不一样,直线是两点确定一条直线,而曲线里的起点和终点,表示一个矩形的左上顶点和右下顶点
    参数二:起始角度
    参数三:终止角度
    
    然后会根据参数一得到的矩形画出一个与矩形四边都想切的圆
    然后根据起始角度和终止角度从满圆中截取相应的弧
    并且规定相应矩形的水平中位线为零度角,然后顺时针变大
    
    参数四:fill,填充颜色,rgb三元组,或者颜色名
    参数五:width,线条宽度
    """
    draw.arc([0, 0, 600, 400], 0, 360, fill="blue", width=2)
    """
    如果矩形跑到了画板的外面,仍然会按照相应的规则画圆,截取
    就假装有画板,只是显示的时候超出画板的部分不显示
    有时候我们想画出一条曲线的时候,便可以采用这种办法
    通过画圆的方式,然后截取一部分弧
    """
    draw.arc([-100, -100, 1000, 200], 0, 360, fill="red", width=2)
    im.show()
    

    绘制圆或者椭圆

    这个和上面的arc类似,其实arc也算是用来画圆的

    from PIL import Image
    from PIL import ImageDraw
    
    im = Image.new("RGB", (800, 600), (100, 100, 100))
    draw = ImageDraw.Draw(im)
    
    """
    参数一:和arc的第一个参数是一样的
    此时不需要起始和终止角度了,因为画的就是圆或者椭圆
    
    参数二:fill,填充色,圆或者椭圆内部的颜色
    参数三:outline,轮廓的颜色
    参数四:width,线条的宽度
    """
    draw.ellipse([100, 100, 600, 600], fill="blue")
    draw.ellipse([100, 100, 500, 300], outline="red", width=2)
    im.show()
    

    draw.chord

    用法和arc类似,只不过fill变成填充色,arc中的表示轮廓的fill在arc里面成为了outline

    from PIL import Image
    from PIL import ImageDraw
    
    im = Image.new("RGB", (800, 600), (100, 100, 100))
    draw = ImageDraw.Draw(im)
    
    draw.chord([0, 0, 600, 400], 0, 360, fill="blue", width=2)
    
    draw.arc([-100, -100, 1000, 200], 0, 360, fill="red", width=2)
    im.show()
    

    绘制扇形

    参数和chord一样

    from PIL import Image
    from PIL import ImageDraw
    
    im = Image.new("RGB", (800, 600), (100, 100, 100))
    draw = ImageDraw.Draw(im)
    
    draw.pieslice([100, 100, 600, 600], 0, 90, fill="cyan", width=3)
    
    im.show()
    

    绘制多边形

    传入相应点的坐标,会将多个点依次相连

    from PIL import Image
    from PIL import ImageDraw
    
    im = Image.new("RGB", (800, 600), (100, 100, 100))
    draw = ImageDraw.Draw(im)
    
    draw.polygon([(50, 60), (100, 100), (150, 50), (250, 600), (50, 60)], fill="cyan", outline="green")
    
    im.show()
    

    绘制矩形

    from PIL import Image
    from PIL import ImageDraw
    
    im = Image.new("RGB", (800, 600), (100, 100, 100))
    draw = ImageDraw.Draw(im)
    
    draw.rectangle([100, 100, 400, 400], outline="green")
    draw.rectangle([200, 200, 300, 300], fill="blue")
    
    im.show()
    

    字体对象

    既然要画,肯定要有字体啊

    from PIL import Image
    from PIL import ImageFont
    
    im = Image.new("RGB", (800, 600), (100, 100, 100))
    """
    参数一:字体
    参数二:大小,size
    参数三:index,有的字体是一系列字体的组合index表示用第几个,一般不指定
    """
    font = ImageFont.truetype(r"C:WindowsFontsmsth.ttc", 40)
    

    绘制文字

    from PIL import Image
    from PIL import ImageFont
    from PIL import ImageDraw
    
    im = Image.new("RGB", (800, 600), "cyan")
    draw = ImageDraw.Draw(im)
    font = ImageFont.truetype(r"C:WindowsFontssimkai.ttf", 40)
    
    """
    使用text方法绘制文字
    参数一:起始位置
    参数二:文字,text
    参数三:font,字体对象,如果不指定,则使用默认字体
    参数四:fill,字体的填充颜色
    """
    draw.text([100, 200], text="古明地觉最可爱", font=font, fill=(100, 185, 179))
    im.show()
    


    手动生成验证码

    绘制噪点

    from PIL import Image
    from PIL import ImageFont
    from PIL import ImageDraw
    import random
    import string
    
    # 随机生成一个画板颜色
    bg_color = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
    # 定义画板的宽和高
    width, height = 200, 80
    
    # 创建画板
    im = Image.new("RGB", (width, height), bg_color)
    
    # 创建画笔对象,接收画板对象,这样一来,画笔所画的内容都会显示在画板上。
    draw = ImageDraw.Draw(im)
    
    # 绘制噪点,不要过多,一般为宽乘高再乘以0.1
    for _ in range(int(width * height * 0.1)):
        # 噪点的横纵坐标
        x_y_point = random.randint(0, width), random.randint(0, height)
        # 填充色,尽量随机
        fill = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
        # 绘制
        draw.point(x_y_point, fill)
        
    # 先来看看画板长啥样
    im.show()
    

    可以看到噪点此刻绘制出来了,在为其绘制几条直线和曲线

    from PIL import Image
    from PIL import ImageFont
    from PIL import ImageDraw
    import random
    import string
    
    bg_color = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
    width, height = 200, 80
    
    im = Image.new("RGB", (width, height), bg_color)
    
    draw = ImageDraw.Draw(im)
    
    for _ in range(int(width * height * 0.1)):
        x_y_point = random.randint(0, width), random.randint(0, height)
        fill = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
        draw.point(x_y_point, fill)
    
    for _ in range(5):
        """
        直线的长度要从画板的左边到,画板的右边
        因此左端点要在画板左侧上下变化
        因此右端点要在画板右侧上下变化
        """
        left_pos = 0, random.randint(0, height)
        right_pos = width, random.randint(0, height)
        fill = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
        draw.line([left_pos, right_pos], fill=fill)
    
    # 再为其绘制几条曲线
    for _ in range(5):
        """
        这里我们要超出画板
        这样最终在画板上显示的部分只是大圆的一条弧,看起来就像是一条曲线
        不然整个圆都显示的话,就不是我们想要的曲线了
        """
        left_pos = (-100, -100)
        right_pos = (width * 5, random.randint(0, height))
        fill = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
        draw.arc([left_pos, right_pos], 0, 360, fill=fill)
    
    # 来看看长什么样
    im.show()
    

    可以看到,背景的噪点和线段已经绘制完成,下面开始绘制文字

    from PIL import Image
    from PIL import ImageFont
    from PIL import ImageDraw
    import random
    import string
    
    bg_color = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
    width, height = 200, 80
    
    im = Image.new("RGB", (width, height), bg_color)
    
    draw = ImageDraw.Draw(im)
    
    for _ in range(int(width * height * 0.1)):
        x_y_point = random.randint(0, width), random.randint(0, height)
        fill = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
        draw.point(x_y_point, fill)
    
    for _ in range(5):
        left_pos = 0, random.randint(0, height)
        right_pos = width, random.randint(0, height)
        fill = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
        draw.line([left_pos, right_pos], fill=fill)
    
    for _ in range(5):
        left_pos = (-100, -100)
        right_pos = (width * 5, random.randint(0, height))
        fill = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
        draw.arc([left_pos, right_pos], 0, 360, fill=fill)
    
    # 验证码是由文字和数字组成,先来获取所有的数字和字母
    alpha_digit = string.ascii_letters + string.digits
    # 验证码一般是四个字符,从里面随机选取4个
    verify_code = random.sample(alpha_digit, 4)
    # 生成字体对象
    font = ImageFont.truetype(r"C:WindowsFontssimkai.ttf", 40)
    # 为四个字符创建四种颜色
    color = [(random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)) for _ in range(4)]
    
    # 绘制文字
    # 注意:坐标加上字体的宽度不要超出画板,否则显示不全
    draw.text([10, 10], verify_code[0], font=font, fill=color[0])
    draw.text([60, 25], verify_code[1], font=font, fill=color[1])
    draw.text([110, 15], verify_code[2], font=font, fill=color[2])
    draw.text([150, 25], verify_code[3], font=font, fill=color[3])
    
    # 释放画笔
    del draw
    
    # 再来查看一下
    im.show()
    
    

    验证码便被成功的绘制出来了


    保存图片

    我们之前的所有案例,都是调用show方法,自动将图片打开。如果我想将图片保存起来呢?要怎么做呢?

    from PIL import Image
    import random
    
    bg_color = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
    width, height = 200, 80
    
    im = Image.new("RGB", (width, height), bg_color)
    
    # 如果我想将im保存起来的话,可以使用save方法
    # 指定文件名和格式
    im.save("本地路径.jpg", format="png")
    
    

    这是一种方法,但是我们生成验证码是为了放在网站使用的,不可能先生成到本地,然后再读取。因此我们可以把字节流放到缓存里。

    from PIL import Image
    import random
    from io import BytesIO
    
    bg_color = random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)
    width, height = 200, 80
    
    im = Image.new("RGB", (width, height), bg_color)
    
    buf = BytesIO()
    # save方法除了传递本地路径,也可以传递一个缓存,这样字节流就都被放到了缓存里
    im.save(buf, "png")
    
    # 有了缓存,那么我们就可以直接在网站上渲染出验证码图片。比如Django
    # 我们就可以使用return HttpResponse(buf.getvalue(), "image/png"),直接渲染到页面上
    
    # 这里我们就用文件演示吧
    with open("1.png", "wb") as f:
        f.write(buf.getvalue())
    
    



    图片转成字符画

    from PIL import Image
    def get_char(r, g, b, alpha=256):
        # 这些字符串是用来和图片的像素进行匹配的
        ascii_char = '''$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,"^`'. '''
        if alpha == 0:
            return " "
        # 别问我为什么要这样进行映射,我也不知道
        length = len(ascii_char)
        gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
        unit = (256.0+1)/length
        return ascii_char[int(gray/unit)]
     
    def get_img(img: str, n: int):
        im = Image.open(img)
        # 有的时候,图片太大了,生成的txt文件没办法全部显示,需要拖动滚动条
        # 显然这样不爽,因此我们可以适当的缩小
        # 具体缩小多少倍,看图片的情况
        height = int(im.size[1]/n)
        width = int(im.size[0]/n)
      
        im = im.resize((width, height), Image.NEAREST)
        txt = ""
        for h in range(height):
            for w in range(width):
                # 获取每一个像素的三原色,匹配相应的字符
                txt += get_char(*im.getpixel((w, h)))
            # 注意换行,不然每一行的像素都合在一行了
            txt += "
    "
        return txt
     
    # 调用main函数,只需传入图片,和生成的txt文件名以及缩小的倍数即可
    def main(image_name: str, art_name: str, n: int=1):
        txt = get_img(image_name, n)
        with open(art_name, "w", encoding="utf-8") as f:
            f.write(txt)
    if __name__ == '__main__':
        main(r"C:UsersAdministratorDesktopkanade.jpg", r"C:UsersAdministratorDesktopkanade.txt")
    
    



    补充:图像的一些格式

    在PIL中,彩色图片,打开之后返回的对象模式为RGB或者RGBA,灰度图像,返回对象的模式为L。
    一般情况我们可以使用Image.open打开任意格式的图片,然后保存的时候保存为想要的格式。
    但是Imgae对象可以直接转换格式,在PIL中共有1,L,P,RGB,RGBA,CMYK,YCbCr,I,F九种格式
    
    
    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im.show()
    
    

    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im1 = im.convert("1")
    print(im1.mode)  # 1
    im1.show()
    
    

    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im1 = im.convert("L")
    """
    L = r * 299 / 1000 + g * 587 / 1000 + b * 114 / 1000
    """
    print(im1.mode)  # L
    im1.show()
    
    
    

    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im1 = im.convert("P")
    print(im1.mode)  # P
    im1.show()
    
    

    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im1 = im.convert("RGBA")
    """
    模式rgba为32位彩色图像,它的每个像素用32个bit表示,
    其中24bit表示红色、绿色、蓝色三个通道,另外8位表示alpha通道,即透明通道
    """
    print(im1.mode)  # RGBA
    im1.show()
    
    

    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im1 = im.convert("CMYK")
    """
    模式cmyk为32位彩色图像,它的每个像素用32位表示
    模式cmyk就是印刷四分色模式,它是彩色印刷是所采用的一种套色模式
    利用色料的三原色混色原理,加上黑色油墨,共计四种颜色混合叠加,形成所谓的'全彩印刷'
    C = 255 - R
    M = 255 - G
    Y = 255 - B
    K = 0
    """
    print(im1.mode)  # CMYK
    im1.show()
    
    

    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im1 = im.convert("YCbCr")
    """
    模式YCbCr为24位彩色图像,它的每个像素用24位表示
    YCbCr其中Y是指亮度分量,Cb是指蓝色色度分量,而Cr是指红色色度分量
    人的肉眼对Y分量更加敏感,因此在通过对色度分量进行子采样来减少色度分量后,肉眼将察觉不到图像的质量变化
    Y = 0.257 * R + 0.504 * G + 0.098 * B + 16
    Cb = -0.148 * R - 0.291 * G + 0.439 * B + 128
    Cr = 0.439 * R - 0.368 * G - 0.071 * B + 128
    """
    print(im1.mode)  # YCbCr
    im1.show()
    
    

    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im1 = im.convert("I")
    """
    模式I为32位整型灰色图像,它的每个像素用32位表示
    0表示灰,255表示白,(0, 255)之间的数字表示不同的灰度
    I = R * 299 / 1000 + G * 587 / 1000 + B * 114 / 1000 
    """
    print(im1.mode)  # I
    im1.show()
    
    

    from PIL import Image
    
    
    im = Image.open("蕾姆.png")
    im1 = im.convert("F")
    """
    模式I为32位浮点灰色图像,它的每个像素用32位表示
    0表示灰,255表示白,(0, 255)之间的数字表示不同的灰度
    F = R * 299 / 1000 + G * 587 / 1000 + B * 114 / 1000
    
    模式F和模式L的转换公式是一样的,都是RGB转成灰色值的公式
    但模式F会保留小数的部分 
    """
    print(im1.mode)  # F
    im1.show()
    
    

    PIL还有一些其他的模块,这里就不介绍了,因为不常用(其实是你懒),目前的这些对于基本的图像处理应该足够了,当然如果后续想到了,会继续添加

  • 相关阅读:
    迭代器相关整理
    闭包的功能举例
    函数参数相关整理
    python中进制转换及IP地址转换
    dD Geometry Kernel ( Geometry Kernels) CGAL 4.13 -User Manual
    2D and 3D Linear Geometry Kernel ( Geometry Kernels) CGAL 4.13 -User Manual
    Monotone and Sorted Matrix Search ( Arithmetic and Algebra) CGAL 4.13 -User Manual
    Algebraic Kernel ( Arithmetic and Algebra) CGAL 4.13 -User Manual
    数论中的环概念
    QT的配置及目录结构
  • 原文地址:https://www.cnblogs.com/traditional/p/11111770.html
Copyright © 2020-2023  润新知