用Python在Excel里画出蒙娜丽莎

之前看到过很多头条,说哪国某人坚持了多少年自学使用excel画画,效果十分惊艳。
对于他们的耐心我十分敬佩。
但是作为一个程序员,自然也得挑战一下自己。
这种需求,我们十分钟就可以完成!

mona-lisa

基本思路

实现这个需求的基本思路是读取这张图片每一个像素的色彩值,然后给excel里的每一个单元格填充上颜色。所以主要用到的是PILopenpyxl这两个库。?

PIL使用

PIL是Python里面做图像处理的时候十分常用的一个库,功能也是十分的强大,这里只需要用到PIL里一小部分的功能。

from PIL import Imageimg = Image.open(img_path) # 读取图片width, height = img.size # 获取图片大小r, g, b = img.getpixel((w - 1, h - 1)) # 获取像素色彩值

Image.open()是PIL里面打开一张图片的函数,支持多种图片类型img_path是图片路径,可以是相对路径,也可以是绝对路径img.size是获取图片的size属性,包含图片的宽和高img.getpixel()是获取图片色彩值的函数,需传入一个tuplelist,值为像素坐标xy

openpyxl使用

openpyxl几乎是Python里功能最全的操作excel文件的库了,这里也只需要用到它的一小部分功能。

import openpyxlfrom openpyxl.styles import fills

workbook = openpyxl.Workbook()worksheet = workbook.activecell.fill = fills.PatternFill(fill_type="solid", fgColor=hex_rgb)workbook.save(out_file)

openpyxl.Workbook()新建一个excel文件workbook.active 激活一个工作表cell.fill = fills.PatternFill(fill_type="solid", fgColor=hex_rgb)填充一个单元格,fill_type="solid"是填充类型,fgColor=hex_rgb是填充的颜色workbook.save()保存文件,需传入要保存的文件名

写一段代码

