PythonChallenge系列-P7图像处理

Smarty

解谜P6之后,转至第七题P7,其url为

http://www.pythonchallenge.com/pc/def/oxygen.html

打开之后,只有一张图片,图片的特点就是中间有一条灰度部分。再查看网页源码,没有发现什么线索。还是从图片着手吧,结合之前的做题经验,每道题都关联着Python的一个重要部分,如P3为字符串匹配,P4为urllib模块使用,P5为数据序列化,P6为zip压缩。那么这一题,应该就是图像处理。

Python中图像处理最重要的一个库就是PIL(Python Image Library),Python3 中不再维护,改为 Pillow。看了看这个库学了点基本的知识,最重要的一个函数就是Image.crop(),它可以用来截取一部分的图像。使用之前,必须先安装Pillow,参考教程

首先要从图片中截取出灰度部分,然后将灰度值转换为对应的ASCII码字符,观察字符能不能给出什么线索或答案

思路

首先要下载oxygen.png 图片到本地,通过urllib模块实现

然后从PIL中导入Image类,使用Image.open()打开图像

然后使用Image.load()函数加载像素到pixel

遍历pixel,找到R=B=G的像素点(即灰度点),将第一个灰度点存储在start中,最后一个存储在end中,所有的灰度值存储在data中

将data中的数值转换为ASCII码对应的字符(chr函数,P1中有介绍过),并存储到alpha中。使用join()函数将aphal连接成一个字符串,并输出。发现输出结果中出了第一个s出现连续出现5次外,其他的都是连续出现7次。下一步需要把连续重复的字符去除。

定义rst用来存放alpha中除去了重复值之后的结果。初始设置count=0,pre=“*”,遍历alpha,如果当前字符i和前一个字符pre相同,则count+1,如果+1后count==5且i==‘s’,说明一个s已经统计完了,下一个出现的字符时不算重复的字符;如果+1后,count==7且i !=’s’,则下一个出现的字符也不算重复字符。不重复的字符都追加到rst中

使用join函数,将rst连接成一个字符串并输出

最后使用Image.crop()将左上角start点到右下角end点之间的矩形区域(即灰度部分)截取并显示(循环中range(40,height)的40就是通过观察图像,尝试出来的)

代码

#-*- coding: utf-8 -*-
import os

#判断图像是否存在,不存在则下载
if os.path.isfile('oxygen.png'):
    pass
    #print 'existed'
else: #download the image
    from urllib.request import urlopen
    response = urlopen('http://www.pythonchallenge.com/pc/def/oxygen.png')
    with open('oxygen.png', 'wb') as f:
        f.write(response.read())

#图像处理
from PIL import Image

try:
    #打开图片
    image = Image.open('oxygen.png')
    print(image.format,image.size,image.mode) #PNG (629, 95) RGBA
    width, height = image.size

    #加载像素
    pixel = image.load()

    #找到图像中的灰度部分
    start = []  #灰度部分的左上角的点坐标
    end = []    #灰度部分的右下角的点坐标
    first = True
    data = []

    #找到r=g=b的像素(即灰度像素)的开始start和结束end点
    for y in range(40,height):#40 is the result of trying
        for x in range(0,width):#RGBA
            if pixel[x,y][0]==pixel[x,y][1] and \
                            pixel[x,y][0]==pixel[x,y][2] and \
                            pixel[x,y][1]==pixel[x,y][2]:
                if(first):
                    start = [x,y]
                    first = False
                else:
                    end = [x,y]
                #print chr(pixel[x,y][0]),
                data.append(pixel[x,y][0])
                #data.append(pixel[x,y][0])
        #print ''
    print (start, end)
    #print ''.join(data)

    #将data中的数据由ASCII码值转换为字符,保存到alpha中
    alpha = []
    for i in data:
        alpha.append(chr(i))
    #print "".join(alpha)

    #去除alpha中的重复值,如果是s则重复数为5,其他的重复数为7
    rst = []
    count = 0
    pre = '*' #可以是任意一个与alpha中不同的字符
    for i in alpha:
        if(i==pre):
            count += 1
            if count==5:
                if i=='s':
                    count = 0
                    pre = '*'
                    continue
            elif count ==7:
                #rst.append(i)
                count = 0
                pre = "*"
                continue
            else:
                pass
        else:
            rst.append(i)
            count = 0
        pre = i

    #print rst
    #print ''.join(alpha)
    print (''.join(rst))

    #将rst中提示的结果转换为ASCII码对应字符(最后结果)
    ans = [105, 110, 116, 101, 103, 114, 105, 116, 121]
    for i in ans:
        print ( chr(i), end="")
    print ('')

    #截取出灰度部分并显示
    box = (start[0], start[1], end[0], end[1])
    #print box
    region = image.crop(box)#截取
    region.show()#显示
except:
    print('cannot open the image')

输出结果:smart guy, you made it. the next level is [105, 110, 116, 101, 103, 114, 105, 116, 121]…

截取的图片为

这里的 [105, 110, 116, 101, 103, 114, 105, 116, 121] 又是什么?

尝试转化成ASCII码字符输出(代码见上述代码中的“最后结果”部分),输出integrity。

解谜

通过将图像中灰度部分的灰度值去除连续重复后再转换为ASCII码对应字符,得到一串数字,再将该串数字转换成对应的ASCII码字符,得到integrity,将url中的oxygen替换为integrity,成功解谜P7,并打开P8

http://www.pythonchallenge.com/pc/def/integrity.html

Python 知识点

  • PIL,Python Image Library,Python3中为Pillow
  • image = Image.open()打开图像
  • pixel = image.load() 加载图像中的像素到pixel
  • width,height = image.size 图像的大小
  • pixel[x,y] 图像像素,其中通道为pixel[x,y][0]…

作者:JarvisChu
原文链接:PythonChallenge系列-P7图像处理
版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0

发表评论