Added features from meganbkratz:
- isocurves - array processing through gradientwidget
This commit is contained in:
parent
7e926ba136
commit
c814499bee
@ -187,7 +187,7 @@ class HistogramDetrend(CtrlNode):
|
|||||||
"""Removes baseline from data by computing mode (from histogram) of beginning and end of data."""
|
"""Removes baseline from data by computing mode (from histogram) of beginning and end of data."""
|
||||||
nodeName = 'HistogramDetrend'
|
nodeName = 'HistogramDetrend'
|
||||||
uiTemplate = [
|
uiTemplate = [
|
||||||
('windowSize', 'intSpin', {'value': 500, 'min': 10, 'max': 1000000}),
|
('windowSize', 'intSpin', {'value': 500, 'min': 10, 'max': 1000000, 'suffix': 'pts'}),
|
||||||
('numBins', 'intSpin', {'value': 50, 'min': 3, 'max': 1000000})
|
('numBins', 'intSpin', {'value': 50, 'min': 3, 'max': 1000000})
|
||||||
]
|
]
|
||||||
|
|
||||||
|
89
functions.py
89
functions.py
@ -409,12 +409,12 @@ def affineSlice(data, shape, origin, vectors, axes, **kargs):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def makeARGB(data, lut=None, levels=None):
|
def makeARGB(data, lut=None, levels=None, useRGBA=False):
|
||||||
"""
|
"""
|
||||||
Convert a 2D or 3D array into an ARGB array suitable for building QImages
|
Convert a 2D or 3D array into an ARGB array suitable for building QImages
|
||||||
Will optionally do scaling and/or table lookups to determine final colors.
|
Will optionally do scaling and/or table lookups to determine final colors.
|
||||||
|
|
||||||
Returns the ARGB array and a boolean indicating whether there is alpha channel data.
|
Returns the ARGB array (values 0-255) and a boolean indicating whether there is alpha channel data.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
data - 2D or 3D numpy array of int/float types
|
data - 2D or 3D numpy array of int/float types
|
||||||
@ -433,6 +433,8 @@ def makeARGB(data, lut=None, levels=None):
|
|||||||
Lookup tables can be built using GradientWidget.
|
Lookup tables can be built using GradientWidget.
|
||||||
levels - List [min, max]; optionally rescale data before converting through the
|
levels - List [min, max]; optionally rescale data before converting through the
|
||||||
lookup table. rescaled = (data-min) * len(lut) / (max-min)
|
lookup table. rescaled = (data-min) * len(lut) / (max-min)
|
||||||
|
useRGBA - If True, the data is returned in RGBA order. The default is
|
||||||
|
False, which returns in BGRA order for use with QImage.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -580,8 +582,11 @@ def makeARGB(data, lut=None, levels=None):
|
|||||||
|
|
||||||
prof.mark('4')
|
prof.mark('4')
|
||||||
|
|
||||||
|
if useRGBA:
|
||||||
|
order = [0,1,2,3] ## array comes out RGBA
|
||||||
|
else:
|
||||||
order = [2,1,0,3] ## for some reason, the colors line up as BGR in the final image.
|
order = [2,1,0,3] ## for some reason, the colors line up as BGR in the final image.
|
||||||
|
|
||||||
if data.shape[2] == 1:
|
if data.shape[2] == 1:
|
||||||
for i in xrange(3):
|
for i in xrange(3):
|
||||||
imgData[..., order[i]] = data[..., 0]
|
imgData[..., order[i]] = data[..., 0]
|
||||||
@ -732,6 +737,84 @@ def rescaleData(data, scale, offset):
|
|||||||
#return facets
|
#return facets
|
||||||
|
|
||||||
|
|
||||||
|
def isocurve(data, level):
|
||||||
|
"""
|
||||||
|
Generate isocurve from 2D data using marching squares algorithm.
|
||||||
|
|
||||||
|
*data* 2D numpy array of scalar values
|
||||||
|
*level* The level at which to generate an isosurface
|
||||||
|
|
||||||
|
This function is SLOW; plenty of room for optimization here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
sideTable = [
|
||||||
|
[],
|
||||||
|
[0,1],
|
||||||
|
[1,2],
|
||||||
|
[0,2],
|
||||||
|
[0,3],
|
||||||
|
[1,3],
|
||||||
|
[0,1,2,3],
|
||||||
|
[2,3],
|
||||||
|
[2,3],
|
||||||
|
[0,1,2,3],
|
||||||
|
[1,3],
|
||||||
|
[0,3],
|
||||||
|
[0,2],
|
||||||
|
[1,2],
|
||||||
|
[0,1],
|
||||||
|
[]
|
||||||
|
]
|
||||||
|
|
||||||
|
edgeKey=[
|
||||||
|
[(0,1),(0,0)],
|
||||||
|
[(0,0), (1,0)],
|
||||||
|
[(1,0), (1,1)],
|
||||||
|
[(1,1), (0,1)]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
## mark everything below the isosurface level
|
||||||
|
mask = data < level
|
||||||
|
|
||||||
|
### make four sub-fields and compute indexes for grid cells
|
||||||
|
index = np.zeros([x-1 for x in data.shape], dtype=np.ubyte)
|
||||||
|
fields = np.empty((2,2), dtype=object)
|
||||||
|
slices = [slice(0,-1), slice(1,None)]
|
||||||
|
for i in [0,1]:
|
||||||
|
for j in [0,1]:
|
||||||
|
fields[i,j] = mask[slices[i], slices[j]]
|
||||||
|
#vertIndex = i - 2*j*i + 3*j + 4*k ## this is just to match Bourk's vertex numbering scheme
|
||||||
|
vertIndex = i+2*j
|
||||||
|
#print i,j,k," : ", fields[i,j,k], 2**vertIndex
|
||||||
|
index += fields[i,j] * 2**vertIndex
|
||||||
|
#print index
|
||||||
|
#print index
|
||||||
|
|
||||||
|
## add lines
|
||||||
|
for i in xrange(index.shape[0]): # data x-axis
|
||||||
|
for j in xrange(index.shape[1]): # data y-axis
|
||||||
|
sides = sideTable[index[i,j]]
|
||||||
|
for l in range(0, len(sides), 2): ## faces for this grid cell
|
||||||
|
edges = sides[l:l+2]
|
||||||
|
pts = []
|
||||||
|
for m in [0,1]: # points in this face
|
||||||
|
p1 = edgeKey[edges[m]][0] # p1, p2 are points at either side of an edge
|
||||||
|
p2 = edgeKey[edges[m]][1]
|
||||||
|
v1 = data[i+p1[0], j+p1[1]] # v1 and v2 are the values at p1 and p2
|
||||||
|
v2 = data[i+p2[0], j+p2[1]]
|
||||||
|
f = (level-v1) / (v2-v1)
|
||||||
|
fi = 1.0 - f
|
||||||
|
p = ( ## interpolate between corners
|
||||||
|
p1[0]*fi + p2[0]*f + i + 0.5,
|
||||||
|
p1[1]*fi + p2[1]*f + j + 0.5
|
||||||
|
)
|
||||||
|
pts.append(p)
|
||||||
|
lines.append(pts)
|
||||||
|
|
||||||
|
return lines ## a list of pairs of points
|
||||||
|
|
||||||
|
|
||||||
def isosurface(data, level):
|
def isosurface(data, level):
|
||||||
|
38
graphicsItems/IsocurveItem.py
Normal file
38
graphicsItems/IsocurveItem.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
|
||||||
|
from GraphicsObject import *
|
||||||
|
import pyqtgraph.functions as fn
|
||||||
|
from pyqtgraph.Qt import QtGui
|
||||||
|
|
||||||
|
|
||||||
|
class IsocurveItem(GraphicsObject):
|
||||||
|
"""
|
||||||
|
Item displaying an isocurve of a 2D array.
|
||||||
|
|
||||||
|
To align this item correctly with an ImageItem,
|
||||||
|
call isocurve.setParentItem(image)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, data, level, pen='w'):
|
||||||
|
GraphicsObject.__init__(self)
|
||||||
|
|
||||||
|
lines = fn.isocurve(data, level)
|
||||||
|
|
||||||
|
self.path = QtGui.QPainterPath()
|
||||||
|
self.setPen(pen)
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
self.path.moveTo(*line[0])
|
||||||
|
self.path.lineTo(*line[1])
|
||||||
|
|
||||||
|
def setPen(self, *args, **kwargs):
|
||||||
|
self.pen = fn.mkPen(*args, **kwargs)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def boundingRect(self):
|
||||||
|
return self.path.boundingRect()
|
||||||
|
|
||||||
|
def paint(self, p, *args):
|
||||||
|
p.setPen(self.pen)
|
||||||
|
p.drawPath(self.path)
|
||||||
|
|
@ -55,6 +55,7 @@ class GradientWidget(GraphicsView):
|
|||||||
self.setMaximumHeight(16777215)
|
self.setMaximumHeight(16777215)
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
|
### wrap methods from GradientEditorItem
|
||||||
return getattr(self.item, attr)
|
return getattr(self.item, attr)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user