Exemplo n.º 1
0
def getSplitView(conn, imageIds, pixelIds, splitIndexes, channelNames,
                 mergedNames, colourChannels, mergedIndexes, mergedColours,
                 width, height, imageLabels, spacer, algorithm, stepping,
                 scalebar, overlayColour, roiZoom, roiLabel):

    """
    This method makes a figure of a number of images, arranged in rows with
    each row being the split-view of a single image. The channels are arranged
    left to right, with the combined image added on the right.
    The combined image is rendered according to current settings on the
    server, but it's channels will be turned on/off according to
    @mergedIndexes.

    The figure is returned as a PIL 'Image'

    @ session           session for server access
    @ pixelIds          a list of the Ids for the pixels we want to display
    @ splitIndexes      a list of the channel indexes to display. Same
                        channels for each image/row
    @ channelNames      the Map of index:names for all channels
    @ zStart            the start of Z-range for projection
    @ zEnd              the end of Z-range for projection
    @ colourChannels    the colour to make each column/ channel
    @ mergedIndexes     list or set of channels in the merged image
    @ mergedColours     index: colour dictionary of channels in the merged
                        image
    @ width             the size in pixels to show each panel
    @ height            the size in pixels to show each panel
    @ spacer            the gap between images and around the figure. Doubled
                        between rows.
    """

    roiService = conn.getRoiService()
    re = conn.createRenderingEngine()
    queryService = conn.getQueryService()    # only needed for movie

    # establish dimensions and roiZoom for the primary image
    # getTheseValues from the server
    rect = getRectangle(roiService, imageIds[0], roiLabel)
    if rect is None:
        raise Exception("No ROI found for the first image.")
    roiX, roiY, roiWidth, roiHeight, yMin, yMax, tMin, tMax = rect

    roiOutline = ((max(width, height)) / 200) + 1

    if roiZoom is None:
        # get the pixels for priamry image.
        pixels = queryService.get("Pixels", pixelIds[0])
        sizeY = pixels.getSizeY().getValue()

        roiZoom = float(height) / float(roiHeight)
        log("ROI zoom set by primary image is %F X" % roiZoom)
    else:
        log("ROI zoom: %F X" % roiZoom)

    textGap = spacer/3
    fontsize = 12
    if width > 500:
        fontsize = 48
    elif width > 400:
        fontsize = 36
    elif width > 300:
        fontsize = 24
    elif width > 200:
        fontsize = 16
    font = imgUtil.getFont(fontsize)
    textHeight = font.getsize("Textq")[1]
    maxCount = 0
    for row in imageLabels:
        maxCount = max(maxCount, len(row))
    leftTextWidth = (textHeight + textGap) * maxCount + spacer

    maxSplitPanelWidth = 0
    totalcanvasHeight = 0
    mergedImages = []
    roiSplitPanes = []
    topSpacers = []         # space for labels above each row

    showLabelsAboveEveryRow = False
    invalidImages = []      # note any image row indexes that don't have ROIs.

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

        if showLabelsAboveEveryRow:
            showTopLabels = True
        else:
            showTopLabels = (row == 0)  # only show top labels for first row

        # need to get the roi dimensions from the server
        imageId = imageIds[row]
        roi = getRectangle(roiService, imageId, roiLabel)
        if roi is None:
            log("No Rectangle ROI found for this image")
            invalidImages.append(row)
            continue
        roiX, roiY, roiWidth, roiHeight, zMin, zMax, tStart, tEnd = roi

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

        zStart = zMin
        zEnd = zMax

        # work out if any additional zoom is needed (if the full-sized image
        # is different size from primary image)
        fullSize = (sizeX, sizeY)
        imageZoom = imgUtil.getZoomFactor(fullSize, width, height)
        if imageZoom != 1.0:
            log("  Scaling down the full-size image by a factor of %F"
                % imageZoom)

        log("  ROI location (top-left) x: %d  y: %d  and size width:"
            " %d  height: %d" % (roiX, roiY, roiWidth, roiHeight))
        log("  ROI time: %d - %d   zRange: %d - %d"
            % (tStart+1, tEnd+1, zStart+1, zEnd+1))
        # get the split pane and full merged image
        roiSplitPane, fullMergedImage, topSpacer = getROIsplitView(
            re, pixels, zStart, zEnd, splitIndexes, channelNames, mergedNames,
            colourChannels, mergedIndexes, mergedColours, roiX, roiY,
            roiWidth, roiHeight, roiZoom, tStart, spacer, algorithm, stepping,
            fontsize, showTopLabels)

        # and now zoom the full-sized merged image, add scalebar
        mergedImage = imgUtil.resizeImage(fullMergedImage, width, height)
        if scalebar:
            xIndent = spacer
            yIndent = xIndent
            # and the scale bar will be half size
            sbar = float(scalebar) / imageZoom
            status, logMsg = figUtil.addScalebar(
                sbar, xIndent, yIndent, mergedImage, pixels, overlayColour)
            log(logMsg)

        # draw ROI onto mergedImage...
        # recalculate roi if the image has been zoomed
        x = roiX / imageZoom
        y = roiY / imageZoom
        roiX2 = (roiX + roiWidth) / imageZoom
        roiY2 = (roiY + roiHeight) / imageZoom
        drawRectangle(
            mergedImage, x, y, roiX2, roiY2, overlayColour, roiOutline)

        # note the maxWidth of zoomed panels and total height for row
        maxSplitPanelWidth = max(maxSplitPanelWidth, roiSplitPane.size[0])
        totalcanvasHeight += spacer + max(height+topSpacer,
                                          roiSplitPane.size[1])

        mergedImages.append(mergedImage)
        roiSplitPanes.append(roiSplitPane)
        topSpacers.append(topSpacer)

    # remove the labels for the invalid images (without ROIs)
    invalidImages.reverse()
    for row in invalidImages:
        del imageLabels[row]

    # 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
    canvasWidth = leftTextWidth + width + spacer + maxSplitPanelWidth + spacer
    figureSize = (canvasWidth, totalcanvasHeight + spacer)
    figureCanvas = Image.new("RGB", figureSize, (255, 255, 255))

    rowY = spacer
    for row, image in enumerate(mergedImages):
        labelCanvas = figUtil.getVerticalLabels(imageLabels[row], font,
                                                textGap)
        vOffset = (image.size[1] - labelCanvas.size[1]) / 2
        imgUtil.pasteImage(labelCanvas, figureCanvas, spacer/2,
                           rowY + topSpacers[row] + vOffset)
        imgUtil.pasteImage(
            image, figureCanvas, leftTextWidth, rowY + topSpacers[row])
        x = leftTextWidth + width + spacer
        imgUtil.pasteImage(roiSplitPanes[row], figureCanvas, x, rowY)
        rowY = rowY + max(image.size[1] + topSpacers[row],
                          roiSplitPanes[row].size[1]) + spacer

    return figureCanvas
Exemplo n.º 2
0
def get_split_view(conn, image_ids, pixel_ids, merged_indexes, merged_colours,
                   width, height, image_labels, spacer, algorithm, stepping,
                   scalebar, overlay_colour, roi_zoom, max_columns,
                   show_roi_duration, roi_label):
    """
    This method makes a figure of a number of images, arranged in rows with
    each row being the split-view of a single image. The channels are arranged
    left to right, with the combined image added on the right.
    The combined image is rendered according to current settings on the
    server, but it's channels will be turned on/off according to
    @mergedIndexes.

    The figure is returned as a PIL 'Image'

    @ session           session for server access
    @ pixelIds          a list of the Ids for the pixels we want to display
    @ mergedIndexes     list or set of channels in the merged image
    @ mergedColours     index: colour dictionary of channels in the merged
                        image
    @ width             the size in pixels to show each panel
    @ height            the size in pixels to show each panel
    @ spacer            the gap between images and around the figure. Doubled
                        between rows.
    """

    roi_service = conn.getRoiService()
    re = conn.createRenderingEngine()
    query_service = conn.getQueryService()  # only needed for movie

    # establish dimensions and roiZoom for the primary image
    # getTheseValues from the server
    for iid in image_ids:
        rect = get_rectangle(roi_service, iid, roi_label)
        if rect is not None:
            break

    if rect is None:
        log("Found no images with rectangle ROIs")
        return
    x, y, roi_width, roi_height, time_shape_map = rect

    roi_outline = ((max(width, height)) // 200) + 1

    if roi_zoom is None:
        # get the pixels for priamry image.
        pixels = query_service.get("Pixels", pixel_ids[0])
        size_y = pixels.getSizeY().getValue()

        roi_zoom = float(height) / float(roi_height)
        log("ROI zoom set by primary image is %F X" % roi_zoom)
    else:
        log("ROI zoom: %F X" % roi_zoom)

    text_gap = spacer // 3
    font_size = 12
    if width > 500:
        font_size = 48
    elif width > 400:
        font_size = 36
    elif width > 300:
        font_size = 24
    elif width > 200:
        font_size = 16
    font = image_utils.get_font(font_size)
    text_height = font.getsize("Textq")[1]
    max_count = 0
    for row in image_labels:
        max_count = max(max_count, len(row))
    left_text_width = (text_height + text_gap) * max_count + spacer

    max_split_panel_width = 0
    total_canvas_height = 0
    merged_images = []
    roi_split_panes = []
    top_spacers = []  # space for labels above each row

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

        # need to get the roi dimensions from the server
        image_id = image_ids[row]
        roi = get_rectangle(roi_service, image_id, roi_label)
        if roi is None:
            log("No Rectangle ROI found for this image")
            del image_labels[row]  # remove the corresponding labels
            continue
        roi_x, roi_y, roi_width, roi_height, time_shape_map = roi

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

        # work out if any additional zoom is needed (if the full-sized image
        # is different size from primary image)
        full_size = (size_x, size_y)
        image_zoom = image_utils.get_zoom_factor(full_size, width, height)
        if image_zoom != 1.0:
            log("  Scaling down the full-size image by a factor of %F" %
                image_zoom)

        log("  ROI location (top-left of first frame) x: %d  y: %d  and size"
            " width: %d  height: %d" % (roi_x, roi_y, roi_width, roi_height))
        # get the split pane and full merged image
        roi_split_pane, full_merged_image, top_spacer = get_roi_movie_view(
            re, query_service, pixels, time_shape_map, merged_indexes,
            merged_colours, roi_width, roi_height, roi_zoom, spacer, algorithm,
            stepping, font_size, max_columns, show_roi_duration)

        # and now zoom the full-sized merged image, add scalebar
        merged_image = image_utils.resize_image(full_merged_image, width,
                                                height)
        if scalebar:
            x_indent = spacer
            y_indent = x_indent
            # and the scale bar will be half size
            sbar = float(scalebar) / image_zoom
            status, log_msg = figUtil.addScalebar(sbar, x_indent, y_indent,
                                                  merged_image, pixels,
                                                  overlay_colour)
            log(log_msg)

        # draw ROI onto mergedImage...
        # recalculate roi if the image has been zoomed
        x = roi_x // image_zoom
        y = roi_y // image_zoom
        roi_x2 = (roi_x + roi_width) // image_zoom
        roi_y2 = (roi_y + roi_height) // image_zoom
        draw_rectangle(merged_image, x, y, roi_x2, roi_y2, overlay_colour,
                       roi_outline)

        # note the maxWidth of zoomed panels and total height for row
        max_split_panel_width = max(max_split_panel_width,
                                    roi_split_pane.size[0])
        total_canvas_height += spacer + max(height + top_spacer,
                                            roi_split_pane.size[1])

        merged_images.append(merged_image)
        roi_split_panes.append(roi_split_pane)
        top_spacers.append(top_spacer)

    # 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
    canvas_width = left_text_width + width + 2 * spacer + max_split_panel_width
    figure_size = (canvas_width, total_canvas_height + spacer)
    figure_canvas = Image.new("RGB", figure_size, (255, 255, 255))

    row_y = spacer
    for row, image in enumerate(merged_images):
        label_canvas = figUtil.getVerticalLabels(image_labels[row], font,
                                                 text_gap)
        v_offset = (image.size[1] - label_canvas.size[1]) // 2
        image_utils.paste_image(label_canvas, figure_canvas, spacer // 2,
                                row_y + top_spacers[row] + v_offset)
        image_utils.paste_image(image, figure_canvas, left_text_width,
                                row_y + top_spacers[row])
        x = left_text_width + width + spacer
        image_utils.paste_image(roi_split_panes[row], figure_canvas, x, row_y)
        row_y = row_y + max(image.size[1] + top_spacers[row],
                            roi_split_panes[row].size[1]) + spacer

    return figure_canvas