写这一个画图的需求需要用到的核心就是上面介绍的PILopenpyxl的几种用法。但是在实际写的时候,还会有一些其他问题,比如:

  1. getpixel()获取的颜色值是rgb十进制的,但fills.PatternFill 里的fgColor`参数接收到的颜色值是十六进制的值这个问题其实就是十进制转十六进制,很容易解决

    def int_to_16(num):    num1 = hex(num).replace(‘0x‘, ‘‘)    num2 = num1 if len(num1) > 1 else ‘0‘ + num1 # 位数只有一位的时候在前面补零    return num2
  2. excel的单元格默认是长方形,修改为正方形才不会使图片变形
    if h == 1:  _w = cell.column  _h = cell.col_idx  # 调整列宽  worksheet.column_dimensions[_w].width = 1
    
    # 调整行高worksheet.row_dimensions[h].height = 6

    这里用到了双重for循环,外层是width,里层是height,是一列一列的填充颜色,因此判断if h == 1,避免多次调整列宽。

  3. excel支持的样式数量有限这个问题比较严重。如果直接对高清大图进行操作,最后输出的excel文件在打开的时候,可能会提示我们文件有问题,需要自动修复。但是等它修复完成之后,会发现填充的所有颜色都消失了!

一开始以为是使用的行列数过多了原因。查询资料后发现,13版excel支持的大行数是1048576,最大列数是16384,我们使用的单元格数量还远没达到限制。在经过更换图片、更换excel版本,修改代码等不充分各种测试,才找到问题的原因所在。原来是因为,excel的原形是由多个xml文件,填充的颜色都存储在一个style.xml文件里面,当这个文件过大就会导致打开的时候报错。所以为了解决这个问题,有两个解决方案,第一是缩小图片,第二是减少图片颜色。缩小图片的时候自带减少图片颜色的功能,减少图片颜色的方法可以采用灰度化、二值化等方法。总体上来讲,就是需要控制颜色数量*单元格数<阈值(3300w左右)

MAX_WIDTH = 300MAX_HEIGHT = 300def resize(img):    w, h = img.size    if w > MAX_WIDTH:        h = MAX_WIDTH / w * h        w = MAX_WIDTH

    if h > MAX_HEIGHT:        w = MAX_HEIGHT / h * w        h = MAX_HEIGHT    return img.resize((int(w), int(h)), Image.ANTIALIAS)

最终效果

苍天不负有心人,打开最后输出的excel已经可以看到效果了!所以说,一切能用Python解决的问题,最终都会用Python来解决。image-20191117175137916

全部代码

# draw_excel.py

from PIL import Imageimport openpyxlfrom openpyxl.styles import fillsimport os

MAX_WIDTH = 300MAX_HEIGHT = 300

def resize(img):    w, h = img.size    if w > MAX_WIDTH:        h = MAX_WIDTH / w * h        w = MAX_WIDTH

    if h > MAX_HEIGHT:        w = MAX_HEIGHT / h * w        h = MAX_HEIGHT    return img.resize((int(w), int(h)), Image.ANTIALIAS)

def int_to_16(num):    num1 = hex(num).replace(‘0x‘, ‘‘)    num2 = num1 if len(num1) > 1 else ‘0‘ + num1    return num2

def draw_jpg(img_path):

    img_pic = resize(Image.open(img_path))    img_name = os.path.basename(img_path)    out_file = ‘./result/‘ + img_name.split(‘.‘)[0] + ‘.xlsx‘    if os.path.exists(out_file):        os.remove(out_file)

    workbook = openpyxl.Workbook()    worksheet = workbook.active

    width, height = img_pic.size

    for w in range(1, width + 1):

        for h in range(1, height + 1):            if img_pic.mode == ‘RGB‘:                r, g, b = img_pic.getpixel((w - 1, h - 1))            elif img_pic.mode == ‘RGBA‘:                r, g, b, a = img_pic.getpixel((w - 1, h - 1))

            hex_rgb = int_to_16(r) + int_to_16(g) + int_to_16(b)

            cell = worksheet.cell(column=w, row=h)

            if h == 1:                _w = cell.column                _h = cell.col_idx                # 调整列宽                worksheet.column_dimensions[_w].width = 1            # 调整行高            worksheet.row_dimensions[h].height = 6

            cell.fill = fills.PatternFill(fill_type="solid", fgColor=hex_rgb)

        print(‘write in:‘, w, ‘  |  all:‘, width + 1)    print(‘saving...‘)    workbook.save(out_file)    print(‘success!‘)

if __name__ == ‘__main__‘:    draw_jpg(‘mona-lisa.jpg‘)

上面说到 颜色数量*单元格数<阈值(256^4左右)的时候,可能有人会有疑惑,这个256^4是怎么来的。这个当然是我测试信口开河得来的。既然是有颜色数量单元格数这两个变量,那么自然要有两个测试方法以上。一个观察颜色数量,一个观察单元格数。但我在这里只做了颜色数量的一个测试。(最大的原因就是生成上万行*上万列的excel实在是太久了...懒...)

    count = 0    MAX_WIDTH = 255    for w in range(1, MAX_WIDTH + 1):        for h in range(1, MAX_WIDTH + 1):            cell = worksheet.cell(column=w, row=h)            if h == 1:                _w = cell.column                _h = cell.col_idx                # 调整列宽                worksheet.column_dimensions[_w].width = 1            # 调整行高            worksheet.row_dimensions[h].height = 6

            if count < 255 ** 3:                back = int_to_16(num=count)                back = ‘0‘ * (6 - len(back)) + back            else:                back = ‘‘.join([int_to_16(random.randint(0, 255)) for _ in range(3)])            cell.fill = fills.PatternFill(fill_type="solid", fgColor=back)            count += 1

count是记录颜色的变量,确保每一个颜色都不重复,但目前计算机RGB表示的颜色最多只有256^3种通过调整MAX_WIDTH的值来测试excel的阈值

最后生成的测试excel如下:

...还有点好看。!??

原文地址:https://www.cnblogs.com/7758520lzy/p/12152282.html

时间: 2024-10-06 15:00:24

用Python在Excel里画出蒙娜丽莎的相关文章

Python matplotlib 基础练习:画出正弦曲线等

初学者,练习以下片段: 代码1:用 一元一次函数 画直线 import matplotlib.pyplot as plt import numpy as np x = np.linspace(-2, 2, 50) print(x) y = 2*x + 1 plt.plot(x, y) ax = plt.gca() ax.spines['bottom'].set_position(('data',0)) ax.spines['left'].set_position(('data',0)) plt.

Word或Excel里画柱状图和折线图组合体

不多说,直接上干货! 最近,在帮导师,干此项目.其中需要 现在,我带你来一步一步地画出来. 第一步:插入  ->  图表 第二步: 第三步:弹出,默认的数据和图表. 第四步: 第五步: 第六步: 第七步:显示出数据 第八步:做最后的修改

使用Python的turtle模块画出简单的柱状图

代码如下: import turtle heights = [856, 420,360,260,205] def main(): t = turtle.Turtle() t.hideturtle() for i in range(5): drawFilledRectangle(t,-200+(76*i),0,76,heights[i]/4,"black","light blue") displayText(t) def drawFilledRectangle(t,x

真伪难定 达芬奇还画了半裸版《蒙娜丽莎》?q

且看?"忽如一夜春风来,千树万树梨花开".与俄方人员沟通协调后,"雪鹰12"第二个飞行架次才开始转移受困人员.王先生说,10月中旬有人挖开路面进地沟维修管道,维修完毕之后重新抹了路面,但是挖出来的砖块土石却堆放在了巷子里.这次会议通过了"维也纳宣言",选举产生了新一届领导.定罪证据确实.充分,但影响量刑的证据存疑的,应当在量刑时作出有利于被告人的处理."读者服务部定期召开读者座谈会,诚恳征求读者意见,交流读报心得,向读者推荐书刊,开展有

你了解蒙娜丽莎(敏捷大数据)的真正面目吗

我在前文<论大数据的泡沫.价值与应用陷阱>有说到,大数据现象源于我们对未来不确定性的恐惧,和应对软件在加速吞噬世界(软件越来越庞杂,操作越来越自动化,数据越来越丰富,而大部分人却对其原理和特性却知之甚少)这一大背景下的管理失控问题.大数据规律的可预测性创造了一种新的知识体系和管理思维,但分析模型的黑箱和操作的自动化却削弱了人类对其深层规律的理解和探索能力,机器的量化能力与人的主观判断能力短时间内还难以有机融合,大数据应用不缺预测模型.计算资源和数据科学家,而是缺乏提出正确问题和利用大数据工具解

如何在论文中画出漂亮的插图?

知乎用户的回答(1259票)]: 强烈推荐 Python 的绘图模块 matplotlib: python plotting .画出来的图真的是高端大气上档次,低调奢华有内涵~ 适用于从 2D 到 3D,从标量到矢量的各种绘图.能够保存成从 eps, pdf 到 svg, png, jpg 的多种格式.并且 Matplotlib 的绘图函数基本上都与 Matlab 的绘图函数名字都差不多,迁移的学习成本比较低.开源免费.如图所示(题目描述中的图在最后): (以下图片均引用自 Thumbnail

linux下处理excel里copy的某列的字符串,去除行末空格并添加特殊字段

背景:从excel里copy出一列数据到txt,然后放到lunx下处理,发现每一行末尾都是固定个数的空格,我想要在每行字符串末尾加固定字段并逗号隔开输出, cat fastjason.txt | awk -F / '{print $3}' | sort | uniq > fast.log将特定字段取出 :cat fast.log |xargs echo >fast.log 去掉每行末尾的不定个数空格,全部放到一行,每个应用以空格隔开:sed -i 's/ /\n/g' fast.log,将空格

python—networkx:在一张图中画出多个子图

通过plt.subplot能够在一张图中画出多个子图 #coding: utf-8 #!/usr/bin/env python """ Draw a graph with matplotlib. You must have matplotlib for this to work. """ __author__ = """Aric Hagberg ([email protected])"""

用Python提取XML里的内容,存到Excel中

最近做一个项目是解析XML文件,提取其中的chatid和lt.timestamp等信息,存到excel里. 1.解析xml,提取数据 使用python自带的xml.dom中的minidom(也可以用lxml) xml文件如下: minidom.parse()#解析文件,返回DOM对象 _get_documentElement()DOM是树形结构,获得了树形结构的根节点 getElementsByTagName()根据name查找根目录下的子节点 getAttribute()获取DOM节点的属性的