

当方java初心者の者です。現在、画像を取り込み縦横比を維持したまま指定した大きさにリサイズしてBUfferedImageで返すプログラムを書きたいのですが何をどうすればよいかがわかりません。できるだけ画質は落としたくないのですが...画像や描画の仕組みに疎い節もありかなり難航しております。アドバイスまたはサンプルや画像の仕組みについてわかりやすく解説してくださっているサイトなどがあれば教えていただけると幸いです。どうかよろしくお願いします。


CC BY-SA 3.0
2017-09-27T14:27:27.573
38241
2017-11-01T03:43:47.140
24534
question
java
画像のリサイズについて


画質はどうかわかりませんが、標準ライブラリでやるのが簡単だと思います。

<https://qiita.com/tool-taro/items/1f414424b31a86e97446>  
<http://dotnsf.blog.jp/archives/1062006362.html>

のあたりを参考にしました。

次のようなプログラムではどうでしょうか？ ファイル名やサイズは適宜置き換えてください。

[code]

    import javax.imageio.ImageIO;
    import java.awt.*;
    import java.awt.image.AreaAveragingScaleFilter;
    import java.awt.image.BufferedImage;
    import java.awt.image.FilteredImageSource;
    import java.awt.image.ImageFilter;
    import java.awt.image.ImageProducer;
    import java.io.File;
    import java.io.IOException;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            BufferedImage bi = scaleImage(new File("src.jpg"), 100, 150);
            // 2番目の引数が画像の形式、3番目がファイル名
            ImageIO.write(bi, "jpeg", new File("dest.jpg"));
        }
    
        /**
         * 
         * @param in 読み込むファイル
         * @param destWidth 出力する画像の横の最大サイズ
         * @param destHeight 出力する画像の縦の最大サイズ
         * @return BufferedImage
         * @throws IOException
         */
        public static BufferedImage scaleImage(File in, int destWidth, int destHeight) throws IOException {
            BufferedImage src = ImageIO.read(in);
    
            int width = src.getWidth();    // オリジナル画像の幅
            int height = src.getHeight();  // オリジナル画像の高さ
    
            // 縦横の比率から、scaleを決める
            double widthScale = (double) destWidth / (double) width;
            double heightScale = (double) destHeight / (double) height;
            double scale = widthScale < heightScale ? widthScale : heightScale;
    
            ImageFilter filter = new AreaAveragingScaleFilter(
                (int) (src.getWidth() * scale), (int) (src.getHeight() * scale));
            ImageProducer p = new FilteredImageSource(src.getSource(), filter);
            Image dstImage = Toolkit.getDefaultToolkit().createImage(p);
            BufferedImage dst = new BufferedImage(
                dstImage.getWidth(null), dstImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
            Graphics2D g = dst.createGraphics();
            g.drawImage(dstImage, 0, 0, null);
            g.dispose();
            return dst;
        }
    }
    
[/code]


CC BY-SA 3.0
2017-09-27T20:14:08.517
38246
2017-09-27T20:14:08.517
2214
38241
answer


計算手段やプロセスを知りたい、とのことでしたので、画像処理は専門ではないので稚拙ですが単純な仕組みだけ説明します。

そもそも画像がどのようにして描画されているかを考えれば、リサイズは比較的単純に思いつくと思います。  
すごくざっくり言うと、方眼紙のような正方形のマス目を持ったキャンバスに対して、一マスずつ色を塗って出来たものを遠くから見たものが画像です。(ドット絵のようなものを思い浮かべると分かりやすい)

これをリサイズする場合、全てのマスに対して塗るマスの大きさを均等に変えてあげれば画像のサイズが変わります。  
マスの大きさを変えるのはどうするか、単純にマスの塗る数を増やしてあげれば良いだけです(そして、その分のサイズのキャンバスを別途用意する)  
縦横比を維持したい、とのことなので、マスの大きさを変える際に縦横比を維持しながらマスの大きさを変えることで対応できるはずです。たとえば、縦が10cmで横が30cmの画像をリサイズするときは、各マスに対して縦:横=1:3の比率でマスの大きさを変えてあげれば良い。

ただ、このような変換を単純に行うと、画像を大きくすればするほど画像が粗くなっていくことが容易に想像出来ますよね。  
そこで、たとえば境界線をぼかしたり(隣り合うマスに対して、それぞれの中間色でマスを埋めたり)、境界線を丸めたりする作業が必要になります。  
また、画像を小さくする際には、逆に今まで塗っていた範囲が塗れなくなるため、不要な色(とは？)を削る必要が出てきます。そうすると、画像が潰れて見えるような事象が発生してしまうので、それをどうにかする必要が出てきたりします。

と、ここまでが簡単な理屈を文章で説明していきましたが、簡単に調べてみたらすごくちょうど良いスライドがあったので共有します。  
<https://www.slideshare.net/ginrou799/ss-12685973>

画像処理の世界はかなり奥深く、その分野の研究に対して興味があったり、学習目的でない限りは自力での実装はあまりオススメできません。  
簡単な理屈だけ頭に入れておいて、あとは外部ライブラリなどに処理を委ねるのが良いかと思います。


CC BY-SA 3.0
2017-10-31T15:29:10.057
39185
2017-10-31T15:29:10.057
7655
38241
answer


（画像処理の一般論として回答します）

> 画像を取り込み縦横比を維持したまま指定した大きさにリサイズ  
>  できるだけ画質は落としたくないのですが..

古典的なデジタル画像の拡大・縮小アルゴリズムとしては、以下のものが良く用いられます。いずれも複数の参照元画像ピクセル値から生成先画像のピクセル値を計算（加算と乗算）していくアルゴリズムとなっています。

  * バイリニア(Bilinear)法
  * バイキュービック(Bicubic)法
  * Lanczos法（Lancozs3フィルタ）
  * 平均画素法 [縮小専用]

上記はいずれも教科書に載るレベルの古典アルゴリズムですから、技術詳細は信頼できる情報源にゆずります。また機械学習技術を用いた新しい拡大アルゴリズム（いわゆる"超解像"技術）としては、[waifu2x](http://waifu2x.udp.jp/index.ja.html)
なども存在します。


CC BY-SA 3.0
2017-11-01T03:43:47.140
39197
2017-11-01T03:43:47.140
49
38241
answer