最快的性能过滤图像

时间:2015-07-15 02:51:59

标签: java

上下文 我正在尝试用java创建动画。 动画只是拍摄一张图像,并使其从最暗的像素显示到最亮的像素。

问题: 定义像素变换的内部算法不是我的问题。 我是Java和计算的新手。我做了一些研究,并且知道有很多API可以帮助进行图像过滤/转换。 我的问题是表现,理解它。

在实现中,我创建了一个执行以下操作的方法:

  1. 收到BufferedImage。
  2. 获取BufferedImage的WritableRaster。
  3. 使用setSample和getSample,逐个像素地处理和更改。
  4. 返回BufferedImage。
  5. 之后,我使用Timer调用该方法。 返回的BufferedImage在每次调用后通过setIcon附加到JButton。

    对于500x500图像,我的机器需要大约3ms来处理每个呼叫。 对于标准1080p图像,它需要大约30ms,大约每秒33帧。

    我的目标是以30fps的速度处理/动画全高清图像...而且我无法使用我正在追踪的路径。不在大多数计算机中。

    我错了什么?我怎么能让它更快?使用getDataBuffer或getPixels而不是getSample可以改进它吗?

    提前致谢!抱歉我的英语。

    部分结论: 感谢这里的一些帮助。我改变了概念。我没有使用getSample和setSample,而是将BufferedImage的像素ARGB信息存储到数组中。所以我处理数组并将其全部复制到另一个BufferedImage的Raster中。

    处理时间从30ms(获取/设置样本)减少到1ms。 (测得很差,但在同一台机器,环境和代码中)。

    下面是我编写实现它的一个小类。该类只能在亮度级别下过滤像素,其他像素变为透明(alpha = 0)。

    希望将来能够搜索相同的解决方案。要小心我在Java中的新手级别以下,因此代码可能组织不当/优化。

    import java.awt.Graphics2D;
    import java.awt.image.*;
    
    /**
     * @author Psyny
     */
    public class ImageAppearFX {
        //Essencial Data
        BufferedImage imgProcessed;
        int[] RAWoriginal;
        int[] RAWprocessed;
        WritableRaster rbgRasterProcessedW;
    
        //Information about the image
        int x,y;
        int[] mapBrightness;
    
        public ImageAppearFX(BufferedImage inputIMG) {
            //Store Dimensions
            x = inputIMG.getWidth();
            y = inputIMG.getHeight();
    
            //Convert the input image to INT_ARGB and store it. 
            this.imgProcessed = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB); 
            Graphics2D canvas = this.imgProcessed.createGraphics();
            canvas.drawImage(inputIMG, 0, 0, x, y, null); 
            canvas.dispose();
    
            //Create an int Array of the pixels informations.
            //p.s.: Notice that the image was converted to INT_ARGB
            this.RAWoriginal = ((DataBufferInt) this.imgProcessed.getRaster().getDataBuffer()).getData();
            //Dupplication of original pixel array. So we can make changes based on original image
            this.RAWprocessed = this.RAWoriginal.clone();
    
            //Get Raster. We will need the raster to write pixels on
            rbgRasterProcessedW = imgProcessed.getRaster();
    
            //Effect Information: Store brightness information
            mapBrightness = new int[x*y];
            int r,g,b,a,greaterColor;
            // PRocess all pixels
            for(int i=0 ; i < this.RAWoriginal.length ; i++) {   
                a = (this.RAWoriginal[i] >> 24) & 0xFF;
                r = (this.RAWoriginal[i] >> 16) & 0xFF;
                g = (this.RAWoriginal[i] >>  8) & 0xFF;
                b = (this.RAWoriginal[i]      ) & 0xFF;
    
                //Search for Stronger Color
                greaterColor = r;
                if( b > r ) {
                        if( g > b ) greaterColor = g;
                        else greaterColor = b;        
                } else if ( g > r ) {
                    greaterColor = g;
                }
    
                this.mapBrightness[i] = greaterColor;
            }
        }
    
        //Effect: Show only in a certain percent of brightness
        public BufferedImage BrightnessLimit(float percent) {
            // Adjust input values
            percent = percent / 100;
    
            // Pixel Variables
            int hardCap = (int)(255 * percent);
            int r,g,b,a,bright;
    
            // Process all pixels
            for(int i=0 ; i < this.RAWoriginal.length ; i++) {   
                    //Get information of a pixel of the ORIGINAL image 
                    a = (this.RAWoriginal[i] >> 24) & 0xFF;
                    r = (this.RAWoriginal[i] >> 16) & 0xFF;
                    g = (this.RAWoriginal[i] >>  8) & 0xFF;
                    b = (this.RAWoriginal[i]      ) & 0xFF;
    
                    //Brightness information of that same pixel
                    bright = this.mapBrightness[i];
    
                    //
                    if( bright > hardCap  ) {     
                        a = 0;                 
                    }
                    this.RAWprocessed[i] = ((a << 24) + (r << 16) + (g << 8) + ( b )); //Write ARGB in byte format
            }
    
            //Copy the processed array into the raster of processed image
            rbgRasterProcessedW.setDataElements(0, 0, x, y, RAWprocessed);
    
            return imgProcessed;
        }
    
        //Return reference to the processed image
        public BufferedImage getImage() {
            return imgProcessed;
        }
    }
    

1 个答案:

答案 0 :(得分:1)

虽然改变所导致的时差并不能证明重复搜索是瓶颈,但它确实暗示了它。

如果你愿意/能够交换内存的时间,我会首先按亮度排序所有像素位置的列表。接下来,我将在动画期间使用排序列表来查找要复制的下一个像素。

额外建议:使用Java内置的排序方法之一。制作自己的教育很有教育意义,但学习如何排序似乎不是你的目标。此外,如果我对瓶颈的猜测是错误的,那么你会希望尽量减少花时间来回答这个问题。