美文网首页
图像处理

图像处理

作者: __method__ | 来源:发表于2020-07-05 20:54 被阅读0次

    最终效果

    有这么一个视频:
    链接:https://pan.baidu.com/s/1_DYeC8p6c-cxZ_Uh6586Zg
    提取码:c1wt

    python转换后如下:


    demo2.gif

    案例演示

    首先:

    pip install pillow
    

    代码:

    from PIL import Image
    
    
    IMG = 'boy.jpg'
    WIDTH = 80
    HEIGHT = 40
    OUTPUT = 'jpg2.txt'
    
    # 我们定义的不重复的字符列表,灰度值大(亮)的用列表开头的符号,灰度值小(暗)的用列表末尾的符号
    ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'.                     ")
    
    # 将256灰度映射到90个字符上
    def get_char(r,g,b,alpha):
    
        if alpha == 0:
            return ' '
    
        length = len(ascii_char)
        gray = int(0.299 * r + 0.587 * g + 0.114 * b)
    
        return ascii_char[int((gray/256)*length)]#0表示黑,255表示白
    
    if __name__ == '__main__':
    
        im = Image.open(IMG)
        im = im.resize((WIDTH,HEIGHT))
    
        txt = ""
    
        #将图片看成由像素点组成的二维数组,i代表每一行,j代表每一列
        for i in range(HEIGHT):
            for j in range(WIDTH):
                #getpixel()函数的参数是由每个像素点在图片中的相对位置(w,h)组成的元组
                #返回值是一个代表图片像素值的(r,g,b,alpha)元组
                tup = im.getpixel((j, i))
    
                alpha = 256
    
                if len(tup) < 4:
                    r, g, b = tup
                else:
                    r, g, b, alpha = tup
    
                txt += get_char(r, g, b, alpha)
    
            txt += '\n'
    
    
        #字符画输出到文件
        if OUTPUT:
            with open(OUTPUT,'w') as f:
                f.write(txt)
        else:
            with open("output.txt",'w') as f:
                f.write(txt)
    
    
                                                                                    
                                     $$$odOOOo$$                                    
                               $d||||||<    U|     YO$                              
                            B||||||||Q]      t      w||J$                           
                         B|||||||||||o    )   ;t  < <||||J                          
                       $||||||||||ro< 0      < uUu< p    0t$                        
                      B|||||||||M      o    u h+  Lb      U0)'0                     
                     d|||||||t     )o)'       bLLLLL ]'         $                   
                    &|||||||p                  ;8#u     '<))))' 0                   
                   $||||||Q)    ';)))U00p0t;     p              $                   
                   k|||||t                       ;)     ;U0)  ]                     
                   c|||||o     LLLLLLLZ*&qZh&0)' ')        ;u $                     
                   n|||||'    )LLLLLLLLLLLLLLLLLLLLLLLLLLLq   $                     
                   Q|||||      LLLLLLLLLLLLLLLLLLLLLLLLLLw                          
                   $|||||      tLL*wf-\Y*bLLLLLLLLLLLLLLM    $                      
                    r||||u      )-----------\dLLLLLLLLL)    $                       
                    $|||||        c-----------1LLLLLLW     $                        
                     B||||d;       p-----------0LLLZ      $                         
                      $|||||<         )c--------*;      '$                          
                       $t||||M           'u00$&&&&&&&0)$                            
                         $||||ro*OLLLLLL)       w`|wYkoh$                           
                          $*LLLhw||||||o        0   ; Y $                           
                            |||||||||||n        Y   j ] )                           
                            O|||||||||||w      p bu|b                               
                            $||||||||od;  <pu'          p$  $a<'u$                  
                             ||JOr||||O  )              )$'        $                
                             O||||||||o  <              o          0                
                             $||||||||r    '          <            0                
                       $LLLL&$|||||||||c      ')0))'  ]p           $                
                       $LLLL*$|||||||||||u           w|)          u                 
                             o||||||||||||||wp)uMJt||||o         U                  
                             |||||||||||||||||||||tOB$$ &       $                   
                             |||||||||||||||Y$                                      
                         <   0||||||||||n$                                          
                              u||||||td$                                            
                                  UU$                                               
                         $           $                                              
                          $u                                                        
                             $$U))a$                                                
                                                                                    
    
    
                           /il!l!i>>>>>>>>>>>>>><<<><~iM         .cUJJJLUYJj        
                        |Illllllll!ii>><>>>>>>><>>>>>>>>+]$   /JCCJJJJJJJJJCCJJ     
                       ,l!!llllll!!>>>>>>>>>>>><>>>>>>>>>>>?UJJJJJCCCJUJCJCCCJJJJ   
                     &ill!!lllllllll!!!i>>>>><>>><>~b0{1>>_JJJCCCCCCCU  JJJJJJJJJU; 
                    :lll!!lllllllllllll!>>>!,\.        >8pCJJCCCJ;      JJJJJCJJJJJ 
                   oIllllllllllllllli^r                  UJJCCCCJUzYJY  JJCJJJCCCCC?
                  8Illllllllll!'                i#t      UJJJJCJJJJJJz  CCCJJCCCJJJC
                  z!llll,Ii                    k         JJJJJJJCCCCJv  CCJJJJJJJJCU
                  M!lll?                                 JJJJJJJCCCCJ)  JJJJJJJJJJCX
                  q!lll`                                 uJJCCCCCCCCC^  JJJJJJJCCJJ[
                  8illl,:   k                             rJJJCCCCCCJ,  UJJJJJJCCCu 
                   &Ill;                            @B_    ;CJJCCCCCJL]XUJJJJJJCC   
                   ,oll[                                     _CJJCCCJJJJJJCCCJU"    
                    w8n                                         ,YUJJCCJJLU}  B     
                     08         vq^                               B "W        8     
                      #                                           8 +8        L     
                   >O  m                     '             ]      b;{%        (q    
                   B  hWx                                 I       \Yn8        Xk    
                   B  B o                          )     [   l    {u*8        *U    
                    Wx {WB                                        8 @         B     
                      &0  &                                l     BJ p        WB     
                        $%l8               &             -     Oollv W       %>     
                           L8                `.       :      JQW[llLb#@     Ba      
                             B                             Mu} aMllld)M)   8%       
                              dh                        M   \n O&llllM&@  BB        
                                 &%              :MB1      &#  BqlIllllB$@!         
                                  B w;ll#  ^b          B%X   &%_!llllZ+ld@          
                                \@'Y &!ll#Z  !%8p%B@U    %Bk?!lllllW-i8I!B@         
                               8n  %  BlllIBo      z8%McllllIIQzpJ|Ic8]lllB$        
                             &8    Q% iW!!!i!ll!<!lIlllllM}&M-L#i_l!lllllll@@       
                           #B       B  B~!lllllll;!!I&:n!!h<II!illlllllllll[%b      
                         uB        $%W %i!lll0I<!;%Z<a0;{#W8B<;xoBBBBb+i!llIZ%      
                       ^$j      j%8  B8x!llll!1vM!l!!ll!%Wl!I$x         Wf%#l%%     
                 >@oj.        w$     b8Illllll!l!ll!>8%:c8I;B             i!!!@*    
                   &B&l     Z8        %llllllllllll+J!BBi~%@%           O' QhI|${   
                       $l @b          8X!llllllllllllI@B%k:M@            W% [M!&8   
                       $o             n&lllllllllll!!llII\%|BI            d8 #8-B1  
                                       8!lllllllllll;0BplIll*%             W% 8v88  
                                       B&8888%8%M#0<Il!llll!l%%             WX 808  
                                       1Willlllllllllllllllll;8@             &Mm8&  
    
    

    图像知识

    灰度:灰度使用黑色调来表示物体,即用黑色为基准色,不同饱和度的黑色来显示图像。每个灰度对象都具有从0%(白色)到100%(黑色)的亮度值。需要注意这个百分比是以纯黑为基准的百分比,百分比越高颜色越偏黑,百分比越低颜色越偏白。灰度也可认为是亮度,简单的说就是色彩的深浅程度。

    image

    灰度值:指黑白图像中点的颜色深浅(浓淡)程度,范围一般从0到255,白色为255,黑色为0,故黑白图片也称灰度图像。

    灰度图像:灰度图像是每个像素只有一个采样颜色的图像。这类图像通常显示为从最暗黑色到最亮的白色的灰度。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑白两种颜色(0和255),灰度图像在黑色与白色之间还有许多级的颜色深度(0~255)。一幅完整的彩色图像,是由红色、绿色和蓝色三个通道组成的,红色、绿色和蓝色三个通道的缩览图都是以灰度图显示的,用不同的灰度色阶来表示红色、绿色和蓝色在图像中的比重。

    image

    灰度图像

    在PIL中,图像模式大致分为九种,分别为:1,L,P,RGB,RGBA,CMYK,YCbCr,I, F。
    其中L模式为灰度图像。

    image

    模式"L"

    模式"L"为灰度图像,它的每个像素用8个bit位表示,其中0表示黑,255表示白,其它数字表示不同的灰度。在PIL模式中, 从模式"RGB"转换到模式"L",有一个计算公式,即:L = R * 299/1000 + G * 587/1000+ B * 114/1000(只取整数部分)。
    下面将模式"RGB"的图像转换为模式"L"的图像:

    from PIL import Image
    
    empire = Image.open('empire.jpg')
    print(empire.mode)                       # RGB
    empire_1 = empire.convert('L')
    print(empire_1.mode)                     # 1
    print(empire.size, empire_1.size)        # (1920, 1080) (1920, 1080)
    print(empire.getpixel((0, 0)))           # (9, 5, 2)
    print(empire.getpixel((10, 120)))        # (21, 16, 10)
    print(empire_1.getpixel((0, 0)))         # 5
    print(empire_1.getpixel((10, 120)))      # 16
    
    for i in range(empire_1.size[1]):
        for j in range(empire_1.size[0]):
            empire_1.putpixel((j,i), 0)
    
    empire_1.save("empire_L.jpg")
    
    

    先是打开一个RGB模式的图片,然后将其转换为模式为"L"的图片,可以看到模式变化后,图片大小前后并未发生改变,然后对比了相同坐标位置的不同模式下的像素值,可以看到,对于RGB模式图像,像素值包含R,G,B三点要素的占比,而对于模式为"L"的图像,像素值可以取到0-255之间的任何值。然后校验一下"RGB"与"L"模式转换的像素转换公式:

    image

    最后,将转换成功的模式为"L"的图像保存,图片显示如下:

    image

    将开始的2张图片转为灰度图像

    image.png image.png

    其中,png透明图像转灰度图像的代码如下(我们后面再解释):

    from PIL import Image
    
    
    if __name__ == '__main__':
    
        im = Image.open('cat.png')
    
        for i in range(im.size[0]):
            for j in range(im.size[1]):
                r,g,b,alpha = im.getpixel((i,j))
                gray = int(0.299 * r + 0.587 * g + 0.114 * b)
                im.putpixel((i,j),(gray,gray,gray,alpha))
    
        im.save('cat_gray.png')
    
    

    图像转字符画核心代码解析

      im = Image.open(IMG)
      im = im.resize((WIDTH,HEIGHT))
    

    打开图片文件
    将图片大小调整为WIDTH宽,HEIGHT高,目的是为了转换为字符画后好看。

        txt = ""
    
        #将图片看成由像素点组成的二维数组,i代表每一行,j代表每一列
        for i in range(HEIGHT):
            for j in range(WIDTH):
                #getpixel()函数的参数是由每个像素点在图片中的相对位置(w,h)组成的元组
                #返回值是一个代表图片像素值的(r,g,b,alpha)元组
                tup = im.getpixel((j, i))
                r, g, b = tup
                txt += get_char(r, g, b)
    
            txt += '\n'#换行
    

    txt = "",定义一个字符串保存最终转换后的文本。
    将图片看成由像素点组成的二维数组,i代表每一行,j代表每一列。
    嵌套for循环,取出图片中的每一个像素的r,g,b值(通过im.getpixel((j, i))),调用get_char函数,获得该像素点对应的字符。
    最后追加到txt上。

    看一下get_char函数的实现

    ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'.                     ")
    
    # 将256灰度映射到90个字符上
    def get_char(r,g,b):
    
        length = len(ascii_char)
        gray = int(0.299 * r + 0.587 * g + 0.114 * b)
    
        return ascii_char[int((gray/256)*length)]#0表示黑,255表示白
    

    ascii_char是一个字符数组,观察字符数组中的每一个字符,可以发现越靠前面的字符越宽,越靠后面的字符越细,到最后变成空白字符。我们使用这样的字符数组来对应灰度图像的黑色深浅程度。白色或浅色的像素对应空白或窄的字符(数组后面的字符),黑色或深色的像素对应更宽的字符(数组前面的字符)。

    上面函数稍微复杂点的地方在于最后一行,gray是灰度值,范围是(0---255),数值越大,代表颜色越深;除以256,代表颜色的深浅程度(0---1)之间的一个数,越接近0,颜色越深。再乘以length,找到符号数组中对应的字符,返回出去。

    这里除以256而不是255,是防止数组越界。

    透明图片的处理

    这张机器猫图片的格式是png,是透明图片。

       #将图片看成由像素点组成的二维数组,i代表每一行,j代表每一列
        for i in range(HEIGHT):
            for j in range(WIDTH):
                #getpixel()函数的参数是由每个像素点在图片中的相对位置(w,h)组成的元组
                #返回值是一个代表图片像素值的(r,g,b,alpha)元组
                tup = im.getpixel((j, i))
    
                alpha = 256
    
                if len(tup) < 4:
                    r, g, b = tup
                else:
                    r, g, b, alpha = tup
    
                txt += get_char(r, g, b, alpha)
    

    对于png格式的图片,getpixel返回的元组中有4个值,比普通rgb格式的图片多了一个参数alpha,这个参数代表透明度。是一个0-255之间的数字,数字越大代表越不透明。

    get_char函数加一个判断,如果是透明像素,则返回空白字符。

    # 将256灰度映射到70个字符上
    def get_char(r,g,b,alpha):
    
        if alpha == 0:
            return ' '
    
        length = len(ascii_char)
        gray = int(0.299 * r + 0.587 * g + 0.114 * b)
    
        return ascii_char[int((gray/256)*length)]#0表示黑,255表示白
    

    图片加水印

    我们通过一段给图片加水印的功能,来理解一下透明度。

    from PIL import Image, ImageDraw, ImageFont
    # 添加文字水印
    # RGBA的意思是(Red-Green-Blue-Alpha)它是在RGB上扩展包括了“alpha”通道,运行对颜色值设置透明度
    im = Image.open("boy.jpg").convert('RGBA')
    txt=Image.new('RGBA', im.size, (0,0,0,0))    # 图像的大小 颜色的四个属性 数字越大越表现这个通道属性
    d=ImageDraw.Draw(txt)##获得一个绘图的上下文环境,可以抽象为一张画布以及笔墨等等的总合
    
    fnt=ImageFont.truetype("c:/Windows/fonts/Candara.ttf", 50)        # 选水印的字体 选暗色字体,显色的无法出现不知原因
    d.text((txt.size[0]-420,txt.size[1]-50), "Hello",font=fnt,fill=(0,0,255,250))
    txt.save('txt.png')
    
    out=Image.alpha_composite(im,txt)
    # out.show()
    out.save("water.png")
    
    image.png

    python对象序列化与反序列化模块pickle

    python对象的序列化与反序列化

    特点

    1、只能在python中使用,只支持python的基本数据类型。

    2、可以处理复杂的序列化语法。(例如自定义的类的方法,游戏的存档等)

    一、内存中操作:
    dumps方法将对象转成字节(序列化)
    loads方法将字节还原为对象(反序列化)

    import pickle
    #dumps
    li = [11,22,33]
    r = pickle.dumps(li)
    print(r)
    
    
    #loads
    result = pickle.loads(r)
    print(result)
    

    二、文件中操作:

    #dump:
    import pickle
    
    li = [11,22,33]
    pickle.dump(li,open('db','wb'))
    
    #load
    ret = pickle.load(open('db','rb'))
    print(ret)
    

    视频转字符视频

    pip install opencv-python
    

    总体思路

    1.打开视频
    2.循环读取视频的每一帧,进行前面类似的处理(将图片转换成字符串),将该字符串保存到一个字符串集合中。
    3.最后将该字符串集合,序列化到文件中。

    导入依赖,定义常量

    import cv2
    import pickle
    ascii_char =  "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'.                     "
    
    filename = 'basketball.mp4'#要转换的视频文件
    show_width, show_heigth = 130,40#转换后的每一帧图形的宽,高
    dst_path = 'frames2.dat'#转换后要保存的文件名称
    

    1.打开视频

    vc = cv2.VideoCapture(filename)  # 加载一个视频
    print('processing ' + filename)
    if vc.isOpened():  # 正常打开
        rval, frame = vc.read()
    else:
        print('open failed! Abort.')
        exit(1)
    

    2.循环读取视频的每一帧,进行前面类似的处理(将图片转换成字符串),将该字符串保存到一个字符串集合中。
    这一步是重点

    frame_count = 0  # 帧数
    outputList = []  # 初始化输出列表
    while rval:
        # 循环读取视频帧
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 使用opencv转化成灰度图
        gray = cv2.resize(gray, (show_width, show_heigth))  # resize灰度图
        text = ""
        for pixel_line in gray:
            for pixel in pixel_line:  # 字符串拼接
                text += ascii_char[int(pixel / 256 * len(ascii_char))]
            text += "\n"
        outputList.append(text)
        frame_count = frame_count + 1
        if frame_count % 100 == 0:
            print(str(frame_count) + " frames processed")
        rval, frame = vc.read()
    

    3.最后将该字符串集合,序列化到文件中。

        # 持久化
    with open(dst_path, 'wb') as f:
        pickle.dump(outputList, f)
    
    print("compeletd!")
    

    全部代码

    import cv2
    import pickle
    ascii_char =  "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'.                     "
    
    filename = 'basketball.mp4'#要转换的视频文件
    show_width, show_heigth = 130,40#转换后的每一帧图形的宽,高
    dst_path = 'frames2.dat'#转换后要保存的文件名称
    
    vc = cv2.VideoCapture(filename)  # 加载一个视频
    print('processing ' + filename)
    if vc.isOpened():  # 正常打开
        rval, frame = vc.read()
    else:
        print('open failed! Abort.')
        exit(1)
    
    
    frame_count = 0  # 帧数
    outputList = []  # 初始化输出列表
    while rval:
        # 循环读取视频帧
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 使用opencv转化成灰度图
        gray = cv2.resize(gray, (show_width, show_heigth))  # resize灰度图
        text = ""
        for pixel_line in gray:
            for pixel in pixel_line:  # 字符串拼接
                text += ascii_char[int(pixel / 256 * len(ascii_char))]
            text += "\n"
        outputList.append(text)
        frame_count = frame_count + 1
        if frame_count % 100 == 0:
            print(str(frame_count) + " frames processed")
        rval, frame = vc.read()
    
    
        # 持久化
    with open(dst_path, 'wb') as f:
        pickle.dump(outputList, f)
    
    print("compeletd!")
    

    字符串视频播放

    #!/usr/bin/python
    import pickle
    import time
    
    with open('./frames2.dat', 'rb') as f:
        frameList = pickle.load(f)
        for frame in frameList:
            print(frame)
            time.sleep(0.05)
    
    
    

    通道的理解

    image.png

    这幅图的本质是一个400*300*3的一个矩阵
    PI[ 400, 300, 3 ]
    列 行 分量
    说明这个图像有400列,300行,以及在色彩上有三个分量,分别是:

    image.png image.png image.png

    每个分量单独拿出来都是一个400*300(*1)的矩阵
    它们并不是彩色的,而是一幅灰度图像
    对于一副8bit的图像来说,矩阵元素的取值范围是从0-255(0 - 2^8-1)

    矩阵中的元素对应我们所说的像素(pixel),其值即该像素的灰度值,数值越大,像素的颜色越‘白/浅’;数值越小,像素的颜色越’黑/深‘ .

    对于图像每个分量来说,它只是灰度,谈论色彩没有意义,它是“黑白”的!(用黑白来描述灰度图像并不准确,用深浅可能更准确一些。)

    在图像显示时,我们把图像的R分量放进红色通道里,B分量放进蓝色通道里,G分量放进绿色通道里。经过一系列处理,显示在屏幕上的就是我们所看到的彩色图像了。

    通道类似颜料。 想要什么颜色,对应的通道里的灰度值就大一点就行了。(三原色)

    随便在椅子上取一个样点,其灰度值分别是(R:179,G:45,B:9)。所以在显示的时候,红色通道里灰度值大,绿色通道和蓝色通道里的灰度值小,显示出来的就是红色(绿色通道里的灰度值又比蓝色大一些,所以最终显示的结果有点接近橘红色)

    如果我们交换一下分量放置的顺序,把G分量放进红色通道里,把R分量放进绿色通道里,B分量放进蓝色通道里,会怎么样呢 ?

    变成了这样 :

    image.png

    代码:

    from PIL import Image
    
    
    if __name__ == '__main__':
    
        im = Image.open('chat.jpg')
    
        for i in range(im.size[0]):
            for j in range(im.size[1]):
                r,g,b = im.getpixel((i,j))
    
                im.putpixel((i,j),(g,r,b))
    
        im.save('chatbak.jpg')
    
    

    分离三个通道,分别上色

    1.jpg
    from PIL import Image
    
    im1 = Image.open("1.jpg")
    
    ##图像处理##
    
    # 转换为RGB图像
    im1_sp = im1.convert("RGB")
    
    # 将RGB三个通道分开
    r, g, b = im1_sp.split()
    
    #上色图保存
    r.save("0rr.jpg")
    g.save("0gg.jpg")
    b.save("0bb.jpg")
    
    # 将RGB分通道图像上色
    imd = Image.new("L", im1.size, 0)
    r_color = Image.merge("RGB", (r, imd, imd))
    g_color = Image.merge("RGB", (imd, g, imd))
    b_color = Image.merge("RGB", (imd, imd, b))
    
    #上色图保存
    r_color.save("1rr.jpg")
    g_color.save("1gg.jpg")
    b_color.save("1bb.jpg")
    
    
    
    
    1rr.jpg 1gg.jpg 1bb.jpg

    相关文章

      网友评论

          本文标题:图像处理

          本文链接:https://www.haomeiwen.com/subject/pqrbqktx.html