4

ブーストを使用するのは初めてです。それを使用して、画像のコレクションをロードします。問題は、フォルダー内の画像の数が増え続け、最終的にはすべての画像を表示プログラムに追加したくないということです。私は OS X で C++ を使用しています。

このサンプルコードを調整して、ディレクトリの上部または下部から 30 枚の画像のみをロードするようにするにはどうすればよいですか? 最新のファイルだけをロードするのは素晴らしいことですが、これを変更するだけで解決できます。残念ながら、私のループで (it <30) と言うだけでは機能しません。これは fs::directory_iterator と同等である必要があるためです。

コード例:

fs::path pPhoto( photobooth_texture_path );
for ( fs::directory_iterator it( pPhoto ); it != fs::directory_iterator(); ++it )
{
    if ( fs::is_regular_file( *it ) )
    {
        // -- Perhaps there is a better way to ignore hidden files
        string photoFileName = it->path().filename().string();
        if( !( photoFileName.compare( ".DS_Store" ) == 0 ) )
        {
            photoboothTex.push_back( gl::Texture( loadImage( photobooth_texture_path + photoFileName ), mipFmt) );
            cout << "Loaded: " << photoFileName <<endl;
        }
    }
}

編集:これが私がやった方法です。2 つの方法のハイブリッドのようなものですが、逆方向に並べ替える必要がありました。世界で最もクリーンなものではありませんが、私は彼らのアイデアを私が理解しているC++のフレーバーに変換する必要がありました

    vector<string> fileList;
int count = 0;

photoboothTex.clear();//clear this out to make way for new photos

fs::path pPhoto( photobooth_texture_path );
for ( fs::directory_iterator it( pPhoto ); it != fs::directory_iterator(); ++it )    {
    if ( fs::is_regular_file( *it ) )
    {
        // -- Perhaps there is a better way to ignore hidden files
        string photoFileName = it->path().filename().string();

        if( !( photoFileName.compare( ".DS_Store" ) == 0 ) )
        {
            fileList.push_back(photoFileName);
        }
    }
}
for (int i=(fileList.size()-1); i!=0; i--) {

        photoboothTex.push_back( gl::Texture( loadImage( photobooth_texture_path + fileList[i%fileList.size()] )) );
        cout << "Loaded Photobooth: " << fileList[i%fileList.size()] <<endl;
        if(++count ==40) break; //loads a maximum of 40 images
}
4

2 に答える 2

5

boost::filter_iteratorwith を使用しdirectory_iteratorて、通常のファイルへのパスをベクターに格納する実際の例を次に示し ます。に基づいてベクトルをソートしましたlast_write_time()。また、簡潔にするためにエラー チェックを省略しました。ディレクトリ内のファイルが 30 未満の場合、この例はクラッシュします。

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/filesystem.hpp>
#include <boost/iterator/filter_iterator.hpp>
namespace fs = boost::filesystem;

int main()
{
    fs::path p("My image directory");
    fs::directory_iterator dir_first(p), dir_last;
    std::vector<fs::path> files;

    auto pred = [](const fs::directory_entry& p)
    {
        return fs::is_regular_file(p);
    };

    std::copy(boost::make_filter_iterator(pred, dir_first, dir_last),
              boost::make_filter_iterator(pred, dir_last, dir_last),
              std::back_inserter(files)
              );

    std::sort(files.begin(), files.end(),
              [](const fs::path& p1, const fs::path& p2)
              {
                  return fs::last_write_time(p1) < fs::last_write_time(p2);
              });

    std::copy_n(files.begin(), 30, std::ostream_iterator<fs::path>(std::cout, "\n"));
}

例を機能させるには、次のように for ループを構成できます。

fs::path pPhoto( photobooth_texture_path );
fs::directory_iterator it( pPhoto );

for ( size_t i = 0;  i < 30 && it != fs::directory_iterator(); ++it )
{
    if ( fs::is_regular_file( *it ) )
    {
        // load the image
        ++i;
    }
}
于 2012-07-11T20:27:20.367 に答える
3

it < 3030 は directory_iterator ではないため、言うことはできません。

そして、できたとしても、それは最初の 30 個のファイルの期間のみをカウントし、最初の 30 個の非表示のファイルはカウントしません。 '.'" を使用し、これらのファイルが最初に来る傾向があります)。

ただし、カウントを自分で簡単に追跡できます。

int count = 0;

fs::path pPhoto( photobooth_texture_path );
for ( fs::directory_iterator it( pPhoto ); it != fs::directory_iterator(); ++it )
{
    if ( fs::is_regular_file( *it ) )
    {
        // -- Perhaps there is a better way to ignore hidden files
        string photoFileName = it->path().filename().string();
        if( !( photoFileName.compare( ".DS_Store" ) == 0 ) )
        {
            photoboothTex.push_back( gl::Texture( loadImage( photobooth_texture_path + photoFileName ), mipFmt) );
            cout << "Loaded: " << photoFileName <<endl;
            if (++count == 30) break;
        }
    }
}

それでおしまい。

最新のファイルだけをロードするのは素晴らしいことですが、これを変更するだけで解決できます。

これは最新の 30 を取得するのではなく、「some 30」だけを取得します。boost::filesystemは「あたかも POSIX readdir_r() を呼び出すかのように」反復し、 readdir_rは「特定のディレクトリ内のすべてのディレクトリ エントリの順序付けられたシーケンス」として指定されたディレクトリ ストリームを反復しますが、何を伝える方法はありません。そのシーケンスに必要な順序。

もちろん、リスト全体を読み込んでから、必要に応じて並べ替えることで、自分で順序付けを追加できます。それについては、上記の jrok の回答を参照してください。しかし、これにはいくつかの欠点があります。

  • それほど単純ではありません。
  • ディレクトリが大きい場合は、はるかに遅くなります (30 個を読み取るだけでなく、3000 個のエントリすべてを読み取って、場合によっては stat して並べ替える必要があるため)。
  • より多くのメモリを必要とします。

最終的には、それはトレードオフです。

それほど単純ではありませんが、誰か (jrok) が既にコードを作成しており、彼のコードを理解することは、いずれにしても価値のある学習経験です。「はるかに遅い」とはいえ、それでも「十分に速い」可能性があります。「はるかに多くのメモリ」が必要ですが、それでもバケツのほんの一滴に過ぎない可能性があります。ただし、これらの要因を評価して、自分で決定する必要があります。

他に 2 つの簡単な点について説明します。

まず、速度が問題ではなく、メモリが問題である場合 (ほとんどありませんが、完全に不可能というわけではありません)、すべてのファイルではなく、これまでに見つかった最後の 30 個のファイルを保持するだけで、コードをもう少し複雑にすることができます。(たとえば、ベクトルの代わりにセットに貼り付けます。新しい値ごとに、セット内の最も古い値より古い場合は無視します。そうでない場合は、セットに挿入して最も古い値を削除します。)

第二に、移植性を気にせず、boost::filesystem からプラットフォーム固有の見苦しい C ベースの API に移行する意思がある場合、プラットフォームには、ディレクトリ エントリをソートされた順序で読み取る方法がある可能性があります。しかし、順序付けと効率の両方が本当に必要で、移植性と単純さを完全に犠牲にしても構わないと思っている場合を除き、私はこれを追求しません。

于 2012-07-12T00:54:35.670 に答える