zoukankan      html  css  js  c++  java
  • PIL处理图片信息

      最近遇到了图片处理的一些问题,python提供了一些库可以很方便地帮助我们解决这些问题,在这里把我这几天的学习总结一下。

    一、提取图片的RGB值

      

      1、非代码:如果只是为了提取某张图片或者某个像素点的RGB值,用qq的截图工具就可以看到,如果不嫌麻烦也可以用下万能的Photoshop...但是我是一枚程序媛!

      2、python实现

      (1)先安装PIL库,windows下直接下载exe文件执行即可,linux、mac下easy_install、pip一下

        ——PIL:Python Imaging Library,基本可以看作Python平台事实上的图像处理标准库。

      (2)代码:因为是一张图片,就取一个位置的RGB值即可  

        load方法 返回对象的像素值,也可以用来修改像素值 

    1 from PIL import Image
    2 im = Image.open('6,jpg')
    3 pix=im.load()
    4 pix[0,0]

    二、基于rgb分量的最低位的隐写术

      隐写术,顾名思义,就是把一些信息以隐含的方式写在图片信息当中。基于rgb分量最低位的隐写术一种比较简单也比较常见的方式。

      1、RGB:彩色图像用3个字节来分别记录RGB三种颜色在一个像素点中的亮度,一个字节8个比特位,表示的值从0~255,0即最暗,也就是完全不显示这种颜色,255为最亮,RGB(0,0,0)为纯黑,RGB(255,255,255)为纯白。上述提到的隐写术就是改变某一个颜色分量最低的比特位,最低的比特位对图像整体的影响最小,改变一位换算成十进制也就是加减1,比如从223变成了224或者222,影响极其小。

      2、基于rgb分量最低位的隐写术:以红色分量为例,即是操纵“红色亮度”字节最后一个比特位。譬如我们想把’A’隐藏进来的话,就可以把A转成16进制的0x61再转成二进制的01100001,再修改为红色通道的最低位为这些二进制串。

      3、python实现  

     1 from PIL import Image  
     2 def f(pixel):
     3     if pixel%2 == 1:
     4         return 255
     5     return 0
     6 im=Image.open('145.png')
     7 im.getdata()  
     8 r,g,b=im.split()
     9 newImg = Image.eval(r, f)
    10 newImg.save("115.png","PNG")
    11 newImg.show()

      (1)Image.getdata()方法:返回一个图像内容的像素值序列。不过,这个返回值是 PIL 内部的数据类型,只支持确切的序列操作符,包括迭代器和基本序列方法。我们可以通过 list(im.getdata())  为其生成普通的序列。此步骤也可以替换为im.load()

      (2)自定义的f方法,即是对像素点进行处理,如果低位为1,则设置为白色,若为0,则设置为红色

      (3)Image.eval : 使用带一个参数的函数作用于给定图片的每一个像素。如果给定的图片有超过一个的 频段(band),则该函数也会作用于每一个频段。

        在上述代码中,f指定了函数,r指定了红色频段(band),所以这个函数会作用于红色频段,如果低位为1,置为白色,如果为0,置为黑色。

        然而,这是为什么呢?

    三、同图搜索

      1、安装python-Levenshtein库,这个库提供了一些计算字串相似度的方法

      (1)先下载安装VCForPython

      (2)再下载python-Levenshtein的源码,python setup.py install安装

      2、把图片hash成一段指纹,这个指纹和图片的大小、格式、明暗均无关,只和图片的内容本身有关。

       下面是一个完整的代码,image2文件夹包含30张图片,image1文件夹包含5000+张图片,对于image2中的每一张图片,image2中均有一张与其对应,找出这些图片。

       关于具体算法,提供一个资料,里面有更加详细的解释 http://blog.jobbole.com/65914/ 

       解释一点,为什么不是直接比较两个图片的hash值是否相等,而是用到了Levenshtein.hamming()方法,是因为图片之间因为各种原因,最终生成的hash值并不完全一致,实际处理过程中允许一些小的差异,所以计算了一下两个hash值的汉明距离,代码的第43行设置了一个最外层循环,k值代表的就是汉明距离,从1开始,如果两个hash图片的汉明距离小于这个k值那就记录下来;如果当前的k值导致有些图片还不能找到相同图片,那就加大k的值继续计算。这里有一点,如果已经找到了就不要用之后的更新了,肯定是k值越小情况下找到的图片越准。

     1 from PIL import Image
     2 import os
     3 import Levenshtein
     4 
     5 def dhash(image,hash_size=8):
     6     image=image.convert('L').resize((hash_size+1,hash_size),Image.ANTIALIAS,)
     7 
     8     pixels=list(image.getdata())
     9     difference=[]
    10     for row in range(hash_size):
    11         for col in range(hash_size):
    12             left=image.getpixel((col,row))
    13             right=image.getpixel((col+1,row))
    14             difference.append(left>right)
    15 
    16     decimal_value=0
    17     hex_string=[]
    18     for index,value in enumerate(difference):
    19         if value:
    20             decimal_value+=2**(index%8)
    21         if(index % 8)==7:
    22             hex_string.append(hex(decimal_value)[2:].rjust(2,'0'))
    23             decimal_value=0
    24     return ''.join(hex_string)
    25 
    26 source=[]
    27 for i in range(1,31):
    28     if os.path.exists('./image2/'+str(i)+'.jpg'):
    29         image=Image.open('./image2/'+str(i)+'.jpg')
    30     else:
    31         image=Image.open('./image2/'+str(i)+'.png')
    32     source.append(dhash(image))
    33 print len(source)
    34 des=[]
    35 for i in range(1,5693):
    36     if os.path.exists('./image1/'+str(i)+'.jpg'):
    37         image=Image.open('./image1/'+str(i)+'.jpg')
    38     else:
    39         image=Image.open('./image1/'+str(i)+'.png')
    40     des.append(dhash(image))
    41 print len(des)
    42 res=[0]*31
    43 for k in range(1,15):
    44     for i in range(len(source)):
    45         if res[i+1]!=0:
    46             continue
    47         for j in range(len(des)):
    48             if Levenshtein.hamming(des[j],source[i])<k:
    49                 res[i+1]=j+1
    50                 print i+1,j+1
    51                 break

    四、提供一下我的安装包:http://pan.baidu.com/s/1sktCtmH

  • 相关阅读:
    poj 3468 A Simple Problem with Integers (线段树区间更新求和lazy思想)
    hdu 1166 敌兵布阵(线段树区间求和)
    队列和栈
    完数的输出
    数据类型
    ASP.NET 图片上传工具类 upload image简单好用功能齐全
    ASP.NET 文件上传类 简单好用
    将form表单元素转为实体对象 或集合 -ASP.NET C#
    .NET框架面向对象分层的个人想理
    .NET VS2012 将代码同步上传到 oschina.net 和 github
  • 原文地址:https://www.cnblogs.com/naonaoling/p/5154398.html
Copyright © 2011-2022 走看看