在放大的图像上查找缩放中心坐标
Posted
技术标签:
【中文标题】在放大的图像上查找缩放中心坐标【英文标题】:Finding zoom center coordinates on a zoomed-in image 【发布时间】:2021-01-12 15:20:56 【问题描述】:我正在尝试在图像上实现以鼠标光标为中心的放大/缩小。为简单起见,假设我只需要在水平轴上放大/缩小。我使用 Qt 和 QPainter 来绘制我的场景,并使用 QWidget:: mouseWheelEvent 覆盖来计算缩放因子和缩放位置。
在显示代码之前,缩放因子和缩放位置定义了从原始图像转换为缩放图像所需的转换(换句话说,我不组合矩阵或类似的东西,但在绘制事件中计算绝对变换),最终可以在这里看到:
void MyWidget::paintEvent(QPaintEvent* e)
QPainter painterthis;
painter.translate(m_zoomCenterX, 0.);
painter.scale(m_zoomFactor, 1.);
painter.translate(-m_zoomCenterX, 0.);
// content margins are all 0 btw
painter.drawImage(contentsRect(), m_image);
在鼠标滚轮事件中,我尝试计算缩放中心与添加到缩放中心的新位置之间的比例差。缩放因子是根据角度增量简单地通过乘以一个常数来计算的。最后的 if-else 分支会进行一些边界检查(这是我想做的事情,以便图像在视图中保持拉伸并且不会移动到我不想移动的地方):
void MyWidget::wheelEvent(QWheelEvent* e)
const QRect rect = contentsRect();
// m_zoomCenterX is first initialized to 0 in the MyWidget constructor, m_zoomFactor to 1.
const qreal diff = (e->pos().x() - m_zoomCenterX) / m_zoomFactor;
qDebug() << diff;
m_zoomCenterX += diff;
static constexpr const qreal ZOOM_IN_FACTOR = 1.1,
ZOOM_OUT_FACTOR = .9;
m_zoomFactor *= e->angleDelta().y() > 0. ? ZOOM_IN_FACTOR : ZOOM_OUT_FACTOR;
if (m_zoomFactor < 1.)
m_zoomFactor = 1.;
m_zoomCenterX = 0.;
else if (m_zoomFactor > 5.)
m_zoomFactor = 5.;
if (m_zoomCenterX < 0)
m_zoomCenter = 0;
else if (m_zoomCenterX >= rect.width())
m_zoomCenterX = rect.width() - 1;
update();
这似乎不起作用,一旦我在假设放大后尝试放大/缩小(参见图片:,抱歉,如果它不多),缩放中心位置可能没有正确计算但我不确定为什么。当光标位于新位置时,qDebug 行在连续滚动后给我非零差异,但在第一次滚动后它应该为零......
我想这一定是微不足道的事情,但我现在很困惑。
【问题讨论】:
【参考方案1】:好吧,我让它工作了。我使用逆矩阵来计算新的缩放中心,但是一旦放大,它就会与鼠标位置不匹配,所以整个图像必须额外由inverted_position - mouse_position
平移。这是任何未来流浪者的最终代码。 m_extraTranslation
显然在构造函数中初始化了 0
。
QMatrix MyWidget::computeScaleMatrix() const noexcept
QMatrix scaleMatrix1., 0., 0., 1., 0., 0.;
scaleMatrix.translate(-m_extraTranslation, 0.);
scaleMatrix.translate(m_zoomCenter.x(), 0.);
scaleMatrix.scale(m_zoomFactor, 1.);
scaleMatrix.translate(-m_zoomCenter.x(), 0.);
return scaleMatrix;
void MyWidget::wheelEvent(QWheelEvent* e)
const QMatrix invScaleMatrix = computeScaleMatrix().inverted();
const QPointF invPos = invScaleMatrix.map(e->pos());
m_zoomCenter.setX(invPos.x());
static constexpr const qreal ZOOM_IN_FACTOR = 1.1,
ZOOM_OUT_FACTOR = .9;
m_zoomFactor *= e->angleDelta().y() > 0. ? ZOOM_IN_FACTOR : ZOOM_OUT_FACTOR;
m_extraTranslation = invPos.x() - e->pos().x();
// here I'm making sure the image corners do not wander off inside the widget, this is necessary to do for zooming out
const QMatrix scaleMatrix = computeScaleMatrix();
const qreal startX = scaleMatrix.map(QPointF0., 0.).x(),
endX = scaleMatrix.map(QPointF(contentsRect().width() - 1, 0.)).x();
if (startX > 0.)
m_extraTranslation += startX;
else if (endX < contentsRect().width() - 1)
m_extraTranslation -= contentsRect().width() - endX - 1;
if (m_zoomFactor < 1.)
m_zoomFactor = 1.;
m_zoomCenter = 0, 0;
m_extraTranslation = 0;
else if (m_zoomFactor > 5.)
m_zoomFactor = 5.;
if (m_zoomCenter.x() < 0)
m_zoomCenter.setX(0);
else if (m_zoomCenter.x() >= contentsRect().width())
m_zoomCenter.setX(contentsRect().width() - 1);
update();
e->accept();
void MyWidget::paintEvent(QPaintEvent* e)
QPainter painterthis;
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setMatrix(computeScaleMatrix()));
painter.drawImage(contentsRect(), m_image);
将其扩展到 Y 轴应该很简单,因为它会遵循相同的逻辑。
【讨论】:
以上是关于在放大的图像上查找缩放中心坐标的主要内容,如果未能解决你的问题,请参考以下文章