Java - 删除某个alpha值以下的像素

时间:2016-02-16 14:17:36

标签: java bufferedimage alpha

我的图像中包含许多消除锯齿的线条,并尝试删除低于某个Alpha通道阈值的像素(高于阈值的任何内容都会转换为完整的255 alpha)。我已经对它进行了编码和工作,它只是没有在大图像上运行它时的速度。有没有人有他们建议的替代方法?

//This will convert all pixels with > minAlpha to 255
public static void flattenImage(BufferedImage inSrcImg, int minAlpha)
{
    //loop through all the pixels in the image
    for (int y = 0; y < inSrcImg.getHeight(); y++)
    {
        for (int x = 0; x < inSrcImg.getWidth(); x++)
        {
            //get the current pixel (with alpha channel)
            Color c = new Color(inSrcImg.getRGB(x,y), true);

            //if the alpha value is above the threshold, convert it to full 255
            if(c.getAlpha() >= minAlpha)
            {
                inSrcImg.setRGB(x,y, new Color(c.getRed(), c.getGreen(), c.getBlue(), 255).getRGB());
            }
            //otherwise set it to 0
            else
            {
                inSrcImg.setRGB(x,y, new Color(0,0,0,0).getRGB()); //white (transparent)
            }
        }
    }
}

根据@BenoitCoudour的评论我已经相应地修改了代码,但它似乎影响了像素的RGB值,任何想法我可能做错了什么?

public static void flattenImage(BufferedImage src, int minAlpha)
{
    int w = src.getWidth();
    int h = src.getHeight();

    int[] rgbArray = src.getRGB(0, 0, w, h, null, 0, w);

    for (int i=0; i<w*h; i++)
    {
        int a = (rgbArray[i] >> 24) & 0xff;
        int r = (rgbArray[i] >> 16) & 0xff;
        int b = (rgbArray[i] >> 8) & 0xff;
        int g = rgbArray[i] & 0xff;

        if(a >= minAlpha) { rgbArray[i] = (255<<24) | (r<<16) | (g<<8) | b; }
        else { rgbArray[i] = (0<<24) | (r<<16) | (g<<8) | b; }
    }

    src.setRGB(0, 0, w, h, rgbArray, 0, w);
}

2 个答案:

答案 0 :(得分:1)

可能减慢你速度的是每个像素的Color对象的实例化。 请参阅此答案以迭代BufferedImage中的像素并访问Alpha通道:https://stackoverflow.com/a/6176783/3721907

我只是粘贴下面的代码

public Image alpha2gray(BufferedImage src) {

    if (src.getType() != BufferedImage.TYPE_INT_ARGB)
        throw new RuntimeException("Wrong image type.");

    int w = src.getWidth();
    int h = src.getHeight();

    int[] srcBuffer = src.getData().getPixels(0, 0, w, h, null);
    int[] dstBuffer = new int[w * h];

    for (int i=0; i<w*h; i++) {
        int a = (srcBuffer[i] >> 24) & 0xff;
        dstBuffer[i] = a | a << 8 | a << 16;
    }

    return Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(w, h, pix, 0, w));
}

这非常接近你想要达到的目标。

答案 1 :(得分:0)

您的理论复杂度为O(n),您可以通过执行字节操作来优化它。

你可以进一步使用线程(你有一个令人尴尬的并行问题),但由于大多数用户机器最多有8个物理线程,所以它不会让你太过分。您可以通过一次操作图像的一部分来添加另一级优化,适应系统中的内存缓冲区和不同的缓存级别。

由于我已经提到过你有一个令人尴尬的并行问题,最好的解决方案是执行GPU编程。

您可以在simple image processing with cuda上关注本教程,并将过滤器的代码更改为此类

void blur(unsigned char* input_image, unsigned char* output_image, int width, int height) {

const unsigned int offset = blockIdx.x*blockDim.x + threadIdx.x;
const int currentoffset = (offset)*4;
if(offset < width*height) {
           if (input_image[currentoffset+3]>= threshold )
                output_red = input_image[currentoffset]; 
                output_green = input_image[currentoffset+1];
                output_blue = input_image[currentoffset+2];
                output_alpha = 255;
            }else{
                output_red = 0; 
                output_green = 0;
                output_blue = 0;
                output_alpha = 0;
            }
        }
    }
    output_image[currentoffset*3] = output_red;
    output_image[currentoffset*3+1] = output_green;
    output_image[currentoffset*3+2] = output_blue;
    output_image[currentoffset*3+3] = output_alpha
    }

}

如果您已开始使用Java,那么您可以在这里找到关于如何开始使用using java with nvidia gpu

的绝佳答案