碎碎念
国庆假期过去了,我快乐的自由时间又要被该死的学校的课打断了。入秋天气渐凉,唯一找到的下午晒太阳学习的地方也不能去了。晚上回到宿舍打算看看正则表达式的教程,半路也被新番吸引。。。学习路上真是坎坷
不过听到一个有趣的需求,大概是将图像转换成文本,然后把文本在转为图像。背景是图像加密。这让我想起之前有个新闻提到泄露商业秘密的那个大佬,将图片写在普通文件里的操作。
在和同学吹了一阵牛逼之后,想着还是自己试着写写吧,就用刚刚学的python和包就可以解决呢。
需求
将图片文件转换为文本文件,再将文本文件转换为图像文件。
工具
使用语言选择python,需要用到的包有openCV,re(正则表达式包),numpy(矩阵运算包)
思路
图片文件无非是一个巨大的多位数组,把这些数组按照行列挨个读出,转换为字符串写入文件即可。反之在将文本文件读入,转换成数组按照图片保存不就对了吗。看似很简单嘛。
实现
首先,根据之前的学习,可以使用cv2.read()函数将图片放到变量中,再使用open()函数创建一个文本文件。这里为了方便就先使用灰度图像书写逻辑。
import cv2
img = cv2.imread("/Users/wch/Desktop/changed.jpeg",0)
f = open("image",'w')
然后呢,我们按照存有图片的变量img的大小进行遍历像素(在这里,img是一个numpy.array对象,和二维列表还有所不同。不过这时候我还没有意识到,只是自以为是的继续做咯。)。这里用到一个 图片对象的 .shape() 方法,读出图片的宽和长,返回一个列表。由于是一个像素一个像素写入文件,在每个像素后面添加“,”在每一列之间添加换行。
for x in range(img.shape[0]):
for y in range(img.shape[1]):
f.write(str(img[x][y])+',')
f.write("\n")
f.close()
到这里,第一个目标实现啦,我们输出一下试试:
效果还不错呢。到这一步,加密处理还是怎样都随意咯。但是真正的困难是还原图像。第一步就是将文本文件读入变量了,这很容易的。(熟练的写下一下代码,注释部分会解释哦)
#import cv2
#import re
#import numpy as np
f = open("/Users/wch/Desktop/image",'r')
走到这里,傻眼了。忽然意识到无论我怎么读取这个文件,都需要进行字符串分割,还要转换成整形,而且还要注意行列。也许大佬不以为意,但是我是学C语言出身的,到这里以我的思路就是使用文件指针顺序读入。使用格式化读取可以方便的处理字符串,文件指针也会自动顺序读取。可是python该怎么做呢?如果手动读入每个字符,转换成整形还需要进行位处理!没个像素值的位数还不同!这种面向过程的思考方式着实害我不浅。
既然面向对象,我怎样才能直接处理这串超长的文件呢。。。正则表达式啊!而且正则表达式的包还能自动将匹配结果转换成列表呢!列表不就是图像了吗!
走到这里,我频繁试错长达20分钟。看来,思想还需要改进啊。
导入re包,使用正则表达式进行匹配。
prog = re.compile('(\d+),')
#\d表示匹配数字,+表示多次匹配,‘,’表示匹配字符是‘,’结尾,
#()表示匹配完成后只取括号内的字符。
ones = f.readlines() #读入文件,按行返回二维列表
end = [] #创建空数组,存储图像数据
for one in ones :
twos = re.findall(prog,one) #re方法,匹配每一行字符串中所有符合条件的值,返回列表
pixel = [] #创建空数组,用来存储行像素
for two in twos:
pixel.append(int(two)) #将单个像素信息写入行列表
end.append(pixel) #将单行列表写入图像列表
到这里,文件的转换已经大功告成,虽然我相信python一定有更简洁的表达方式,但是这个写法,起码是学到现在我可以写出的比较短的代码了呢。
最后就是把变量end用opencv保存了,看看是否能成功把!
cv2.imwrite("/Users/wch/Desktop/ttt.jpeg",end)
# Traceback (most recent call last):
# File "/Users/wch/Desktop/ttt2.py", line 17, in <module>
# cv2.imwrite("/Users/wch/Desktop/ttt.jpeg",end)
# TypeError: img is not a numpy array, neither a scalar
类型错误。。。不过这个numpy array像是在哪里见过呢。经过查找,发现他是矩阵的形式,所以呢,导入numpy包,使用 .array()将二维数组转换为二维矩阵。
cv2.imwrite("/Users/wch/Desktop/ttt.jpeg",np.array(end))
成功输出图像!
总结
这次的尝试真的受益匪浅。再次验证了学习语言一定要动手这条原则。当你尝试去写的时候才发现,那些脑袋里的想法有多么天真。多写程序,多尝试不同的思考模式,最后才能成为一个真正的“创作型程序猿”。所以,看完之后不妨自己试试写一个彩色图像的处理的,或者创建一个有交互的小程序吧!