1

我正在制作类似程序的图像编辑,当我想编辑大图像时,它真的开始变慢。什么是快速编辑大图像的好方法?这个例子调整了图像的亮度,它可以工作,但是当我得到像 3456x2304 这样的大图像时,它真的很慢。

我有一个滑块,每次移动时都会调用这个函数。

// Slider in a dialog box
private void sldBrightnessStateChanged(javax.swing.event.ChangeEvent evt) {
    // Get the position of the slider
    int val = sldBrightness.getValue();
    // Set the text in the textbox
    txtBrightness.setText("" + val);
    // New Brightness class (see below)
    Brightness adjustment = new Brightness();
    adjustment.amount(val);
    adjustment.applyFilter();
    // get the result built by applyFilter();
    Canvas.preview = Preview.getImage();
    // Update main program
    this.getParent().repaint();
}

然后是过滤器:

package pocketshop.graphics.adjustments;

import java.awt.image.BufferedImage;
import pocketshop.Canvas;
import pocketshop.graphics.Colors;
import pocketshop.graphics.Preview;

public class Brightness{

    protected int amount = 0;

    public void amount(int amount){
        this.amount = amount;
    }

    public void applyFilter(){
        int width = Canvas.image.getWidth();
        int height = Canvas.image.getHeight();
        int[] pixels = new int[width * height];

        Canvas.image.getRGB(0, 0, width, height, pixels, 0, width);
        for(int i = 0; i < pixels.length; i++){
            int pixel = pixels[i];
            //int pixel = Canvas.image.getRGB(x, y);
            int red = Colors.red(pixel);
            int green = Colors.green(pixel);
            int blue = Colors.blue(pixel);

            red += amount;
            if(red > 255){
                red = 255;
            }else if(red < 0){
                red = 0;
            }

            green += amount;
            if(green > 255){
                green = 255;
            }else if(green < 0){
                green = 0;
            }

            blue += amount;
            if(blue > 255){
                blue = 255;
            }else if(blue < 0){
                blue = 0;
            }
            pixels[i] = Colors.rgba(red, green, blue);
        }
        //BrightnessContrastDialog.preview.setRGB(0, 0, width, height, pixels, 0, width);
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        img.setRGB(0, 0, width, height, pixels, 0, width);
        Preview.setImage(img);
    }
}
4

4 回答 4

3

我有一个滑块,每次移动时都会调用这个函数。

在滑块停止移动之前不要调整图像。我不知道 Swing,但我打赌有一个测试可以evt说明它是在移动还是已经停止。

按照您的方式,随着滑块的移动,applyFilter 可能会被调用 100 次或更多次。

于 2012-11-14T23:52:25.480 回答
1

据我了解,图片是为用户提供的,以便立即反馈所做的更改,您可以做什么我们显示图片的下采样版本并在滑块移动时对其执行亮度更改,这将很快。一旦用户对她使用滑块选择的值感到满意,您就可以将更改应用于原始图像。您可以添加应用按钮或其他东西

于 2012-11-15T06:48:33.553 回答
0

我建议您研究OpenCL及其 Java 绑定JOCL。OpenCL 是一个用于直接与各种不同显卡上的 GPU 交互的库。JOCL 是 OpenCL API 的 Java 绑定库。

公平的警告,这可能比您想要解决的要多得多,因为您将在比 Swing 低得多的水平上工作。

于 2012-11-15T02:53:42.513 回答
0

我不确定,但看起来您使用的是BufferedImage.TYPE_INT_ARGB类型的 BufferedImage。这意味着 BufferedImage 正在使用 WritableRaster,而该 WritableRaster 正在使用 DataBufferInt 类型的 DataBuffer。在其最简单的形式中,DataBufferInt 只不过是一个 int[] 的包装器。如果您可以获取 Canvas 正在使用的 BufferedImage,则获取其 WritableRaster 并从那里获取 DataBufferInt:

WritableRaster raster = Canvas.image.getRaster();
DataBufferInt dataBuffer = (DataBufferInt)raster.getDataBuffer();
int[] pixels = dataBuffer.getData();

现在您有了代表像素的 int[],您可以遍历它并更改组件:

for (int i = 0, len = pixels.len; i < len; ++i) {
  int pixel = pixels[i];

  int red = ((pixel & 0x00FF0000) >> 16) + amount;
  if (red < 0) red = 0 else if (red > 255) red = 255;

  int green = ((pixel & 0x0000FF00) >> 8) + amount;
  if (green < 0) green = 0 else if (green > 255) green = 255;

  int blue = (pixel & 0x000000FF) + amount;
  if (blue < 0) blue = 0 else if (blue > 255) blue = 255;

  pixels[i] = (pixels[i] & 0xFF000000) + (red << 16) + (green << 8) + blue;
}

这意味着预览中的 BufferedImage 中的像素正在就地更改,而无需创建另一个新像素的 int[] 和另一个 BufferedImage。

我不确定这是否会起作用,但很多时候它有助于 Java 省去中间人并且不创建尽可能多的对象。

如果这不起作用,请查看Java Advanced Imaging

于 2012-11-15T04:32:21.740 回答