Exemplo n.º 1
0
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
Exemplo n.º 2
0
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])
Exemplo n.º 3
0
        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()
Exemplo n.º 5
0
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()
Exemplo n.º 6
0
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]
Exemplo n.º 7
0
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]
Exemplo n.º 8
0
# 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
    ]
Exemplo n.º 11
0
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