ROI tests pass with row-major axis order
This commit is contained in:
parent
956251f7ee
commit
df691596a7
@ -3,6 +3,7 @@ from .Qt import QtCore, QtGui
|
|||||||
from .Point import Point
|
from .Point import Point
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class SRTTransform(QtGui.QTransform):
|
class SRTTransform(QtGui.QTransform):
|
||||||
"""Transform that can always be represented as a combination of 3 matrices: scale * rotate * translate
|
"""Transform that can always be represented as a combination of 3 matrices: scale * rotate * translate
|
||||||
This transform has no shear; angles are always preserved.
|
This transform has no shear; angles are always preserved.
|
||||||
@ -165,6 +166,7 @@ class SRTTransform(QtGui.QTransform):
|
|||||||
|
|
||||||
def matrix(self):
|
def matrix(self):
|
||||||
return np.array([[self.m11(), self.m12(), self.m13()],[self.m21(), self.m22(), self.m23()],[self.m31(), self.m32(), self.m33()]])
|
return np.array([[self.m11(), self.m12(), self.m13()],[self.m21(), self.m22(), self.m23()],[self.m31(), self.m32(), self.m33()]])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from . import widgets
|
from . import widgets
|
||||||
|
@ -37,9 +37,6 @@ class GraphicsItem(object):
|
|||||||
if register:
|
if register:
|
||||||
GraphicsScene.registerObject(self) ## workaround for pyqt bug in graphicsscene.items()
|
GraphicsScene.registerObject(self) ## workaround for pyqt bug in graphicsscene.items()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def getViewWidget(self):
|
def getViewWidget(self):
|
||||||
"""
|
"""
|
||||||
Return the view widget for this item.
|
Return the view widget for this item.
|
||||||
@ -95,7 +92,6 @@ class GraphicsItem(object):
|
|||||||
def forgetViewBox(self):
|
def forgetViewBox(self):
|
||||||
self._viewBox = None
|
self._viewBox = None
|
||||||
|
|
||||||
|
|
||||||
def deviceTransform(self, viewportTransform=None):
|
def deviceTransform(self, viewportTransform=None):
|
||||||
"""
|
"""
|
||||||
Return the transform that converts local item coordinates to device coordinates (usually pixels).
|
Return the transform that converts local item coordinates to device coordinates (usually pixels).
|
||||||
|
@ -279,6 +279,42 @@ class ImageItem(GraphicsObject):
|
|||||||
if gotNewData:
|
if gotNewData:
|
||||||
self.sigImageChanged.emit()
|
self.sigImageChanged.emit()
|
||||||
|
|
||||||
|
def dataTransform(self):
|
||||||
|
"""Return the transform that maps from this image's input array to its
|
||||||
|
local coordinate system.
|
||||||
|
|
||||||
|
This transform corrects for the transposition that occurs when image data
|
||||||
|
is interpreted in row-major order.
|
||||||
|
"""
|
||||||
|
# Might eventually need to account for downsampling / clipping here
|
||||||
|
tr = QtGui.QTransform()
|
||||||
|
if self.axisOrder == 'row-major':
|
||||||
|
# transpose
|
||||||
|
tr.scale(1, -1)
|
||||||
|
tr.rotate(-90)
|
||||||
|
return tr
|
||||||
|
|
||||||
|
def inverseDataTransform(self):
|
||||||
|
"""Return the transform that maps from this image's local coordinate
|
||||||
|
system to its input array.
|
||||||
|
|
||||||
|
See dataTransform() for more information.
|
||||||
|
"""
|
||||||
|
tr = QtGui.QTransform()
|
||||||
|
if self.axisOrder == 'row-major':
|
||||||
|
# transpose
|
||||||
|
tr.scale(1, -1)
|
||||||
|
tr.rotate(-90)
|
||||||
|
return tr
|
||||||
|
|
||||||
|
def mapToData(self, obj):
|
||||||
|
tr = self.inverseDataTransform()
|
||||||
|
return tr.map(obj)
|
||||||
|
|
||||||
|
def mapFromData(self, obj):
|
||||||
|
tr = self.dataTransform()
|
||||||
|
return tr.map(obj)
|
||||||
|
|
||||||
def quickMinMax(self, targetSize=1e6):
|
def quickMinMax(self, targetSize=1e6):
|
||||||
"""
|
"""
|
||||||
Estimate the min/max values of the image data by subsampling.
|
Estimate the min/max values of the image data by subsampling.
|
||||||
|
@ -1017,7 +1017,7 @@ class ROI(GraphicsObject):
|
|||||||
If returnSlice is set to False, the function returns a pair of tuples with the values that would have
|
If returnSlice is set to False, the function returns a pair of tuples with the values that would have
|
||||||
been used to generate the slice objects. ((ax0Start, ax0Stop), (ax1Start, ax1Stop))
|
been used to generate the slice objects. ((ax0Start, ax0Stop), (ax1Start, ax1Stop))
|
||||||
|
|
||||||
If the slice can not be computed (usually because the scene/transforms are not properly
|
If the slice cannot be computed (usually because the scene/transforms are not properly
|
||||||
constructed yet), then the method returns None.
|
constructed yet), then the method returns None.
|
||||||
"""
|
"""
|
||||||
## Determine shape of array along ROI axes
|
## Determine shape of array along ROI axes
|
||||||
@ -1104,7 +1104,8 @@ class ROI(GraphicsObject):
|
|||||||
|
|
||||||
shape, vectors, origin = self.getAffineSliceParams(data, img, axes, fromBoundingRect=fromBR)
|
shape, vectors, origin = self.getAffineSliceParams(data, img, axes, fromBoundingRect=fromBR)
|
||||||
if not returnMappedCoords:
|
if not returnMappedCoords:
|
||||||
return fn.affineSlice(data, shape=shape, vectors=vectors, origin=origin, axes=axes, **kwds)
|
rgn = fn.affineSlice(data, shape=shape, vectors=vectors, origin=origin, axes=axes, **kwds)
|
||||||
|
return rgn
|
||||||
else:
|
else:
|
||||||
kwds['returnCoords'] = True
|
kwds['returnCoords'] = True
|
||||||
result, coords = fn.affineSlice(data, shape=shape, vectors=vectors, origin=origin, axes=axes, **kwds)
|
result, coords = fn.affineSlice(data, shape=shape, vectors=vectors, origin=origin, axes=axes, **kwds)
|
||||||
@ -1119,29 +1120,34 @@ class ROI(GraphicsObject):
|
|||||||
(shape, vectors, origin) to extract a subset of *data* using this ROI
|
(shape, vectors, origin) to extract a subset of *data* using this ROI
|
||||||
and *img* to specify the subset.
|
and *img* to specify the subset.
|
||||||
|
|
||||||
|
If *fromBoundingRect* is True, then the ROI's bounding rectangle is used
|
||||||
|
rather than the shape of the ROI.
|
||||||
|
|
||||||
See :func:`getArrayRegion <pyqtgraph.ROI.getArrayRegion>` for more information.
|
See :func:`getArrayRegion <pyqtgraph.ROI.getArrayRegion>` for more information.
|
||||||
"""
|
"""
|
||||||
if self.scene() is not img.scene():
|
if self.scene() is not img.scene():
|
||||||
raise Exception("ROI and target item must be members of the same scene.")
|
raise Exception("ROI and target item must be members of the same scene.")
|
||||||
|
|
||||||
origin = self.mapToItem(img, QtCore.QPointF(0, 0))
|
origin = img.mapToData(self.mapToItem(img, QtCore.QPointF(0, 0)))
|
||||||
|
|
||||||
## vx and vy point in the directions of the slice axes, but must be scaled properly
|
## vx and vy point in the directions of the slice axes, but must be scaled properly
|
||||||
vx = self.mapToItem(img, QtCore.QPointF(1, 0)) - origin
|
vx = img.mapToData(self.mapToItem(img, QtCore.QPointF(1, 0))) - origin
|
||||||
vy = self.mapToItem(img, QtCore.QPointF(0, 1)) - origin
|
vy = img.mapToData(self.mapToItem(img, QtCore.QPointF(0, 1))) - origin
|
||||||
|
|
||||||
lvx = np.sqrt(vx.x()**2 + vx.y()**2)
|
lvx = np.sqrt(vx.x()**2 + vx.y()**2)
|
||||||
lvy = np.sqrt(vy.x()**2 + vy.y()**2)
|
lvy = np.sqrt(vy.x()**2 + vy.y()**2)
|
||||||
pxLen = img.width() / float(data.shape[axes[0]])
|
#pxLen = img.width() / float(data.shape[axes[0]])
|
||||||
#img.width is number of pixels, not width of item.
|
##img.width is number of pixels, not width of item.
|
||||||
#need pxWidth and pxHeight instead of pxLen ?
|
##need pxWidth and pxHeight instead of pxLen ?
|
||||||
sx = pxLen / lvx
|
#sx = pxLen / lvx
|
||||||
sy = pxLen / lvy
|
#sy = pxLen / lvy
|
||||||
|
sx = 1.0 / lvx
|
||||||
|
sy = 1.0 / lvy
|
||||||
|
|
||||||
vectors = ((vx.x()*sx, vx.y()*sx), (vy.x()*sy, vy.y()*sy))
|
vectors = ((vx.x()*sx, vx.y()*sx), (vy.x()*sy, vy.y()*sy))
|
||||||
if fromBoundingRect is True:
|
if fromBoundingRect is True:
|
||||||
shape = self.boundingRect().width(), self.boundingRect().height()
|
shape = self.boundingRect().width(), self.boundingRect().height()
|
||||||
origin = self.mapToItem(img, self.boundingRect().topLeft())
|
origin = img.mapToData(self.mapToItem(img, self.boundingRect().topLeft()))
|
||||||
origin = (origin.x(), origin.y())
|
origin = (origin.x(), origin.y())
|
||||||
else:
|
else:
|
||||||
shape = self.state['size']
|
shape = self.state['size']
|
||||||
@ -1150,10 +1156,10 @@ class ROI(GraphicsObject):
|
|||||||
shape = [abs(shape[0]/sx), abs(shape[1]/sy)]
|
shape = [abs(shape[0]/sx), abs(shape[1]/sy)]
|
||||||
|
|
||||||
if getConfigOption('imageAxisOrder') == 'row-major':
|
if getConfigOption('imageAxisOrder') == 'row-major':
|
||||||
vectors = [vectors[1][::-1], vectors[0][::-1]]
|
# transpose output
|
||||||
|
vectors = vectors[::-1]
|
||||||
shape = shape[::-1]
|
shape = shape[::-1]
|
||||||
origin = origin[::-1]
|
|
||||||
|
|
||||||
return shape, vectors, origin
|
return shape, vectors, origin
|
||||||
|
|
||||||
def renderShapeMask(self, width, height):
|
def renderShapeMask(self, width, height):
|
||||||
|
@ -8,7 +8,7 @@ from pyqtgraph.tests import assertImageApproved, mouseMove, mouseDrag, mouseClic
|
|||||||
app = pg.mkQApp()
|
app = pg.mkQApp()
|
||||||
|
|
||||||
|
|
||||||
def test_getArrayRegion():
|
def test_getArrayRegion(transpose=False):
|
||||||
pr = pg.PolyLineROI([[0, 0], [27, 0], [0, 28]], closed=True)
|
pr = pg.PolyLineROI([[0, 0], [27, 0], [0, 28]], closed=True)
|
||||||
pr.setPos(1, 1)
|
pr.setPos(1, 1)
|
||||||
rois = [
|
rois = [
|
||||||
@ -23,13 +23,19 @@ def test_getArrayRegion():
|
|||||||
|
|
||||||
origMode = pg.getConfigOption('imageAxisOrder')
|
origMode = pg.getConfigOption('imageAxisOrder')
|
||||||
try:
|
try:
|
||||||
pg.setConfigOptions(imageAxisOrder='col-major')
|
if transpose:
|
||||||
check_getArrayRegion(roi, 'roi/'+name, testResize)
|
pg.setConfigOptions(imageAxisOrder='row-major')
|
||||||
pg.setConfigOptions(imageAxisOrder='row-major')
|
check_getArrayRegion(roi, 'roi/'+name, testResize, transpose=True)
|
||||||
check_getArrayRegion(roi, 'roi/'+name, testResize, transpose=True)
|
else:
|
||||||
|
pg.setConfigOptions(imageAxisOrder='col-major')
|
||||||
|
check_getArrayRegion(roi, 'roi/'+name, testResize)
|
||||||
finally:
|
finally:
|
||||||
pg.setConfigOptions(imageAxisOrder=origMode)
|
pg.setConfigOptions(imageAxisOrder=origMode)
|
||||||
|
|
||||||
|
|
||||||
|
def test_getArrayRegion_axisorder():
|
||||||
|
test_getArrayRegion(transpose=True)
|
||||||
|
|
||||||
|
|
||||||
def check_getArrayRegion(roi, name, testResize=True, transpose=False):
|
def check_getArrayRegion(roi, name, testResize=True, transpose=False):
|
||||||
initState = roi.getState()
|
initState = roi.getState()
|
||||||
@ -55,8 +61,8 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False):
|
|||||||
vb2.setPos(6, 203)
|
vb2.setPos(6, 203)
|
||||||
vb2.resize(188, 191)
|
vb2.resize(188, 191)
|
||||||
|
|
||||||
img1 = TransposedImageItem(border='w', transpose=transpose)
|
img1 = pg.ImageItem(border='w')
|
||||||
img2 = TransposedImageItem(border='w', transpose=transpose)
|
img2 = pg.ImageItem(border='w')
|
||||||
|
|
||||||
vb1.addItem(img1)
|
vb1.addItem(img1)
|
||||||
vb2.addItem(img2)
|
vb2.addItem(img2)
|
||||||
@ -68,6 +74,9 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False):
|
|||||||
data[:, :, 2, :] += 10
|
data[:, :, 2, :] += 10
|
||||||
data[:, :, :, 3] += 10
|
data[:, :, :, 3] += 10
|
||||||
|
|
||||||
|
if transpose:
|
||||||
|
data = data.transpose(0, 2, 1, 3)
|
||||||
|
|
||||||
img1.setImage(data[0, ..., 0])
|
img1.setImage(data[0, ..., 0])
|
||||||
vb1.setAspectLocked()
|
vb1.setAspectLocked()
|
||||||
vb1.enableAutoRange(True, True)
|
vb1.enableAutoRange(True, True)
|
||||||
@ -75,6 +84,12 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False):
|
|||||||
roi.setZValue(10)
|
roi.setZValue(10)
|
||||||
vb1.addItem(roi)
|
vb1.addItem(roi)
|
||||||
|
|
||||||
|
if isinstance(roi, pg.RectROI):
|
||||||
|
if transpose:
|
||||||
|
assert roi.getAffineSliceParams(data, img1, axes=(1, 2)) == ([28.0, 27.0], ((1.0, 0.0), (0.0, 1.0)), (1.0, 1.0))
|
||||||
|
else:
|
||||||
|
assert roi.getAffineSliceParams(data, img1, axes=(1, 2)) == ([27.0, 28.0], ((1.0, 0.0), (0.0, 1.0)), (1.0, 1.0))
|
||||||
|
|
||||||
rgn = roi.getArrayRegion(data, img1, axes=(1, 2))
|
rgn = roi.getArrayRegion(data, img1, axes=(1, 2))
|
||||||
#assert np.all((rgn == data[:, 1:-2, 1:-2, :]) | (rgn == 0))
|
#assert np.all((rgn == data[:, 1:-2, 1:-2, :]) | (rgn == 0))
|
||||||
img2.setImage(rgn[0, ..., 0])
|
img2.setImage(rgn[0, ..., 0])
|
||||||
|
Loading…
Reference in New Issue
Block a user