gpt4 book ai didi

python - 放大图像时控制平移(锚定点)

转载 作者:行者123 更新时间:2023-11-28 16:39:45 26 4
gpt4 key购买 nike

我正在编写一个简单的图像查看器并实现平移和缩放功能(分别使用鼠标拖动和鼠标滚轮滚动)。我已经成功地实现了平移(简单模式)和天真的“进入左上角”缩放。
我现在想细化缩放,使缩放时用户鼠标的坐标成为“焦点”:也就是说,缩放时,平移会更新,以便用户鼠标下的(图像的)像素保持不变相同(以便他们真正放大那个区域)

图像是通过在一个普通的 QWidget 上覆盖 paintEvent 来查看的。
尽我所能尝试使用直观的方法,我似乎无法实现正确的缩放行为。

属性 scale 表示当前缩放级别(比例为 2 表示图像被查看为真实大小的两倍,0.5 表示一半,并且 scale > 0),以及 position 是当前查看的图像区域左上角的坐标(通过平移)。

下面是实际图像显示的执行方式

def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)

painter.drawImage(0, 0,
self.image.scaled(
self.image.width() * self.scale,
self.image.height() * self.scale,
QtCore.Qt.KeepAspectRatio),
self.position[0], self.position[1])

painter.end()

下面是平移代码(比较简单):
(pressedanchor 完全用于平移,指的是 初始鼠标按下的位置此时的 ImageView 位置时间(分别))

def mousePressEvent(self, event):
self.pressed = event.pos()
self.anchor = self.position

def mouseReleaseEvent(self, event):
self.pressed = None

def mouseMoveEvent(self, event):
if (self.pressed):
dx, dy = event.x() - self.pressed.x(), event.y() - self.pressed.y()
self.position = (self.anchor[0] - dx, self.anchor[1] - dy)
self.repaint()

这里是缩放代码没有尝试调整平移。它会导致一切从/到屏幕左上角缩小或增长

def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale
self.repaint()

这里是缩放代码通过平移来保留(锚定)可见区域的左上角。放大时,屏幕左上角的像素不会改变。

def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200
if (self.scale < 0.1):
self.scale = oldscale

self.position = (self.position[0] * (self.scale / oldscale),
self.position[1] * (self.scale / oldscale))
self.repaint()

我想要上述效果,但 anchor 在滚动时位于用户的鼠标上。这是我的尝试,效果非常轻微:缩放仍然不是我想要的,而是滚动到鼠标的一般区域,没有锚定。事实上,将鼠标保持在同一位置并放大似乎遵循一条弯曲的路径,向右平移然后向左平移。

def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale

oldpoint = self.mapFromGlobal(QtGui.QCursor.pos())
dx, dy = oldpoint.x() - self.position[0], oldpoint.y() - self.position[1]
newpoint = (oldpoint.x() * (self.scale/oldscale),
oldpoint.y() * (self.scale/oldscale))
self.position = (newpoint[0] - dx, newpoint[1] - dy)

这背后的理论是,在缩放之前,鼠标“下方”的像素距左上角(位置)的长度为 dxdy )。缩放后,我们计算这个像素的新位置,并通过调整我们的 self.positiondxdy 来强制它在屏幕上的同一坐标下 像素的西边和北边。

我不完全确定哪里出错了:我怀疑 old point 到我的屏幕坐标的映射在某种程度上不正确,或者更可能的是:我的数学是错误的,因为我'我们混淆了像素和屏幕坐标。
我已经尝试了一些直观的变化,但没有什么能接近预期的锚定。

我认为这对于文件查看器来说是一项很常见的任务(因为大多数文件似乎都是这样缩放的),但我发现研究这些算法非常困难。

这是修改缩放的完整代码(需要 PyQt4):
http://pastebin.com/vvpdZy9g

感谢任何帮助!

最佳答案

好的,我设法让它工作

def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale

screenpoint = self.mapFromGlobal(QtGui.QCursor.pos())
dx, dy = screenpoint.x(), screenpoint.y()
oldpoint = (screenpoint.x() + self.position[0], screenpoint.y() + self.position[1])
newpoint = (oldpoint[0] * (self.scale/oldscale),
oldpoint[1] * (self.scale/oldscale))
self.position = (newpoint[0] - dx, newpoint[1] - dy)

这里的逻辑:

  • 我们得到鼠标在屏幕上的位置 (screenpoint),并使用它,我们得到我们的锚定像素和屏幕边缘之间的距离(根据定义)
  • 我们使用 screenpointposition 来根据图像的平面找到鼠标的坐标(即:悬停像素的 2D 索引),如 旧点
  • 应用缩放,我们计算像素的新二维索引(新点)
  • 我们希望这个像素在我们的屏幕上,但不在左上角:我们希望它在左上角的 dxdy (位置)

问题确实是图像和显示坐标之间的细微混淆。

关于python - 放大图像时控制平移(锚定点),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20942586/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com