def createMovieFigure(conn, pixelIds, tIndexes, zStart, zEnd, width, height,
                      spacer, algorithm, stepping, scalebar, overlayColour,
                      timeUnits, imageLabels, maxColCount):
    """
    Makes the complete Movie figure: A canvas showing an image per row with
    multiple columns showing frames from each image/movie. Labels obove each
    frame to show the time-stamp of that frame in the specified units and
    labels on the left name each image.

    @param session          The OMERO session
    @param pixelIds         A list of the Pixel IDs for the images in the
                            figure
    @param tIndexes         A list of tIndexes to display frames from
    @param zStart           Projection Z-start
    @param zEnd             Projection Z-end
    @param width            Maximum width of panels
    @param height           Max height of panels
    @param spacer           Space between panels
    @param algorithm        Projection algorithm e.g. "MAXIMUMINTENSITY"
    @param stepping         Projecttion z-step
    @param scalebar         A number of microns for scale-bar
    @param overlayColour    Color of the scale bar as tuple (255,255,255)
    @param timeUnits        A string such as "SECS"
    @param imageLabels      A list of lists, corresponding to pixelIds, for
                            labelling each image with one or more strings.
    """

    mode = "RGB"
    white = (255, 255, 255)

    # create a rendering engine
    re = conn.createRenderingEngine()
    queryService = conn.getQueryService()

    rowPanels = []
    totalHeight = 0
    totalWidth = 0
    maxImageWidth = 0
    physicalSizeX = 0

    for row, pixelsId in enumerate(pixelIds):
        log("Rendering row %d" % (row))

        pixels = queryService.get("Pixels", pixelsId)
        sizeX = pixels.getSizeX().getValue()
        sizeY = pixels.getSizeY().getValue()
        sizeZ = pixels.getSizeZ().getValue()
        sizeT = pixels.getSizeT().getValue()

        if pixels.getPhysicalSizeX():
            physicalX = pixels.getPhysicalSizeX().getValue()
            unitsX = pixels.getPhysicalSizeX().getSymbol()
        else:
            physicalX = 0
            unitsX = ""
        if pixels.getPhysicalSizeY():
            physicalY = pixels.getPhysicalSizeY().getValue()
            unitsY = pixels.getPhysicalSizeY().getSymbol()
        else:
            physicalY = 0
            unitsY = ""
        log("  Pixel size: x: %s %s  y: %s %s"
            % (str(physicalX), unitsX, str(physicalY), unitsY))
        if row == 0:    # set values for primary image
            physicalSizeX = physicalX
            physicalSizeY = physicalY
        else:            # compare primary image with current one
            if physicalSizeX != physicalX or physicalSizeY != physicalY:
                log(" WARNING: Images have different pixel lengths. Scales"
                    " are not comparable.")

        log("  Image dimensions (pixels): x: %d  y: %d" % (sizeX, sizeY))
        maxImageWidth = max(maxImageWidth, sizeX)

        # set up rendering engine with the pixels
        re.lookupPixels(pixelsId)
        if not re.lookupRenderingDef(pixelsId):
            re.resetDefaults()
        if not re.lookupRenderingDef(pixelsId):
            raise "Failed to lookup Rendering Def"
        re.load()

        proStart = zStart
        proEnd = zEnd
        # make sure we're within Z range for projection.
        if proEnd >= sizeZ:
            proEnd = sizeZ - 1
            if proStart > sizeZ:
                proStart = 0
            log(" WARNING: Current image has fewer Z-sections than the"
                " primary image.")

        # if we have an invalid z-range (start or end less than 0), show
        # default Z only
        if proStart < 0 or proEnd < 0:
            proStart = re.getDefaultZ()
            proEnd = proStart
            log("  Display Z-section: %d" % (proEnd+1))
        else:
            log("  Projecting z range: %d - %d   (max Z is %d)"
                % (proStart+1, proEnd+1, sizeZ))

        # now get each channel in greyscale (or colour)
        # a list of renderedImages (data as Strings) for the split-view row
        renderedImages = []

        for time in tIndexes:
            if time >= sizeT:
                log(" WARNING: This image does not have Time frame: %d. "
                    "(max is %d)" % (time+1, sizeT))
            else:
                if proStart != proEnd:
                    renderedImg = re.renderProjectedCompressed(
                        algorithm, time, stepping, proStart, proEnd)
                else:
                    planeDef = omero.romio.PlaneDef()
                    planeDef.z = proStart
                    planeDef.t = time
                    renderedImg = re.renderCompressed(planeDef)
                # create images and resize, add to list
                image = Image.open(StringIO.StringIO(renderedImg))
                resizedImage = imgUtil.resizeImage(image, width, height)
                renderedImages.append(resizedImage)

        # make a canvas for the row of splitview images...
        # (will add time labels above each row)
        colCount = min(maxColCount, len(renderedImages))
        rowCount = int(math.ceil(float(len(renderedImages)) / colCount))
        font = imgUtil.getFont(width/12)
        fontHeight = font.getsize("Textq")[1]
        canvasWidth = ((width + spacer) * colCount) + spacer
        canvasHeight = rowCount * (spacer/2 + fontHeight + spacer + height)
        size = (canvasWidth, canvasHeight)
        # create a canvas of appropriate width, height
        canvas = Image.new(mode, size, white)

        # add text labels
        queryService = conn.getQueryService()
        textX = spacer
        textY = spacer/4
        colIndex = 0
        timeLabels = figUtil.getTimeLabels(
            queryService, pixelsId, tIndexes, sizeT, timeUnits)
        for t, tIndex in enumerate(tIndexes):
            if tIndex >= sizeT:
                continue
            time = timeLabels[t]
            textW = font.getsize(time)[0]
            inset = (width - textW) / 2
            textdraw = ImageDraw.Draw(canvas)
            textdraw.text((textX+inset, textY), time, font=font,
                          fill=(0, 0, 0))
            textX += width + spacer
            colIndex += 1
            if colIndex >= maxColCount:
                colIndex = 0
                textX = spacer
                textY += (spacer/2 + fontHeight + spacer + height)

        # add scale bar to last frame...
        if scalebar:
            scaledImage = renderedImages[-1]
            xIndent = spacer
            yIndent = xIndent
            # if we've scaled to half size, zoom = 2
            zoom = imgUtil.getZoomFactor(scaledImage.size, width, height)
            # and the scale bar will be half size
            sbar = float(scalebar) / zoom
            status, logMsg = figUtil.addScalebar(
                sbar, xIndent, yIndent, scaledImage, pixels, overlayColour)
            log(logMsg)

        px = spacer
        py = spacer + fontHeight
        colIndex = 0
        # paste the images in
        for i, img in enumerate(renderedImages):
            imgUtil.pasteImage(img, canvas, px, py)
            px = px + width + spacer
            colIndex += 1
            if colIndex >= maxColCount:
                colIndex = 0
                px = spacer
                py += (spacer/2 + fontHeight + spacer + height)

        # Add labels to the left of the panel
        canvas = addLeftLabels(canvas, imageLabels, row, width, spacer)

        # most should be same width anyway
        totalWidth = max(totalWidth, canvas.size[0])
        # add together the heights of each row
        totalHeight = totalHeight + canvas.size[1]

        rowPanels.append(canvas)

    # make a figure to combine all split-view rows
    # each row has 1/2 spacer above and below the panels. Need extra 1/2
    # spacer top and bottom
    figureSize = (totalWidth, totalHeight+spacer)
    figureCanvas = Image.new(mode, figureSize, white)

    rowY = spacer / 2
    for row in rowPanels:
        imgUtil.pasteImage(row, figureCanvas, 0, rowY)
        rowY = rowY + row.size[1]

    return figureCanvas
Esempio n. 2
0
def createmovie_figure(conn, pixel_ids, t_indexes, z_start, z_end, width,
                       height, spacer, algorithm, stepping, scalebar,
                       overlay_colour, time_units, image_labels,
                       max_col_count):
    """
    Makes the complete Movie figure: A canvas showing an image per row with
    multiple columns showing frames from each image/movie. Labels obove each
    frame to show the time-stamp of that frame in the specified units and
    labels on the left name each image.

    @param conn             The OMERO session
    @param pixel_ids        A list of the Pixel IDs for the images in the
                            figure
    @param t_indexes        A list of tIndexes to display frames from
    @param z_start          Projection Z-start
    @param z_end            Projection Z-end
    @param width            Maximum width of panels
    @param height           Max height of panels
    @param spacer           Space between panels
    @param algorithm        Projection algorithm e.g. "MAXIMUMINTENSITY"
    @param stepping         Projecttion z-step
    @param scalebar         A number of microns for scale-bar
    @param overlay_colour   Color of the scale bar as tuple (255,255,255)
    @param time_units       A string such as "SECS"
    @param image_labels     A list of lists, corresponding to pixelIds, for
                            labelling each image with one or more strings.
    """

    mode = "RGB"
    white = (255, 255, 255)

    # create a rendering engine
    re = conn.createRenderingEngine()
    query_service = conn.getQueryService()

    row_panels = []
    total_height = 0
    total_width = 0
    max_image_width = 0
    physical_size_x = 0

    for row, pixels_id in enumerate(pixel_ids):
        log("Rendering row %d" % (row))

        pixels = query_service.get("Pixels", pixels_id)
        size_x = pixels.getSizeX().getValue()
        size_y = pixels.getSizeY().getValue()
        size_z = pixels.getSizeZ().getValue()
        size_t = pixels.getSizeT().getValue()

        if pixels.getPhysicalSizeX():
            physical_x = pixels.getPhysicalSizeX().getValue()
            units_x = pixels.getPhysicalSizeX().getSymbol()
        else:
            physical_x = 0
            units_x = ""
        if pixels.getPhysicalSizeY():
            physical_y = pixels.getPhysicalSizeY().getValue()
            units_y = pixels.getPhysicalSizeY().getSymbol()
        else:
            physical_y = 0
            units_y = ""
        log("  Pixel size: x: %s %s  y: %s %s" %
            (str(physical_x), units_x, str(physical_y), units_y))
        if row == 0:  # set values for primary image
            physical_size_x = physical_x
            physical_size_y = physical_y
        else:  # compare primary image with current one
            if physical_size_x != physical_x or physical_size_y != physical_y:
                log(" WARNING: Images have different pixel lengths. Scales"
                    " are not comparable.")

        log("  Image dimensions (pixels): x: %d  y: %d" % (size_x, size_y))
        max_image_width = max(max_image_width, size_x)

        # set up rendering engine with the pixels
        re.lookupPixels(pixels_id)
        if not re.lookupRenderingDef(pixels_id):
            re.resetDefaults()
        if not re.lookupRenderingDef(pixels_id):
            raise "Failed to lookup Rendering Def"
        re.load()

        pro_start = z_start
        pro_end = z_end
        # make sure we're within Z range for projection.
        if pro_end >= size_z:
            pro_end = size_z - 1
            if pro_start > size_z:
                pro_start = 0
            log(" WARNING: Current image has fewer Z-sections than the"
                " primary image.")

        # if we have an invalid z-range (start or end less than 0), show
        # default Z only
        if pro_start < 0 or pro_end < 0:
            pro_start = re.getDefaultZ()
            pro_end = pro_start
            log("  Display Z-section: %d" % (pro_end + 1))
        else:
            log("  Projecting z range: %d - %d   (max Z is %d)" %
                (pro_start + 1, pro_end + 1, size_z))

        # now get each channel in greyscale (or colour)
        # a list of renderedImages (data as Strings) for the split-view row
        rendered_images = []

        for time in t_indexes:
            if time >= size_t:
                log(" WARNING: This image does not have Time frame: %d. "
                    "(max is %d)" % (time + 1, size_t))
            else:
                if pro_start != pro_end:
                    rendered_img = re.renderProjectedCompressed(
                        algorithm, time, stepping, pro_start, pro_end)
                else:
                    plane_def = omero.romio.PlaneDef()
                    plane_def.z = pro_start
                    plane_def.t = time
                    rendered_img = re.renderCompressed(plane_def)
                # create images and resize, add to list
                image = Image.open(io.BytesIO(rendered_img))
                resized_image = image_utils.resize_image(image, width, height)
                rendered_images.append(resized_image)

        # make a canvas for the row of splitview images...
        # (will add time labels above each row)
        col_count = min(max_col_count, len(rendered_images))
        row_count = int(math.ceil(float(len(rendered_images)) / col_count))
        font = image_utils.get_font(width / 12)
        font_height = font.getsize("Textq")[1]
        canvas_width = ((width + spacer) * col_count) + spacer
        canvas_height = row_count * (spacer / 2 + font_height + spacer +
                                     height)
        size = (canvas_width, canvas_height)
        # create a canvas of appropriate width, height
        canvas = Image.new(mode, size, white)

        # add text labels
        query_service = conn.getQueryService()
        text_x = spacer
        text_y = spacer / 4
        col_index = 0
        time_labels = figUtil.getTimeLabels(query_service, pixels_id,
                                            t_indexes, size_t, time_units)
        for t, t_index in enumerate(t_indexes):
            if t_index >= size_t:
                continue
            time = time_labels[t]
            text_w = font.getsize(time)[0]
            inset = (width - text_w) / 2
            textdraw = ImageDraw.Draw(canvas)
            textdraw.text((text_x + inset, text_y),
                          time,
                          font=font,
                          fill=(0, 0, 0))
            text_x += width + spacer
            col_index += 1
            if col_index >= max_col_count:
                col_index = 0
                text_x = spacer
                text_y += (spacer / 2 + font_height + spacer + height)

        # add scale bar to last frame...
        if scalebar:
            scaled_image = rendered_images[-1]
            x_indent = spacer
            y_indent = x_indent
            # if we've scaled to half size, zoom = 2
            zoom = image_utils.get_zoom_factor(scaled_image.size, width,
                                               height)
            # and the scale bar will be half size
            sbar = float(scalebar) / zoom
            status, log_msg = figUtil.addScalebar(sbar, x_indent, y_indent,
                                                  scaled_image, pixels,
                                                  overlay_colour)
            log(log_msg)

        px = spacer
        py = spacer + font_height
        col_index = 0
        # paste the images in
        for i, img in enumerate(rendered_images):
            image_utils.paste_image(img, canvas, px, py)
            px = px + width + spacer
            col_index += 1
            if col_index >= max_col_count:
                col_index = 0
                px = spacer
                py += (spacer / 2 + font_height + spacer + height)

        # Add labels to the left of the panel
        canvas = add_left_labels(canvas, image_labels, row, width, spacer)

        # most should be same width anyway
        total_width = max(total_width, canvas.size[0])
        # add together the heights of each row
        total_height = total_height + canvas.size[1]

        row_panels.append(canvas)

    # make a figure to combine all split-view rows
    # each row has 1/2 spacer above and below the panels. Need extra 1/2
    # spacer top and bottom
    figure_size = (total_width, total_height + spacer)
    figure_canvas = Image.new(mode, figure_size, white)

    row_y = spacer / 2
    for row in row_panels:
        image_utils.paste_image(row, figure_canvas, 0, row_y)
        row_y = row_y + row.size[1]

    return figure_canvas
Esempio n. 3
0
def getROImovieView(re,
                    queryService,
                    pixels,
                    timeShapeMap,
                    mergedIndexes,
                    mergedColours,
                    roiWidth,
                    roiHeight,
                    roiZoom,
                    spacer=12,
                    algorithm=None,
                    stepping=1,
                    fontsize=24,
                    maxColumns=None,
                    showRoiDuration=False):
    """
    This takes a ROI rectangle from an image and makes a movie canvas of the
    region in the ROI, zoomed by a defined factor.
    """

    mode = "RGB"
    white = (255, 255, 255)

    sizeX = pixels.getSizeX().getValue()
    sizeY = pixels.getSizeY().getValue()
    sizeZ = pixels.getSizeZ().getValue()
    sizeC = pixels.getSizeC().getValue()
    sizeT = pixels.getSizeT().getValue()

    if pixels.getPhysicalSizeX():
        physicalX = pixels.getPhysicalSizeX().getValue()
    else:
        physicalX = 0
    if pixels.getPhysicalSizeY():
        physicalY = pixels.getPhysicalSizeY().getValue()
    else:
        physicalY = 0
    log("  Pixel size (um): x: %s  y: %s" % (str(physicalX), str(physicalY)))
    log("  Image dimensions (pixels): x: %d  y: %d" % (sizeX, sizeY))
    log(" Projecting Movie Frame ROIs...")

    # set up rendering engine with the pixels
    pixelsId = pixels.getId().getValue()
    re.lookupPixels(pixelsId)
    if not re.lookupRenderingDef(pixelsId):
        re.resetDefaults()
    if not re.lookupRenderingDef(pixelsId):
        raise "Failed to lookup Rendering Def"
    re.load()

    # now get each channel in greyscale (or colour)
    # a list of renderedImages (data as Strings) for the split-view row
    renderedImages = []
    panelWidth = 0
    channelMismatch = False
    # first, turn off all channels in pixels
    for i in range(sizeC):
        re.setActive(i, False)

    # turn on channels in mergedIndexes.
    for i in mergedIndexes:
        if i >= sizeC or i < 0:
            channelMismatch = True
        else:
            print "Turning on channel:", i
            re.setActive(i, True)
            if i in mergedColours:
                rgba = mergedColours[i]
                print "Setting rgba", rgba
                re.setRGBA(i, *rgba)

    # get the combined image, using the existing rendering settings
    channelsString = ", ".join([str(i) for i in mergedIndexes])
    log("  Rendering Movie channels: %s" % channelsString)

    timeIndexes = list(timeShapeMap.keys())
    timeIndexes.sort()

    if showRoiDuration:
        log(" Timepoints shown are ROI duration, not from start of movie")
    timeLabels = figUtil.getTimeLabels(queryService, pixelsId, timeIndexes,
                                       sizeT, None, showRoiDuration)
    # The last value of the list will be the Units used to display time
    print "Time label units are:", timeLabels[-1]

    fullFirstFrame = None
    for t, timepoint in enumerate(timeIndexes):
        roiX, roiY, proStart, proEnd = timeShapeMap[timepoint]
        box = (roiX, roiY, int(roiX + roiWidth), int(roiY + roiHeight))
        log("  Time-index: %d Time-label: %s  Projecting z range: %d - %d "
            "(max Z is %d) of region x: %s y: %s" %
            (timepoint + 1, timeLabels[t], proStart + 1, proEnd + 1, sizeZ,
             roiX, roiY))

        merged = re.renderProjectedCompressed(algorithm, timepoint, stepping,
                                              proStart, proEnd)
        fullMergedImage = Image.open(StringIO.StringIO(merged))
        if fullFirstFrame is None:
            fullFirstFrame = fullMergedImage
        roiMergedImage = fullMergedImage.crop(box)
        # make sure this is not just a lazy copy of the full image
        roiMergedImage.load()
        if roiZoom is not 1:
            newSize = (int(roiWidth * roiZoom), int(roiHeight * roiZoom))
            roiMergedImage = roiMergedImage.resize(newSize)
        panelWidth = roiMergedImage.size[0]
        renderedImages.append(roiMergedImage)

    if channelMismatch:
        log(" WARNING channel mismatch: The current image has fewer channels"
            " than the primary image.")

    # now assemble the roi split-view canvas, with space above for text
    colCount = len(renderedImages)
    rowCount = 1
    if maxColumns:
        rowCount = colCount / maxColumns
        if (colCount % maxColumns) > 0:
            rowCount += 1
        colCount = maxColumns
    font = imgUtil.getFont(fontsize)
    textHeight = font.getsize("Textq")[1]
    # no spaces around panels
    canvasWidth = ((panelWidth + spacer) * colCount) - spacer
    rowHeight = renderedImages[0].size[1] + spacer + textHeight
    canvasHeight = rowHeight * rowCount
    size = (canvasWidth, canvasHeight)
    # create a canvas of appropriate width, height
    canvas = Image.new(mode, size, white)

    px = 0
    textY = spacer / 2
    panelY = textHeight + spacer
    # paste the images in, with time labels
    draw = ImageDraw.Draw(canvas)

    col = 0
    for i, img in enumerate(renderedImages):
        label = timeLabels[i]
        indent = (panelWidth - (font.getsize(label)[0])) / 2
        draw.text((px + indent, textY), label, font=font, fill=(0, 0, 0))
        imgUtil.pasteImage(img, canvas, px, panelY)
        if col == (colCount - 1):
            col = 0
            px = 0
            textY += rowHeight
            panelY += rowHeight
        else:
            col += 1
            px = px + panelWidth + spacer

    # return the roi splitview canvas, as well as the full merged image
    return (canvas, fullFirstFrame, textHeight + spacer)
Esempio n. 4
0
def getROImovieView(re, queryService, pixels, timeShapeMap, mergedIndexes,
                    mergedColours, roiWidth, roiHeight, roiZoom, spacer=12,
                    algorithm=None, stepping=1, fontsize=24, maxColumns=None,
                    showRoiDuration=False):

    """
    This takes a ROI rectangle from an image and makes a movie canvas of the
    region in the ROI, zoomed by a defined factor.
    """

    mode = "RGB"
    white = (255, 255, 255)

    sizeX = pixels.getSizeX().getValue()
    sizeY = pixels.getSizeY().getValue()
    sizeZ = pixels.getSizeZ().getValue()
    sizeC = pixels.getSizeC().getValue()
    sizeT = pixels.getSizeT().getValue()

    if pixels.getPhysicalSizeX():
        physicalX = pixels.getPhysicalSizeX().getValue()
    else:
        physicalX = 0
    if pixels.getPhysicalSizeY():
        physicalY = pixels.getPhysicalSizeY().getValue()
    else:
        physicalY = 0
    log("  Pixel size (um): x: %s  y: %s" % (str(physicalX), str(physicalY)))
    log("  Image dimensions (pixels): x: %d  y: %d" % (sizeX, sizeY))
    log(" Projecting Movie Frame ROIs...")

    # set up rendering engine with the pixels
    pixelsId = pixels.getId().getValue()
    re.lookupPixels(pixelsId)
    if not re.lookupRenderingDef(pixelsId):
        re.resetDefaults()
    if not re.lookupRenderingDef(pixelsId):
        raise "Failed to lookup Rendering Def"
    re.load()

    # now get each channel in greyscale (or colour)
    # a list of renderedImages (data as Strings) for the split-view row
    renderedImages = []
    panelWidth = 0
    channelMismatch = False
    # first, turn off all channels in pixels
    for i in range(sizeC):
        re.setActive(i, False)

    # turn on channels in mergedIndexes.
    for i in mergedIndexes:
        if i >= sizeC or i < 0:
            channelMismatch = True
        else:
            print "Turning on channel:", i
            re.setActive(i, True)
            if i in mergedColours:
                rgba = mergedColours[i]
                print "Setting rgba", rgba
                re.setRGBA(i, *rgba)

    # get the combined image, using the existing rendering settings
    channelsString = ", ".join([str(i) for i in mergedIndexes])
    log("  Rendering Movie channels: %s" % channelsString)

    timeIndexes = list(timeShapeMap.keys())
    timeIndexes.sort()

    if showRoiDuration:
        log(" Timepoints shown are ROI duration, not from start of movie")
    timeLabels = figUtil.getTimeLabels(
        queryService, pixelsId, timeIndexes, sizeT, None, showRoiDuration)
    # The last value of the list will be the Units used to display time
    print "Time label units are:", timeLabels[-1]

    fullFirstFrame = None
    for t, timepoint in enumerate(timeIndexes):
        roiX, roiY, proStart, proEnd = timeShapeMap[timepoint]
        box = (roiX, roiY, int(roiX+roiWidth), int(roiY+roiHeight))
        log("  Time-index: %d Time-label: %s  Projecting z range: %d - %d "
            "(max Z is %d) of region x: %s y: %s"
            % (timepoint+1, timeLabels[t], proStart+1, proEnd+1, sizeZ, roiX,
               roiY))

        merged = re.renderProjectedCompressed(
            algorithm, timepoint, stepping, proStart, proEnd)
        fullMergedImage = Image.open(StringIO.StringIO(merged))
        if fullFirstFrame is None:
            fullFirstFrame = fullMergedImage
        roiMergedImage = fullMergedImage.crop(box)
        # make sure this is not just a lazy copy of the full image
        roiMergedImage.load()
        if roiZoom is not 1:
            newSize = (int(roiWidth*roiZoom), int(roiHeight*roiZoom))
            roiMergedImage = roiMergedImage.resize(newSize)
        panelWidth = roiMergedImage.size[0]
        renderedImages.append(roiMergedImage)

    if channelMismatch:
        log(" WARNING channel mismatch: The current image has fewer channels"
            " than the primary image.")

    # now assemble the roi split-view canvas, with space above for text
    colCount = len(renderedImages)
    rowCount = 1
    if maxColumns:
        rowCount = colCount / maxColumns
        if (colCount % maxColumns) > 0:
            rowCount += 1
        colCount = maxColumns
    font = imgUtil.getFont(fontsize)
    textHeight = font.getsize("Textq")[1]
    # no spaces around panels
    canvasWidth = ((panelWidth + spacer) * colCount) - spacer
    rowHeight = renderedImages[0].size[1] + spacer + textHeight
    canvasHeight = rowHeight * rowCount
    size = (canvasWidth, canvasHeight)
    # create a canvas of appropriate width, height
    canvas = Image.new(mode, size, white)

    px = 0
    textY = spacer/2
    panelY = textHeight + spacer
    # paste the images in, with time labels
    draw = ImageDraw.Draw(canvas)

    col = 0
    for i, img in enumerate(renderedImages):
        label = timeLabels[i]
        indent = (panelWidth - (font.getsize(label)[0])) / 2
        draw.text((px+indent, textY), label, font=font, fill=(0, 0, 0))
        imgUtil.pasteImage(img, canvas, px, panelY)
        if col == (colCount - 1):
            col = 0
            px = 0
            textY += rowHeight
            panelY += rowHeight
        else:
            col += 1
            px = px + panelWidth + spacer

    # return the roi splitview canvas, as well as the full merged image
    return (canvas, fullFirstFrame, textHeight + spacer)
