有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用JAI在Java中使用TIFF渲染提高性能

我一直在开发分析显微镜数据的软件,该软件存储为多层tiff文件。在浏览了StackOverflow和JAI文档之后,我纠结在一起编写了一些代码来存储tiff堆栈并正确呈现它

然而,它有一些相当糟糕的性能。在阅读了以下文章后,我希望能有更快的表现: Anyone have any luck writing a very fast tiff viewer/editor in Java?

不幸的是,它远没有我希望的那么好。我没有太多使用外部图像库的经验,也没有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();
}

我已将多层tiff加载到带有JAI的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中提取渲染图像,将其转换为BuffereImage(以便可以与ImageIcon一起使用),缩放它,并将其设置为显示的图像。我认为缓慢的部分是将其转换为缓冲图像,并对其进行缩放。有什么方法可以更快地做到这一点吗

有没有人对如何改进东西有什么建议,或者从类似的经历中有什么见解

任何帮助都将不胜感激


共 (4) 个答案

  1. # 1 楼答案

    您是否尝试过使用DisplayJAI而不是使用JLabel的BuffereImage和ImageIcon? 它可以直接显示渲染图像

  2. # 2 楼答案

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

    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 Nashhere:我们基本上从原始光栅和缓冲图像的像素阵列中获取像素阵列,以填充并执行System.arraycopy而不是“昂贵的”image.setData(raster),后者更具可移植性,但对于每个像素,调用一些方法来检查一致性和类型,虽然我们已经有了我们需要的所有信息

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

  3. # 3 楼答案

    您可以将renderd图像更改为缓冲区,然后在j标签中显示,因为renderd图像是jai图像,而j标签仅获取缓冲区图像,而不尝试在jai中显示。您可以在jLabel中尝试

  4. # 4 楼答案

    //可以使用以下代码呈现输出 受保护的void doGet(HttpServletRequest请求,HttpServletResponse响应)抛出ServletException,IOException{ //TODO自动生成的方法存根 系统出来println(“内部获取…”); 字符串pageNumb=请求。获取参数(“页面”); 系统出来println(“pageNumb::”+pageNumb); 字符串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();
    }