我一直在研究分析显微镜数据的软件,该软件存储为多层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中提取渲染图像,将其转换为BufferedImage(以便它可以与ImageIcon一起使用),缩放它,并将其设置为显示的图像。我认为缓慢的部分是将其转换为缓冲图像,并进行缩放。有没有办法更快地做到这一点?
有没有人对如何改进事物或从类似经历中获得洞察力有任何建议?
非常感谢任何帮助。
答案 0 :(得分: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 here:我们基本上从原始Raster获取像素数组,并使BufferedImage的像素数组填满并执行{{1}而不是“昂贵的”System.arraycopy
,它更便携,但是,对于每个像素,调用一些方法来检查一致性和类型,而我们已经拥有了我们需要的所有信息。
此代码应该对image.setData(raster)
有效,但我必须承认我无法测试它,但我知道它正在BufferedImage.TYPE_INT_RGB
(和BufferedImage.TYPE_BYTE_GRAY
/ {{1 }})。
答案 1 :(得分:0)
您是否尝试过使用DisplayJAI而不是将BufferedImage和ImageIcon用于JLabel? 它可以直接显示RenderedImage。
答案 2 :(得分:0)
您可以将渲染图像更改为缓冲区,然后将其显示在j标签中,因为渲染图像是jai图像,j标签采用onley缓冲区图像,不要尝试在jai中显示它在jLabel中尝试
答案 3 :(得分:0)
//可以使用以下代码呈现输出 受保护的void doGet(HttpServletRequest请求,HttpServletResponse响应)抛出ServletException,IOException { // TODO自动生成的方法存根 System.out.println(“内部GET ...”); 字符串pageNumb = request.getParameter(“ page”); System.out.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();
}