def findPeaks(img4D, params): """ img4D: a 4D RandomAccessibleInterval params["frames"]: the number of consecutive time points to average towards detecting peaks with difference of Gaussian. Returns a list of lists of peaks found, one list per time point. """ frames = params["frames"] # Work image: the current sum sum3D = ArrayImgs.unsignedLongs([img4D.dimension(d) for d in [0, 1, 2]]) peaks = [] # Sum of the first set of frames compute(add([Views.hyperSlice(img4D, 3, i) for i in xrange(frames)])).into(sum3D) # Extract nuclei from first sum3D peaks.append(doGPeaks(sum3D, params)) # Running sums: subtract the first and add the last for i in xrange(frames, img4D.dimension(3), 1): compute(add(sub(sum3D, Views.hyperSlice(img4D, 3, i - frames)), Views.hyperSlice(img4D, 3, i))) \ .into(sum3D) # Extract nuclei from sum4D peaks.append(doGPeaks(sum3D, params)) return peaks
def as2DKernel(imgE, weights): """ imgE: a RandomAccessible, such as an extended view of a RandomAccessibleInterval. weights: an odd-length list defining a square convolution kernel centered on the pixel, with columns moving slower than rows. Returns an ImgMath op. """ # Check preconditions: validate kernel if 1 != len(weights) % 2: raise Error("list of kernel weights must have an odd length.") side = int(pow(len(weights), 0.5)) # sqrt if pow(side, 2) != len(weights): raise Error("kernel must be a square.") half = side / 2 # Generate ImgMath ops # Note that multiplications by weights of value 1 or 0 will be erased automatically # so that the hierarchy of operations will be the same as in the manual approach above. return add([mul(weight, offset(imgE, [index % side - half, index / side - half])) for index, weight in enumerate(weights) if 0 != weight])
c.fwd() c.localize(pos) print "Cursor:", pos, "::", c.get() # Test RandomAccess ra = iraf.randomAccess() c = iraf.cursor() while c.hasNext(): c.fwd() ra.setPosition(c) c.localize(pos) print "RandomAccess:", pos, "::", ra.get() # Test source img: should be untouched c = img.cursor() while c.hasNext(): print "source:", c.next() # Test interval view: the middle 2x2 square v = Views.interval(iraf, [1, 1], [2, 2]) IL.wrap(v, "+2 view").show() # An array from 0 to 15 a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] pixels = array(a, 'b') img = ArrayImgs.unsignedBytes(pixels, [4, 4]) test(add(img, 2).view()) test(add(img, 2).view(FloatType()))
blockHB = block(imgE, cornersHB) op3 = sub(blockHT, blockHB) op4 = sub(blockHB, blockHT) # Two bright-black-bright vertical features 4x8 - 4x8 - 4x8 corners3VL = [[x - 2, y] for x, y in cornersVL] corners3VC = [[x + 2, y] for x, y in cornersVL] corners3VR = [[x + 2, y] for x, y in cornersVR] print corners3VL print corners3VC print corners3VR block3VL = block(imgE, corners3VC) block3VC = block(imgE, corners3VL) block3VR = block(imgE, corners3VR) op5 = sub(block3VC, block3VL, block3VR) # center minus sides op6 = sub(add(block3VL, block3VR), block3VC) # sides minus center # Two bright-black-bright horizontal features 4x8 / 4x8 / 4x8 corners3HT = [[x, y - 2] for x, y in cornersHT] corners3HC = [[x, y + 2] for x, y in cornersHT] corners3HB = [[x, y + 2] for x, y in cornersHB] print corners3HT print corners3HC print corners3HB block3HT = block(imgE, corners3HT) block3HC = block(imgE, corners3HC) block3HB = block(imgE, corners3HB) op7 = sub(block3HC, block3HT, block3HB) # center minus top and bottom op8 = sub(add(block3HT, block3HB), block3HC) # top and bottom minus center for name, op in ((name, eval(name)) for name in vars()
from net.imglib2.type.numeric.real import FloatType ft = FloatType(10) ft.pow(2) print ft from net.imglib2.algorithm.math.ImgMath import compute, add, power from net.imglib2.img.array import ArrayImgs from net.imglib2.img.display.imagej import ImageJFunctions as IL img = ArrayImgs.floats([10, 10, 10]) compute(add(img, 5)).into(img) # in place compute(power(img, 2)).into(img) # in place print 25 * 10 * 10 * 10 == sum(t.get() for t in img.cursor()) IL.wrap(img, "5 squared").show()
def filterBank(img, bs=4, bl=8, sumType=UnsignedLongType(), converter=Util.genericRealTypeConverter()): """ Haar-like features from Viola and Jones using integral images tuned to identify neuron membranes in electron microscopy. bs: length of the short side of a block bl: length of the long side of a block sumType: the type with which to add up pixel values in the integral image converter: for the IntegralImg, to convert from input to sumType """ # Create the integral image, stored as 64-bit alg = IntegralImg(img, sumType, converter) alg.process() integralImg = alg.getResult() imgE = Views.extendBorder(integralImg) # corners of a 4x8 or 8x4 rectangular block where 0,0 is the top left cornersV = [[0, 0], [bs -1, 0], # Vertical [0, bl -1], [bs -1, bl - 1]] cornersH = [[0, 0], [bl -1, 0], # Horizontal [0, bs -1], [bl -1, bs - 1]] # Two adjacent vertical rectangles 4x8 - 4x8 centered on the pixel blockVL = block(imgE, shift(cornersV, -bs, -bl/2)) blockVR = block(imgE, shift(cornersV, 0, -bl/2)) op1 = let("VL", blockVL, "VR", blockVR, IF(GT("VL", "VR"), THEN(div("VR", "VL")), ELSE(div("VL", "VR")))) #op1 = sub(blockVL, blockVR) #op2 = sub(blockVR, blockVL) # Two adjacent horizontal rectangles 8x4 - 8x4 centered on the pixel blockHT = block(imgE, shift(cornersH, -bs, -bl/2)) blockHB = block(imgE, shift(cornersH, -bs, 0)) op3 = let("HT", blockHT, "HB", blockHB, IF(GT("HT", "HB"), THEN(div("HB", "HT")), # div works better than sub ELSE(div("HT", "HB")))) #op3 = sub(blockHT, blockHB) #op4 = sub(blockHB, blockHT) # Two bright-black-bright vertical features 4x8 - 4x8 - 4x8 block3VL = block(imgE, shift(cornersV, -bs -bs/2, -bl/2)) block3VC = block(imgE, shift(cornersV, -bs/2, -bl/2)) block3VR = block(imgE, shift(cornersV, bs/2, -bl/2)) op5 = let("3VL", block3VL, "3VC", block3VC, "3VR", block3VR, IF(AND(GT("3VL", "3VC"), GT("3VR", "3VC")), THEN(sub(add("3VL", "3VR"), "3VC")), # like Viola and Jones 2001 ELSE(div(add("3VL", "3VC", "3VR"), 3)))) # average block value # Purely like Viola and Jones 2001: work poorly for EM membranes #op5 = sub(block3VC, block3VL, block3VR) # center minus sides #op6 = sub(add(block3VL, block3VR), block3VC) # sides minus center # Two bright-black-bright horizontal features 8x4 / 8x4 / 8x4 block3HT = block(imgE, shift(cornersH, -bl/2, -bs -bs/2)) block3HC = block(imgE, shift(cornersH, -bl/2, -bs/2)) block3HB = block(imgE, shift(cornersH, -bl/2, bs/2)) op7 = let("3HT", block3HT, "3HC", block3HC, "3HB", block3HB, IF(AND(GT("3HT", "3HC"), GT("3HB", "3HC")), THEN(sub(add("3HT", "3HB"), "3HC")), # like Viola and Jones 2001 ELSE(div(add("3HT", "3HC", "3HB"), 3)))) # average block value # Purely like Viola and Jones 2001: work poorly for EM membranes #op7 = sub(block3HC, block3HT, block3HB) # center minus top and bottom #op8 = sub(add(block3HT, block3HB), block3HC) # top and bottom minus center # Combination of vertical and horizontal edge detection #op9 = maximum(op1, op3) #op10 = maximum(op6, op8) #op10 = maximum(op5, op7) """ # corners of a square block where 0,0 is at the top left cornersS = [[0, 0], [bs, 0], [0, bs], [bs, bs]] # 2x2 squares for oblique edge detection blockSTL = block(imgE, shift(cornersS, -bs, -bs)) # top left blockSTR = block(imgE, shift(cornersS, 0, -bs)) # top right blockSBL = block(imgE, shift(cornersS, -bs, 0)) # bottom left blockSBR = block(imgE, cornersS) # bottom right op11 = sub(add(blockSTL, blockSBR), blockSTR, blockSBL) op12 = sub(add(blockSTR, blockSBL), blockSTL, blockSBR) """ # Combination of vertical, horizontal and oblique edge detection #op13 = maximum(op1, op3, op6, op8, op11, op12) #op13 = maximum(op1, op3, op5, op7, op11, op12) # combinations are terrible for RandomForest # Edge detectors: sum of 3 adjacent pixels (not dividing by the other 6 # to avoid penalizing Y membrane configurations) """ op14 = maximum(add(offset(op13, [-1, -1]), op13, offset(op13, [ 1, 1])), add(offset(op13, [ 0, -1]), op13, offset(op13, [ 0, 1])), add(offset(op13, [ 1, -1]), op13, offset(op13, [-1, 1])), add(offset(op13, [-1, 0]), op13, offset(op13, [ 1, 0]))) """ #opMean, opVariance = filterBankBlockStatistics(img, integralImgE=imgE, sumType=sumType, converter=converter) # Return an ordered list of all ops #return [op1, op2, op3, op4, op5, op6, op7, op8, op9, op10, op11, op12, op13, op14] #return [op1, op3, op5, op7, opMean, opVariance] return [op1, op3, op5, op7]
def filterBankOrthogonalEdges(img, bs=4, bl=8, sumType=UnsignedLongType(), converter=Util.genericRealTypeConverter()): """ Haar-like features from Viola and Jones using integral images of a set of rotated images tuned to identify neuron membranes in electron microscopy. bs: length of the short side of a block bl: length of the long side of a block sumType: the type with which to add up pixel values in the integral image converter: for the IntegralImg, to convert from input to sumType """ # Create the integral image, stored as 64-bit alg = IntegralImg(img, sumType, converter) alg.process() integralImg = alg.getResult() imgE = Views.extendBorder(integralImg) # corners of a 4x8 or 8x4 rectangular block where 0,0 is the top left cornersV = [[0, 0], [bs -1, 0], # Vertical [0, bl -1], [bs -1, bl - 1]] cornersH = [[0, 0], [bl -1, 0], # Horizontal [0, bs -1], [bl -1, bs - 1]] # Two adjacent vertical rectangles 4x8 - 4x8 centered on the pixel blockVL = block(imgE, shift(cornersV, -bs, -bl/2)) blockVR = block(imgE, shift(cornersV, 0, -bl/2)) op1 = sub(blockVL, blockVR) op2 = sub(blockVR, blockVL) # Two adjacent horizontal rectangles 8x4 - 8x4 centered on the pixel blockHT = block(imgE, shift(cornersH, -bs, -bl/2)) blockHB = block(imgE, shift(cornersH, -bs, 0)) op3 = sub(blockHT, blockHB) op4 = sub(blockHB, blockHT) # Two bright-black-bright vertical features 4x8 - 4x8 - 4x8 block3VL = block(imgE, shift(cornersV, -bs -bs/2, -bl/2)) block3VC = block(imgE, shift(cornersV, -bs/2, -bl/2)) block3VR = block(imgE, shift(cornersV, bs/2, -bl/2)) op5 = let("3VL", block3VL, "3VC", block3VC, "3VR", block3VR, IF(AND(GT("3VL", "3VC"), GT("3VR", "3VC")), THEN(sub(add("3VL", "3VR"), "3VC")), # like Viola and Jones 2001 ELSE(div(add("3VL", "3VC", "3VR"), 3)))) # average block value # Purely like Viola and Jones 2001: work poorly for EM membranes #op5 = sub(block3VC, block3VL, block3VR) # center minus sides #op6 = sub(add(block3VL, block3VR), block3VC) # sides minus center # Two bright-black-bright horizontal features 8x4 / 8x4 / 8x4 block3HT = block(imgE, shift(cornersH, -bl/2, -bs -bs/2)) block3HC = block(imgE, shift(cornersH, -bl/2, -bs/2)) block3HB = block(imgE, shift(cornersH, -bl/2, bs/2)) op7 = let("3HT", block3HT, "3HC", block3HC, "3HB", block3HB, IF(AND(GT("3HT", "3HC"), GT("3HB", "3HC")), THEN(sub(add("3HT", "3HB"), "3HC")), ELSE(div(add("3HT", "3HC", "3HB"), 3)))) # average block value TODO make a single block #op7 = sub(block3HC, block3HT, block3HB) # center minus top and bottom #op8 = sub(add(block3HT, block3HB), block3HC) # top and bottom minus center # Two adjacent horizontal rectanges, 12x12 - 4x4 bll = bl + bl/2 cornersLarge = [[0, 0], [bll -1, 0], [0, bll -1], [bll -1, bll -1]] cornersSmall = [[0, 0], [bs -1, 0], [0, bs -1], [bs -1, bs -1]] # Subtract a large black rectangle from a small bright one - aiming at capturing synapses # Bright on the right blockLargeL = block(imgE, shift(cornersLarge, -bll, -bll/2)) blockSmallR = block(imgE, shift(cornersSmall, 0, -bs/2)) op9 = sub(blockSmallR, blockLargeL) # Bright on the left blockLargeR = block(imgE, shift(cornersLarge, 0, -bll/2)) blockSmallL = block(imgE, shift(cornersSmall, -bs, -bs/2)) op10 = sub(blockSmallL, blockLargeR) # Bright at the bottom blockLargeT = block(imgE, shift(cornersLarge, -bll/2, -bll)) blockSmallB = block(imgE, shift(cornersSmall, -bs/2, 0)) op11 = sub(blockSmallB, blockLargeT) # Bright at the top blockLargeB = block(imgE, shift(cornersLarge, -bll/2, 0)) blockSmallT = block(imgE, shift(cornersSmall, -bs/2, -bs)) op12 = sub(blockSmallT, blockLargeB) return [op1, op2, op3, op4, op5, op7, op9, op10, op11, op12]
# Create the integral image of an 8-bit input, stored as 64-bit target = ArrayImgs.unsignedLongs(Intervals.dimensionsAsLongArray(img)) # Copy input onto the target image compute(img).into(target) # Extend target with zeros, so that we can read at coordinate -1 imgE = Views.extendZero(target) # Integrate every dimension, cummulatively by writing into # a target image that is also the input for d in xrange(img.numDimensions()): coord = [0] * img.numDimensions() # array of zeros coord[d] = -1 # Cummulative sum along the current dimension # Note that instead of the ImgMath offset op, # we could have used Views.translate(Views.extendZero(target), [1, 0])) # (Notice though the sign change in the translation) integral = add(target, offset(imgE, coord)) compute(integral).into(target) # The target is the integral image integralImg = target # Read out blocks of radius 5 (i.e. 10x10 for a 2d image) # in a way that is entirely n-dimensional (applies to 1d, 2d, 3d, 4d ...) radius = 5 nd = img.numDimensions() op = div(block(Views.extendBorder(integralImg), [radius] * nd), pow(radius * 2, nd)) # divide by total number of pixels in the block blurred = ArrayImgs.floats(Intervals.dimensionsAsLongArray(img)) compute(op).into(blurred, FloatType())
blockVR = block(imgE, shift(cornersV, 0, -bl / 2)) op1 = sub(blockVL, blockVR) op2 = sub(blockVR, blockVL) # Two adjacent horizontal rectangles 8x4 - 8x4 centered on the pixel blockHT = block(imgE, shift(cornersH, -bs, -bl / 2)) blockHB = block(imgE, shift(cornersH, -bs, 0)) op3 = sub(blockHT, blockHB) op4 = sub(blockHB, blockHT) # Two bright-black-bright vertical features 4x8 - 4x8 - 4x8 block3VL = block(imgE, shift(cornersV, -bs - bs / 2, -bl / 2)) block3VC = block(imgE, shift(cornersV, -bs / 2, -bl / 2)) block3VR = block(imgE, shift(cornersV, bs / 2, -bl / 2)) op5 = sub(block3VC, block3VL, block3VR) # center minus sides op6 = sub(add(block3VL, block3VR), block3VC) # sides minus center # Two bright-black-bright horizontal features 8x4 / 8x4 / 8x4 block3HT = block(imgE, shift(cornersH, -bl / 2, -bs - bs / 2)) block3HC = block(imgE, shift(cornersH, -bl / 2, -bs / 2)) block3HB = block(imgE, shift(cornersH, -bl / 2, bs / 2)) op7 = sub(block3HC, block3HT, block3HB) # center minus top and bottom op8 = sub(add(block3HT, block3HB), block3HC) # top and bottom minus center # Combination of vertical and horizontal edge detection op9 = maximum(op1, op3) op10 = maximum(op6, op8) # corners of a square block where 0,0 is at the top left cornersS = [[0, 0], [bs, 0], [0, bs], [bs, bs]]
def filterBank(img, sumType=UnsignedLongType(), converter=Util.genericRealTypeConverter()): """ Haar-like features from Viola and Jones tuned to identify neuron membranes in electron microscopy. """ # Create the integral image, stored as 64-bit alg = IntegralImg(img, sumType, converter) alg.process() integralImg = alg.getResult() imgE = Views.extendBorder(integralImg) # corners of a 4x8 or 8x4 rectangular block where 0,0 is the top left bs = 4 # short side bl = 8 # long side cornersV = [ [0, 0], [bs - 1, 0], # Vertical [0, bl - 1], [bs - 1, bl - 1] ] cornersH = [ [0, 0], [bl - 1, 0], # Horizontal [0, bs - 1], [bl - 1, bs - 1] ] # Two adjacent vertical rectangles 4x8 - 4x8 centered on the pixel blockVL = block(imgE, shift(cornersV, -bs, -bl / 2)) blockVR = block(imgE, shift(cornersV, 0, -bl / 2)) op1 = sub(blockVL, blockVR) op2 = sub(blockVR, blockVL) # Two adjacent horizontal rectangles 8x4 - 8x4 centered on the pixel blockHT = block(imgE, shift(cornersH, -bs, -bl / 2)) blockHB = block(imgE, shift(cornersH, -bs, 0)) op3 = sub(blockHT, blockHB) op4 = sub(blockHB, blockHT) # Two bright-black-bright vertical features 4x8 - 4x8 - 4x8 block3VL = block(imgE, shift(cornersV, -bs - bs / 2, -bl / 2)) block3VC = block(imgE, shift(cornersV, -bs / 2, -bl / 2)) block3VR = block(imgE, shift(cornersV, bs / 2, -bl / 2)) op5 = sub(block3VC, block3VL, block3VR) # center minus sides op6 = sub(add(block3VL, block3VR), block3VC) # sides minus center # Two bright-black-bright horizontal features 8x4 / 8x4 / 8x4 block3HT = block(imgE, shift(cornersH, -bl / 2, -bs - bs / 2)) block3HC = block(imgE, shift(cornersH, -bl / 2, -bs / 2)) block3HB = block(imgE, shift(cornersH, -bl / 2, bs / 2)) op7 = sub(block3HC, block3HT, block3HB) # center minus top and bottom op8 = sub(add(block3HT, block3HB), block3HC) # top and bottom minus center # Combination of vertical and horizontal edge detection op9 = maximum(op1, op3) op10 = maximum(op6, op8) # corners of a square block where 0,0 is at the top left cornersS = [[0, 0], [bs, 0], [0, bs], [bs, bs]] # 2x2 squares for oblique edge detection blockSTL = block(imgE, shift(cornersS, -bs, -bs)) # top left blockSTR = block(imgE, shift(cornersS, 0, -bs)) # top right blockSBL = block(imgE, shift(cornersS, -bs, 0)) # bottom left blockSBR = block(imgE, cornersS) # bottom right op11 = sub(add(blockSTL, blockSBR), blockSTR, blockSBL) op12 = sub(add(blockSTR, blockSBL), blockSTL, blockSBR) # Combination of vertical, horizontal and oblique edge detection op13 = maximum(op1, op3, op6, op8, op11, op12) # Edge detectors: sum of 3 adjacent pixels (not dividing by the other 6 # to avoid penalizing Y membrane configurations) op14 = maximum(add(offset(op13, [-1, -1]), op13, offset(op13, [1, 1])), add(offset(op13, [0, -1]), op13, offset(op13, [0, 1])), add(offset(op13, [1, -1]), op13, offset(op13, [-1, 1])), add(offset(op13, [-1, 0]), op13, offset(op13, [1, 0]))) # Return a list of all ops #return [ob for name, ob in vars().iteritems() if re.match(r"^op\d+$", name)] # Ordered return [ op1, op2, op3, op4, op5, op6, op7, op8, op9, op10, op11, op12, op13, op14 ]
def test(red, green, blue, easy=True): saturation = let( "red", red, "green", green, "blue", blue, "max", maximum("red", "green", "blue"), "min", minimum("red", "green", "blue"), IF(EQ(0, "max"), THEN(0), ELSE(div(sub("max", "min"), "max")))) brightness = div(maximum(red, green, blue), 255.0) hue = IF( EQ(0, saturation), THEN(0), ELSE( let( "red", red, "green", green, "blue", blue, "max", maximum("red", "green", "blue"), "min", minimum("red", "green", "blue"), "range", sub("max", "min"), "redc", div(sub("max", "red"), "range"), "greenc", div(sub("max", "green"), "range"), "bluec", div(sub("max", "blue"), "range"), "hue", div( IF( EQ("red", "max"), THEN(sub("bluec", "greenc")), ELSE( IF(EQ("green", "max"), THEN(sub(add(2, "redc"), "bluec")), ELSE(sub(add(4, "greenc"), "redc"))))), 6), IF(LT("hue", 0), THEN(add("hue", 1)), ELSE("hue"))))) #print hierarchy(hue) #print "hue view:", hue.view( FloatType() ).iterationOrder() if easy: # About 26 ms """ hsb = Views.stack( hue.view( FloatType() ), saturation.view( FloatType() ), brightness.view( FloatType() ) ) """ # About 13 ms: half! Still much worse than plain ImageJ, # but the source images are iterated 4 times, rather than just once, # and the saturation is computed twice, # and the min, max is computed 3 and 4 times, respectively. hsb = Views.stack(hue.viewDouble(FloatType()), saturation.viewDouble(FloatType()), brightness.viewDouble(FloatType())) """ # Even worse: ~37 ms width, height = rgb.dimension(0), rgb.dimension(1) h = compute(hue).into(ArrayImgs.floats([width, height])) s = compute(saturation).into(ArrayImgs.floats([width, height])) b = compute(brightness).into(ArrayImgs.floats([width, height])) hsb = Views.stack( h, s, b ) """ imp = IL.wrap(hsb, "HSB view") else: # Tested it: takes more time (~40 ms vs 26 ms above) width, height = rgb.dimension(0), rgb.dimension(1) hb = zeros(width * height, 'f') sb = zeros(width * height, 'f') bb = zeros(width * height, 'f') h = ArrayImgs.floats(hb, [width, height]) s = ArrayImgs.floats(sb, [width, height]) b = ArrayImgs.floats(bb, [width, height]) #print "ArrayImg:", b.iterationOrder() ImgUtil.copy(ImgView.wrap(hue.view(FloatType()), None), h) ImgUtil.copy(ImgView.wrap(saturation.view(FloatType()), None), s) ImgUtil.copy(ImgView.wrap(brightness.view(FloatType()), None), b) stack = ImageStack(width, height) stack.addSlice(FloatProcessor(width, height, hb, None)) stack.addSlice(FloatProcessor(width, height, sb, None)) stack.addSlice(FloatProcessor(width, height, bb, None)) imp = ImagePlus("hsb", stack) return imp