利用python在excel上绘画1、前言1.1、实现效果1.2、使用的库安装2、代码分开说明2.1、对象定义和初始化2.2、对象方法1 :调整高列宽以防止图像失真
一、前言
以前学习EXCEL的时候,看到n大神利用EXCEL画画,觉得很不可思议。 今天我想学一个月的python,膨胀后用excel画画。 当然,用实际画画这个词并不严密。 实际上,您只需要使用opencv遍历每个像素的rgb值,将其转换为十六进制数字,最后调用openpyxl进行填充。
1.1、实现效果的效果如下图所示
1.2、安装所需库所需的库如下。
导入importcv2#opencv库import xlsxwriter #使用此调整调整行高列宽import openpyxl #使用此填充颜色导入numpy as NP #下的两个是数据存储区以这种方式处理数据时,比列表更高效,具体地说,除了文档import pandas as pd中的第一个库之外,可以直接通过pip安装到命令提示符行或利用编辑器的自动安装功能具体请参考本文第3节“3,开始安装”
如果直接在pip 3安装opencv-python上安装第一个库,无论网络速度有多快,它的速度都将非常慢,如下所示:
如果能安装就好了,但关键是等几分钟可能也不行。 就这样出现了几十行红色的字,我看着头痛。 经过百度才知道这是安装源的问题。 切换到国内的安装源就可以了,利用以下命令,
pip3install-I https://pypi.tuna.Tsinghua.edu.cn/simple opencv-python
如下图所示,我打算把安装速度与上面的进行比较,就这样安装了
二、代码分开说明。 本文利用面相对象的编程思维进行。
2.1、对象定义及初始化classimagetoexcel (: def _ init _ (self,image_path,excel_path ) :self.imgviewx=cv2
其中image_path和excel_path变量是图像的保存路径和后续excel文件的保存位置。
第三行中的self.imgviewx=cv2.imread (image _ path,cv2.IMREAD_COLOR )表示调用opencv中的im read以读取图像。 第一个参数是在实例化对象时传递的图像存储路径。 此函数返回一个三维数组,表示x、y和rgb是对应于x和y坐标的rgb值。 其中,x、y的单位为1像素。 最后,将此三维数组传递给对象的属性imgviewx,并等待后续对象方法的调用。 我们把那个打印如下。
第四行self.excel_path=excel_path将实例化对象时传递的excel_path传递给对象的属性excel_path,然后传递给后续对象的方法
2.2、对象方法1 :调整高列宽,防止图像变形# 按excel行的高度列宽排列defexcel_size(self ) : workbook=xlsx writer.workbook ) self.excel_path ) worksheet=workbook worksook
第二行第三行基本上是明白的。 在刚开始实例化对象时传递的路径中创建工作簿,并添加名为test的工作表。
第三行意味着将a列到CAA列的列宽设置为1。 (注意:如果其中设置为1,不知为什么在工作表中为0.94,列宽也同样小。 )
第4行也是同样的意思,但是行高不能一起循环。
虽然看起来像最后一次关闭,但其实最重要的功能是保存。 如果没有此行,则不保存以前的所有设置。
2.3、对象方法2 :从十进制到十六进制的转换#从十进制到十六进制的转换deften2_16(self,num ) :num1=hex(num ).replace('0x ',' )。
16进制是以0x开头的,而16进制颜色码中明显没有,所以要用replace去掉。如果rgb值是16以内的,以16进制显示的话会是1位数,而同样这个在16进制颜色码中也没有,所以最后一行的意思就是一位数的话在开头补0。 2.4、对象的方法3:获取r、g、b值并运用方法1转化为16进制颜色码 #获取像素数据并转化为16进制 def get_rgb_data(self): self.excel_size() data_r=pd.DataFrame( np.array(self.imgviewx)[:,:,2] ).applymap(self.ten2_16) data_g=pd.DataFrame( np.array(self.imgviewx)[:,:,1] ).applymap(self.ten2_16) data_b=pd.DataFrame( np.array(self.imgviewx)[:,:,0] ).applymap(self.ten2_16) return (data_r+data_g+data_b).values
其中第二行<<self.excel_size()>>是在本方法本调用时候先调用方法1调整行高列宽。我们后面说,这关系到对象方法之间的参数传递,我们后续说。
三四五行的代码结构一样,我们挑一个说。比如第三行
<<data_r=pd.DataFrame( np.array(self.imgviewx)[:,:,2] ).applymap(self.ten2_16)>>
这个代码我们可以拆开成下面的代码
r=np.array(self.imgviewx)[:,:,2]tmp=pd.DataFrame( r )data_r=tmp.applymap(self.ten2_16)这下就容易懂了
第一行意思是将刚开始对象初始化时候得到的包含目标图片的所有像素点的rgb值的三维列表转化为数组并提取其中的r。
第二行是将第一行得到的数组转化为DataFrame对象并存储在tmp变量中,以便第三行的处理。
第三行是利用DataFrame中的applymap将r值转化为16进制。
最后一行<<return (data_r+data_g+data_b).values>>意思是将转化为16进制的rgb值合并后就得到了16进制的颜色码并转化为数组。
2.5、对象的方法4;颜色填充 def color_fill(self): rgb_list=self.get_rgb_data() wb = openpyxl.load_workbook(self.excel_path) ws = wb['test'] for x,tmp1 in list(enumerate(rgb_list)): print('总共有%s行,已填充%s行,还剩下%s行'%(len(rgb_list),x+1,len(rgb_list)-x-1)) for y ,tmp2 in list(enumerate(tmp1)): ws.cell(x+1,y+1).fill = openpyxl.styles.fills.GradientFill(stop=[str(tmp2),str(tmp2)]) wb.save(self.excel_path)第二行<<rgb_list=self.get_rgb_data()>>是不是似曾相识,对,就是在方法2中调用方法1时候用的。
这里就是在本方法也就是方法3中调用方法2。唯一的区别就是有没有返回值。
我们这样在方法3中调用方法2然后方法2中调用方法1。这样在对象外的时候我们就只用对象实例化并调用方法3即可实现功能。
第三行、第四行就是调用openpyxl.load_workbook打开我们在方法1中新建的工作簿中的test工作表
五到七行两个循环嵌套很容易懂就是利用循环遍历每个工作表
第八行的代码可能可以简化 ,这个是我修改网上的一个填充渐变色的代码。
最后一行就是工作表的保存,没什么可说的。
最后四行前两行可以直接写在第三行中,就是对象的实例化中
另外还有一点,image_path中的 tttt.png是直接和我的py文件放在一起的,不然运行会报错。
好啦,到此所有东西已全部搞定,当然还有很多要注意的,
第一、方法3中红绿蓝的提取中这部分的编号是刚好相反的,提取时候需要注意
如下
当然你也可以尝试改变这个值看最后会得到什么结果。蓝色的太阳 红色的天空 或者是绿色的帽子,哈哈 好吧这个就你们自己发挥了。
第二、除了以上一点需要注意的,还有一个需要注意,就是像素不能太高。我测试了下342*218的话我的i7-6700u打开excel就不是很流畅了。
你可以遍历的时候以2个像素点或者四个像素点为步长,不过这样我没试过,可能颗粒感比较明显吧(自己猜测没试过),或者把原始图片修改下。
第三、如果对这篇文章有任何问题,欢迎私信,评论。
Title: the third blog
By:P&p
Time:2020-03-09 15.39 (学python的第38天)