You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PyQt5获取图片像素坐标并在点击位置绘制可更新的点

实现方案

你需要新增点击位置存储逻辑和重绘逻辑即可满足需求,以下是完整修改后的代码:

核心修改点

  • 新增实例变量存储最新点击的控件坐标
  • 拦截QLabel的绘制事件,在图片上层绘制红色标记点
  • 每次有效点击后更新坐标并触发重绘,自动清除旧标记
  • 加载新图片时自动清空历史标记

完整可运行代码

from PyQt5 import QtCore, QtGui, QtWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        layout = QtWidgets.QGridLayout(self)

        self.getImageButton = QtWidgets.QPushButton('选择图片')
        layout.addWidget(self.getImageButton)
        self.getImageButton.clicked.connect(self.load_image)

        self.resim1 = QtWidgets.QLabel()
        layout.addWidget(self.resim1)
        self.resim1.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter)
        self.resim1.setScaledContents(True)
        self.resim1.setFixedSize(701,451)

        # 给QLabel安装事件过滤器捕获鼠标事件、绘制事件
        self.resim1.installEventFilter(self)
        # 存储最新点击位置(控件坐标系),初始为空
        self.last_click_pos = None

    def load_image(self):
        filename, filter = QtWidgets.QFileDialog.getOpenFileName(None, '加载图片', '.', '图片文件 (*.png *.jpg *.jpeg *.bmp *.tif)')
        if not filename:
            return
        self.resim1.setPixmap(QtGui.QPixmap(filename))
        # 加载新图片后清空历史点击标记
        self.last_click_pos = None
        self.resim1.update()

    def eventFilter(self, source, event):
        # 处理绘制事件:先画原图,再画点击标记点
        if event.type() == QtCore.QEvent.Paint and source == self.resim1:
            # 先让QLabel完成默认的图片绘制逻辑
            super().eventFilter(source, event)
            # 如果有最新点击位置,在对应位置绘制红色圆点
            if self.last_click_pos is not None:
                painter = QtGui.QPainter(source)
                painter.setRenderHint(QtGui.QPainter.Antialiasing)
                # 设置画笔:红色、宽度6像素、实线,绘制出的点大小适中容易识别
                painter.setPen(QtGui.QPen(QtCore.Qt.red, 6, QtCore.Qt.SolidLine))
                painter.drawPoint(self.last_click_pos)
                painter.end()
            return True
        
        # 处理鼠标点击事件
        if (source == self.resim1 and source.pixmap() and not source.pixmap().isNull() and 
            event.type() == QtCore.QEvent.MouseButtonPress and
            event.button() == QtCore.Qt.LeftButton):
                self.getClickedPosition(event.pos())
        return super().eventFilter(source, event)

    def getClickedPosition(self, pos):
        # 保存控件坐标系的点击位置,用于后续绘制
        click_widget_pos = pos
        # 计算控件内边距区域
        contentsRect = QtCore.QRectF(self.resim1.contentsRect())
        if pos not in contentsRect:
            # 点击位置在控件边距外,忽略
            return

        # 坐标转换为相对于内边距区域的位置
        pos -= contentsRect.topLeft()

        pixmapRect = self.resim1.pixmap().rect()
        if self.resim1.hasScaledContents():
            # 开启了缩放适配,转换为原图像素坐标
            x = pos.x() * pixmapRect.width() / contentsRect.width()
            y = pos.y() * pixmapRect.height() / contentsRect.height()
            pos = QtCore.QPoint(x, y)
        else:
            align = self.resim1.alignment()
            pixmapRect = QtCore.QRectF(pixmapRect)

            # 根据对齐方式计算原图在控件中的实际位置
            if align & QtCore.Qt.AlignRight:
                pixmapRect.moveRight(contentsRect.x() + contentsRect.width())
            elif align & QtCore.Qt.AlignHCenter:
                pixmapRect.moveLeft(contentsRect.center().x() - pixmapRect.width() / 2)
            if align & QtCore.Qt.AlignBottom:
                pixmapRect.moveBottom(contentsRect.y() + contentsRect.height())
            elif align & QtCore.Qt.AlignVCenter:
                pixmapRect.moveTop(contentsRect.center().y() - pixmapRect.height() / 2)

            if not pos in pixmapRect:
                # 点击位置在图片区域外,忽略
                return
            # 转换为原图像素坐标
            pos = (pos - pixmapRect.topLeft()).toPoint()

        print('原图像素坐标:X={}, Y={}'.format(pos.x(), pos.y()))
        # 更新最新点击位置,触发重绘
        self.last_click_pos = click_widget_pos
        self.resim1.update()


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

内容的提问来源于stack exchange,提问作者Barun Basnet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 06:24:04