Commit c814499b authored by Luke Campagnola's avatar Luke Campagnola
Browse files

Added features from meganbkratz:

 - isocurves
 - array processing through gradientwidget
parent 7e926ba1
......@@ -187,7 +187,7 @@ class HistogramDetrend(CtrlNode):
"""Removes baseline from data by computing mode (from histogram) of beginning and end of data."""
nodeName = 'HistogramDetrend'
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})
]
......
......@@ -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
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:
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.
levels - List [min, max]; optionally rescale data before converting through the
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')
order = [2,1,0,3] ## for some reason, the colors line up as BGR in the final image.
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.
if data.shape[2] == 1:
for i in xrange(3):
imgData[..., order[i]] = data[..., 0]
......@@ -732,8 +737,86 @@ def rescaleData(data, scale, offset):
#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):
"""
Generate isosurface from volumetric data using marching tetrahedra algorithm.
......
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)
\ No newline at end of file
......@@ -55,6 +55,7 @@ class GradientWidget(GraphicsView):
self.setMaximumHeight(16777215)
def __getattr__(self, attr):
### wrap methods from GradientEditorItem
return getattr(self.item, attr)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment