2012-10-09 66 views
2

我有大约20个图像已被彩色编码。我想扫描每个图像并将像素匹配到与该颜色关联的标签。我已经编写了下面的代码,但是它需要大约30分钟才能完成这个看起来很简单的任务。这些图像具有960×720C++:OpenCV性能问题扫描图像

我的代码的分辨率:

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值表示)。

+0

那么,unordered_map ** [] **运算符的复杂性,在最坏的情况下,[容器大小的线性...](http://www.cplusplus.com/参考/ STL /图/)。设置的容器插入操作是对数的。因此,在最坏的情况下,整个批次将是上述复杂度的960x720x20像素倍。 –

回答

3

性能问题是您每像素做了太多工作。

对于每个文件(就在堆叠的for-loops开始之前)制作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在许多年都没有编码++),但上面的应该剔除掉了很多额外的处理工作。

+0

嗨,这似乎比我的改进好,所以会删除我的答案。我会接受这一点,但会首先编辑它,以删除一些语法错误,并会接受一旦编辑已被批准 – Aly

1

您正在使用错误的数据类型和错误的功能。以下是有关如何改进的建议。我想它会在几秒钟内运行。

您的工作的第1步是从3通道图像到单通道图像的查找表。你可以使用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); 

编辑此时你在LookupTable中你label

你计算的最后一步计算值实际上已经是一个直方图。那么你为什么不使用OpenCV中的直方图函数呢?查看calcHist()的文档,看看它最适合你的算法。请注意,calcHist()可以立即执行更多图像的直方图,因此您可能想要将colorCoded图像保存在一个矢量中,然后将它们的直方图一起提取。

+0

我不确定是否需要LUT,因为我不是要更改图像中的像素,而是我,正如你所说,试图建立一个特定颜色的直方图(rgb值),其中每个特定的rgb值对应于一个标签(即建筑物,汽车,猫等) – Aly

+0

我看过了文档对于calcHist(),但是我不清楚我是否可以将它用于我的目的。例如,是否有可能计算一个图像的直方图,其中分箱的rgb值为{(123,45,65),(144,44,89)}? – Aly

+0

我的代码的第一部分将(r,g,b)仓转换为一个整数值。然后,使用查找表,将它们转换为您想要的标签值,并且该操作等同于您在做'label_to_files_map [label] .insert(file);'之前所做的操作。然后,calcHist应该能够做到这一行的等价物,但要快得多 – Sam

0

除了与代码优化有关的其他答案之外,还应考虑处理图像直方图。图像中的几个像素将具有完全相同的颜色,因此先计算直方图,然后针对图像中的每种不同颜色进行处理。这应该大大加快速度