How can I find the value of the pixel at the mouse pointer in a grey-scale image

2,035 views
Skip to first unread message

Stephen Shillitoe

unread,
Feb 17, 2020, 10:19:11 AM2/17/20
to pyqtgraph

I have built a PyQt5, Python 3.7 windows application that uses PyQtGraph to view monochrome (greyscale) Magnetic Resonance DICOM images. As I move the mouse pointer over the image, I would like to display the value of the pixel under the pointer on the window. There is no obvious (to me) functionality in PyQtGraph to do this. I would be very grateful for any suggestions by more experienced developers of how to do this. Here is an edited code segment showing how I display the image (pixelArray) in an MDI subwindow.

layout = QVBoxLayout()
widget = QWidget()
widget.setLayout(layout)
self.subWindow.setWidget(widget) 

imageViewer = pg.GraphicsLayoutWidget()
viewBox = imageViewer.addViewBox()
image= pg.ImageItem(border='w')
viewBox.addItem(image)
imageView = pg.ImageView(view=viewBox, imageItem=image)
layout.addWidget(imageView)
imageView.setImage(pixelArray)

Patrick

unread,
Feb 17, 2020, 9:47:29 PM2/17/20
to pyqtgraph
Hi,


You may need to convert the axis coordinates (probably just rounding/casting to integer), and maybe do some bounds checking, but then just take the mouse move event coordinates and use them to index the value from your pixelArray.

Patrick

s.shil...@ntlworld.com

unread,
Feb 18, 2020, 5:32:42 AM2/18/20
to pyqt...@googlegroups.com, Patrick
Thank you Patrick for your suggestion. It looks promising, I'll investigate it further
Steve

--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/cb625e45-ceb8-4227-a4bd-d5e8d3e38527%40googlegroups.com.

 

Stephen Shillitoe

unread,
Feb 18, 2020, 8:38:21 AM2/18/20
to pyqtgraph
I've tried to adapt the crosshair example to my code without success - I cannot get the mouse clicked event to fire.  I think I must be missing something basic.  Here is the code I have tried.  I am new to pyqtgraph, so any suggestions would be gratefully received.

imageViewer = pg.GraphicsLayoutWidget()
imageViewer.setMouseTracking(True)
viewBox = imageViewer.addViewBox()
imageViewer.scene().sigMouseClicked.connect(self.getPixel)
#also tried, without success
#viewBox.proxy = pg.SignalProxy(viewBox.scene().sigMouseClicked, rateLimit=60, slot=self.getPixel)

def getPixel(self, event):
        print('getPixel')
        print (str(event.pos().x()),str(event.pos().y()))
        event.accept()

Patrick

unread,
Feb 19, 2020, 1:07:26 AM2/19/20
to pyqtgraph
A working example, hopefully should help you out:

#!/usr/bin/env python3

import numpy as np
from PyQt5 import QtWidgets
import pyqtgraph as pg

#!/usr/bin/env python3

import numpy as np
from PyQt5 import QtWidgets
import pyqtgraph as pg
class TestImage(QtWidgets.QMainWindow):

   
def __init__(self):
       
super().__init__()

       
# Basic UI layout
       
self.statusbar = QtWidgets.QStatusBar(self)
       
self.setStatusBar(self.statusbar)
       
self.glw = pg.GraphicsLayoutWidget()
       
self.setCentralWidget(self.glw)

       
# Make image plot
       
self.p1 = self.glw.addPlot()
       
self.p1.getViewBox().setAspectLocked()
       
# Draw axes and ticks above image/data
       
[ self.p1.getAxis(ax).setZValue(10) for ax in self.p1.axes ]
       
self.data = np.random.rand(120, 100)
       
self.img = pg.ImageItem(self.data)
       
self.p1.addItem(self.img)
       
# Centre axis ticks on pixel
       
self.img.setPos(-0.5, -0.5)

       
# Swap commented lines to choose between hover or click events
       
self.p1.scene().sigMouseMoved.connect(self.mouseMovedEvent)
       
#self.p1.scene().sigMouseClicked.connect(self.mouseClickedEvent)

   
def mouseClickedEvent(self, event):
       
self.mouseMovedEvent(event.pos())

   
def mouseMovedEvent(self, pos):
       
# Check if event is inside image, and convert from screen/pixels to image xy indicies
       
if self.p1.sceneBoundingRect().contains(pos):
            mousePoint
= self.p1.getViewBox().mapSceneToView(pos)
            x_i
= round(mousePoint.x())
            y_i
= round(mousePoint.y())
           
if x_i > 0 and x_i < self.data.shape[0] and y_i > 0 and y_i < self.data.shape[1]:
               
self.statusbar.showMessage("({}, {}) = {:0.2f}".format(x_i, y_i, self.data[x_i, y_i]))
               
return
       
self.statusbar.clearMessage()

def main():
   
import sys
    app
= QtWidgets.QApplication(sys.argv)
    mainwindow
= TestImage()
    mainwindow
.show()
    sys
.exit(app.exec_())

if __name__ == '__main__':
    main
()


Patrick

s.shil...@ntlworld.com

unread,
Feb 19, 2020, 3:14:26 AM2/19/20
to pyqt...@googlegroups.com, Patrick
Thank you Patrick, that looks very helpful. I'll integrate it into my application and let you know how I get on
Steve


           
if x_i > 0 and x_i < self . data . shape [ 0 ] and y_i > 0 and y_i < self . data . shape [ 1 ]:
               
