JavaFX:将图像转换为灰度

JavaFX: Convert Image to Greysacale

我需要在我的程序中这样做。我必须通过两种方式来做到这一点:

1.) 自己的,代码如下:`

private Image convertToGrayScale(Image image) {
         WritableImage result = new WritableImage((int) image.getWidth(), (int) 
                                      image.getHeight());
         PixelReader preader = image.getPixelReader();
         PixelWriter pwriter = result.getPixelWriter();

         for (int i = 0; i < result.getWidth(); i++) {
             for (int j = 0; j < result.getHeight(); j++) {
                 Color c = preader.getColor(i, j);
                 double red = (c.getRed() * 0.299);
                 double green = (c.getGreen() * 0.587);
                 double blue = (c.getBlue() * 0.114);
                 
                 double sum = c.getRed() + c.getBlue() + c.getGreen();
                 pwriter.setColor(i , j, new Color(sum, sum, sum, 1.0));
             }
         }
         return result;  
    }

2.) 在 openCV 库的帮助下,使用以下代码(几乎完美地从他们的站点复制):

public WritableImage loadAndConvert() throws Exception {
   //Loading the OpenCV core library
   System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

   String input = "C:/Users/Dan Ivgy/eclipse-workspace/LuckyBride/sample/20180402_170204.jpg";

   //Reading the image
   Mat src = Imgcodecs.imread(input);

   //Creating the empty destination matrix
   Mat dst = new Mat();

   //Converting the image to gray scale and saving it in the dst matrix
   Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY);
   
   // Imgcodecs.imwrite("C:/opencv/GeeksforGeeks.jpg", dst);

   //Extracting data from the transformed image (dst)
   byte[] data1 = new byte[dst.rows() * dst.cols() * (int)(dst.elemSize())];
   dst.get(0, 0, data1);

   //Creating Buffered image using the data
   BufferedImage bufImage = new BufferedImage(dst.cols(),dst.rows(), 
      BufferedImage.TYPE_BYTE_GRAY);

   //Setting the data elements to the image
   bufImage.getRaster().setDataElements(0, 0, dst.cols(), dst.rows(), data1);

   //Creating a WritableImage
   WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
   System.out.println("Converted to Grayscale");
   return writableImage;
}

 

在这两种情况下,问题是我没有得到“灰度”输出,只是有些不同(在你之前 问:是的,我已经尝试在几张照片上这样做,而不仅仅是一张)

这是输入图片和输出图片:

好吧,如你所见,这不是灰度!也许是日落规模..

非常感谢您的帮助,谢谢 :)

(特别是如果有更快的东西,因为这些解决方案需要一段时间 运行)

如果有人知道,为什么 javaFX 中没有一些内置选项,因为有很多复杂的 imageview 效果,而这个效果又简单又流行。

更新: 我找到了一个网站,它做的事情与我所做的类似 - 但不知何故我得到了不同的输出!我不明白 这是 website.

这是我电脑的输出: my output

更新#2:正如@matt 正确询问的那样,这是使用此方法的代码:

ImageIO.write(SwingFXUtils
            .fromFXImage
            (convertToGrayScale(new Image(getClass().getResource("1_CNc4RxV85YgthtvZh2xO5Q.jpeg").toExternalForm()) ), null), "jpg", file);

最初的目标是向用户显示图像,但问题就出在这里,所以我将代码更改为保存图像的代码,这样我就可以更轻松地隔离问题..

我决定在 awt 中工作,然后创建一个 javafx 图像。

public class App extends Application {
    
    @Override
    public void start(Stage stage) {
        WritableImage gray = null;
        try {
            BufferedImage awtImage = ImageIO.read(new URL("https://i.stack.imgur.com/ysIrl.jpg"));
            gray = new WritableImage(awtImage.getWidth(), awtImage.getHeight());
            BufferedImage img2 = new BufferedImage(awtImage.getWidth(), awtImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
            for(int i = 0; i<awtImage.getWidth(); i++){
                for(int j = 0; j<awtImage.getHeight(); j++){
                    int c = awtImage.getRGB(i, j);
                    int r = (c>>16)&255;
                    int g = (c>>8)&255;
                    int b = (c)&255;

                    int s = (int)(r*0.299 + g*0.587 + b*0.114);
                    int gr = (255<<24) + (s<<16) + (s<<8) + s;
                    img2.setRGB(i, j, gr);
                }
            }
            gray = SwingFXUtils.toFXImage(img2, gray);
        } catch (IOException e) {
            e.printStackTrace();
        }

        ImageView view = new ImageView(gray);
        ScrollPane pane = new ScrollPane(view);
        Scene scene = new Scene(new StackPane(pane), 640, 480);
        stage.setScene(scene);
        stage.show();
    }

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

}

这两种方法都对我有用,所以我不确定这是否对你有帮助。我也可以保存结果。

System.out.println("saving " +
                ImageIO.write(img2, "PNG", new File("tested.png")) );

如果您使用的是 oracles jdk,我认为您可以保存 JPEG。我正在使用 OpenJDK,它似乎无法编写 JPEG。

好的伙计们,经过一些研究和无数次的尝试,我得到了我需要的东西 为了解决这个问题,我在这里展示我的解决方案,并总结出我对这个问题的见解..

首先,我将区分“保存文件”和“在 ImageView 中设置文件”。

当我们只想在图像视图中显示它时,我使用此处建议的几乎所有解决方案都没有遇到任何问题。最简单、简短和甜蜜(在我看来)是以下一个:

 private Image convertToGrayScale(Image image) {
 WritableImage result = new WritableImage((int) image.getWidth(), (int) image.getHeight());
 PixelReader preader = image.getPixelReader();
 PixelWriter pwriter = result.getPixelWriter();

 for (int i = 0; i < result.getWidth(); i++) 
     for (int j = 0; j < result.getHeight(); j++)
         pwriter.setColor(i , j, preader.getColor(i, j).grayscale());
 return result;  
 }

(为了方便,我忽略了异常处理)

当我将它与以下代码一起使用时,它工作正常:

Image img1 = convertToGrayScale(new Image(filepath);
    imageView.setImage(img1);

关于保存此输出图像,经过一些研究并使用@trashgold 的参考资料,this important one

我的解决方案如下:

private void saveBadImage(BufferedImage originalImage, File dest) throws IOException
{
    // use the following line if you want the first parameter to be a filepath to src image instead of Image itself
    //BufferedImage originalImage = ImageIO.read(file);

    // jpg needs BufferedImage.TYPE_INT_RGB
    // png needs BufferedImage.TYPE_INT_ARGB

    // create a blank, RGB, same width and height
    BufferedImage newBufferedImage = new BufferedImage(
            originalImage.getWidth(),
            originalImage.getHeight(),
            BufferedImage.TYPE_INT_RGB);

    // draw a white background and puts the originalImage on it.
    newBufferedImage.createGraphics().drawImage(originalImage,0,0,null);

    // save an image
    ImageIO.write(newBufferedImage, "jpg", dest);
}

并且,我将它与以下代码一起使用:

Image img1 = convertToGrayScale(new Image(filepath));

BufferedImage img2 = new BufferedImage((int) img1.getWidth(), (int) img1.getHeight(), BufferedImage.TYPE_INT_ARGB);

saveBadImage(img2, file);

而且,它工作得很好!

谢谢大家,希望我的见解能对一些人有所帮助