以最快、最简单的方式缩放缓冲图像

任务:我有一些图像,我缩小它们,并将它们连接到一个图像。但我在实现方面有一点问题:

具体问题:我想调整/缩放缓冲区图像。getScaledInstance 方法返回一个 Image 对象,但我无法将其强制转换为 BufferedImage:

Exception in thread "main" java.lang.ClassCastException: sun.awt.image.ToolkitImage cannot be cast to java.awt.image.BufferedImage

(我不知道为什么它是一个工具包图像而不是一个图像...)

我找到了一个解决方案:

Image tmp = bi.getScaledInstance(SMALL_SIZE, SMALL_SIZE, BufferedImage.SCALE_FAST);
BufferedImage buffered = new BufferedImage(SMALL_SIZE,SMALL_SIZE,BufferedImage.TYPE_INT_RGB);
buffered.getGraphics().drawImage(tmp, 0, 0, null);

但它很慢,我认为应该有更好的方法来做到这一点。

我需要BufferedImage,因为我必须获取像素才能连接小图像。

有没有更好(更好/更快)的方法来做到这一点?

编辑:如果我先将图像投射到 ToolkitImage,它有一个 getBufferedImage() 方法。但它始终返回 null。你知道为什么吗?


答案 1

该对象有一个方法,用于在同时执行调整大小操作的同时进行绘制:GraphicsImage

Graphics.drawImage(Image, int, int, int, int, int, ImageObserver)方法可用于在绘制时指定位置以及图像的大小。

因此,我们可以使用如下代码:

BufferedImage otherImage = // .. created somehow
BufferedImage newImage = new BufferedImage(SMALL_SIZE, SMALL_SIZE, BufferedImage.TYPE_INT_RGB);

Graphics g = newImage.createGraphics();
g.drawImage(otherImage, 0, 0, SMALL_SIZE, SMALL_SIZE, null);
g.dispose();

这将采取并绘制它与 宽度和高度.otherImagenewImageSMALL_SIZE


或者,如果您不介意使用库,缩略图器可以完成相同的操作:

BufferedImage newImage = Thumbnails.of(otherImage)
                             .size(SMALL_SIZE, SMALL_SIZE)
                             .asBufferedImage();

缩略图器还将比使用更快地执行调整大小操作,同时还比仅使用 执行更高质量的调整大小操作。Image.getScaledInstanceGraphics.drawImage

免责声明:我是缩略图库的维护者。


答案 2

你也可以使用OpenCV Java库。它的调整大小操作比Imgscalr的更快:

测试

图像 5184 x 3456 缩放到 150 x 100(这是较小的版本,因为原始文件大于 2mb):enter image description here

Imgscalr

屬地:

<dependency>
    <groupId>org.imgscalr</groupId>
    <artifactId>imgscalr-lib</artifactId>
    <version>4.2</version>
</dependency>

法典:

BufferedImage thumbnail = Scalr.resize(img,
            Scalr.Method.SPEED,
            Scalr.Mode.AUTOMATIC,
            150,
            100);

结果图像:

enter image description here

平均时间:80 毫

开放CV

屬地:

<dependency>
    <groupId>nu.pattern</groupId>
    <artifactId>opencv</artifactId>
    <version>2.4.9-4</version>
</dependency>

将 BufferedImage 转换为 Mat 对象(必须):

BufferedImage img = ImageIO.read(image); // load image
byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer())
            .getData();
Mat matImg = new Mat(img.getHeight(), img.getWidth(), CvType.CV_8UC3);
matImg.put(0, 0, pixels);

法典:

Imgproc.resize(matImg, resizeimage, sz);

其他配置(用于窗口):

将opencv_java249.dll添加到 JDK 的 bin 目录中。

结果图像:

enter image description here

平均时间:13毫

总体结果

在测试中,仅计算“调整大小”函数时间。Imgscalr将给定图像的大小调整为80毫英寸,其中OpenCV在13毫英寸内完成了相同的任务。你可以在这里找到下面的整个项目来稍微玩一下。

正如你问的,也很容易,如果Imgscalr库的性能对你有好处,那么它就非常容易。因为要使用 OpenCV,因为您看到的库文件必须位于所有开发环境和服务器上。此外,您必须使用Mat对象。

整个项目

啪.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.btasdemir</groupId>
    <artifactId>testapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>testapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.imgscalr</groupId>
            <artifactId>imgscalr-lib</artifactId>
            <version>4.2</version>
        </dependency>

        <dependency>
            <groupId>nu.pattern</groupId>
            <artifactId>opencv</artifactId>
            <version>2.4.9-4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin> 
                <groupId>org.bytedeco</groupId> 
                <artifactId>javacpp</artifactId> 
                <version>0.9</version> 
            </plugin>
        </plugins>
    </build>

</project>

应用.java:

package com.btasdemir.testapp;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.imgscalr.Scalr;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;


/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args ) throws IOException
    {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        File image = new File("C:\\your_dir\\test.jpg");
        BufferedImage img = ImageIO.read(image); // load image
        long startTime = System.currentTimeMillis();//imgscalr------------------------------------------------------
        //resize to 150 pixels max
        BufferedImage thumbnail = Scalr.resize(img,
                Scalr.Method.SPEED,
                Scalr.Mode.AUTOMATIC,
                150,
                100);
//      BufferedImage thumbnail = Scalr.resize(img,
//                Scalr.Method.SPEED,
//                Scalr.Mode.AUTOMATIC,
//                150,
//                100,
//                Scalr.OP_ANTIALIAS);
        System.out.println(calculateElapsedTime(startTime));//END-imgscalr------------------------------------------------------
        File outputfile = new File("C:\\your_dir\\imgscalr_result.jpg");
        ImageIO.write(thumbnail, "jpg", outputfile);


        img = ImageIO.read(image); // load image
        byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer())
                .getData();
        Mat matImg = new Mat(img.getHeight(), img.getWidth(), CvType.CV_8UC3);
        matImg.put(0, 0, pixels);

        Mat resizeimage = new Mat();
        Size sz = new Size(150, 100);
        startTime = System.currentTimeMillis();//opencv------------------------------------------------------

        Imgproc.resize(matImg, resizeimage, sz);
//      Imgproc.resize(matImg, resizeimage, sz, 0.5, 0.5, Imgproc.INTER_CUBIC);

        System.out.println(calculateElapsedTime(startTime));//END-opencv------------------------------------------------------
        Highgui.imwrite("C:\\your_dir\\opencv_result.jpg", resizeimage);


    }

    protected static long calculateElapsedTime(long startTime) {
        long stopTime = System.currentTimeMillis();
        long elapsedTime = stopTime - startTime;
        return elapsedTime;
    }
}

推荐