当前位置: 首页 > 知识库问答 >
问题:

过滤图像的最快性能

夏炎彬
2023-03-14

上下文:我试图用Java创建一个动画。动画是简单地采取一个图像,并使它出现从最暗的像素到最亮。

问题:定义像素转换的内部算法不是我的问题。我对Java和一般计算都是新手。我做了一些研究,知道有很多API有助于图像筛选/转换。我的问题是表现,理解它。

对于实现,我创建了一个方法,它执行以下操作:

  1. 接收BufferedImage。
  2. 获取BufferedImage的WritableRaster。
  3. 使用setSample和getSample,逐像素处理和更改。
  4. 返回BufferedImage。

之后,我使用计时器调用该方法。返回的BufferedImage在每次调用后通过setIcon附加到JButton。

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

我的目标是处理/动画的全高清图像在30fps...我不能用我正在走的路。在大多数电脑里都没有。

我搞错了什么?我怎么能让它更快?使用getDataBuffer或getPixels代替getSample可以改进吗?

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

部分结论:多亏了这里的一些帮助。我改变了观念。我没有使用getSample和setSample,而是将BufferedImage的像素ARGB信息存储到一个数组中。因此,我处理了数组,并将其一次复制到另一个BufferedImage的光栅中。

处理时间从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个答案

萧芷阳
2023-03-14

虽然变化产生的时差并不能证明重复搜索是瓶颈,但它确实强烈地暗示了它。

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

另外一个建议:使用Java内置的排序方法之一。做自己的东西是有教育意义的,但学习如何分类似乎不是你的目标。此外,如果我对瓶颈的猜测是错误的,你会希望尽量减少你的时间追求这个答案。

 类似资料:
  • 问题内容: 几个用户询问在numpy的或SciPy的[图像卷积的速度或存储器消耗1,2,3,4 ]。从回答和我使用Numpy的经验来看,与Matlab或IDL相比,我认为这可能是numpy的主要缺点。 到目前为止,没有一个答案能解决整个问题,所以这里是:“用Python计算2D卷积最快的方法是什么?” 常见的python模块是公平的游戏:numpy,scipy和PIL(其他?)。为了比较具有挑战性

  • 问题内容: 我会写 我还可以使用其他哪些过滤器? 我可以使用这样的东西吗? 问题答案: Docker v1.13.0支持以下条件: 或用于按某些值过滤图像: 参考文献 码头工人图像过滤 码头工人文档

  • 在Tableau中,使用度量和维度上的右键单击选项可以快速获得许多过滤器类型。这些过滤器具有足够的功能来解决大多数日常过滤需求。这些过滤器称为快速过滤器。 以下屏幕截图显示了如何访问快速过滤器: 下表给出了在Tableau中各种快速过滤器及其用法。 过滤器 作用/目的 单值(列表) 它在列表中一次只选择一个值。 单值(下拉) 它在下拉列表中选择单个值。 多值(列表) 它在列表中一次可选择一个或多个

  • 视图过滤 可以对视图的渲染输出进行过滤 <?php namespace app\index\controller; use think\Controller; class Index extends Controller { public function index() { // 使用视图输出过滤 return $this->filter(fu

  • 我需要在javafx tableview中实现一个拥有庞大数据(大约10万)的过滤器, 我试过这个教程。它可以工作,但与swing排序和过滤相比,过滤速度非常慢。 谁能帮我提速吗。 现在正在发生的事情是,当我键入textproperty change fire up和filterdata时,但速度很慢,我需要一些东西来显示筛选结果,并在swing中快速键入。 提前谢谢。 p、 我也看过这个。

  • 问题内容: 我一直在尝试使用docker process命令获取docker实例的容器ID,但是当我尝试使用 名称 过滤器时,对我来说效果 很好 。 结果容器ID: 3c7e865f1dfb 但是,当我使用 图像进行 过滤时,我将获得所有实例容器ID: 结果容器ID: 5570dc09b581 3c7e865f1dfb 但我希望仅获得mariadb的容器ID。 如何使用过滤器作为图像获取Docke