3

私は、とりわけ画像のフォルダ(通常は約2000 jpeg画像)を取得してサイズを変更し、画像のタイムラインに追加するプログラムを作成しています。この結果は次のとおりです。

ここに画像の説明を入力してください

これは問題なく機能しますが、私がこれを行った方法は非常に非効率的です。これらの画像を処理するコードを以下に示します。

public void setTimeline(Vector<String> imagePaths){
    
    int numberOfImages = imagePaths.size();     
    
    JLabel [] TotalImages = new JLabel[numberOfImages];
    setGridPanel.setLayout(new GridLayout(1, numberOfImages, 10, 0));
    
    Dimension image = new Dimension(96, 72);

    if (imagePaths != null){
        for(int i = 0; i <numberOfImages; i++){
            TotalImages[i] = new JLabel("");
            TotalImages[i].setPreferredSize(image);
            
            ImageIcon tempicon = new ImageIcon(imagePaths.elementAt(i));
            Image tempimage = tempicon.getImage();
            
            Image newimg = tempimage.getScaledInstance(96, 72,  java.awt.Image.SCALE_SMOOTH);
            ImageIcon newIcon = new ImageIcon(newimg);
            TotalImages[i].setIcon(newIcon);

            setGridPanel.add(TotalImages[i]);
        }
    }
}

ご覧のとおり、このコードは各画像パスをループし、それをラベルに追加してパネルに追加します。正しい出力で正確に実行されます。

ただし、これを行うのにかかる時間はかなりのものです。通常、2000枚の画像の場合は約5分です(マシンによって異なります)。さまざまな手法を使用してこのパフォーマンスを向上させる方法はないかと思いました。

どんな助けでも大歓迎です。

4

6 に答える 6

4

スケーリングされたインスタンスを保存して直接ロードします。ハードドライブの容量は安価です。これは親指を生成する初期コストを回避することはできませんが、その後の出現は非常に高速になります。

于 2012-05-29T21:44:36.340 に答える
3

画像のフォルダを取ります

を使用したプロセスtempimage.getScaledInstance(96, 72, java.awt.Image.SCALE_SMOOTH);

  • use JTable、機能を減らしても使用JListできます

通常、2000 枚の画像で約 5 分

Image.getScaledInstance単純な非同期であり、高速でパフォーマンスが保証されていない場合は、画像の読み込みをバックグラウンド タスクにリダイレクトする必要があります。

  • 利点 画像の最初の部分はすぐに利用できます

  • dis_advantage は、ユーザーの読み込みステータスを表示する必要がありますSwingEvent Dispatch Thread

Runnable#Threadを見て、出力を に出力することをお勧めします。DefaultTableModelこの出力は、invokeLater

もう 1 つの最も複雑な方法は useですが、 andについてもSwingWorker十分な知識が必要です。JavaSwing

于 2012-05-29T21:47:25.620 に答える
3

mKorbel の優れた回答に加えて、SwingWorker などのバックグラウンド スレッドを使用することは間違いありません。これでプログラムが速くなることはないかもしれませんが、かなり速くなったように見えます。何かのようなもの:

// use List<String> not Vector<String> so you can use Vector now, or change your 
// mind and use ArrayList later if desired
// pass dimensions and components in as parameters to be cleaner
public void setTimeLine2(List<String> imagePaths, Dimension imgSize,
     JComponent imgDisplayer) {

  if (imagePaths != null && imgSize != null && imgDisplayer != null) {

     // are you sure you want to set the layout in here?
     imgDisplayer.setLayout(new GridLayout(1, 0, 10, 0));

     // create your SwingWorker, passing in parameters that it will need
     ImageWorker imgWorker = new ImageWorker(imagePaths, imgSize,
           imgDisplayer);
     imgWorker.execute(); // then ask it to run doInBackground on a background thread
  } else {
     // TODO: throw exception
  }
}

private class ImageWorker extends SwingWorker<Void, ImageIcon> {
  private List<String> imagePaths;
  private JComponent imgDisplayer;
  private int imgWidth;
  private int imgHeight;

  public ImageWorker(List<String> imagePaths, Dimension imgSize,
        JComponent imgDisplayer) {
     this.imagePaths = imagePaths;
     this.imgDisplayer = imgDisplayer;
     imgWidth = imgSize.width;
     imgHeight = imgSize.height;
  }

  // do image creation in a background thread so as not to lock the Swing event thread
  @Override
  protected Void doInBackground() throws Exception {
     for (String imagePath : imagePaths) {
        BufferedImage bImg = ImageIO.read(new File(imagePath));
        Image scaledImg = bImg.getScaledInstance(imgWidth, imgHeight,
              Image.SCALE_SMOOTH);
        ImageIcon icon = new ImageIcon(scaledImg);
        publish(icon);
     }
     return null;
  }

  // but do all Swing manipulation on the event thread
  @Override
  protected void process(List<ImageIcon> chunks) {
     for (ImageIcon icon : chunks) {
        JLabel label = new JLabel(icon);
        imgDisplayer.add(label);
     }
  }
}
于 2012-05-29T22:13:43.303 に答える
2

タイルを使用します。つまり、画面に表示されていない画像を操作するのではなく、画面に画像を表示する必要がある場合にのみ操作しました。

表示される画像だけでなく、タイムラインの論理的な位置も維持する必要があります。ユーザーがカーソルを以前の非表示の位置に移動すると、次に表示する必要がある画像を計算します。画像がまだ処理されていない場合は、それらを処理します。これは、Web ブラウザーがパフォーマンスのために使用する手法と同じです。

于 2012-05-29T21:39:09.580 に答える
1
  • 最初にできることは、すべての画像を一度に追加しようとするのではなく、画像を非同期的に追加することです。それらをループしてパネルに追加し、いくつかの画像ごとにレンダリングするか、ユーザーが長い初期化時間を待つ必要がないようにします。

  • 画像オブジェクトを再利用します。flyweight パターンが頭に浮かび、非同期読み込みで新しい画像を追加する部分のみに画面の再描画を制限する可能性があります。

  • 将来、同じ画像を再描画する (または同じフォルダーをリロードする) 可能性がある場合は、画像オブジェクトの一部をキャッシュすることを検討し、サイズ変更されたサムネイルをファイルに保存することを検討してください (多くの写真ビューアーはこれを行い、サムネイルのバージョンといくつかの有用なメタデータを隠しファイルまたはフォルダーに保存するため、次回はそれらをより速くリロードできます。

于 2012-05-29T21:39:59.067 に答える
-1

高速化するためにできることは、4 つのスレッドを作成し、それらに同時に画像を計算させることです。ただし、VMがそれらを複数のCPUコアに分散させるかどうかはわかりません。マルチコアPCのパフォーマンスを向上させるため、検討すべきこと

于 2012-05-29T21:44:44.073 に答える