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
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
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)
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)
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