java - 如何创建JavaFX 16位灰度图像

标签 java image javafx 16-bit ushort

我有一个生成16位灰度图像的应用程序。当前,这些图像作为数据类型为DataBuffer.TYPE_USHORT的awt BufferedImage生成。

在我的应用程序中,我从BufferedImage中提取16位数据,规格化为8位,然后使用canvas.getGraphicsContext2D()。getPixelWriter()。setPixels(...)将其渲染到FX Canvas中。

它可以工作,但是看起来很乱,我想知道是否可以实现JavaFX Image或WritableImage,让我们称之为由我的16位数据支持的UShortImage。 UShortImage可以具有用于规范化级别的FX属性,但否则可以与任何JavaFX Image完全一样地使用。

任何有关如何以良好的运行时效率实现这一目标的帮助或指示,将不胜感激!

最佳答案

我不知道这是否正是您要寻找的内容,因为我可能不明白您的问题。但是您可以通过使用ColorAdjust效果使颜色去饱和来将彩色图像转换为灰色图像。

ColorAdjust monochrome = new ColorAdjust();
monochrome.setSaturation(-1);
ImageView gray = new ImageView(new Image(IMAGE_LOC));
gray.setEffect(monochrome);


我不确定为什么可怜的奶奶和爷爷必须褪色成黑白,但这一定是。

coloradjust

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.*;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class GrayScale extends Application {

    @Override
    public void start(Stage stage) {
        ColorAdjust monochrome = new ColorAdjust();
        monochrome.setSaturation(-1);
        Image image = new Image(IMAGE_LOC);
        ImageView color = new ImageView(image);
        ImageView gray = new ImageView(image);
        gray.setEffect(monochrome);

        HBox layout = new HBox(10, color, gray);
        layout.setPadding(new Insets(10));

        Scene scene = new Scene(layout);
        scene.setFill(Color.BLACK);
        stage.setScene(scene);

        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    // source: http://www.photoshopessentials.com/photo-editing/black-and-white-tutorials/desaturate/
    private static final String IMAGE_LOC =
            "http://pe-images.s3.amazonaws.com/photo-effects/black-and-white/grandparents.jpg";
}


如果ColorAdjust不适合您,则可以使用WritableImage上的PixelReaders和PixelWriters在逐个像素的基础上进行操作。 (正如您在问题中提到的那样,我看不出涉及画布的原因)。有关使用WritableImage的相关实现,请参见:


Reduce number of colors and get color of a single pixel




也许您还希望扩展一种新类型的PixelFormat并扩展PixelReader以读取您的数据缓冲区,但这可能是可行的,尽管我猜想并不需要完成您想要的操作:

PixelReader reader = new GrayScalePixelReader(); 
reader.getPixels(0, 0, W, H, 
    GrayScalePixelFormat.instance(), grayScaleByteBuffer, 0, scanlineStride); 
Image img = new WritableImage(reader, W, H); 


其中GrayScalePixelReader和GrayScalePixelFormat是您通过扩展名创建的新类。


  FX支持由PixelFormat定义的像素类型,例如BYTE_BGRA和BYTE_BGRA_PRE;我希望增加对新像素类型的支持,该像素类型每个像素有一个样本,这是16个无符号数据值。

pixelFormat = PixelFormat.createByteIndexedInstance(LUT);
getPixelWriter().setPixels(0, 0, w, h, pixelFormat, normalisedImageData, 0, w); 



是的,您几乎可以做到,但这有点棘手。我同意Java 8中现有的PixelFormat并不是真的很容易被用户扩展,原因如下:


  有些方法(例如WritabelImage类的getPixelWriter())是最终方法,因此您甚至无法覆盖它们。图像基础结构看起来似乎并非旨在以这种方式扩展。


通常,当涉及到JavaFX时,这种可扩展性的缺乏是有目的的。原因如下:


安全性,通过覆盖核心功能还执行恶意副作用,使人们更难将平台颠覆成恶意软件。
向应用程序开发人员提供简化的界面,以使其更易于理解和使用API​​。
故意使平台的某些部分不透明,以便库开发人员更容易维护核心库实现并随意更改它,而不会影响用户程序。


当然,这种折衷(在这种情况下)可能会缺乏尝试完成您想要的目标的灵活性。

如果您研究JavaFX中的Image实现,它有四个不同的组件:


javafx.scene.image APIs
支持图像API的平台实现(prism)(请参见source)。
image io libraries用于读取常见的图像格式(png,jpg等)。
图形硬件加速器API或软件呈现API(例如es2)的接口,最终,它们通常通常将图像视为输入到硬件图形API(例如OpenGL或Direct3D)的纹理。


关于灰度像素格式的有趣之处在于,它们没有直接在(1)javafx.scene.image API中公开。但是,棱镜平台的实现,图像io库和硬件加速器(2、3和4)确实具有一定程度的内置灰度支持。例如,一个PNG文件可能具有灰度格式,而imageIO将识别该格式,并将灰度缓冲区直接传递给prism Image class进行交互。

硬件加速层也支持灰度缓冲区,如ES2Texture实现所示。因此,这为灰度像素格式编码的缓冲区提供了一种理想的情况,该缓冲区可以将图像直接渲染为硬件加速纹理。但是请注意,Prism / ES2渲染系统支持的current pixel format for the grayscale byte buffer是8位编码,而不是您理想中要求的16位编码(尽管有关棱镜像素格式的注释并不认为16位类型可能会将来需要;-):

// L8, A8 types:
// NOTE : we might need L8A8 16-bit type
BYTE_GRAY    (DataType.BYTE,  1, true,  true), 


因此,这意味着您正在寻找的许多基础结构都已经可以通过JavaFX运行时直接解释灰度编码的图像缓冲区,但是将其放置在com.sun类和私有API中,而不是直接暴露给用户在公共javafx.scene.image API中。

可以创建feature request来启用用于灰度像素格式的公共API,也可以在openjfx-dev mailing list上进行询问。实现此类功能的最短时间框架将是Java10。看起来这样的请求可能已经存在,因此您可以对其进行评论或在openjfx-dev邮件列表中提出该请求以帮助将其推进:


High bit-depth Grayscale WritableImage support
Support Writable Gray Image


以上信息是否对您当前的问题有任何帮助->可能不会:-)但希望它有助于理解该平台及其功能,局限性以及将来扩展以完全支持您的要求的潜在机制。

关于java - 如何创建JavaFX 16位灰度图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43068319/

相关文章:

java - 从 c :out tag to struts s:text tag 传递一个参数

java - 如何在 Java 测试结果中查看我的场景名称

css - 使图像对搜索引擎和 Facebook 不可见?

JavaFX 与较大的 Canvas 尺寸存在巨大的滞后

java - JVM 到 JVM 通信的所有方式

java - 如何在不同于 'Application' 和 'Activity' 的扩展中实现全局变量?

html - 如何将图片连续放置bootstrap

java - 如何在Java小程序中使用图标?

JavaFX TableView 性能问题

java - 为什么 JavaFX 包含重复的颜色常量?