实战PyQt5: 121-使用QImage实现一个看图应用
ztj100 2025-07-10 22:13 30 浏览 0 评论
QImage简介
QImage类提供了独立于硬件的图像表示形式,该图像表示形式可以直接访问像素数据,并且可以用作绘制设备。QImage是QPaintDevice子类,因此可以使用QPainter直接在图像上绘制。在QImage上使用QPainter时,可以在当前GUI线程以外的其他线程中执行绘制。
QImage提供了多种方式来读取图像文件,在创建QImage对象时可以加载图像文件,也可以在创建对象之后,使用load()或者loadFrameData()函数来加载图像。加载图像时,文件名可以是磁盘上的实际文件,也可以是嵌入到应用程序的资源。
QImage类支持包括单色,8位,32位和alpha混合图像。QImage提供了一组函数用于获取有关图像的各种信息和实现图像转换。
- 几何尺寸信息: 函数size(), width(), height(), dotsPerMeterX()和dotsPerMeterY()提供了图像的尺寸和纵横比信息。rect()函数返回图像的包围矩形,vaild()函数用于判断一组坐标是否位于这个包围矩形内。
- 色彩信息: 使用pixel()函数可以获得指定像素的颜色,该颜色是一个独立于文件格式的QRgb值。对于单色或者8位图像,colorCount()和colorTable() 函数提供了有关用于存储图数据的颜色分量的信息。hasAlphaChannel()返回函数是否有alpha通道的信息。
- 文本信息: text() 函数返回给定文本关键值的图像文本信息。函数textKeys()返回图像的文本关键值信息。
- 底层信息: depth()函数返回图像的位深度信息。图像支持的深度信息把包括1(单色),8、16、24和32位。bitPlaneCount()返回图像的位平面数。
像素操作
QImage的像素操作功能取决于图像格式而有所不同,原因是单色和8位图像的颜色是基于索引值,使用颜色查找表来获得,而32位图像则直接存储ARGB值。
如果是32位图像,则可以使用setPixel()函数为给定的像素设置一个ARGB颜色值。例如:
image = QImage(3, 3, QImage.Format_RGB32)
value = qRgb(180, 149, 39) # 0xffbd9527
image.setPixel(1, 1, value)
value = qRgb(122, 163, 39) # 0xff7aa327
image.setPixel(0, 1, value)
image.setPixel(1, 0, value)
value = qRgb(237, 187, 51) # 0xffedba31
image.setPixel(2, 1, value)
用一个方格表示一个像素,上面代码生成的图像可以用下图来描述:
对于8位和单色图像,像素值为图像颜色表中的索引值,因此setPixel()函数只能用于将给定位置的像素颜色设置为图像颜色表中的预定义的颜色值,即是说,它只能改变像素的索引值。若需要更改颜色或者将颜色添加到图像的颜色表中,可以使用setColor()函数来完成。颜色表中的一项为一个ARGB颜色值,使用qRgb()和qRgba()函数可以为setColor()提供需要的QRgb值。例如:
image = QImage(3, 3, QImage.Format_Indexed8)
value = qRgb(122, 163, 39) # 0xff7aa327
image.setColor(0, value)
value = qRgb(237, 187, 51) # 0xffedba31
image.setColor(1, value)
value = qRgb(180, 149, 39) # 0xffbd9527
image.setColor(2, value)
image.setPixel(0, 1, 0)
image.setPixel(1, 0,0)
image.setPixel(1,1,2)
image.setPixel(2,1,1)
用一个方格表示一个像素,上面代码生成的图像可以用下图来描述:
图像格式
QImage中存储的每个像素都由整数表示。整数的大小取决于格式。QImage支持QImage.Format枚举描述的图像格式。Qt提供以下图像格式:
- QImage.Format_Invalid (0): 无效图片。
- QImage.Format_Mono (1): 每像素使用1位存储图像。字节首先用高位(MSB方式打包)。
- QImage.Format_MonoLSB (2): 每像素使用1位存储图像。字节首先用低位(LSB方式打包)。
- QImage.Format_Indexed8 (3): 使用8位索引将图像存储到颜色表中。
- QImage.Format_RGB32 (4): 图像使用32位RGB格式(0xffRRGGBB)存储。
- QImage.Format_ARGB32 (5): 图像使用32位ARGB格式(0xAARRGGBB)存储。
- QImage.Format_ARGB32_Premultiplied (6): 使用预乘的32位ARGB格式(0xAARRGGBB)存储图像,即红色,绿色和蓝色通道乘以除以255的alpha分量。(如果RR,GG或BB的值大于alpha使用预乘ARGB32的某些操作(例如使用alpha混合的图像合成)要比使用普通ARGB32更快。
- QImage.Format_RGB16 (7): 图像以16位RGB格式(5-6-5)存储。
- QImage.Format_ARGB8565_Premultiplied (8): 使用预乘的24位ARGB格式(8-5-6-5)存储图像。
- QImage.Format_RGB666 (9): 图像以24位RGB格式(6-6-6)存储。未使用的最高有效位始终为零。
- QImage.Format_ARGB6666_Premultiplied (10): 使用预乘的24位ARGB格式(6-6-6-6)存储图像。
- QImage.Format_RGB555 (11): 图像以16位RGB格式(5-5-5)存储。未使用的最高有效位始终为零。
- QImage.Format_ARGB8555_Premultiplied (12): 使用预乘的24位ARGB格式(8-5-5-5)存储图像。
- QImage.Format_RGB888 (13): 图像以24位RGB格式(8-8-8)存储。
- QImage.Format_RGB444 (14): 图像以16位RGB格式(4-4-4)存储。未使用的位始终为零。
- QImage.Format_ARGB4444_Premultiplied (15): 使用预乘的16位ARGB格式(4-4-4-4)存储图像。
- QImage.Format_RGBX8888 (16): 图像使用32位字节排序的RGB(x)格式(8-8-8-8)存储。这与Format_RGBA8888相同,除了alpha必须始终为255。(在Qt 5.2中添加)
- QImage.Format_RGBA8888 (17): 图像使用32位字节顺序RGBA格式(8-8-8-8)存储。与ARGB32不同,这是一种字节排序格式,这意味着32位编码在大字节序和小字节序架构之间有所不同,分别为(0xRRGGBBAA)和(0xAABBGGRR)。如果读取为字节0xRR,0xGG,0xBB,0xAA,则颜色顺序在任何体系结构上都是相同的。(在Qt 5.2中添加)。
- QImage.Format_RGBA8888_Premultiplied (18): 使用预乘的32位字节排序RGBA格式(8-8-8-8)存储图像。(在Qt 5.2中添加)。
- QImage.Format_BGR30 (19): 图像使用32位BGR格式(x-10-10-10)存储。(在Qt 5.4中添加)。
- QImage.Format_A2BGR30_Premultiplied (20): 图像使用32位预乘ABGR格式(2-10-10-10)存储。(在Qt 5.4中添加)。
- QImage.Format_RGB30 (21): 图像以32位RGB格式(x-10-10-10)存储。(在Qt 5.4中添加)。
- QImage.Format_A2RGB30_Premultiplied (22): 图像使用32位预乘ARGB格式(2-10-10-10)存储。(在Qt 5.4中添加)。
- QImage.Format_Alpha8 (23): 图像使用仅8位alpha格式存储。(在Qt 5.5中添加)。
- QImage.Format_Grayscale8 (24): 图像使用8位灰度格式存储。(在Qt 5.5中添加)。
- QImage.Format_Grayscale16 (28): 图像使用16位灰度格式存储。(在Qt 5.13中添加)。
- QImage.Format_RGBX64 (25): 使用64位半字排序的RGB(x)格式(16-16-16-16)存储图像。这与Format_RGBA64相同,除了alpha必须始终为65535。(在Qt 5.12中添加)。
- QImage.Format_RGBA64 (26): 图像使用64位半字排序RGBA格式(16-16-16-16)存储。(在Qt 5.12中添加)。
- QImage.Format_RGBA64_Premultiplied (27): 使用预乘的64位半字排序RGBA格式(16-16-16-16)存储图像。(在Qt 5.12中添加)。
- QImage.Format_BGR888 (29): 图像使用24位BGR格式存储。(在Qt 5.14中添加)。
图像变换和图像属性修改
QImage支持许多用于创建新图像的功能:
- createAlphaMask(): 从该图像的alpha缓冲区生成并返回一个1-bpp的蒙版
- mirrored(): 生成一个径向图像
- scaled(): 生成一个缩放图像
- rgbSwapped(): 从RGB图像构造一个BGR图像
- scaledToWidth(): 返回缩放到指定宽度的图像
- caledToHeight(): 返回缩放到指定高度的图像
- transformed():返回使用给定的转换矩阵和转换模式转换的图像
一些用于就地图像属性的函数:
- setDotsPerMeterX(): 设置物理单位的水平像素数来定义纵横比。
- setDotsPerMeterY(): 设置物理单位的垂直像素数来定义纵横比。
- fill(): 用给定的像素值填充整个图像。
- invertPixels(): 使用给定的InvertMode值反转图像中的所有像素值。
- setColorTable(): 设置用于转换颜色索引的颜色表。仅单色和8位格式。
- setColorCount(): 调整颜色表的大小。仅单色和8位格式。
创建一个看图应用
参考pyqt5-examples样例文件imageviewer.py, 实现一个简单的看图程序,完整代码如下:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QDir
from PyQt5.QtGui import QImage, QPainter, QPixmap, QPalette
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction,
QFileDialog, QMessageBox, QLabel, QScrollArea, QSizePolicy)
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter
class ImageViewer(QMainWindow):
def __init__(self, parent=None):
super(ImageViewer, self).__init__(parent)
# 设置窗口标题
self.setWindowTitle('实战Qt for Python: QImage实现一个看图应用')
# 设置窗口大小
self.resize(500, 400)
self.initUi()
def initUi(self):
#打印
self.printer = QPrinter()
#缩放因子
self.scaleFactor = 0.0
#创建显示图片的窗口
self.imgLabel = QLabel()
self.imgLabel.setBackgroundRole(QPalette.Base)
self.imgLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.imgLabel.setScaledContents(True)
self.scrollArea = QScrollArea()
self.scrollArea.setBackgroundRole(QPalette.Dark)
self.scrollArea.setWidget(self.imgLabel)
self.setCentralWidget(self.scrollArea)
self.initMenuBar()
def initMenuBar(self):
menuBar = self.menuBar()
menuFile = menuBar.addMenu('文件(&F)')
menuView = menuBar.addMenu('视图(&V)')
actionOpen = QAction('打开(&O)...', self, shortcut='Ctrl+O', triggered=self.onFileOpen)
self.actionPrint = QAction('打印(&P)...', self, shortcut='Ctrl+P', enabled=False, triggered=self.onFilePrint)
actionExit = QAction('退出(&X)', self, shortcut='Ctrl+Q', triggered=QApplication.instance().quit)
self.actionZoomIn = QAction('放大(25%)(&I)', self, shortcut='Ctrl++', enabled=False, triggered=self.onViewZoomIn)
self.actionZoomOut = QAction('缩小(25%)(&O)', self, shortcut='Ctrl++', enabled=False, triggered=self.onViewZoomOut)
self.actionNormalSize = QAction('原始尺寸(&N)', self, shortcut='Ctrl+S', enabled=False, triggered=self.onViewNormalSize)
self.actionFitToWindow = QAction('适应窗口(&F)', self, shortcut='Ctrl+F', enabled=False, checkable=True, triggered=self.onViewFitToWindow)
menuFile.addAction(actionOpen)
menuFile.addAction(self.actionPrint)
menuFile.addSeparator()
menuFile.addAction(actionExit)
menuView.addAction(self.actionZoomIn)
menuView.addAction(self.actionZoomOut)
menuView.addAction(self.actionNormalSize)
menuView.addSeparator()
menuView.addAction(self.actionFitToWindow)
#打开文件
def onFileOpen(self):
filename,_ = QFileDialog.getOpenFileName(self, '打开文件', QDir.currentPath())
if filename:
image = QImage(filename)
if image.isNull():
QMessageBox.information(self, '图像浏览器', '不能加载文件%s.' % filename)
return
self.imgLabel.setPixmap(QPixmap.fromImage(image))
self.scaleFactor = 1.0
self.actionPrint.setEnabled(True)
self.actionFitToWindow.setEnabled(True)
self.updateActions()
if not self.actionFitToWindow.isChecked():
self.imgLabel.adjustSize()
#打印
def onFilePrint(self):
dlg = QPrintDialog(self.printer, self)
if dlg.exec():
painter = QPainter(self.printer)
rect = painter.viewport()
size = self.imgLabel.pixmap().size()
size.scale(rect.size(), Qt.KeepAspectRatio)
painter.setViewport(rect.x(), rect.y(), size.width(), size.height())
painter.setWindow(self.imgLabel.pixmap().rect())
painter.drawPixmap(0, 0, self.imgLabel.pixmap())
#放大图像
def onViewZoomIn(self):
self.scaleIamge(1.25)
def onViewZoomOut(self):
self.scaleIamge(0.8)
def onViewNormalSize(self):
self.imgLabel.adjustSize()
self.scaleFactor = 1.0
def onViewFitToWindow(self):
fitToWindow = self.actionFitToWindow.isChecked()
self.scrollArea.setWidgetResizable(fitToWindow)
if not fitToWindow:
self.onViewNormalSize()
self.updateActions()
def updateActions(self):
checked = not self.actionFitToWindow.isChecked()
self.actionZoomIn.setEnabled(checked)
self.actionZoomOut.setEnabled(checked)
self.actionNormalSize.setEnabled(checked)
def scaleIamge(self, factor):
self.scaleFactor *= factor
self.imgLabel.resize(self.scaleFactor * self.imgLabel.pixmap().size())
self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor)
self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor)
self.actionZoomIn.setEnabled(self.scaleFactor < 4.0)
self.actionZoomOut.setEnabled(self.scaleFactor > 0.25)
def adjustScrollBar(self, scrollBar, factor):
scrollBar.setValue(int(factor * scrollBar.value() + ((factor - 1) * scrollBar.pageStep()/2)))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = ImageViewer()
window.show()
sys.exit(app.exec())
运行结果如下图:
本文知识点
- QImage支持的图像格式
- 使用QImage进行图像变换
- 创建一个简单的图像浏览应用
前一篇: 实战PyQt5:120-像素图QPixmap和QBitmap
请多多关注,评论,收藏,点赞,和转发。
相关推荐
- Linux集群自动化监控系统Zabbix集群搭建到实战
-
自动化监控系统...
- systemd是什么如何使用_systemd/system
-
systemd是什么如何使用简介Systemd是一个在现代Linux发行版中广泛使用的系统和服务管理器。它负责启动系统并管理系统中运行的服务和进程。使用管理服务systemd可以用来启动、停止、...
- Linux服务器日常巡检脚本分享_linux服务器监控脚本
-
Linux系统日常巡检脚本,巡检内容包含了,磁盘,...
- 7,MySQL管理员用户管理_mysql 管理员用户
-
一、首次设置密码1.初始化时设置(推荐)mysqld--initialize--user=mysql--datadir=/data/3306/data--basedir=/usr/local...
- Python数据库编程教程:第 1 章 数据库基础与 Python 连接入门
-
1.1数据库的核心概念在开始Python数据库编程之前,我们需要先理解几个核心概念。数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,它就像一个电子化的文件柜,能让我们高效...
- Linux自定义开机自启动服务脚本_linux添加开机自启动脚本
-
设置WGCloud开机自动启动服务init.d目录下新建脚本在/etc/rc.d/init.d新建启动脚本wgcloudstart.sh,内容如下...
- linux系统启动流程和服务管理,带你进去系统的世界
-
Linux启动流程Rhel6启动过程:开机自检bios-->MBR引导-->GRUB菜单-->加载内核-->init进程初始化Rhel7启动过程:开机自检BIOS-->M...
- CentOS7系统如何修改主机名_centos更改主机名称
-
请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习1.前言本文将讲解CentOS7系统如何修改主机名。...
- 前端工程师需要熟悉的Linux服务器(SSH 终端操作)指令
-
在Linux服务器管理中,SSH(SecureShell)是远程操作的核心工具。以下是SSH终端操作的常用命令和技巧,涵盖连接、文件操作、系统管理等场景:一、SSH连接服务器1.基本连接...
- Linux开机自启服务完全指南:3步搞定系统服务管理器配置
-
为什么需要配置开机自启?想象一下:电商服务器重启后,MySQL和Nginx没自动启动,整个网站瘫痪!这就是为什么开机自启是Linux运维的必备技能。自启服务能确保核心程序在系统启动时自动运行,避免人工...
- Kubernetes 高可用(HA)集群部署指南
-
Kubernetes高可用(HA)集群部署指南本指南涵盖从概念理解、架构选择,到kubeadm高可用部署、生产优化、监控备份和运维的全流程,适用于希望搭建稳定、生产级Kubernetes集群...
- Linux项目开发,你必须了解Systemd服务!
-
1.Systemd简介...
- Linux系统systemd服务管理工具使用技巧
-
简介:在Linux系统里,systemd就像是所有进程的“源头”,它可是系统中PID值为1的进程哟。systemd其实是一堆工具的组合,它的作用可不止是启动操作系统这么简单,像后台服务...
- Linux下NetworkManager和network的和平共处
-
简介我们在使用CentoOS系统时偶尔会遇到配置都正确但network启动不了的问题,这问题经常是由NetworkManager引起的,关闭NetworkManage并取消开机启动network就能正...
你 发表评论:
欢迎- 一周热门
-
-
MySQL中这14个小玩意,让人眼前一亮!
-
旗舰机新标杆 OPPO Find X2系列正式发布 售价5499元起
-
面试官:使用int类型做加减操作,是线程安全吗
-
C++编程知识:ToString()字符串转换你用正确了吗?
-
【Spring Boot】WebSocket 的 6 种集成方式
-
PyTorch 深度学习实战(26):多目标强化学习Multi-Objective RL
-
pytorch中的 scatter_()函数使用和详解
-
与 Java 17 相比,Java 21 究竟有多快?
-
基于TensorRT_LLM的大模型推理加速与OpenAI兼容服务优化
-
这一次,彻底搞懂Java并发包中的Atomic原子类
-
- 最近发表
-
- Linux集群自动化监控系统Zabbix集群搭建到实战
- systemd是什么如何使用_systemd/system
- Linux服务器日常巡检脚本分享_linux服务器监控脚本
- 7,MySQL管理员用户管理_mysql 管理员用户
- Python数据库编程教程:第 1 章 数据库基础与 Python 连接入门
- Linux自定义开机自启动服务脚本_linux添加开机自启动脚本
- linux系统启动流程和服务管理,带你进去系统的世界
- CentOS7系统如何修改主机名_centos更改主机名称
- 前端工程师需要熟悉的Linux服务器(SSH 终端操作)指令
- Linux开机自启服务完全指南:3步搞定系统服务管理器配置
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)