Search code examples
pythonpyside2pyqtgraph

Antialiasing images in pyqtgraph ImageView


I am using PyQtGraph and am really enjoying it, but have hit upon an issue that may force me to move to something else.

I am displaying medical images (CT/MRI etc.) as numpy 2D or 3D arrays in the ImageView which gives the nice slider view for volume data. The problem is theses images are often low res (256x256) and when viewed on large monitors or just zoomed-in they look blocky and horrible.

enter image description here

How can I show these images antialiased? This seems to be possible as mentioned here: How can anti-aliasing be enabled in a pyqtgraph ImageView?

and a few other places suggesting all you need to do is:

import pyqtgraph as pg
pg.setConfigOptions(antialias=True)

and enable antialiasing in the graphics view, which I assume would be this:

myImageViewWidget = pg.ImageView(parent=None)
myImageViewWidget.ui.graphicsView.setAntialiasing(True)

But this doesn't seem to do anything different in my code. What am I doing wrong?

I'm using Windows 10 (but need it to work on MacOs - Darwin), Python 3.7, PySide 2 (5.15.12) and PyQtGraph 0.12.3

'Minimum' code to reproduce the issue (not quite but I want to keep ImageView subclassed as that's how I have it in my code):

import sys
from PySide2.QtWidgets import (
    QApplication,
    QHBoxLayout,
    QMainWindow,
    QWidget,
)
import pyqtgraph as pg
import numpy as np

pg.setConfigOptions(antialias=True)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.cw = QWidget(self)
        self.cw.setAutoFillBackground(True)
        self.setCentralWidget(self.cw)

        self.layout = QHBoxLayout()
        self.cw.setLayout(self.layout)

        self.ImgWidget = MyImageWidget(parent=self)
        self.layout.addWidget(self.ImgWidget)

        self.show()


class MyImageWidget(pg.ImageView):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.ui.histogram.hide()
        self.ui.roiBtn.hide()
        self.ui.menuBtn.hide()
        self.ui.graphicsView.setAntialiasing(True)

        # 5 frames of 50x50 random noise
        img = (1000 * np.random.normal(size=(5, 50, 50))) - 500
        self.setImage(img)


def main():
    app = QApplication()
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Solution

  • What you're referring to is not antialiasing.

    Antialiasing "smoothens" the portions of an image that cannot "fit" precisely a single physical pixel.

    What you are seeing is in fact the opposite, as each source pixel is actually large enough to be shown as it is: a square that possibly occupies more physical pixels.

    What you probably want is a blur effect, which can be achieved through a QGraphicsBlurEffect set on the self.imageItem of the view:

    class MyImageWidget(pg.ImageView):
        def __init__(self, parent=None):
            # ...
            self.blurEffect = QGraphicsBlurEffect(blurRadius=1.1)
            self.imageItem.setGraphicsEffect(self.blurEffect)
    

    Note that since the image item is always scaled and the blur effect is proportional, you might need to adjust the blur radius to even smaller values depending on the shown resolution (but still bigger than 1.0).