简体   繁体   English

如何创建JavaFX 16位灰度图像

[英]How to Create JavaFX 16 bit Greyscale Images

I have an application that generates 16 bit grey scale images. 我有一个生成16位灰度图像的应用程序。 Currently these images are generated as an awt BufferedImage with data type DataBuffer.TYPE_USHORT. 目前,这些图像是作为具有数据类型DataBuffer.TYPE_USHORT的awt BufferedImage生成的。

In my app, I extract the 16 bit data from the BufferedImage, normalise to 8 bit, then render it into an FX Canvas with canvas.getGraphicsContext2D().getPixelWriter().setPixels(...) 在我的应用程序中,我从BufferedImage中提取16位数据,规范化为8位,然后使用canvas.getGraphicsContext2D()将其渲染到FX Canvas中.getPixelWriter()。setPixels(...)

It works but looks messy I am wondering if it is possible to implement a JavaFX Image or WritableImage, lets call it a UShortImage that is backed by my 16 bit data. 它工作但看起来很乱我想知道是否有可能实现JavaFX Image或WritableImage,让我们称之为由我的16位数据支持的UShortImage。 The UShortImage could have FX properties for the normalisation levels, but otherwise could be used exactly as any JavaFX Image. UShortImage可以具有规范化级别的FX属性,但是可以与任何JavaFX Image完全一样使用。

Any help or pointers on how to achieve this with good run time efficiency would be appreciated! 任何有关如何以良好的运行时效率实现此目的的帮助或指示将不胜感激!

I don't know if this is exactly what you are looking for as perhaps I don't understand your question. 我不知道这是不是你正在寻找的,也许我不明白你的问题。 But you can convert a color image to a gray image by desaturating the color using a ColorAdjust effect. 但是,您可以使用ColorAdjust效果通过去饱和颜色将彩色图像转换为灰色图像。

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

I am not sure why poor grandma and grandpa must be faded to black and white, but it must be so. 我不确定为什么贫穷的奶奶和爷爷必须褪色为黑白,但一定是这样。

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";
}

If ColorAdjust doesn't work for you, then you could just do manipulation on a pixel-by-pixel bases using PixelReaders and PixelWriters on a WritableImage. 如果ColorAdjust不适合你,那么你可以在WritableImage上使用PixelReaders和PixelWriters在逐个像素的基础上进行操作。 (I don't see a reason for a canvas to be involved as you mention in your question). (我没有看到你在问题中提到画布的原因)。 For an related implementation using a WritableImage see: 有关使用WritableImage的相关实现,请参阅:


Perhaps you are also looking to extend PixelFormat with a new type and extend PixelReader to read your data buffer, which may be possible, though I guess that wouldn't be necessary to accomplish what you want: 也许您也希望使用新类型扩展PixelFormat并扩展PixelReader以读取您的数据缓冲区,这可能是可能的,但我想这不是必要的,以实现您想要的:

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

where GrayScalePixelReader and GrayScalePixelFormat are new classes you create via extension. 其中GrayScalePixelReader和GrayScalePixelFormat是您通过扩展创建的新类。

FX supports pixel types define by PixelFormat such as BYTE_BGRA and BYTE_BGRA_PRE; FX支持PixelFormat定义的像素类型,如BYTE_BGRA和BYTE_BGRA_PRE; I am looking to add support for a new pixel type which has a single sample per pixel which is a 16 unsigned data value. 我希望添加对新像素类型的支持,每个像素具有单个样本,这是16个无符号数据值。

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

Yeah, you can almost do it, but it is a little tricky. 是的,你几乎可以做到,但这有点棘手。 I agree that existing PixelFormat in Java 8 is not really very readily user extensible, for reasons such as you mention: 我同意Java 8中现有的PixelFormat并不是非常容易用户扩展,原因就像你提到的那样:

Some methods eg getPixelWriter() of the WritabelImage class are final so you can't even override them. 一些方法,例如WritabelImage类的getPixelWriter()是最终的,所以你甚至不能覆盖它们。 The Image infrastructure looks like it is not designed to be extended in this way. Image基础架构看起来不像是以这种方式扩展。

