def rotatedView(img, angle, enlarge=True, extend=Views.extendBorder): """ Return a rotated view of the image, around the Z axis, with an expanded (or reduced) interval view so that all pixels are exactly included. img: a RandomAccessibleInterval angle: in degrees """ cx = img.dimension(0) / 2.0 cy = img.dimension(1) / 2.0 toCenter = AffineTransform2D() toCenter.translate(-cx, -cy) rotation = AffineTransform2D() # Step 1: place origin of rotation at the center of the image rotation.preConcatenate(toCenter) # Step 2: rotate around the Z axis rotation.rotate(radians(angle)) # Step 3: undo translation to the center rotation.preConcatenate(toCenter.inverse()) rotated = RV.transform(Views.interpolate(extend(img), NLinearInterpolatorFactory()), rotation) if enlarge: # Bounds: bounds = repeat((sys.maxint, 0)) # initial upper- and lower-bound values # for min, max to compare against transformed = zeros(2, 'f') for corner in product(*zip(repeat(0), Intervals.maxAsLongArray(img))): rotation.apply(corner, transformed) bounds = [(min(vmin, int(floor(v))), max(vmax, int(ceil(v)))) for (vmin, vmax), v in zip(bounds, transformed)] minC, maxC = map(list, zip(*bounds)) # transpose list of 2 pairs # into 2 lists of 2 values imgRot = Views.zeroMin(Views.interval(rotated, minC, maxC)) else: imgRot = Views.interval(rotated, img) return imgRot
# by using the 'transformed' float array. # We compute the bounds by, for every corner, checking if the floor of each dimension # of a corner coordinate is smaller than the previously found minimum value, # and by checking if the ceil of each corner coordinate is larger than the # previously found value, packing the new pair of minimum and maximum values # into the list of pairs that is 'bounds'. # Notice the min coordinates can have negative values, as the rotated image # has pixels now somewhere to the left and up from the top-left 0,0,0 origin # of coordinates. That's why we use Views.zeroMin, to ensure that downstream # uses of the transformed image see it as fitting within bounds that start at 0,0,0. bounds = repeat( (sys.maxint, 0) ) # initial upper- and lower-bound values for min, max to compare against transformed = zeros(img.numDimensions(), 'f') for corner in product(*zip(repeat(0), Intervals.maxAsLongArray(img))): rotation.apply(corner, transformed) bounds = [(min(vmin, int(floor(v))), max(vmax, int(ceil(v)))) for (vmin, vmax), v in zip(bounds, transformed)] minC, maxC = map(list, zip(*bounds)) # transpose list of lists imgRot2dFit = IL.wrap(Views.zeroMin(Views.interval(rotated, minC, maxC)), imp.getTitle() + " - rot2dFit") imgRot2dFit.show() matrix = rotation.getRowPackedCopy() pprint([list(matrix[i:i + 4]) for i in xrange(0, 12, 4)])
# Load entire 4D IsoView deconvolved and registered data set img4D = readN5(n5dir, dataset_name) # Remove the channel dimension which has size of 1 img4D = Views.dropSingletonDimensions(img4D) print img4D # A mask: only nuclei whose x,y,z coordinate has a non-zero value in the mask will be considered mask = None # Split CM00+CM01 (odd) from CM02+CM03 (even) into two series series = ["CM00-CM01", "CM02-CM03"] img4Da = Views.subsample(img4D, [1, 1, 1, 2]) # step img4Db = Views.subsample( Views.interval(img4D, [0, 0, 0, 1], Intervals.maxAsLongArray(img4D)), [1, 1, 1, 2]) # step showStack(img4Da, title="%s registered+deconvolved" % series[0]) showStack(img4Db, title="%s registered+deconvolved" % series[1]) calibration = [1.0, 1.0, 1.0] somaDiameter = 8 * calibration[0] # Parameters for detecting nuclei with difference of Gaussian params = { "frames": 5, # number of time frames to average, 5 is equivalent to 3.75 seconds: 0.75 * 5 "calibration": calibration, # Deconvolved images have isotropic calibration "somaDiameter": somaDiameter, # in pixels