如何获取加载图像的坐标而不是显示图像的坐标
How to get the coordinate of the loaded image and not the one from the display
我正在开发带有按钮的图像查看器,该按钮允许在单击它时获取加载图像的坐标。但是,当我放大图像并单击它时,我得到了图像所在的显示器的坐标,与图像在正方形内的中心位置无关。我想得到的是点击它的加载图像的坐标。这意味着如果显示中的图像片段被缩放或滚动(up/down 或 right/left),坐标应相应地调整。这可能是一个容易回答的简单问题,但是我在这个问题上停留了一个多星期,尽管我试图理解 Qt website 的文档但没有成功
例如,我尝试替换行
self.photo_clicked.emit(QtCore.QPoint(event.pos()))
来自
self.photo_clicked.emit(QtCore.QPoint(QGraphicsView.mapFromScene(event.pos())))
但它给了我错误:
TypeError: descriptor 'mapFromScene' requires a 'PySide2.QtWidgets.QGraphicsView' object but received a 'PySide2.QtCore.QPoint'
这是脚本(部分灵感来自):
from PySide2.QtWidgets import (QWidget, QApplication, QSlider,
QGraphicsView, QGraphicsScene, QVBoxLayout)
from PySide2.QtGui import QPainter, QColor
from PySide2 import QtCore, QtWidgets, QtGui
from PySide2.QtOpenGL import *
from PySide2.QtCore import *
from PySide2.QtGui import *
import sys
image_path_str='image.jpg'
class View(QGraphicsView):
photo_clicked = QtCore.Signal(QtCore.QPoint)
def __init__(self, parent):
super(View, self).__init__()
self.scene = QtWidgets.QGraphicsScene(self)
self.photo = QtWidgets.QGraphicsPixmapItem()
self.scene.addItem(self.photo)
pixmap = QtGui.QPixmap(image_path_str)
self.photo.setPixmap(pixmap)
self.setScene(self.scene)
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
def Hand_drag(self):
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
def pixel_pointer(self):
self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
def mousePressEvent(self, event):
if self.photo.isUnderMouse():
self.photo_clicked.emit(QtCore.QPoint(event.pos()))
super(View, self).mousePressEvent(event)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = View(self)
self.btn_hand_drag = QtWidgets.QCheckBox("Hand drag", self)
self.btn_hand_drag.clicked.connect(self.view.Hand_drag)
self.btn_hand_drag.clicked.connect(self.btn_hand_drag_uncheck_others)
self.btn_pix_info1 = QtWidgets.QCheckBox("Point 1", self)
self.btn_pix_info1.clicked.connect(self.view.pixel_pointer)
self.btn_pix_info1.clicked.connect(self.btn_pix_info1_drag_uncheck_other)
self.editPixInfo1 = QtWidgets.QLineEdit(self)
self.editPixInfo1.setReadOnly(True)
self.btn_pix_info2 = QtWidgets.QCheckBox("Point 2", self)
self.btn_pix_info2.clicked.connect(self.view.pixel_pointer)
self.btn_pix_info2.clicked.connect(self.btn_pix_info2_drag_uncheck_other)
self.editPixInfo2 = QtWidgets.QLineEdit(self)
self.editPixInfo2.setReadOnly(True)
self.view.photo_clicked.connect(self.photo_clicked)
slider = QSlider(Qt.Horizontal, self)
slider.setRange(1, 500)
slider.setValue(100)
slider.valueChanged[int].connect(self.zoom)
vbox = QVBoxLayout()
vbox.addWidget(self.btn_hand_drag)
vbox.addWidget(self.btn_pix_info1)
vbox.addWidget(self.editPixInfo1)
vbox.addWidget(self.btn_pix_info2)
vbox.addWidget(self.editPixInfo2)
vbox.addWidget(self.view)
vbox.addWidget(slider)
self.setLayout(vbox)
self.setWindowTitle("Image viewer")
self.setGeometry(200, 200, 1000, 800)
def zoom(self, value):
val = value / 100
self.view.resetTransform()
self.view.scale(val, val)
def btn_hand_drag_uncheck_others(self):
self.btn_pix_info1.setChecked(False)
self.btn_pix_info2.setChecked(False)
def btn_pix_info1_drag_uncheck_other(self):
self.btn_hand_drag.setChecked(False)
self.btn_pix_info2.setChecked(False)
def btn_pix_info2_drag_uncheck_other(self):
self.btn_hand_drag.setChecked(False)
self.btn_pix_info1.setChecked(False)
def photo_clicked(self, pos):
if self.btn_pix_info1.isChecked():
self.editPixInfo1.setText('%d, %d' % (pos.x(), pos.y()))
if self.btn_pix_info2.isChecked():
self.editPixInfo2.setText('%d, %d' % (pos.x(), pos.y()))
app = QApplication.instance()
if app is None:
app = QApplication([])
w = Window()
w.show()
w.raise_()
app.exec_()
当您缩放并按下一个像素时,这可以代表一组像素,反之亦然,我想您明白这一点,因为显示图像是下采样或上采样,视情况而定。所以最后,无论它是什么,你都会得到一个不会很理想但非常接近的像素。直奔主题,考虑到在@ekhumuro 的实现中没有项目升级,使用鼠标位置相对于项目坐标系而不是场景是正确的,因为项目可以移动,所以考虑到item不变形的一般解决方案是:
def mousePressEvent(self, event):
if self._photo.isUnderMouse():
p = self._photo.mapToItem(self._photo, self.mapToScene(event.pos()))
self.photoClicked.emit(p.toPoint())
super(PhotoViewer, self).mousePressEvent(event)
我正在开发带有按钮的图像查看器,该按钮允许在单击它时获取加载图像的坐标。但是,当我放大图像并单击它时,我得到了图像所在的显示器的坐标,与图像在正方形内的中心位置无关。我想得到的是点击它的加载图像的坐标。这意味着如果显示中的图像片段被缩放或滚动(up/down 或 right/left),坐标应相应地调整。这可能是一个容易回答的简单问题,但是我在这个问题上停留了一个多星期,尽管我试图理解 Qt website 的文档但没有成功
例如,我尝试替换行
self.photo_clicked.emit(QtCore.QPoint(event.pos()))
来自
self.photo_clicked.emit(QtCore.QPoint(QGraphicsView.mapFromScene(event.pos())))
但它给了我错误:
TypeError: descriptor 'mapFromScene' requires a 'PySide2.QtWidgets.QGraphicsView' object but received a 'PySide2.QtCore.QPoint'
这是脚本(部分灵感来自
from PySide2.QtWidgets import (QWidget, QApplication, QSlider,
QGraphicsView, QGraphicsScene, QVBoxLayout)
from PySide2.QtGui import QPainter, QColor
from PySide2 import QtCore, QtWidgets, QtGui
from PySide2.QtOpenGL import *
from PySide2.QtCore import *
from PySide2.QtGui import *
import sys
image_path_str='image.jpg'
class View(QGraphicsView):
photo_clicked = QtCore.Signal(QtCore.QPoint)
def __init__(self, parent):
super(View, self).__init__()
self.scene = QtWidgets.QGraphicsScene(self)
self.photo = QtWidgets.QGraphicsPixmapItem()
self.scene.addItem(self.photo)
pixmap = QtGui.QPixmap(image_path_str)
self.photo.setPixmap(pixmap)
self.setScene(self.scene)
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
def Hand_drag(self):
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
def pixel_pointer(self):
self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
def mousePressEvent(self, event):
if self.photo.isUnderMouse():
self.photo_clicked.emit(QtCore.QPoint(event.pos()))
super(View, self).mousePressEvent(event)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = View(self)
self.btn_hand_drag = QtWidgets.QCheckBox("Hand drag", self)
self.btn_hand_drag.clicked.connect(self.view.Hand_drag)
self.btn_hand_drag.clicked.connect(self.btn_hand_drag_uncheck_others)
self.btn_pix_info1 = QtWidgets.QCheckBox("Point 1", self)
self.btn_pix_info1.clicked.connect(self.view.pixel_pointer)
self.btn_pix_info1.clicked.connect(self.btn_pix_info1_drag_uncheck_other)
self.editPixInfo1 = QtWidgets.QLineEdit(self)
self.editPixInfo1.setReadOnly(True)
self.btn_pix_info2 = QtWidgets.QCheckBox("Point 2", self)
self.btn_pix_info2.clicked.connect(self.view.pixel_pointer)
self.btn_pix_info2.clicked.connect(self.btn_pix_info2_drag_uncheck_other)
self.editPixInfo2 = QtWidgets.QLineEdit(self)
self.editPixInfo2.setReadOnly(True)
self.view.photo_clicked.connect(self.photo_clicked)
slider = QSlider(Qt.Horizontal, self)
slider.setRange(1, 500)
slider.setValue(100)
slider.valueChanged[int].connect(self.zoom)
vbox = QVBoxLayout()
vbox.addWidget(self.btn_hand_drag)
vbox.addWidget(self.btn_pix_info1)
vbox.addWidget(self.editPixInfo1)
vbox.addWidget(self.btn_pix_info2)
vbox.addWidget(self.editPixInfo2)
vbox.addWidget(self.view)
vbox.addWidget(slider)
self.setLayout(vbox)
self.setWindowTitle("Image viewer")
self.setGeometry(200, 200, 1000, 800)
def zoom(self, value):
val = value / 100
self.view.resetTransform()
self.view.scale(val, val)
def btn_hand_drag_uncheck_others(self):
self.btn_pix_info1.setChecked(False)
self.btn_pix_info2.setChecked(False)
def btn_pix_info1_drag_uncheck_other(self):
self.btn_hand_drag.setChecked(False)
self.btn_pix_info2.setChecked(False)
def btn_pix_info2_drag_uncheck_other(self):
self.btn_hand_drag.setChecked(False)
self.btn_pix_info1.setChecked(False)
def photo_clicked(self, pos):
if self.btn_pix_info1.isChecked():
self.editPixInfo1.setText('%d, %d' % (pos.x(), pos.y()))
if self.btn_pix_info2.isChecked():
self.editPixInfo2.setText('%d, %d' % (pos.x(), pos.y()))
app = QApplication.instance()
if app is None:
app = QApplication([])
w = Window()
w.show()
w.raise_()
app.exec_()
当您缩放并按下一个像素时,这可以代表一组像素,反之亦然,我想您明白这一点,因为显示图像是下采样或上采样,视情况而定。所以最后,无论它是什么,你都会得到一个不会很理想但非常接近的像素。直奔主题,考虑到在@ekhumuro 的实现中没有项目升级,使用鼠标位置相对于项目坐标系而不是场景是正确的,因为项目可以移动,所以考虑到item不变形的一般解决方案是:
def mousePressEvent(self, event):
if self._photo.isUnderMouse():
p = self._photo.mapToItem(self._photo, self.mapToScene(event.pos()))
self.photoClicked.emit(p.toPoint())
super(PhotoViewer, self).mousePressEvent(event)