利用python在excel中畫圖的實現方法

一、前言

以前大學時候,學EXCEL看到N多大神利用excel畫圖,覺得很不可思議。今兒個學了一個來月python,膨脹了就想用excel畫圖。當然,其實用畫圖這個詞不甚嚴謹,實際上是利用opencv遍歷每一個像素的rgb值,再將其轉化為16進制,最後調用openpyxl進行填充即可。

這是小編準備的python基礎學習資料,關注,轉發,私信小編“01”即可免費領取!

利用python在excel中畫圖的實現方法


1.1、實現效果

效果如下圖

利用python在excel中畫圖的實現方法

1.2、需要用到的庫的安裝

需要用到庫如下:

<code>import cv2 #導入OpenCV庫
import xlsxwriter #利用這個調整行高列寬
import openpyxl #利用這個填充顏色
import numpy as np #下面這兩個是數據存儲的兩種方式,用此種方式處理數據,比列表高效,具體可自行查看文檔
import pandas as pd/<code>

除了第一個庫其他的可以直接用pip在命令提示行進行安裝,或者利用編輯器的一些自動安裝功能也非常的方便,具體的請參看這篇文章 的第三節。

第一個庫如果你直接用pip3 install opencv-python 進行安裝的話,無論你網速多麼快,都會非常慢幾k/s,如下:

利用python在excel中畫圖的實現方法

如果能安裝好還行,關鍵有的可能等上幾分鐘也不行,直接出現幾十行的紅色字看的頭疼。幾經百度後才知道是安裝源的問題,切換為國內的安裝源即可,利用如下命令:

pip3 install -i https://pypi.tuna.tsinghua.ed... opencv-python

如下圖,我準備截取安裝速度和上面的作對比的,結果直接安裝好了

利用python在excel中畫圖的實現方法

二、代碼分開講解

本文我們利用面相對象的編程思維進行。

2.1、對象的定義以及初始化

<code>class ImageToExcel():
def __init__(self,image_path,excel_path):
self.imgviewx=cv2.imread(image_path,cv2.IMREAD_COLOR)
self.excel_path=excel_path/<code>

前面兩行很好理解就是定義對象的格式以及初始化對象。

其中image_path和excel_path這兩個變量是你的圖像儲存路徑和後續的excel文件保存位置。

第三行self.imgviewx=cv2.imread(image_path,cv2.IMREAD_COLOR)意思是調用opencv的imread讀取圖片。其中第一個參數就是對象實例化時候傳遞進來的圖像儲存路徑。該函數返回的是一個三維數組,分別表示x,y,rgb 就是x,y座標對應的rgb值,其中x,y單位為1像素。最後將這個三維數組傳遞給對象的一個屬性imgviewx,等待後續對象方法調用。我們將之打印出來如下。

利用python在excel中畫圖的實現方法

第四行<<self.excel>>是將對象實例化時候傳遞進來的excel_path傳遞給對象的屬性excel_path,同樣等待後續對象的方法調用。/<self.excel>

2.2、對象的方法

1:行高列寬調整,以防止圖像變形

<code>#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()/<code>

這個其實你可以後續在excel中調整也可以。

第二行第三行基本一看就懂,就是在你剛開始對象實例化時候傳入的一個路徑中創建一個工作簿並添加一個名為test的工作表。

第三行意思是將A列到CAA列的列寬設置為1(注意:這裡面設置為1不知道為什麼在工作表中就是0.94,列寬同樣小點)

第四行意思同樣,不過行高不能批量只能通過循環。

最後一樣看著像關閉,其實最主要功能是保存,沒有這一行,前面的所有設置都不會被保存。

2.3、對象的方法2:10進制轉化為16進制

<code>#10進制轉化為16進制
def ten2_16(self,num):
num1 = hex(num).replace('0x', '')
return num1 if len(num1) > 1 else '0' + num1/<code>

這個方法不用細說,就是利用系統自帶的函數hex將10進制轉化為16進制。我們都知道hex返回的16進制是以0x開頭的,而16進制顏色碼中明顯沒有,所以要用replace去掉。

如果rgb值是16以內的,以16進制顯示的話會是1位數,而同樣這個在16進制顏色碼中也沒有,所以最後一行的意思就是一位數的話在開頭補0。

2.4、對象的方法3:獲取r、g、b值並運用方法1轉化為16進制顏色碼

<code>#獲取像素數據並轉化為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/<code>

其中第二行self.excel_size() 是在本方法本調用時候先調用方法1調整行高列寬。我們後面說,這關係到對象方法之間的參數傳遞,我們後續說。

三四五行的代碼結構一樣,我們挑一個說。比如第三行data_r=pd.DataFrame( np.array(self.imgviewx)[:,:,2] ).applymap(self.ten2_16)這個代碼我們可以拆開成下面的代碼:

<code>r=np.array(self.imgviewx)[:,:,2]
tmp=pd.DataFrame( r )
data_r=tmp.applymap(self.ten2_16)/<code>

這下就容易懂了。

第一行意思是將剛開始對象初始化時候得到的包含目標圖片的所有像素點的rgb值的三維列表轉化為數組並提取其中的r。

第二行是將第一行得到的數組轉化為DataFrame對象並存儲在tmp變量中,以便第三行的處理。

第三行是利用DataFrame中的applymap將r值轉化為16進制。

最後一行return (data_r+data_g+data_b).values意思是將轉化為16進制的rgb值合併後就得到了16進制的顏色碼並轉化為數組。

2.5、對象的方法4:顏色填充

<code>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)/<code>

第二行rgb_list=self.get_rgb_data()是不是似曾相識,對,就是在方法2中調用方法1時候用的。

這裡就是在本方法也就是方法3中調用方法2。唯一的區別就是有沒有返回值。

我們這樣在方法3中調用方法2然後方法2中調用方法1。這樣在對象外的時候我們就只用對象實例化並調用方法3即可實現功能。

第三行、第四行就是調用openpyxl.load_workbook打開我們在方法1中新建的工作簿中的test工作表。

五到七行兩個循環嵌套很容易懂就是利用循環遍歷每個工作表。

第八行的代碼可能可以簡化 ,這個是我修改網上的一個填充漸變色的代碼。

最後一行就是工作表的保存,沒什麼可說的。

三、完整代碼

<code>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文件放在一起的,不然運行會報錯。/<code>

四、結語

好啦,到此所有東西已全部搞定,當然還有很多要注意的:

第一、方法3中紅綠藍的提取中這部分的編號是剛好相反的,提取時候需要注意。

如下:

利用python在excel中畫圖的實現方法

當然你也可以嘗試改變這個值看最後會得到什麼結果。藍色的太陽、紅色的天空或者是綠色的帽子,這個就你們自己發揮了。

第二、除了以上一點需要注意的,還有一個需要注意,就是像素不能太高。我測試了下342*218的話我的i7-6700u打開excel就不是很流暢了。

你可以遍歷的時候以2個像素點或者四個像素點為步長,不過這樣我沒試過,可能顆粒感比較明顯吧(自己猜測沒試過),或者把原始圖片修改下。


分享到:


相關文章: