3

我一直在研究分析显微镜数据的软件,这些数据存储为多层 tiff 文件。在查看了 StackOverflow 和 JAI 文档之后,我拼凑了一些代码来存储 tiff 堆栈并正确呈现它。

但是,它的性能很差。在阅读了这样的帖子后,我曾希望能获得更快的性能: 任何人都有用 Java 编写一个非常快速的 tiff 查看器/编辑器的运气吗?

不幸的是,它并没有我希望的那么好。我在使用外部图像库或 Java 的图形功能方面没有太多经验,所以我不确定如何改进这一点。

在某些情况下,这是我在遍历 tiff 堆栈时遇到的“口吃”视频: http ://www.youtube.com/watch?v=WiR4o6TsqyM&feature=channel_video_title

请注意,当拖动滑块时,帧偶尔会出现断断续续的情况。

我通过在缩放时移除平滑来提高图像放大时的性能,但它仍然没有我想要的那么快。

我的代码如下:

/** Converts the RenderedImage into a BufferedImage, which is more flexible
 * @param img   The original RenderedImage
 * @return  The new BufferedImage
 */
public BufferedImage convertRenderedImage(RenderedImage img) {
    if (img instanceof BufferedImage) {
        return (BufferedImage)img;  
    }   
    ColorModel cm = img.getColorModel();
    int width = img.getWidth();
    int height = img.getHeight();
    WritableRaster raster = cm.createCompatibleWritableRaster(width, height);
    boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
    Hashtable<String, Object> properties = new Hashtable<String, Object>();
    String[] keys = img.getPropertyNames();
    if (keys!=null) {
        for (int i = 0; i < keys.length; i++) {
            properties.put(keys[i], img.getProperty(keys[i]));
        }
    }
    BufferedImage result = new BufferedImage(cm, raster, isAlphaPremultiplied, properties);
    img.copyData(raster);
    return result;
}

/** Draws everything on top of the scaled image
 * @param scale The current scale value
 */
private void setScaledImage(double scale) 
{
    //Optimizes the image type for drawing onto the screen
    GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice device = env.getDefaultScreenDevice();
    GraphicsConfiguration config = device.getDefaultConfiguration();

    int w = (int)(scale*currImage.getWidth());
    int h = (int)(scale*currImage.getHeight());
    scaled = config.createCompatibleImage(w, h, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = scaled.createGraphics();
    g2.drawImage(currImage, 0, 0, w, h, null);
    g2.dispose();
}

我已经使用 JAI 将多层 tiff 加载到 imageDecoder 中,并在拖动滑块时显示正确的图层,我使用以下代码:

try {
    currImage = convertRenderedImage(imageStack.decodeAsRenderedImage(currentLayerSlider.getValue()-1));
    setScaledImage (scaleSlider.getValue()/100.0);
    curves.changeFrame(currentLayerSlider.getValue());
    drawImageOverlay ();} 
catch (IOException e) {
    e.printStackTrace();
    currImage = null;}

基本上,每当拖动滑块时,我都会从 imageStack 中提取渲染图像,将其转换为 BufferedImage(以便它可以与 ImageIcon 一起使用),对其进行缩放,并将其设置为显示的图像。我认为缓慢的部分是将其转换为缓冲图像,并对其进行缩放。有什么办法可以更快地做到这一点?

有没有人对如何改进事情有任何建议,或者从类似的经历中获得洞察力?

任何帮助将非常感激。

4

4 回答 4

3

我遇到了完全相同的问题并最终使用decodeAsRaster()传递给转换方法:

public static BufferedImage convertRenderedImage(Raster raster) {
    int w = raster.getWidth();
    int h = raster.getHeight();
    BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    int[] sourcePixels = ((DataBufferInt)raster.getDataBuffer()).getData();
    int[] destPixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
    System.arraycopy(pixels, 0, rasterData, 0, pixels.length); // The speed-up!
    return image;
}

然后将您的代码更改为:

currImage = convertRenderedImage(imageStack.decodeAsRaster(currentLayerSlider.getValue()-1));

速度改进的功劳在这里归还给@Brent Nash :我们基本上从原始 Raster 获取像素数组,并为 BufferedImage 填充像素数组并执行 a而不是更便携但更便携System.arraycopy的“昂贵” image.setData(raster),对于每个像素,调用一些方法来检查一致性和类型,而我们已经拥有了我们需要的所有信息。

此代码应该对 有效BufferedImage.TYPE_INT_RGB,尽管我必须承认我无法测试它,但我知道它正在运行BufferedImage.TYPE_BYTE_GRAY(和byte[]/ DataBufferByte)。

于 2013-03-19T19:11:23.710 回答
0

您可以将渲染图像更改为缓冲区,然后将其显示在 j 标签中,因为渲染图像是 jai 图像,而 j 标签仅使用缓冲区图像,不要尝试在 jai 中显示它,您可以在 jLabel 中尝试

于 2014-02-04T05:46:31.153 回答
0

您是否尝试过使用 DisplayJAI,而不是为 JLabel 使用 BufferedImage 和 ImageIcon?它可以直接显示RenderedImage。

于 2012-03-14T12:43:58.330 回答
0

// 可以使用以下代码呈现输出 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO 自动生成的方法 stub System.out.println("inside GET ..."); String pageNumb = request.getParameter("page"); System.out.println("pageNumb:: "+pageNumb); String filePath = "/Users/test/Downloads/Multi_page24bpp.tif";

    SeekableStream s = new FileSeekableStream(filePath.trim());
    TIFFDecodeParam param = null;
    ImageDecoder dec = ImageCodec.createImageDecoder("tiff", s, param);
    String totNumberOfPage =String.valueOf(dec.getNumPages());
    System.out.println("number of pages:: "+totNumberOfPage);
    RenderedImage op = dec.decodeAsRenderedImage(Integer.parseInt(pageNumb)); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write (op, "jpeg", baos);
//    response = ServletActionContext.getResponse();
    response.setContentType("image/jpeg");
    OutputStream out = response.getOutputStream();
    out.write(baos.toByteArray());
    out.flush();
}
于 2018-09-27T20:04:30.580 回答