后端编程Python3-图形处理类(python图形化编程工具哪个好)
off999 2024-10-19 07:15 27 浏览 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图形处理类,更多实操示例请参照视频讲解。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。
相关推荐
- 华硕售后服务中心查询(华硕售后维修服务网点查询)
-
首先查看包装盒、保修卡、机器底部。三个地方的SN码及机器的序列号是不是一致。如果不一致那一定是有问题的。2然后,如果一致,我们可以拨打华硕的客服,通过机器的序列号,查询机器的基本情况,然后与说明书上的...
- 如何更改硬盘分区(硬盘怎么更改分区)
-
要修改磁盘分区,首先需要使用磁盘管理工具,如DiskManagement(Windows)或DiskUtility(Mac)。在工具中,选择要修改的磁盘并右键点击,然后选择“修改分区”选项。接着,...
- 无线路由器当交换机使用(路由器当交换机用无线wifi还可以上网吗)
-
若您想将无线路由器用作交换机,您可以按照以下步骤操作:1.确保您的无线路由器具有交换器功能。不是所有的无线路由器都具备此功能,请先确保您的设备支持。2.将您的无线路由器与网络中的其他设备连接。通常...
- computer(computer lab)
-
"电脑"这个名称实际上是人们对具有计算功能电子设备的俗称。而计算机(Computer)则是这个设备的正式名称,因为"计算"是其核心功能。在英文中,Computer是指可...
- 电脑重置20多个小时了(重置电脑一直12%)
-
重置电脑时间太长了解决办法如下1、将电脑关机然后开机或者直接点击重启,然后按住DELETE键,电脑会自动进入到BIOS;2、电脑屏幕上会显示两个选项,两个选项一般都在电脑屏幕的右方;3、其中一个选项是...
- 电脑虚拟机是什么(电脑虚拟机有啥用)
-
电脑虚拟机(VirtualMachine,VM),也称为虚拟计算机,是一种软件模拟的计算机,它在现有的计算机硬件上创建一个虚拟的计算机环境。这个虚拟环境可以用来运行操作系统、应用程序等软件,就像是在...
- 键盘图片大图(键盘图片大图清晰)
-
这个是仿苹果机上的无线键盘(妙控一代)的,属于山寨产品。1、在手机的微信或者短信或者其他可以打开键盘的应用中打开键盘,点击键盘左上角的输入法设置图标,页面显示输入法的各种设置功能;2、在输入法的设置...
- win11系统可以更新吗(w11系统可以用了吗)
-
可以1.点击“开始”,打开“设置”。2.找到“更新和安全”,选择“预览体验计划”。3.点击“开始”,需要登录微软账户。4.登录完成后弹出一个升级的渠道,选择dev进行下载win11即可。方法二:首...
- winxp安装系统镜像iso下载(xp的镜像系统怎么安装)
-
要安装一个ISO镜像文件,首先需要将ISO文件挂载到计算机上。在Windows系统中,可以右键点击ISO文件,并选择“挂载”选项,然后打开文件资源管理器就能看到ISO文件被挂载的虚拟驱动器。在Linu...
-
- 海尔电脑系统一键还原(海尔电脑怎么重置系统)
-
第一步:安装驱动程序保障计算机内至少有一个呵呵作系统且保证系统完好,如果有多个呵呵作系统,在呵呵作系统完好的情况下需要在各呵呵作系统内安装驱动程序,如果呵呵作系统为Windows98/ME,则需要安装haier98.exe;如果呵呵作系统为...
-
2025-12-27 01:51 off999
- 拼多多下载安装(拼多多下载安装免费2025版本)
-
一般有人问你有没有拼多多,都是想请你帮忙拼多多平台活动助力。 ...
- 联想电脑安装系统步骤(联想电脑安装系统教程)
-
联想电脑系统重装的方法如下1、制作好U盘启动盘,然后把下载的联想win7系统iso文件直接复制到U盘的GHO目录下:2、在联想电脑上插入U盘,重启后不停按F12或Fn+F12快捷键打开启动菜单,选择U...
- ppt自动生成网站(ppt 自动生成)
-
可以使用以下方法一键生成PPT:1.使用PPT模板:选用一个PPT模板,将图片插入到模板中相应的位置即可。2.使用图像转换器:将多张图片转换成PPT格式,然后将它们放在PPT中的相应位置。3.使用第...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
python入门到脱坑 输入与输出—str()函数
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
失业程序员复习python笔记——条件与循环
-
系统u盘安装(win11系统u盘安装)
-
- 最近发表
- 标签列表
-
- 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)