self . statusbar . showMessage ( "({}, {}) = {:0.2f}" . format ( x_i , y_i , self . data [ x_i , y_i ]))
               
return
       
self . statusbar . clearMessage ()

def main ():
   
import sys
    app
= QtWidgets . QApplication ( sys . argv )
    mainwindow
= TestImage ()
    mainwindow
. show ()
    sys
. exit ( app . exec_ ())

if __name__ == '__main__' :
    main
()


Patrick

On Wednesday, 19 February 2020 00:08:21 UTC+10:30, Stephen Shillitoe wrote:
I've tried to adapt the crosshair example to my code without success - I cannot get the mouse clicked event to fire.  I think I must be missing something basic.  Here is the code I have tried.  I am new to pyqtgraph, so any suggestions would be gratefully received.

imageViewer = pg.GraphicsLayoutWidget()
imageViewer.setMouseTracking( True)
viewBox = imageViewer.addViewBox()
imageViewer.scene(). sigMouseClicked.connect(self. getPixel)
#also tried, without success
#viewBox.proxy = pg.SignalProxy(viewBox.scene() .sigMouseClicked, rateLimit=60, slot=self.getPixel)

def getPixel(self, event):
        print('getPixel')
        print (str(event.pos().x()),str( event.pos().y()))
        event.accept()


On Monday, February 17, 2020 at 3:19:11 PM UTC, Stephen Shillitoe wrote:

I have built a PyQt5, Python 3.7 windows application that uses PyQtGraph to view monochrome (greyscale) Magnetic Resonance DICOM images. As I move the mouse pointer over the image, I would like to display the value of the pixel under the pointer on the window. There is no obvious (to me) functionality in PyQtGraph to do this. I would be very grateful for any suggestions by more experienced developers of how to do this. Here is an edited code segment showing how I display the image (pixelArray) in an MDI subwindow.

layout = QVBoxLayout()
widget = QWidget()
widget.setLayout(layout)
self.subWindow.setWidget(widget) 

imageViewer = pg.GraphicsLayoutWidget()
viewBox = imageViewer.addViewBox()
image= pg.ImageItem(border='w')
viewBox.addItem(image)
imageView = pg.ImageView(view=viewBox, imageItem=image)
layout.addWidget(imageView)
imageView.setImage(pixelArray)

--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+...@googlegroups.com.

Stephen Shillitoe

unread,
Feb 20, 2020, 2:25:20 PM2/20/20
to pyqtgraph
Thank you for your previous post. Because of this, I have managed to get the following code working.  However, in function getPixel, in order to get the commented out code to work, I need to pass imv (ImageView) and pixelArray (the image)  into getPixel.  So when I change
 imv.getView().scene().sigMouseMoved.connect(self.getPixel), which works 
to
imv.getView().scene().sigMouseMoved.connect(lambda: self.getPixel(imv, pixelArray)

I get an error informing me that there is no positional argument for pos; thus,
Traceback (most recent call last):
  File "C:\Users\scsssh\source\repo1\Weasel\Weasel.py", line 736, in <lambda>
    lambda: self.getPixel(imv, pixelArray))
TypeError: getPixel() missing 1 required positional argument: 'pos'

So, I think the question is how do I pass imv and pixelArray into getPixel as function arguments.

    def getPixel(self, pos):
        try:
            print ("Image position: {}".format(pos))
           # container = imv.getView()
          #  if container.sceneBoundingRect().contains(pos): 
           #     mousePoint = container.getViewBox().mapSceneToView (pos) 
           #     x_i = round(mousePoint.x()) 
             #   y_i = round(mousePoint.y()) 
            #    if x_i > 0 and x_i < img.shape [ 0 ] \
            #        and y_i > 0 and y_i < img.shape [ 1 ]: 
             #      print( "({}, {}) = {:0.2f}" . format ( x_i , y_i , img [ x_i , y_i ])) 

On Monday, February 17, 2020 at 3:19:11 PM UTC, Stephen Shillitoe wrote:

Patrick

unread,
Feb 20, 2020, 7:00:12 PM2/20/20
to pyqtgraph
Hi,

Your lambda function need to accept the "pos" argument received from the mouse move signal and pass it on to your getPixel function, along with whatever else you need to. So something like:
imv.getView().scene().sigMouseMoved.connect(lambda pos: self.getPixel(pos, imv, pixelArray))
# ...
def getPixel(self, pos, imv, pixelArray):
   
# ...


Just as a side note, I consider the pyqtgraph ImageView as more of an example of how to build the pyqtgraph components into an application, rather than a component to be integrated into your own apps. As such, it's not easy to extend or modify, as you have just found out... I might suggest copy-pasting the ImageView code into your own class (built on QMainWindow for example, as in my previous code), as if you decide to further change the appearance or behaviour of ImageView, you'll find yourself doing more awkward coding tricks like this. I know it's probably not a popular suggestion to re-write your application, but might be a good time to do it now if it saves more problems in the future!

Patrick

Stephen Shillitoe

unread,
Feb 21, 2020, 4:43:29 AM2/21/20
to pyqtgraph
Thank you for help Patrick, that worked.  I take your point about including pyqtgraph source code in my project, it looks like the way forward. Thanks again Steve


On Monday, February 17, 2020 at 3:19:11 PM UTC, Stephen Shillitoe wrote:
Reply all
Reply to author
Forward
0 new messages