一、前言
以前学习EXCEL的时候,看到n大神利用EXCEL画画,觉得很不可思议。 今天我想学一个月的python,膨胀后用excel画画。 当然,用实际画画这个词并不严密。 实际上,您只需要使用opencv遍历每个像素的rgb值,将其转换为十六进制数字,最后调用openpyxl进行填充。
1.1、实现效果
效果如下图所示
1.2、所需库的安装
所需的库如下:
导入importcv2#opencv库
import xlsxwriter #利用此来调整行的高度、列宽
import openpyxl #使用该填充的颜色
import numpy as np #以下两种方法是数据存储,通过这种方法处理数据比列表更高效,具体来说,您可以自己查看文档
导入pandas as PD
除了第一个库以外,您可以直接通过pip安装在命令提示符行中,也可以使用编辑器的自动安装功能。 具体请参考本文第三节“3,开始安装”
如果直接在pip 3安装opencv-python上安装第一个库,无论网络速度有多快,它的速度都将非常慢,如下所示:
如果能安装就好了,但关键是等几分钟可能也不行。 就这样出现了几十行红色的字,我看着头痛。 经过百度才知道这是安装源的问题。 切换到国内的安装源就可以了,利用以下命令,
pip3install-I https://pypi.tuna.Tsinghua.edu.cn/simple opencv-python
如下图所示,我打算把安装速度与上面的进行比较,就这样安装了
二、分码说明
本文采用方面对象的编程思维进行。
2.1、对象的定义及初始化
class ImageToExcel () :
def_init_(self,image_path,excel_path ) :
self.imgviewx=cv2.im read (image _ path,cv2.IMREAD_COLOR ) )。
self.excel_path=excel_path
前面两行很清楚定义对象的格式和初始化对象
其中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,并等待后续对象方法的调用。 我们把那个打印如下。
第四行将实例化对象时传递的excel_path传递给对象的属性excel_path,并以相同的方式等待后续对象的方法调用。
2.2、对象方法
1 )调整行高列宽,防止图像失真
#excel行高列宽调整
efexcel_size(self ) :
工作簿=xlsx writer.workbook (self.excel _ path ) )。
worksheet=workbook.add _ worksheet (' test ' )
worksheet.set _ column (' a : CAA ',1 ) ) ) ) ) ) ) )。
forxinrange(2000 ) :worksheet.set_row(x ) x,8.4 ) )。
workbook.close (
这个其实可以稍后用Excel调整。
第二行第三行基本上是明白的。 在刚开始实例化对象时传递的路径中创建工作簿,并添加名为test的工作表。
第三行意味着将a列到CAA列的列宽设置为1。 (注意:如果其中设置为1,不知为什么在工作表中为0.94,列宽也同样小。 )
第4行也是同样的意思,但是行高不能一起循环。
虽然看起来像最后一次关闭,但其实最重要的功能是保存。 如果没有此行,则不保存以前的所有设置。
2.3、对象方法2 :从十进制转换为十六进制
#从十进制转换为十六进制
deften2_16(self,num ) :
num1=hex(num ).replace ) '0x ','')
返回编号1 if len (num1)1 else '0' num1
这种方法不言而喻,它利用系统提供的函数hex将十进制数转换为十六进制数。 我们知道hex返回的十六进制数以0x开头,但十六进制颜色代码中不清楚,所以要用replace将其去除。
如果rgb值小于或等于16,则以十六进制表示为1位;同样,由于十六进制颜色代码中也没有该值,因此最后一行表示如果是1位,则在开头添加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
其中第二行<>是在本方法本调用时候先调用方法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进制。
最后一行<>意思是将转化为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)
第二行<>是不是似曾相识,对,就是在方法2中调用方法1时候用的。
这里就是在本方法也就是方法3中调用方法2。唯一的区别就是有没有返回值。
我们这样在方法3中调用方法2然后方法2中调用方法1。这样在对象外的时候我们就只用对象实例化并调用方法3即可实现功能。
第三行、第四行就是调用openpyxl.load_workbook打开我们在方法1中新建的工作簿中的test工作表
五到七行两个循环嵌套很容易懂就是利用循环遍历每个工作表
第八行的代码可能可以简化 ,这个是我修改网上的一个填充渐变色的代码。
最后一行就是工作表的保存,没什么可说的。
三、完整代码
import cv2 #导入OpenCV库
import xlsxwriter #利用这个调整行高列宽
import openpyxl #利用这个填充颜色
import numpy as np #下面这两个是数据存储的两种方式,用此种方式处理数据,比列表高效
import pandas as pd
class ImageToExcel():
#初始化
def __init__(self,image_path,excel_path):
self.imgviewx=cv2.imread(image_path,cv2.IMREAD_COLOR)
self.excel_path=excel_path
# excel行高列宽调整
def excel_size(self):
workbook = xlsxwriter.Workbook(self.excel_path)
worksheet = workbook.add_worksheet('test')
worksheet.set_column('A:CAA', 1)
for x in range(2000): worksheet.set_row(x, 8.4)
workbook.close()
#rgb转16进制颜色码
def ten2_16(self,num):
tmp = hex(num).replace('0x', '')
return tmp if len(tmp) > 1 else '0' + tmp
#获取像素数据并转化为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
#颜色填充
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)
excel_path='test23.xlsx'
image_path='tttt.png'
image=ImageToExcel(image_path,excel_path)
image.color_fill()
最后四行前两行可以直接写在第三行中,就是对象的实例化中
另外还有一点,image_path中的 tttt.jpg是直接和我的py文件放在一起的,不然运行会报错。
四、结语
好啦,到此所有东西已全部搞定,当然还有很多要注意的,
第一、方法3中红绿蓝的提取中这部分的编号是刚好相反的,提取时候需要注意
如下
当然你也可以尝试改变这个值看最后会得到什么结果。蓝色的太阳 红色的天空 或者是绿色的帽子,哈哈 好吧这个就你们自己发挥了。
第二、除了以上一点需要注意的,还有一个需要注意,就是像素不能太高。我测试了下342*218的话我的i7-6700u打开excel就不是很流畅了。
你可以遍历的时候以2个像素点或者四个像素点为步长,不过这样我没试过,可能颗粒感比较明显吧(自己猜测没试过),或者把原始图片修改下。
到此这篇关于利用python在excel中画图的实现方法的文章就介绍到这了,更多相关python excel画图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!