【问题标题】:Java Streams - process rgb valuesJava Streams - 处理 rgb 值
【发布时间】:2016-04-17 14:54:56
【问题描述】:

我正在开发一个简单的图像处理工具,它应该能够在给定图像上应用滤镜。我想知道如何使用 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;
});

【问题讨论】:

  • 您当前的代码有什么问题?
  • 如上一段所述,getKernelValues() 返回一个 argb 整数值的 ArrayList。但当然你需要分别处理所有颜色通道。
  • 目前还不清楚你期待什么样的输出。可以举个例子吗?
  • 嗯,我仍然不确定如何更好地解释它。也许它有助于举例说明我从 getKernelValues() 获得的值。此示例适用于我图片中随机位置的 9x9 滤镜尺寸。 int: -8224126 /// hex: 0xff828282 int: -8092540 /// hex: 0xff848484 int: -8224126 /// hex: 0xff828282 int: -8224126 /// hex: 0xff828282 int: -8092540 ///44 hex: 0xff88 int: -8224126 /// hex: 0xff828282 int: -8224126 /// hex: 0xff828282 int: -8092540 /// hex: 0xff848484 int: -8224126 /// hex: 0xff828282 抱歉,这里接缝输入不起作用

标签: java lambda filter java-stream argb


【解决方案1】:

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

static int[] unpackARGB(int argb){
    return new int[] { (argb >> 16) & 0xff, (argb >> 8) & 0xff, argb & 0xff };
}

static int packARGB(int[] ints){
    return (0xff << 24 + ints[0] & 0xff) << 16 + (ints[1] & 0xff) << 8 + ints[2] & 0xff;
}

您想使用流,所以如果我们使用整数数组进行求和,我们需要将流转换为流,并使用求和操作减少单个项目:

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

稍后我们需要将每个值除以将其恢复到其 8 位范围内,因此这种方便的方法会有所帮助:

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

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

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());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-22
    • 1970-01-01
    • 2017-01-07
    • 2015-10-19
    • 1970-01-01
    相关资源
    最近更新 更多