def render(self): # Convert data to QImage for display. profile = debug.Profiler() if self.image is None or self.image.size == 0: return if isinstance(self.lut, collections.Callable): lut = self.lut(self.image) else: lut = self.lut if self.logScale: image = self.image + 1 with np.errstate(invalid="ignore"): image = image.astype(np.float) np.log(image, where=image >= 0, out=image) # map to 0-255 else: image = self.image if self.autoDownsample: # reduce dimensions of image based on screen resolution o = self.mapToDevice(QPointF(0, 0)) x = self.mapToDevice(QPointF(1, 0)) y = self.mapToDevice(QPointF(0, 1)) w = Point(x - o).length() h = Point(y - o).length() if w == 0 or h == 0: self.qimage = None return xds = max(1, int(1.0 / w)) yds = max(1, int(1.0 / h)) axes = [1, 0] if self.axisOrder == "row-major" else [0, 1] image = fn.downsample(image, xds, axis=axes[0]) image = fn.downsample(image, yds, axis=axes[1]) self._lastDownsample = (xds, yds) else: pass # if the image data is a small int, then we can combine levels + lut # into a single lut for better performance levels = self.levels if levels is not None and levels.ndim == 1 and image.dtype in ( np.ubyte, np.uint16): if self._effectiveLut is None: eflsize = 2**(image.itemsize * 8) ind = np.arange(eflsize) minlev, maxlev = levels levdiff = maxlev - minlev levdiff = 1 if levdiff == 0 else levdiff # don't allow division by 0 if lut is None: efflut = fn.rescaleData(ind, scale=255.0 / levdiff, offset=minlev, dtype=np.ubyte) else: lutdtype = np.min_scalar_type(lut.shape[0] - 1) efflut = fn.rescaleData(ind, scale=(lut.shape[0] - 1) / levdiff, offset=minlev, dtype=lutdtype, clip=(0, lut.shape[0] - 1)) efflut = lut[efflut] self._effectiveLut = efflut lut = self._effectiveLut levels = None # Assume images are in column-major order for backward compatibility # (most images are in row-major order) if self.axisOrder == "col-major": image = image.transpose((1, 0, 2)[:image.ndim]) if self.logScale: with np.errstate(invalid="ignore"): levels = np.log(np.add(levels, 1)) levels[0] = np.nanmax([levels[0], 0]) argb, alpha = fn.makeARGB(image, lut=lut, levels=levels) self.qimage = fn.makeQImage(argb, alpha, transpose=False)
def makeARGBwithNaNs(data, lut=None, levels=None, scale=None, useRGBA=False): """ This is the same as pyqtgraph.makeARGB, except that all NaN's in the data are set to transparent pixels """ nanlocations = np.isnan(data) profile = debug.Profiler() if data.ndim not in (2, 3): raise TypeError("data must be 2D or 3D") if data.ndim == 3 and data.shape[2] > 4: raise TypeError("data.shape[2] must be <= 4") if lut is not None and not isinstance(lut, np.ndarray): lut = np.array(lut) if levels is None: # automatically decide levels based on data dtype if data.dtype.kind == 'u': levels = np.array([0, 2**(data.itemsize * 8) - 1]) elif data.dtype.kind == 'i': s = 2**(data.itemsize * 8 - 1) levels = np.array([-s, s - 1]) elif data.dtype.kind == 'b': levels = np.array([0, 1]) else: raise Exception( 'levels argument is required for float input types') if not isinstance(levels, np.ndarray): levels = np.array(levels) if levels.ndim == 1: if levels.shape[0] != 2: raise Exception('levels argument must have length 2') elif levels.ndim == 2: if lut is not None and lut.ndim > 1: raise Exception( 'Cannot make ARGB data when both levels and lut have ndim > 2') if levels.shape != (data.shape[-1], 2): raise Exception('levels must have shape (data.shape[-1], 2)') else: raise Exception("levels argument must be 1D or 2D (got shape=%s)." % repr(levels.shape)) profile() # Decide on maximum scaled value if scale is None: if lut is not None: scale = lut.shape[0] - 1 else: scale = 255. # Decide on the dtype we want after scaling if lut is None: dtype = np.ubyte else: dtype = np.min_scalar_type(lut.shape[0] - 1) # Apply levels if given if levels is not None: if isinstance(levels, np.ndarray) and levels.ndim == 2: # we are going to rescale each channel independently if levels.shape[0] != data.shape[-1]: raise Exception( "When rescaling multi-channel data, there must be the same number of levels as channels (data.shape[-1] == levels.shape[0])" ) newData = np.empty(data.shape, dtype=int) for i in range(data.shape[-1]): minVal, maxVal = levels[i] if minVal == maxVal: maxVal += 1e-16 newData[..., i] = fn.rescaleData(data[..., i], scale / (maxVal - minVal), minVal, dtype=dtype) data = newData else: # Apply level scaling unless it would have no effect on the data minVal, maxVal = levels if minVal != 0 or maxVal != scale: if minVal == maxVal: maxVal += 1e-16 data = fn.rescaleData(data, scale / (maxVal - minVal), minVal, dtype=dtype) profile() # apply LUT if given if lut is not None: data = fn.applyLookupTable(data, lut) else: if data.dtype is not np.ubyte: data = np.clip(data, 0, 255).astype(np.ubyte) #Set NaNs to transparent data[nanlocations] = [0, 0, 0, 0] profile() # this will be the final image array imgData = np.empty(data.shape[:2] + (4, ), dtype=np.ubyte) profile() # decide channel order 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. # copy data into image array if data.ndim == 2: # This is tempting: # imgData[..., :3] = data[..., np.newaxis] # ..but it turns out this is faster: for i in range(3): imgData[..., i] = data elif data.shape[2] == 1: for i in range(3): imgData[..., i] = data[..., 0] else: for i in range(0, data.shape[2]): imgData[..., i] = data[..., order[i]] profile() # add opaque alpha channel if needed if data.ndim == 2 or data.shape[2] == 3: alpha = False imgData[..., 3] = 255 else: alpha = True profile() return imgData, alpha
def render(self): # Convert data to QImage for display. profile = debug.Profiler() if self.image is None or self.image.size == 0: return # Request a lookup table if this image has only one channel if self.image.ndim == 2 or self.image.shape[2] == 1: if isinstance(self.lut, Callable): lut = self.lut(self.image) else: lut = self.lut else: lut = None if self.autoDownsample: # reduce dimensions of image based on screen resolution o = self.mapToDevice(QtCore.QPointF(0, 0)) x = self.mapToDevice(QtCore.QPointF(1, 0)) y = self.mapToDevice(QtCore.QPointF(0, 1)) # Check if graphics view is too small to render anything if o is None or x is None or y is None: return w = Point(x - o).length() h = Point(y - o).length() if w == 0 or h == 0: self.qimage = None return xds = max(1, int(1.0 / w)) yds = max(1, int(1.0 / h)) axes = [1, 0] if self.axisOrder == 'row-major' else [0, 1] image = fn.downsample(self.image, xds, axis=axes[0]) image = fn.downsample(image, yds, axis=axes[1]) self._lastDownsample = (xds, yds) # Check if downsampling reduced the image size to zero due to inf values. if image.size == 0: return else: image = self.image # if the image data is a small int, then we can combine levels + lut # into a single lut for better performance levels = self.levels if levels is not None and levels.ndim == 1 and image.dtype in ( np.ubyte, np.uint16): if self._effectiveLut is None: eflsize = 2**(image.itemsize * 8) ind = np.arange(eflsize) minlev, maxlev = levels levdiff = maxlev - minlev levdiff = 1 if levdiff == 0 else levdiff # don't allow division by 0 if lut is None: efflut = fn.rescaleData(ind, scale=255. / levdiff, offset=minlev, dtype=np.ubyte) else: lutdtype = np.min_scalar_type(lut.shape[0] - 1) efflut = fn.rescaleData(ind, scale=(lut.shape[0] - 1) / levdiff, offset=minlev, dtype=lutdtype, clip=(0, lut.shape[0] - 1)) efflut = lut[efflut] self._effectiveLut = efflut lut = self._effectiveLut levels = None # Convert single-channel image to 2D array if image.ndim == 3 and image.shape[-1] == 1: image = image[..., 0] # Assume images are in column-major order for backward compatibility # (most images are in row-major order) if self.axisOrder == 'col-major': image = image.transpose((1, 0, 2)[:image.ndim]) # Get bounds of view box viewBounds = np.array(self.getViewBox().viewRange()) viewBounds[0][0] = max(viewBounds[0][0] - 1, 0) viewBounds[0][1] = min(viewBounds[0][1] + 1, image.shape[1]) viewBounds[1][0] = max(viewBounds[1][0] - 1, 0) viewBounds[1][1] = min(viewBounds[1][1] + 1, image.shape[0]) # Send image to ARGB worker self.imageARGBWorker.prepareForNewImage(image, lut, levels, viewBounds, self.onlyRenderVisible) self.sigImageReadyForARGB.emit()
def render(self): #The same as pyqtgraph's ImageItem.render, with the exception that the makeARGB function is slightly different profile = debug.Profiler() if self.image is None or self.image.size == 0: return if isinstance(self.lut, Callable): lut = self.lut(self.image) else: lut = self.lut if self.autoDownsample: # reduce dimensions of image based on screen resolution o = self.mapToDevice(QtCore.QPointF(0, 0)) x = self.mapToDevice(QtCore.QPointF(1, 0)) y = self.mapToDevice(QtCore.QPointF(0, 1)) w = Point(x - o).length() h = Point(y - o).length() if w == 0 or h == 0: self.qimage = None return xds = max(1, int(1.0 / w)) yds = max(1, int(1.0 / h)) axes = [1, 0] if self.axisOrder == 'row-major' else [0, 1] image = fn.downsample(self.image, xds, axis=axes[0]) image = fn.downsample(image, yds, axis=axes[1]) self._lastDownsample = (xds, yds) else: image = self.image # if the image data is a small int, then we can combine levels + lut # into a single lut for better performance levels = self.levels if levels is not None and levels.ndim == 1 and image.dtype in ( np.ubyte, np.uint16): if self._effectiveLut is None: eflsize = 2**(image.itemsize * 8) ind = np.arange(eflsize) minlev, maxlev = levels levdiff = maxlev - minlev levdiff = 1 if levdiff == 0 else levdiff # don't allow division by 0 if lut is None: efflut = fn.rescaleData(ind, scale=255. / levdiff, offset=minlev, dtype=np.ubyte) else: lutdtype = np.min_scalar_type(lut.shape[0] - 1) efflut = fn.rescaleData(ind, scale=(lut.shape[0] - 1) / levdiff, offset=minlev, dtype=lutdtype, clip=(0, lut.shape[0] - 1)) efflut = lut[efflut] self._effectiveLut = efflut lut = self._effectiveLut levels = None # Assume images are in column-major order for backward compatibility # (most images are in row-major order) if self.axisOrder == 'col-major': image = image.transpose((1, 0, 2)[:image.ndim]) argb, alpha = makeARGBwithNaNs(image, lut=lut, levels=levels) self.qimage = fn.makeQImage(argb, alpha, transpose=False)
def render(self): # Convert data to QImage for display. profile = debug.Profiler() if self.image is None or self.image.size == 0: return # Request a lookup table if this image has only one channel if self.image.ndim == 2 or self.image.shape[2] == 1: if isinstance(self.lut, collections.Callable): lut = self.lut(self.image) else: lut = self.lut else: lut = None if self.autoDownsample: # reduce dimensions of image based on screen resolution o = self.mapToDevice(QtCore.QPointF(0,0)) x = self.mapToDevice(QtCore.QPointF(1,0)) y = self.mapToDevice(QtCore.QPointF(0,1)) w = Point(x-o).length() h = Point(y-o).length() if w == 0 or h == 0: self.qimage = None return xds = max(1, int(1.0 / w)) yds = max(1, int(1.0 / h)) axes = [1, 0] if self.axisOrder == 'row-major' else [0, 1] image = fn.downsample(self.image, xds, axis=axes[0]) image = fn.downsample(image, yds, axis=axes[1]) self._lastDownsample = (xds, yds) else: image = self.image # if the image data is a small int, then we can combine levels + lut # into a single lut for better performance levels = self.levels if levels is not None and levels.ndim == 1 and image.dtype in (np.ubyte, np.uint16): if self._effectiveLut is None: eflsize = 2**(image.itemsize*8) ind = np.arange(eflsize) minlev, maxlev = levels levdiff = maxlev - minlev levdiff = 1 if levdiff == 0 else levdiff # don't allow division by 0 if lut is None: efflut = fn.rescaleData(ind, scale=255./levdiff, offset=minlev, dtype=np.ubyte) else: lutdtype = np.min_scalar_type(lut.shape[0]-1) efflut = fn.rescaleData(ind, scale=(lut.shape[0]-1)/levdiff, offset=minlev, dtype=lutdtype, clip=(0, lut.shape[0]-1)) efflut = lut[efflut] self._effectiveLut = efflut lut = self._effectiveLut levels = None # Convert single-channel image to 2D array if image.ndim == 3 and image.shape[-1] == 1: image = image[..., 0] # Assume images are in column-major order for backward compatibility # (most images are in row-major order) if self.axisOrder == 'col-major': image = image.transpose((1, 0, 2)[:image.ndim]) argb, alpha = fn.makeARGB(image, lut=lut, levels=levels) if self.alpha is not None: argb[:,:,3] = self.alpha.T self.qimage = fn.makeQImage(argb, True, transpose=False)