后端编程Python3-图形处理类(python图形化编程工具哪个好)
off999 2024-10-19 07:15 22 浏览 0 评论
本节是第五讲的第十四小节,本节参照上一节所讲的python面向对象的知识,以一个图形处理的类讲解如何创建聚集组合数据的类。
创建聚集组合数据的类(Creating Classes That Aggregate Collections)
用于表示2D颜色图像的一个简单方法是使用一个2维数组,每个数组元素代表一种颜色。因此,如果需要表示一个100x100的图像,我们就必须存储10000个颜色。 对Image类(在文件Image.py中),我们将釆取一种具有更加高效的潜力的做法。Image 存储一种单一的背景色,图像中各个点的颜色则不同于背景色。这是通过将字典用作稀疏数组实现的,字典中的每个键是一个(x,y)坐标,对应的值则为该点的颜色。如果我们有一个100x100的图像,并且其中半数的点都与背景色相同,那么只需要存储 5 000 + 1种颜色,从而大幅节省内存资源。
Image.py模块釆用了我们现在应该已经熟悉的模式:模块从一个shebang行开始,之后是注释中的版权信息。再之后是模块的docstring以及一些doctests/接下来是导入语句,本模块中需要导入os模块与pickle模块。在讲解图像的加载与保存时,我们将简要讲述Pickle模块的使用。在导入相应模块之后,我们创建一些自定义异常类:
class lmageError(Exception): pass
class CoordinateError(lmageError): pass
我们只是展示了头两个异常类,其他异常类(LoadError、SaveError、ExportError 与NoFilenameError)的创建方式是相同的,并且也都继承自ImageError。
Image类的使用者可以对任一种特定的异常进行测试,也可以只对基类的ImageError异常进行测试。
该模块的余下部分包括Image类的主体,最后则是用于运行模块的doctests的标准的三行代码。在具体讲解该类及其方法之前,我们先看一下该类如何使用:
border_color =“#FF0000" # red
square_color = "#0000FF” # blue
width, height = 240, 60
midx,midy = width // 2, height // 2
image = Image.Image(width, height, "square_eye.img")
for x in range(width):
for y in range(height):
if x < 5 or x >= width - 5 or y < 5 or y >= height - 5:
image[x, y] = border_color
elif midx - 20 < x < midx + 20 and midy - 20 < y < midy + 20:
image[x, y] = square_color
image.save()
image.export("square_eye.xpm")
注意,我们可以使用项存取操作符([])来设置图像中的颜色。方括号也可以用于对特定(x,y)坐标的颜色进行获取或删除,也可以有效地将其颜色设置为背景色。坐标是以单独的元组对象的形式进行传递的(借助于其中的逗号操作符),就像我们使用 image[(x, y)]这种表达方式一样。在Python中,实现这种无缝的语法整合是容易的 ——我们只需要实现适当的特殊方法,比如,对项存取操作符,对应的特殊方法包括 __getitem__()、__setitem__()与__delitem__()。
Image类使用HTML风格的十六进制字符串表示颜色。在创建图像时就必须设置背景色,否则就默认为白色。在存储与加载图像时,Image类使用其自定义格式,但也可以使用.xpm格式导出,该格式很多图像处理应用程序都可以理解。如图展示了上面的代码段生成的.xpm图像。
现在我们来看Image类的方法,从class行与初始化程序开始。创建Image时,使用者(该类的使用者)必须指定宽度与高度,但文件名与背景色则是可选的,因为有默认值。字典self.__data的键是(x, y)坐标,值为颜色字符串。集合self.__colors使用背景色进行初始化,并用于追踪图像中使用的各种排他性的颜色。
除文件名外,所有数据属性都是私有属性,因此,必须提供一种途径,以便使用者可以对这些属性进行存取。通过使用特性,可以容易地做到这一点。
class Image:
def __init__(self, width, height, filename=“”,background=“#FFFFFF"):
self.filename = filename
self.__background = background
self.__data = {}
self.__width = width
self.__height = height
self.__colors = {self.__background}
@property
def background(self):
return self.__background
@property
def width(self):
return self.__width
@property
def height(self):
return self.__height
@property
def colors(self):
return set(self.__colors)
在返回对象的某个数据属性时,我们需要知道该属性是属于可变类型还是固定类型,返回固定类型总是安全的,因为这种类型的数据属性不能改变,但对于可变类型的数据属性,我们必须考虑某种折衷。返回对可变属性的引用是非常快速高效的,因为并没有实际的复制操作发生——但这也意味着调用者可以对对象的内部状态进行存取,并可能在对其改变时导致对象无效。一种解决方案是总是返回可变数据属性的副本,除非有证据表明这种做法会对性能产生很大的负面影响。(这种情况下,保证颜色集合有效的一种替代方法是在需要颜色集合时,总是返回set(self.__data.values()) | {self.__background}。)
#这一方法将返回给定坐标的颜色(使用项存取操作符[])
def__getitem__(self, coordinate):
assert len(coordinate) == 2, "coordinate should be a 2-tuple"
if (not (0 <= coordinate[0] < self.width) or not (0 <= coordinate[1] < self.height)):
raise CoordinateError(str(coordinate))
return self.__data.get(tuple(coordinate), self.__background)
下表列出了用于项存取操作符的特殊方法以及其他一些组合类型相关的特殊方法。
特殊方法 使用 描述
__contains__(self,x) x in y 如果x在序列y中或x是映射y中的键,就返回True
__delitem__(self,k) del y[k] 删除序列y中的第k项或映射y中键为k的项
__getitem__(self,k) y[k] 返回序列y中的第k项或映射y中键为k的项的值
__iter__(self) for x in y: pass 返回序列y中的项或映射y中键的迭代子
__len__(self) len(y) 返回y中项的个数
__reversed__(self) reversed(y) 返回序列y中的项或映射y中键的反向迭代子
__setitem__(self, k, v) y[k] = v 将序列y中的第k项(或映射y中键为k的项)设置为v
def__setitem__(self, coordinate, color):
assert len(coordinate) == 2, "coordinate should be a 2-tuple"
if (not (0 <= coordinate[0] < self.width) or not (0 <= coordinate[1] < self.height)):
raise CoordinateError(str(coordinate))
if color == self.__background:
self.__data.pop(tuple(coordinate), None)
else:
self.__data[tuple(coordinate)] = color
self.__colors.add(color)
我们对项存取釆用了两种策略。第一种策略的使用前提是,传递给项存取方法的坐标是长度为2的序列(通常是二元组),并使用断言来确保满足这一约束。第二种策略是接受任意的坐标值,如果超过取值范围,就产生自定义异常。
我们使用dict.get()方法来取回给定坐标的颜色(默认值为背景色),通过这一方法, 如果该坐标处的颜色尚未设置,就正确地返回背景色,而不是产生KeyError异常。
如果使用者将某坐标值设置为背景色,我们可以简单地将相应的字典项删除,因为字典中没有包含的坐标都假定使用背景色。为此,我们必须使用dict.pop()并给定另 一个单元参数,而不是使用del语句,因为这样可以保证在键(坐标)不存在于字典中的情况下,也可以避免产生KeyError异常。
如果颜色不同于背景色,我们就将给定的坐标指定为该颜色,并将该颜色添加到图像使用的颜色集中。
def __delitem__(self, coordinate):
assert len(coordinate) == 2, "coordinate should be a 2-tuple”
if (not (0 <= coordinate[0] < self.width) or not (0 <= coordinate!!] < self.height)):
raise CoordinateError(str(coordinate))
self.__data.pop(tuple(coordinate),None)
如果某坐标的颜色被删除,那么该坐标的颜色被设置为背景色。这里仍然需要使用dict.pop()来移除相应项,因为不管给定的坐标项是否存在于字典中,这一方法总是可以正确工作,而不会产生异常。
我们没有提供__len__()的实现,因为对二维对象而言,这一函数没有实际意义。 另外,我们也没有提供表象形式,因为Image不能仅通过调用Image()就完全实现,因 此,我们也没有提供__repr__()(或__str__())的实现。如果用户对Image对象调用repr() 或str(),那么object.__repr__()这一基类实现将返回适当的字符串,比如'<Image.Image object at 0x9c794ac>'。这是用于无法使用eval()评估的对象的标准格式,十六进制数字是对象ID—这是独一无二的(通常是对象在内存中所在地址),但是短暂的。
我们希望Image类的使用者可以保存与加载其图像数据,因此,我们提供了两个方法来完成这两个任务,分别为save()与load()。
为保存数据,我们采用的做法是对其进行pickling,在Python中,pickling是将 Python对象进行序列化(转换为字节序列,或转换为字符串)的一种方法。pickling 之所以强大,是因为进行pickling处理的对象可以是组合数据类型,比如列表或字典, 并且,即便要进行pickling处理的对象内部包含其他对象(包含其他组合类型,其中又可以嵌套地包含其他组合类型),仍然可以统一进行pickling处理——并且不会使得对象重复出现。
pickle可以直接地读入到Python变量中——我们并不需要进行任何分析或解释处理,因此,使用pickle是存取与加载数据的特别集合时的一种理想选择,尤其对小程序以及个人使用的程序。然而,pickle没有安全机制(没有加密,也没有数字签名),因此,加载来自不可信源的pickle可能是危险的。鉴于此,对那些不纯粹用于个人目的的程序,最好是创建一种专用于该程序的自定义文件格式。
def save(self, filename=None):
if filename is not None:
self.filename = filename
if not self.filename:
raise NoFilenameError()
fh = None
try:
data = [self.width, self.height, self.__background,self.__data]
fh = open(self.filename, "wb")
pickle.dump(data, fh, pickle.HIGHEST_PROTOCOL)
except (EnvironmentError, pickle.PicklingError) as err:
raise SaveError(str(err))
finally:
if fh is not None:
fh.close()
该函数的第一部分纯粹用于处理文件名。如果创建Image对象时没有指定文件名或没有设置文件名,就必须对save()方法给定显式的文件名(对这种情况,可以釆用 “另存为"的方式,并设置内部使用的文件名)。如果没有指定文件名,就使用当前的文件名;如果没有当前使用的文件名,也没有指定文件名,就会产生异常。我们创建一个列表(data)用于存放待存储的对象,包括self.__data字典(其中存放坐标-颜色项),但不包含颜色集,因为该数据集可能被重构。之后,我们以二进制写模式打开文件,并调用pickle.dump()函数将数据对象写入到文件中。这一部分功能实现完毕!pickle模块可以使用多种格式(在文档中称为protocols)对数据进行序列化,不同格式由pickle.dump()的第三个参数指定。Protocol 0表示的是ASCII,在调试时是有用的。我们使用了 protocol 3 (pickle.HIGHEST_PROTOCOL), 一种紧凑的二进制格式,这也是为什么要以二进制格式打开文件。
def load(self, filename=None):
if filename is not None:
self.filename = filename
if not self.filename:
raise NoFilenameError()
fh = None
try:
fh = open(self.filename,"rb")
data = pickle.load(fh)
(self.__width, self.__height, self.__background,self. __data) = data
self.__colors = (set(self.__data.values()) |{self.__background})
except (EnvironmentError, pickle.UnpicklingError) as err:
raise LoadError(str(err))
finally:
If fh is not None:
fh.dose()
读取pickle时,没有指定protocol——pickle.load()函数完全可以推断出用于自己的protocol。
这一函数开始时与save()函数类似,获取待加载文件的文件名。文件必须以二进制读模式打开,并使用语句data = pickle.load(fh)读入数据。data对象是对保存的数据的精确重建,因此,这里实际上是一个列表,包括宽度与长度整数值、背景色字符串以及包含坐标-颜色项的字典。我们使用元组拆分来将data列表的项赋值到适当的变量中,因此,此前存放的图像数据将丢失(可接受的)。
颜色集合的重建是通过提取字典(包含坐标-颜色项)中的所有颜色,之后添加背景色实现的。
def export(self, filename):
if filename.lower().endswith(".xpm"):
self.__export_xpm(filename)
else:
raise ExportError("unsupported export format:" +os.path.splitext(filename)[1])
我们提供了一个通用的导出方法,该方法使用文件扩展名确定调用哪一个私有方 法一对无法导出的文件格式,则产生异常。这里,我们仅支持保存到.xpm文件(仅对包含少于8930种颜色的图像)。我们没有给出__export_xpm()方法,因为该方法并不与本章的主题真正相关,但本书源代码中仍然包含了该方法。
以上内容部分摘自视频课程05后端编程Python14图形处理类,更多实操示例请参照视频讲解。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。
相关推荐
-
- erp管理软件(erp管理软件免费版)
-
用友的ERP应该说从3万-3000都有ERP的价格随着企业的规模不同,价格也是不一样的。因为企业规模不同产生的效果也是不一样的,所以用友的产品分T1/T3/T6/U8/U9/NC3万小企业做个财务业务一体化还是勉强可以做的。只...
-
2025-11-11 09:03 off999
- 笔记本启动黑屏怎么回事(笔记本启动黑屏没反应)
-
笔记本开机后黑屏最常遇到的一种情况:因随便点击垃圾网站而导致电脑中脑或受到木马的侵袭,致使电脑系统瘫痪,解决的办法就是重装电脑系统,装好系统后安装查毒软件,定期对电脑进行杀毒全盘扫描,然后平时尽量不要...
- win7系统怎么开wifi热点(win7如何开wifi热点)
-
1、首先确认你的无线网卡开启。在开始菜单中依次找到“所有程序”--“附件”--“命令提示符”,右键“以管理员身份运行”; 2、在“命令提示符”里输入“netshwlans...
- 无线路由桥接设置方法(无线路由器无线桥接设置)
-
1、首先在电脑上输入并登录第一台路由器的IP地址。2、进入路由器管理界面之后,点击“无线设置”,然后点击基本设置中设置“SSID号”,接着点击“信道”,然后设置固定信号道。3、返回无线设置菜单栏,选择...
- win10企业版激活命令(win10企业版cmd激活命令)
-
关于这个问题,Windows10企业版可以通过以下方法进行激活:1.使用企业版密钥激活:如果你已经有了Windows10企业版的密钥,可以在“设置”中的“更新和安全”中选择“激活”来输入密钥进行...
-
- 如何恢复备份数据(备份的数据怎么恢复到手机上)
-
把备份删了的话,一键还原目前是用不了的。现在唯一的办法,是从网上下载一个数据恢复类的软件,只要的备份还没有被别的软件覆盖,是应该可以数据恢复回来的。不能保证百分之百得成功,但是恢复几率还很大的,你可以试试,操作方法首先点击手机“设置”。然后...
-
2025-11-11 06:51 off999
- 笔记本无线网卡怎么使用(笔记本无线网卡怎么使用教程)
-
笔记本无线网卡设置;第一:你要确定你的本本是否有无线上网功能,如果没有就得加个无线网卡;第二:有的话就打开无线网络接受开关;第三:程序设置主要就是在网上邻居的属性里,打开无线上网打开“网上邻居”的“属...
- 鲁大师电脑版官方下载(鲁大师电脑版官方下载安装)
-
因为鲁大师是跑分软件,它会拖慢电脑的运行速度,还会占据大量的内存,如果你的电脑配置不是太好的话,装了鲁大师只会雪上加霜,非但得不到任何优化作用,还会拖慢电脑的启动速度,造成不必要的损耗。玩游戏都会卡顿...
- win10怎么开机进入安全模式(win10开机怎么进安全模式怎么进)
-
进入Windows10安全模式有以下几种方法:方法一:使用开机高级选项1.在按下电源开机键后,持续按住F8键,直到你进入启动选项页面;2.从菜单中选择“安全模式”。方法二:使用系统配置1...
- 华硕电脑怎么重新安装系统(华硕电脑怎么重新安装系统教程)
-
第一步:备份重要数据重装系统前,务必先备份重要的个人数据。你可以将数据保存在外部存储设备上,或者使用云存储服务,确保数据安全可靠。第二步:下载系统镜像为了重装系统,你需要下载华硕笔记本电脑适用的操作系...
- 电脑显示此windows副本不是正版
-
1、第一步在电脑搜索框搜索命令提示符,鼠标右键以管理员的身份运行,2、第二步以管理员身份进去命令提示符之后输入"SLMGR-REARM",3、第三步按回车键可以看到命令已经成功重启一下...
- 电脑怎么复制粘贴按键(电脑复制粘贴按键是哪个)
-
电脑键盘上的粘贴键是:Ctrl+V按键。具体操作:1、以在excel表格中进行复制粘贴操作为例,首先选中需要复制粘贴操作的单元格。2、然后按下键盘上的“Ctrl+C”按键执行复制操作。3、然后将鼠标单...
- 笔记本黑屏但还在运行(笔记本电脑黑屏但运行)
-
具体修复方法:1、直接按下电脑机箱上的启动键让电脑重启,等待重新正常进入系统中。然后打开电脑系统盘,右键点击c盘进入属性设置面板中;2、在硬盘的属性设置中切换到工具标签;3、在查错选项中点击检查错误按...
- 从u盘启动怎么弄bios(u盘怎么在bios启动)
-
1、开启电脑,在电脑出现开机画面的时候连续按下“Esc”键进入BIOS设置;(部分电脑可能会是Delete、F2或F6)2、进入BIOSFEATURESSETUP中,将Boot(启动顺序)设定为U...
- 两台电脑怎么共享文件夹(如何把电脑c盘的存储移到d盘)
-
一、QQ共享简单易行既然使用QQ直接传递文件行不通,那么不妨试试使用QQ的文件共享功能。1.共享文件点击QQ面板的“菜单”→“工具”→“共享文件”命令。在打开的共享文件窗口中,单击“新建共享”按钮,...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
慕ke 前端工程师2024「完整」
-
失业程序员复习python笔记——条件与循环
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
