Python兴趣编程百例:手把手带你开发一个图片转字符图的小工具

在数字世界的无尽探索中,我们时常被那些看似平凡的技术所启发,它们如同星辰般点缀着我们的创意天空。今天,我突发奇想,想要用Python开发一个将图片转化为字符画的小工具。这不仅是一次技术的实践,更是一场艺术与科技的奇妙融合。

让我们一起踏上这段旅程,用Python的代码,绘制出属于我们自己的字符画世界。在这个世界里,每一行代码都是一笔,每一次运行都是一次创作,每一张字符画都是一次心灵的触动。

1.功能概述

使用PyQt5框架开发的ASCII字符画生成器。用户可以通过该程序加载图片,将其转换为ASCII字符表示,并保存生成的ASCII字符画。

效果图 

2.设计思路

  1. 用户界面设计:使用PyQt5创建一个图形用户界面,包括图片显示区域、文本编辑区域、ASCII字符设置区域和操作按钮。
  2. 图片处理:加载图片后,调整图片大小并转换为灰度图像,以便于生成ASCII艺术。
  3. ASCII艺术生成:根据灰度图像的像素值,将每个像素映射到预设的ASCII字符集中的一个字符。
  4. 保存ASCII艺术:将生成的ASCII字符串保存为文本文件。

3.主要函数解析

  • __init__:初始化主窗口,设置UI元素。
  • initUI:设置窗口标题和布局,添加必要的控件和按钮。
  • load_image:打开文件对话框,加载用户选择的图片。
  • resize_image:调整图片大小,保持宽高比。
  • grayify:将图片转换为灰度图像。
  • generate_ascii:生成ASCII艺术,将灰度图像转换为ASCII字符串,并在文本编辑器中显示。
  • save_ascii:保存生成的ASCII艺术到文本文件。
  • pixels_to_ascii:将灰度图像的像素转换为ASCII字符。

4.详细设计

  1. 界面设计

    • 左侧区域用于显示原始图片。
    • 右侧上半部分用于显示生成的ASCII字符。
    • 右侧下半部分包括:
      • 自定义ASCII字符输入框。
      • 加载图片、生成ASCII、保存ASCII的按钮。
  2. 功能实现

    • 加载图片:用户点击按钮后,通过文件对话框选择图片文件,加载并显示在左侧区域。
    • 生成ASCII:点击按钮后,程序将图片转换为灰度并调整大小,然后根据灰度值映射到ASCII字符,结果显示在右侧文本编辑区域。
    • 保存ASCII:用户点击按钮后,选择保存位置和文件名,将文本编辑区域的内容保存为文本文件。
  3. 错误处理

    • 在加载图片和生成ASCII时,程序会检查是否有图片路径,如果没有则不执行后续操作。
    • 在生成ASCII时,如果自定义的ASCII字符集为空,程序会提示用户输入。
  4. 用户体验

    • 提供清晰的界面布局和直观的操作流程。
    • 在执行可能耗时的操作(如生成ASCII)时,提供进度反馈或加载指示。

5.完整代码 

# -*- coding: gbk -*-
"""
Created on 2024/6/18 11:22

@Deprecated: 
@Author: DanMo
@File : ASCIIArtGenerator.py
"""
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QTextEdit, QFileDialog, QVBoxLayout, \
    QHBoxLayout, QWidget, QLineEdit