Usually, when it comes to JavaFX, this lack of extensibility is built in on purpose. 通常,当谈到JavaFX时,缺乏可扩展性是故意构建的。 Some reasons are: 一些原因是:

  1. Security, to make it more difficult for people to subvert the platform into doing something malicious by overriding core functionality to also perform malicious side effects. 安全性,通过覆盖核心功能以执行恶意副作用,使人们更难以破坏平台做恶意的事情。
  2. Present a simplified interface to the application developer to make it easier to understand and use the API. 向应用程序开发人员提供简化的界面,以便更容易理解和使用API​​。
  3. Deliberately make some parts of the platform opaque, so that it is easier for the library developers to maintain the core library implementation and change it at will without impacting user programs. 故意使平台的某些部分不透明,以便库开发人员更容易维护核心库实现并随意更改它而不会影响用户程序。

Of course the tradeoff (as in this case) can be a lack of flexibility in trying to accomplish what you wish. 当然,权衡(在这种情况下)可能是缺乏灵活性来尝试完成你想要的。

If you look into the Image implementation in JavaFX, it kind of has four different components: 如果你看一下JavaFX中的Image实现,它有四种不同的组件:

  1. The javafx.scene.image APIs . javafx.scene.image API
  2. The platform implementation ( prism ) backing the image APIs (see source ). 支持图像API的平台实现( prism )(参见源代码 )。
  3. The image io libraries for reading common image formats (png, jpg, etc). 用于读取常见图像格式(png,jpg等)的图像io库
  4. Interfaces to graphics hardware accelerator APIs or software rendering APIs, for example es2 , which ultimately, usually treats the image as a texture input to a hardware graphics API such as OpenGL or Direct3D. 与图形硬件加速器API或软件渲染API的接口,例如es2 ,它最终通常将图像视为硬件图形API(如OpenGL或Direct3D)的纹理输入。

The interesting thing about grayscale pixel formats is that they are not directly exposed in (1) the javafx.scene.image APIs. 关于灰度像素格式的有趣之处在于它们不直接暴露在(1)javafx.scene.image API中。 However, the prism platform implementation, the image io libraries and hardware accelerators (2, 3 and 4), do have some level of inbuilt grayscale support. 但是,棱镜平台实现,图像io库和硬件加速器(2,3和4)确实具有一定程度的内置灰度支持。 For instance, a PNG file could have a grayscale format and the imageIO will recognize the format and pass the grayscale buffer directly to the prism Image class to be interpereted. 例如,PNG文件可以具有灰度格式,imageIO将识别格式并将灰度缓冲区直接传递给要进行交互的棱镜Image类

Grayscale buffers are also supported by the hardware acceleration layer, as can be seen in the ES2Texture implementation. 硬件加速层也支持灰度缓冲区,如ES2Texture实现中所示。 So this gives an ideal situation of the grayscale pixel format encoded buffer for the image being able to be directly rendered to a hardware accelerated texture. 因此,这给出了灰度像素格式编码缓冲器的理想情况,该图像缓冲器能够直接渲染到硬件加速纹理。 Note however, that the current pixel format for the grayscale byte buffer supported by the Prism/ES2 rendering system, is for an 8 bit encoding, not a 16 bit encoding you ideally ask for (though comments on the prism pixel format do not that a 16-bit type might be needed in the future ;-): 但请注意,Prism / ES2渲染系统支持的灰度字节缓冲区当前像素格式是8位编码,而不是理想情况下要求的16位编码(尽管对棱镜像素格式的注释不是将来可能需要16位类型;-):

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

So this means that much of the infrastructure that you are looking for that allows direct interpretation of the grayscale encoded image buffer by the JavaFX runtime is already there, however it is placed inside com.sun classes and private API and not directly exposed to the user in the public javafx.scene.image APIs. 因此,这意味着您正在寻找的大部分基础结构允许JavaFX运行时直接解释灰度编码图像缓冲区,但是它放在com.sun类和私有API中,而不是直接暴露给用户在公共javafx.scene.image API中。

A feature request could be created to enable a public API for grayscale pixel formats or you could ask about it on the openjfx-dev mailing list . 可以创建功能请求以启用灰度像素格式的公共API,或者您可以在openjfx-dev邮件列表中询问它。 Shortest timeframe to get such features implemented would be Java 10. It looks like such a request may already exist, so you could comment on it or bring it up on the openjfx-dev mailing list to help move it forward: 实现此类功能的最短时间范围是Java 10.看起来这样的请求可能已经存在,因此您可以对其进行评论或将其提交到openjfx-dev邮件列表以帮助推进它:

Does the above info help you in anyway with your current problem -> probably not :-) But hopefully it helps understanding of the platform and its capabilities, limitations and potential mechanisms for future extension to support your requirements for fully. 以上信息是否可以帮助您解决当前的问题 - >可能不会:-)但希望它有助于理解平台及其功能,限制和未来扩展的潜在机制,以完全支持您的需求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM