QGraphicsPixmapItem.setScale将像素边界设置在不相关的位置

时间:2018-02-05 22:59:26

标签: python c++ qt pyqt

我想使用QGraphicsPixmapItem.setScale缩放图像。然而,在高放大率水平下,即当仅有几个像素填满窗口时,缩放开始非常不稳定。我在PyQt 4.8.7和5.6.0中,在Windows 10以及Ubuntu 16.10上观察到相同的现象。编辑:在最近的PyQt 5.10上测试,结果相同。编辑:在普通的C ++ Qt中测试,见下文。

这是一个缩放因子由鼠标滚轮控制的例子。

import numpy as np
try:
    from PyQt5.QtCore import Qt, QRectF
    from PyQt5.QtGui import QImage, QPixmap
    from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QMainWindow
    qt_ver = 5
except:
    from PyQt4.QtCore import Qt, QRectF
    from PyQt4.QtGui import QImage, QPixmap
    from PyQt4.QtGui import QApplication, QGraphicsScene, QGraphicsView, QMainWindow
    qt_ver = 4

app = QApplication([])


class MyGraphicsView(QGraphicsView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.scene = QGraphicsScene(QRectF())
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setScene(self.scene)
        im = np.random.randint(255, size=(100, 100, 3), dtype=np.uint8)
        qim = QImage(im, 100, 100, QImage.Format_RGB888)
        pix = QPixmap.fromImage(qim)
        self.pixi = self.scene.addPixmap(pix)
        self.pixi.setOffset(-50, -50)
        self.zoom = 0

    def wheelEvent(self, event):
        if qt_ver == 5:
          delta = event.angleDelta().y()
        else:
          delta = event.delta()
        if delta > 0:
            self.zoom += 1
        elif delta < 0:
            self.zoom -= 1
        self.pixi.setScale(np.exp(self.zoom * 0.1))


window = QMainWindow()
window.setGeometry(100, 100, 900, 900)
view = MyGraphicsView(window)
window.setCentralWidget(view)
window.show()
app.exec()    

看起来缩放正在遭遇舍入问题。我做错了吗?

C ++中的行为相同,这不是PyQt / python问题。我想知道这是否可能是由于float32精度差导致的离散效应?这可能很难解决。

# include <cstdint>
# include <cmath>
# include <random>
# include <vector>

# include <QApplication>
# include <QGraphicsPixmapItem>
# include <QGraphicsView>
# include <QImage>
# include <QMainWindow>
# include <QPixmap>
# include <QWheelEvent>
# include <QWidget>

class MyGraphicsView
        : public QGraphicsView
{
private:
    int _zoom = 0;
    std::vector<std::uint8_t> _im_data;
    QGraphicsScene * _scene = nullptr;
    QPixmap _pix;
    QGraphicsPixmapItem * _pixi = nullptr;

public:
    MyGraphicsView(QWidget * parent)
        : QGraphicsView(parent)
    {
        _scene = new QGraphicsScene(QRectF(), this);
        this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        this->setScene(_scene);
        _im_data.resize(100 * 100 * 3);
        std::random_device rd;
        std::mt19937 mt(rd());
        std::uniform_int_distribution<> distr(0, std::numeric_limits<std::uint8_t>::max());
        for (auto & e: _im_data) e = std::uint8_t(distr(mt));
        auto im = QImage(_im_data.data(), 100, 100, QImage::Format_RGB888);
        _pix = QPixmap::fromImage(std::move(im));
        _pixi = _scene->addPixmap(_pix);
        _pixi->setOffset(-50, -50);
    }
    void wheelEvent(QWheelEvent *event) override
    {
        auto delta = event->angleDelta().y();
        if (delta > 0)
            ++_zoom;
        else if (delta < 0)
            --_zoom;
        _pixi->setScale(std::exp(_zoom * 0.1));
    }
};


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    auto window = new QMainWindow();
    window->setGeometry(100, 100, 900, 900);
    auto view = new MyGraphicsView(window);
    window->setCentralWidget(view);
    window->show();

    return a.exec();
}

修改

可能是一个错误。我提交了QTBUG-66310

0 个答案:

没有答案