from PyQt5.QtGui import QPixmap
from PIL import Image


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.ASCII_CHARS = '@%#*+=-:. '

        self.initUI()

    def initUI(self):
        self.setWindowTitle('ASCII Art Generator')

        central_widget = QWidget(self)
        self.setCentralWidget(central_widget)

        # 创建布局
        main_layout = QHBoxLayout(central_widget)

        # 左侧显示图片的部分
        self.label = QLabel(self)
        main_layout.addWidget(self.label)

        # 右侧操作部分
        right_layout = QVBoxLayout()

        self.textEdit = QTextEdit(self)
        right_layout.addWidget(self.textEdit)

        # 添加设置ASCII字符的部分
        ascii_label = QLabel('Custom ASCII Chars:', self)
        right_layout.addWidget(ascii_label)

        self.ascii_edit = QLineEdit(self)
        self.ascii_edit.setText(self.ASCII_CHARS)
        right_layout.addWidget(self.ascii_edit)

        button_layout = QHBoxLayout()
        self.btnLoad = QPushButton('Load Image', self)
        self.btnLoad.clicked.connect(self.load_image)
        button_layout.addWidget(self.btnLoad)

        self.btnGenerate = QPushButton('Generate ASCII', self)
        self.btnGenerate.clicked.connect(self.generate_ascii)
        button_layout.addWidget(self.btnGenerate)

        self.btnSave = QPushButton('Save ASCII', self)
        self.btnSave.clicked.connect(self.save_ascii)
        button_layout.addWidget(self.btnSave)

        right_layout.addLayout(button_layout)
        main_layout.addLayout(right_layout)

        self.resize(800, 600)  # 初始窗口大小

    def load_image(self):
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(self, "Open Image File", "", "Image Files (*.png *.jpg *.jpeg *.bmp)",
                                                  options=options)
        if fileName:
            pixmap = QPixmap(fileName)
            self.label.setPixmap(pixmap)
            self.image_path = fileName

    # 调整图片尺寸并灰度化
    def resize_image(self, image, new_width=100):
        width, height = image.size
        ratio = height / width / 2
        new_height = int(new_width * ratio)
        resized_image = image.resize((new_width, new_height))
        return resized_image

    def grayify(self, image):
        return image.convert('L')

    def generate_ascii(self):
        if not hasattr(self, 'image_path'):
            return
        try:
            image = Image.open(self.image_path)
        except Exception as e:
            print(e)
            return

        image = self.resize_image(image, new_width=100)
        image = self.grayify(image)
        self.ASCII_CHARS = self.ascii_edit.text()
        if not self.ASCII_CHARS:
            print('Please input ASCII_CHARS!')
            return
        ascii_str = self.pixels_to_ascii(image)
        img_width = image.width

        ascii_img = ''
        for i in range(0, len(ascii_str), img_width):
            ascii_img += ascii_str[i:i + img_width] + '\n'

        self.textEdit.setPlainText(ascii_img)

    def save_ascii(self):
        if not hasattr(self, 'image_path'):
            return
        try:
            image = Image.open(self.image_path)
        except Exception as e:
            print(e)
            return

        image = self.resize_image(image, new_width=100)
        image = self.grayify(image)
        self.ASCII_CHARS = self.ascii_edit.text()
        if not self.ASCII_CHARS:
            print('Please input ASCII_CHARS!')
            return
        ascii_str = self.pixels_to_ascii(image)
        img_width = image.width

        ascii_img = ''
        for i in range(0, len(ascii_str), img_width):
            ascii_img += ascii_str[i:i + img_width] + '\n'

        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getSaveFileName(self, "Save ASCII File", "", "Text Files (*.txt)", options=options)
        if fileName:
            with open(fileName, 'w') as f:
                f.write(ascii_img)

    def pixels_to_ascii(self, image):
        pixels = image.getdata()
        ascii_str = ''
        for pixel in pixels:
            # 确保灰度值在合理范围内
            pixel_char = self.ASCII_CHARS[min(len(self.ASCII_CHARS) - 1, pixel // 25)]
            ascii_str += pixel_char
        return ascii_str


def main():
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

 6.效果展示

 自定义设置字符

另存为文本

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/719696.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32学习笔记(三)--EXTI外部中断详解

(1)配置步骤1.配置RCC 打开外设时钟2.配置GPIO 选择端口输入模式3.配置AFIO 选择要用的一路GPIO 连接至EXTI 4.配置EXTI 选择边沿触发方式 上升沿 下降沿 双边沿 选择触发响应方式 中断响应 事件响应 5.配置NVIC 选择一个合适的优先…

乡村养老服务管理系统的设计

管理员账户功能包括:系统首页,个人中心,医疗人员管理,乡村志愿者管理,文娱活动管理,活动报名管理,医疗保健管理 前台账户功能包括:系统首页,个人中心,文娱活…

运维技术栈总结

文章目录 Linux CommandBasecd/lschmod/chown/chgrpvi/vimscptarsudf Installrpmyumdeb/apt Filtertailgrepawkfindnetstatechotelnetwhereistouch/mkdirgzip/rar/tar Statistics Linux MonitorCPUtophtopsar Memoryfreevmstat I/Oiostatpidstatiotop Networknetstatiftoptcpdu…

Azure创建虚拟机

Azure创建虚拟机 一、创建步骤(1)登录到Azure portal(2)启动新实例(3)填写必要信息选择系统镜像(4)选择实例类型(5)配置管理员帐户和入站端口规则(6) 磁盘:保持默认(7) 网络:保持默认(8) 管理:保持默认(9) Monitoring:Boot diagnostics选择Disable(10) 最后直接点击查看 + …

屏蔽房是做什么用的?为什么需要定期检测?

屏蔽房对于不了解的人来说,可能光看名字不知道是做什么的,但是对于一些企业或者机构,却是再熟悉不过的了。和名字一样,屏蔽房是对空间内的信号以及一些外界环境条件进行隔绝,在一些有特殊要求的企业机构中,…

STM32中五个时钟源:HSI、HSE、LSI、LSE、PLL

时钟系统是处理器的核心,或者说时钟是单片机的心脏。 1.单片机内部需要储存器、累加器,这些都需要逻辑门电路。比如锁存器就是一个D触发器,而触发器的置1、清0、置数的功能都需要跳变沿。D触发器就是上升沿后存入数据,而这个上升…

硬件电路基础【5.二极管】

二极管 前言一、基本原理1.1 介绍1.2 结构组成1.3 符号1.4 正负极判断 二、特性参数开关电路注意的参数极限特性电气特性特性曲线 三、应用场景稳压二极管原理故障特点连接方式参数最大额定参数电气特性特性曲线 应用典型的串联型稳压电路过压保护稳压二极管的应用与选择 肖特基…

如何使用ChatGPT等大模型翻译视频?2024最新翻译技巧分享

随着全球化的浪潮,跨语言沟通的需求日益增长。视频,作为一种生动直观的表达方式,也越来越需要跨越语言的障碍,触达更广泛的受众。因此,视频翻译成为了一个重要的领域,为不同语言背景的人们打开了理解彼此、…

ChatGPT的问题与回复的内容导出(Chorme)

我给出两种方式,第一种方式无使用要求,第二种方式必须安装Chorme 个人更推荐第二种方式 第一种方式:使用chatgpt自带的数据导出 缺点:会将当前未归档的所有聊天记录导出,发送到你的电子邮箱中 第二种方式&#xff1a…

基于STM32的智能水产养殖系统(三)

智能水产养殖系统设计 背景 智能水产养殖系统的设计背景主要源于对传统养殖方式的现代化需求和技术进步的推动。以下是该背景的详细阐述: 现代化养殖需求增加: 随着人口增长和食品需求的提升,传统的水产养殖方式面临诸多挑战,如资…

基于51单片机的脉搏测量仪—心率计

基于51单片机的脉搏测量仪 (仿真+程序+原理图+设计报告) 功能介绍 具体功能: 本系统由STC89C51/52单片机LCD1602显示模块5mm红外接收管LM358运放电路按键模块等构成 1.手指放到红外对管中,2…

带你走进CCS光源——环形低角度光源LDR2-LA系列

机器视觉系统中,光源起着重要作用,不同类型的光源应用也不同,选择合适的光源成像效果非常明显。今天我们一起来看看CCS光源——工业用环形低角度光源LDR2-LA系列。 LDR2-LA系列 采用柔性基板,创造最佳倾斜角度。 通过从低角度向…

微信小程序 - 出于性能原因,对长行跳过令牌化。长行的长度可通过 “editor.maxTokenizationLineLength” 进行配置

问题描述 出于性能原因,对长行跳过令牌化。长行的长度可通过 “editor.maxTokenizationLineLength” 进行配置。 解决方案 设置 - 编辑器设置 - 更多编辑器设置... 搜索:maxtoken,原来是 20000,我改成了 200000 即可~

海南云亿商务咨询有限公司抖店开店怎么样?

在数字化浪潮席卷全球的今天,电商行业日新月异,其中抖音电商以其独特的短视频直播模式,迅速崛起成为电商领域的新贵。海南云亿商务咨询有限公司,作为抖音电商服务的佼佼者,凭借专业的团队和丰富的经验,致力…

批量导出兜底回复对话,迭代优化聊天机器人 | Chatopera 云服务

持续优化知识库 聊天机器人的知识库,对话技能,需要长期的优化。这是因为,一方面,初期上线的机器人所依赖的数据量通常有限;另一方面,市场不断变化,客户产品新的问题。 上线聊天机器人的目的之…

基于Django、Bootstrap的电影推荐系统,算法基于用户的协同过滤算法,有爬虫有可视化后台

背景 基于Django和Bootstrap的电影推荐系统结合了用户协同过滤算法,通过爬虫技术获取电影数据,并在可视化后台展示推荐结果。该系统旨在提供个性化的电影推荐服务,帮助用户发现符合其喜好的电影。 用户协同过滤算法是一种常用的推荐算法&am…

蓝卓创始人褚健:工厂操作系统+APP,加速工业数字化转型

如何让众多的中小企业通过低成本的方式实现收益,享受到工业互联网、数字化转型带来的效益,是解决中小企业数字化转型难的核心问题。 中小企业规模庞大,数字化转型压力巨大 褚健表示,中国拥有最庞大的工业企业集群,全国…

STM32高级控制定时器(STM32F103):PWM输出模式

目录 概述 1 PWM模式介绍 2 PWM类型 2.1 PWM边缘对齐模式 2.2 PWM中心对齐模式 3 使用STM32Cube配置PWM 3.1 STM32Cube配置参数 3.2 生成Project 4 设置PWM占空比 4.1 函数介绍 4.3 函数源码 5 测试代码 5.1 编写测试代码 5.2 函数源码 6 运行代码 概述 本文主…

29. 透镜阵列

导论: 物理传播光学(POP)不仅可以用于简单系统,也可以设计优化复杂的光学系统,比如透镜阵列。 设计流程: 透镜阵列建模 在孔径类型中选择“入瞳直径”,并输入2 在视场设定中。设置一个视场&…

将自己md文件发布到自己的博客园实现文件的持久化存储

上传markdown文件到博客园 目录 【0】需求原因【1】功能【2】环境【最佳实践测试】 (1)查看 Typora 设置(2)配置 pycnblog 配置文件 config.yaml(3)运行 pycnblog 中的文件 cnblog_markdown.cmd&#xff0…