Esempio n. 5
0
def getImageFrames(conn, pixelIds, tIndexes, zStart, zEnd, width, height, spacer,
            algorithm, stepping, scalebar, overlayColour, timeUnits):
    
    """
    Makes a canvas showing an image per row with multiple columns showing 
    frames from each image/movie. Labels obove each frame to show the time-stamp of that frame in the 
    specified units. 
    
    @param session        The OMERO session
    @param pixelIds        A list of the Pixel IDs for the images in the figure
    @param tIndexes        A list of tIndexes to display frames from
    @param zStart        Projection Z-start
    @param zEnd            Projection Z-end
    @param width        Maximum width of panels
    @param height        Max height of panels
    @param spacer        Space between panels
    @param algorithm    Projection algorithm e.g. "MAXIMUMINTENSITY"
    @param stepping        Projecttion z-step
    @param scalebar        A number of microns for scale-bar
    @param overlayColour     Colour of the scale-bar as tuple (255,255,255)
    @param timeUnits    A string such as "SECS"
    """
    
    mode = "RGB"
    white = (255, 255, 255)
    
    # create a rendering engine
    re = conn.createRenderingEngine()
    queryService = conn.getQueryService()
    
    rowPanels = []
    totalHeight = 0
    totalWidth = 0
    maxImageWidth = 0
    physicalSizeX = 0
    
    for row, pixelsId in enumerate(pixelIds):
        log("Rendering row %d" % (row))
        
        pixels = queryService.get("Pixels", pixelsId)
        sizeX = pixels.getSizeX().getValue()
        sizeY = pixels.getSizeY().getValue()
        sizeZ = pixels.getSizeZ().getValue()
        sizeC = pixels.getSizeC().getValue()
        sizeT = pixels.getSizeT().getValue()
        
        if pixels.getPhysicalSizeX():
            physicalX = pixels.getPhysicalSizeX().getValue()
        else:
            physicalX = 0 
        if pixels.getPhysicalSizeY():
            physicalY = pixels.getPhysicalSizeY().getValue()
        else:
            physicalY = 0
        log("  Pixel size (um): x: %s  y: %s" % (str(physicalX), str(physicalY)))
        if row == 0:    # set values for primary image
            physicalSizeX = physicalX
            physicalSizeY = physicalY
        else:            # compare primary image with current one
            if physicalSizeX != physicalX or physicalSizeY != physicalY:
                log(" WARNING: Images have different pixel lengths. Scales are not comparable.")
        
        log("  Image dimensions (pixels): x: %d  y: %d" % (sizeX, sizeY))
        maxImageWidth = max(maxImageWidth, sizeX)
        
        # set up rendering engine with the pixels
        re.lookupPixels(pixelsId)
        if not re.lookupRenderingDef(pixelsId):
            re.resetDefaults()
        if not re.lookupRenderingDef(pixelsId):
            raise "Failed to lookup Rendering Def"
        re.load()
        
        proStart = zStart
        proEnd = zEnd
        # make sure we're within Z range for projection. 
        if proEnd >= sizeZ:
            proEnd = sizeZ - 1
            if proStart > sizeZ:
                proStart = 0
            log(" WARNING: Current image has fewer Z-sections than the primary image.")
            
        # if we have an invalid z-range (start or end less than 0), show default Z only
        if proStart < 0 or proEnd < 0:
            proStart = re.getDefaultZ()
            proEnd = proStart
            log("  Display Z-section: %d" % (proEnd+1))
        else:
            log("  Projecting z range: %d - %d   (max Z is %d)" % (proStart+1, proEnd+1, sizeZ))
        
        # now get each channel in greyscale (or colour)
        # a list of renderedImages (data as Strings) for the split-view row
        renderedImages = []
        
        for time in tIndexes:
            if time >= sizeT:
                log(" WARNING: This image does not have Time frame: %d. (max is %d)" % (time+1, sizeT))     
            else: 
                if proStart != proEnd:
                    renderedImg = re.renderProjectedCompressed(algorithm, time, stepping, proStart, proEnd)
                else:
                    planeDef = omero.romio.PlaneDef()
                    planeDef.z = proStart
                    planeDef.t = time
                    renderedImg = re.renderCompressed(planeDef)
                # create images and resize, add to list
                image = Image.open(StringIO.StringIO(renderedImg))
                resizedImage = imgUtil.resizeImage(image, width, height)
                renderedImages.append(resizedImage)

        
        # make a canvas for the row of splitview images...(will add time labels above each row)
        font = imgUtil.getFont(width/12)
        fontHeight = font.getsize("Textq")[1]
        canvasWidth = ((width + spacer) * len(renderedImages)) + spacer
        canvasHeight = spacer/2 + fontHeight + spacer + height
        size = (canvasWidth, canvasHeight)
        canvas = Image.new(mode, size, white)        # create a canvas of appropriate width, height
        
        # add text labels
        queryService = conn.getQueryService()
        textX = spacer
        textY = spacer/4
        timeLabels = figUtil.getTimeLabels(queryService, pixelsId, tIndexes, sizeT, timeUnits)
        for t, tIndex in enumerate(tIndexes):
            if tIndex >= sizeT:
                continue
            time = timeLabels[t]
            textW = font.getsize(time)[0]
            inset = (width - textW) / 2
            textdraw = ImageDraw.Draw(canvas)
            textdraw.text((textX+inset, textY), time, font=font, fill=(0,0,0))
            textX += width + spacer
    
        # add scale bar to last frame...
        if scalebar:
            scaledImage = renderedImages[-1]
            xIndent = spacer
            yIndent = xIndent
            zoom = imgUtil.getZoomFactor(scaledImage.size, width, height)     # if we've scaled to half size, zoom = 2
            sbar = float(scalebar) / zoom            # and the scale bar will be half size
            status, logMsg = figUtil.addScalebar(sbar, xIndent, yIndent, scaledImage, pixels, overlayColour)
            log(logMsg)

                
        px = spacer
        py = spacer + fontHeight
        # paste the images in
        for img in renderedImages:
            imgUtil.pasteImage(img, canvas, px, py)
            px = px + width + spacer
    
        totalWidth = max(totalWidth, canvasWidth)    # most should be same width anyway
        totalHeight = totalHeight + canvasHeight    # add together the heights of each row
        rowPanels.append(canvas)
        
    # make a figure to combine all split-view rows
    # each row has 1/2 spacer above and below the panels. Need extra 1/2 spacer top and bottom
    figureSize = (totalWidth, totalHeight+spacer)
    figureCanvas = Image.new(mode, figureSize, white)
    
    rowY = spacer/2
    for row in rowPanels:
        imgUtil.pasteImage(row, figureCanvas, 0, rowY)
        rowY = rowY + row.size[1]

    return figureCanvas