2

色分けされた約20枚の画像があります。各画像をスキャンし、ピクセルをその色に関連付けられたラベルに一致させたいと思います。以下のコードを書きましたが、この一見単純なタスクを実行するのに約 30 分かかります。画像の解像度は 960 x 720 です。

私のコード:

void go_through_pixels(path &image_dir, string& ground_truth_suffix, string image_format, unordered_map<RGB, string> colors_for_labels){

    if(!exists(image_dir)){
        cerr << image_dir << " does not exist, prematurely returning" << endl;
        exit(-1);
    }

    unordered_map<string, set<path> > label_to_files_map;

    //initialise label_to_files_map
    for(unordered_map<RGB, string>::iterator it = colors_for_labels.begin(); it != colors_for_labels.end(); it++){
        label_to_files_map[it->second] = set<path>();
    }

    directory_iterator end_itr; //default construction provides an end reference

    for(directory_iterator itr(image_dir); itr != end_itr; itr++){

        path file = itr->path();
        string filename = file.filename().string();
        RGB rgb(0,0,0); //default rgb struct, values will be changed in the loop

        if(extension(file) == image_format && filename.find(ground_truth_suffix) != string::npos){
            //ground truth file
            Mat img = imread(file.string(), CV_LOAD_IMAGE_COLOR);

            for(int y = 0; y < img.rows; y++){
                for(int x = 0; x < img.cols; x++){
                    //gives data as bgr instead of rgb
                    Point3_<uchar>* pixel = img.ptr<Point3_<uchar> >(y,x);
                    rgb.red = (int)pixel->z;
                    rgb.green = (int)pixel->y;
                    rgb.blue =(int)pixel->x;
                    string label = colors_for_labels[rgb];
                    label_to_files_map[label].insert(file);
                    cout << label << endl;
                }
            }
        }
    }
}

後でこのデータをさらに処理する予定ですが、パフォーマンスの問題を見つけるためだけにコードを単純化しました。

label_to_files_map[label].insert(file)削除すると、画像をスキャンするだけで約 3 分かかるため、遅延の大部分は が原因であることがわかりました。これはまだ長すぎると思いますが、間違っているのでしょうか?

また、セットにinsertは時間がかかるため (挿入前に重複をチェックする必要があるため)、ここで使用するより良いデータ構造を提案できる人はいますか?

基本的に、写真は建物に対応する 100 ピクセル、車に対応する 100 ピクセルなどを持つことができるので、label_to_files_mapこのファイル (スキャンされている現在の画像) に建物が含まれていることをマップに記録したいだけです (このケースは特定の RGB 値で示されます)。

4

3 に答える 3

3

パフォーマンスの問題は、ピクセルあたりの作業が多すぎることです。

ファイルごとに (スタックされた for ループが開始する直前に) color_for_labels のコピーを作成します。

        Point3_<uchar> oldPixel;
        for(int y = 0; y < img.rows; y++){
            for(int x = 0; x < img.cols; x++){
                //gives data as bgr instead of rgb
                Point3_<uchar>* pixel = img.ptr<Point3_<uchar> >(y,x);
                if(*pixel == oldPixel) 
                    continue; // skip extra work
                oldPixel = *pixel
                rgb.red = (int)pixel->z;
                rgb.green = (int)pixel->y;
                rgb.blue =(int)pixel->x;
                string label = copy_of_colors_for_labels[rgb];
                if(label != null) {
                    label_to_files_map[label].insert(file);
                    copy_of_colors_for_labels[rgb] = null;
                    cout << label << endl;
                }
            }
        }

構文エラーがあるかもしれません (ブラウザで書き直して、何年も C++ でコーディングしていないため) が、上記により多くの余分な処理作業が削減されるはずです。

于 2012-10-09T17:23:54.253 に答える
1

間違ったデータ型と間違った関数を使用しています。改善方法のご提案です。数秒で実行されると思います。

あなたの作業のステップ 1 は、3 チャンネルの画像から 1 チャンネルの画像へのルックアップ テーブルです。cv::LUT を使用できます。ただし、高速化するにはコツが必要です。

ピクセルあたり 4 バイトに変換します。

cv::Mat mat4bytes;
// add 8 bits to each pixel. the fill value is 255
cv::cvtColor(img, mat4bytes, CV_RGB2RGBA); 
// this is a nice hack to interpret 
// the RGBA pixels of the input image as integers 
cv::Mat pseudoInteger(img.size(), CV_32UC1, mat4bytes.data);

これで、LUT を適用できます。

cv::Mat colorCoded;
// you have to convert your colors_for_labels lookup table
// like this: 
lookupTable[i] = 
      ((unsigned int)colors_for_labels.first.x << 24 ) + 
      ((unsigned int)colors_for_labels.first.y << 16 ) +        
      ((unsigned int)colors_for_labels.first.z << 8  ) +        
      255; 
// make sure it is correct!!!
// and lookupTable data MUST be unsigned integer

cv::LUT(pseudoInteger, colorCoded, lookupTable);

EDITこの時点で、lookupTableに計算した値がありますlabel

計算の最後のステップは、実際にはヒストグラムです。では、OpenCV のヒストグラム関数を使用してみませんか? のドキュメントを確認し、calcHist()アルゴリズムに最適な方法を確認してください。calcHist()より多くの画像のヒストグラムを一度に実行できるため、colorCoded画像をベクトルに保持してから、それらすべてのヒストグラムを 1 つに抽出することができます。

于 2012-10-09T18:01:05.760 に答える
0

コードの最適化に関する他の回答に加えて、画像ヒストグラムの作業を検討してください。画像内のいくつかのピクセルはまったく同じ色になるため、最初にヒストグラムを計算してから、画像内のすべての異なる色に対して処理を行います。それは物事を大幅にスピードアップするはずです

于 2012-10-10T14:30:33.967 に答える