前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python 图片转lego积木风格

python 图片转lego积木风格

作者头像
叶子陪你玩
发布2022-05-22 15:00:11
9131
发布2022-05-22 15:00:11
举报

一年前写过一个图片转乐高积木风格的代码,

python 将图像转换为乐高积木风格图片(上)

python 将图像转换为乐高积木风格图片(下)

没想到派上用场了,前一段时间有一个读者关注,说想要给女朋友做一个乐高的画。

当时我直接给它推荐了工具,不知道是没用对,还是工具怎么了,说效果不行。

后面给我发了好几张照片,我想既然这样,我就用我之前的工具给它试试,结果说生成的像素太多了,买积木可能要很多,中间断断续续找我很多次,最后没办法,重新改了一下之前的缩放比例,保证宽不超过60个积木片,效果很满意。

互联网真的很奇妙,没想到我的代码还有这样的功效,有相同需求的可以留言,毕竟做好事我还是愿意的。

没有需求,那就五一快乐吧。

源代码:

代码语言:javascript
复制
from PIL import Image
import matplotlib.pyplot as plt
import collections
import json
from PIL import Image
import numpy as np
import openpyxl
from openpyxl.drawing.image import Image as xl_img
from openpyxl.styles import Alignment

# 忽略numpy 版本警告
np.warnings.filterwarnings('ignore', category=np.VisibleDeprecationWarning)

# 读取颜色数据
with open("color.json","r",encoding="utf-8") as f:
    data = json.load(f)
    
def img_to_pixel(img_name, block_size):
    """
    img:image path
    block_size:pixel size
    """
    pic = Image.open(img_name)
    level = 10 #pic.width//100
    # 将原图缩小level倍
    pic.thumbnail((int(pic.size[0]/level),int(pic.size[1]/level)))
    width, height = pic.size
    board = Image.new(
        "RGB", (width//block_size*block_size, height//block_size*block_size))
    # 循环处理图片
    for y in range(0, height, block_size):
        for x in range(0, width, block_size):
            # 每隔一段距离切一块图片
            temp = pic.crop((x, y, x+block_size, y+block_size))
            temp_list = list(temp.getdata())
            # 获取数量最多的像素值
            max_color = collections.Counter(temp_list).most_common()[0][0]
            # 创建该像素值图片
            temp_past = Image.new("RGB", temp.size, max_color)
            # 粘贴图片
            board.paste(temp_past, (x, y))
    # 再缩小两倍
    board = board.resize((int(board.size[0]/2),int(board.size[1]/2)))
    # 保存到本地
    board.save(f"{img_name[0:-4]}_pixel.jpg")
    # 返回原图和像素图
    return pic, board

# 查找最接近的颜色
def find_approach(pixel):
    # 获取颜色名
    colors = np.array(data)[:,0]
    # 获取RGB值
    colors_pixel = np.array(data)[:,1:].tolist()
    # 计算乐高图片与图片RGB值差值
    compare_value = colors_pixel-np.array(pixel)
    # 计算差值绝对值
    compare_abs = np.abs(compare_value)
    # 将RGB三者的绝对值相加
    compare_add = np.sum(compare_abs,axis=2)
    # 计算相差最小的值
    min_value = np.min(compare_add)
    # 确定最小值所在数据中的索引值
    min_value_index  = np.where(compare_add == min_value)[0]
    # 如果有多个相似值
    if len(min_value_index)>1:
        # 选取第一个
        min_value_index=min_value_index[0]
        # 获取对应的颜色名
        color_name = colors[min_value_index]
    else:
        # 获取颜色名,需要转换一下numpy数据到string
        approach_color = colors[min_value_index]
        color_name = np.array2string(approach_color).replace("['","").replace("']","").replace("'","")
    
    return color_name

# 生成乐高图片
def generate_lego_img(board):
    # 创建一个画板,用来贴图
    new_board = Image.new("RGB", (board.size[0]*20, board.size[1]*20), "white")

    # 创建积木清单字典
    block_list = {}

    # 循环处理图片
    for row in range(board.size[0]):
        for col in range(board.size[1]):
            # 获取像素值
            r, g, b = board.getpixel((row, col))
            # 找到最接近的颜色
            color_name=find_approach([r,g,b])
            # 将积木数量加 1
            if color_name in block_list:
                block_list[color_name] += 1
            else:
                block_list[color_name] = 1
            # 打开最接近颜色的积木图片
            img_temp = Image.open(f"pic/{color_name}.jpg").resize((20,20))
            # 粘贴到画板上
            new_board.paste(img_temp, (20*row, 20*col))
    # 保存乐高图片到本地
    new_board.save(f"{img_name[0:-4]}_lego.jpg")
    # 返回零件清单
    return block_list

# 生成零件清单
def generate_block_list(block_list):
    wb = openpyxl.Workbook()
    ws = wb.active
    # 设置居中样式
    align = Alignment(horizontal="center",vertical="center")
    # 添加表头
    ws.append(["颜色","积木块","数量(块)"])
    ws[f"A1"].alignment = align
    ws[f"B1"].alignment = align
    ws[f"C1"].alignment = align
    # 读取数据添加到表格中,并设置表格样式
    for i in range(len(block_list.keys())):
        color = list(block_list.keys())[i]
        img = xl_img(f"pic/{color}.jpg")
        num = block_list[color]
        ws.append([color,"",num])
        ws.column_dimensions["A"].width = 20
        ws.column_dimensions["B"].width = img.width*0.14
        
        ws.add_image(img,f"B{i+2}")
        ws.row_dimensions[i+2].height = img.height*0.75
        ws[f"A{i+2}"].alignment = align
        ws[f"B{i+2}"].alignment = align
        ws[f"C{i+2}"].alignment = align
    # 保存清单文件
    wb.save(f"{img_name[0:-4]}_积木清单.xlsx")

if __name__ == "__main__":
    img_name = "51.png"
    # 生成像素图
    _,board = img_to_pixel(img_name,1)
    # 生成乐高图,并返回零件数据
    block_list = generate_lego_img(board)
    # 生成零件清单
    generate_block_list(block_list)
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-05-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 叶子陪你玩编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档