Java Streams - 处理rgb值

时间:2016-04-17 14:54:56

标签: java lambda filter java-stream argb

我正在开发一个简单的图像处理工具,它应该能够在给定的图像上应用滤镜。我想知道如何使用lambda表达式和流以函数方式解决这个问题。

我写了一个方法,它返回一个带有argb值的ArrayList内核,然后可以根据我想要应用的过滤器进一步处理。例如,如果我想应用一个盒式过滤器,我必须将所有元素相加并除以元素的数量。但当然,我必须分别对所有rgb值执行此操作。

我以前得到的值如下:

// Get rgb values:  
    r = (argb >> 16) & 0xff;  
    g = (argb >> 8) & 0xff;  
    b = argb & 0xff;  
// Write back to argb:  
    argb = (0xFF << 24) | (r << 16) | (g << 8) | b;

但是我不确定如何用流来写这个,或者在这里插入什么来分割值并独立处理它们并将结果重新组合在一起。

IntStream.range(0, src.length).parallel().forEach(i ->
    dst[i] = getKernelValues(3, src, i, width, height).stream()
                    .mapToInt(Integer::intValue)
                    .sum() / 9);

我在这里写的是完全错误的,因为它需要整个argb值。但也许你们可以帮我改变一个可以用于其他过滤器的工作示例。

提前致谢。

编辑:
与此同时,我通过分割如下的值来解决问题。这有效,但仍然有重复的代码。如果有人在更少的代码中知道如何做到这一点,我会很高兴知道。

非常感谢。

IntStream.range(0, src.length).parallel().forEach(i -> {
    ArrayList<Integer> values = getKernelValues(filterSize, src, i, width, height);
        int r = values
            .stream()
            .map(j -> (j >> 16) & 0xff)
            .reduce(0, (j, k) -> j + k);
        r /= (filterSize * filterSize);

        int g = values
            .stream()
            .map(j -> (j >> 8) & 0xff)
            .reduce(0, (j, k) -> j + k);
        g /= (filterSize * filterSize);

        int b = values
            .stream()
            .map(j -> j & 0xff)
            .reduce(0, (j, k) -> j + k);
        b /= (filterSize * filterSize);

        dst[i] = 0xff << 24 | r << 16 | g << 8 | b;
});

1 个答案:

答案 0 :(得分:0)

听起来你需要平均所有r值,g值和b值。如果我是正确的,首先要注意的是你不能在int的8位空间内对每个值求和,因为在将结果除以值的数量之前,总和将超过8位。因此,您需要做的第一件事是将r,g和b值提取为单独的整数值以保存总和。您可以使用整数字段创建RGB类,但是整数数组将执行:

static int[] sumRGB(int[] arr1, int[] arr2){
    return new int[] { arr1[0] + arr2[0], arr1[1] + arr2[1], arr1[2] + arr2[2] };
}

你想使用流,所以如果我们使用一组int来进行求和,我们需要将流转换为Stream,并使用求和操作减少单个项:

static int[] divRGB(int[] arr1, int divisor){
    return new int[] { arr1[0]/divisor, arr1[1]/divisor, arr1[2]/divisor };
}

稍后我们需要划分每个值以使其回到8位范围,因此这种方便的方法将有所帮助:

public static int averageRGB(IntStream ints, int size) {
    int[] sum = ints
            .parallel()
            .mapToObj(i -> unpackARGB(i))
            .reduce(new int[]{0,0,0}, (a, v) -> sumRGB(a, v));
    return packARGB(divRGB(sum, size));
} 

然后我们可以创建一个执行平均操作的函数:

int result = averageRGB(integerList.stream().mapToInt(i->i), integerList.size());

从你的列表中你可以像这样调用它:

 var class_details_keys = Object.keys($scope.rounds.class_details);
 class_details_keys = class_details_keys.sort(function(a,b) {return (+a.substring(6)) - (+b.substring(6));});
 for(int i=0, length = class_details_keys ; i < length;i++)
    console.log($scope.rounds.class_details[class_details_keys[i]]);