[英]Exception Unhandled Error Scanning an Image with OpenCV Using .at() in c++
[英]C++: OpenCV performance issues scanning images
我大約有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值表示)。
性能問題是您在每個像素上做太多的工作。
對於每個文件(恰好在堆積的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 ++編寫代碼了),但是以上內容應該消除了很多額外的處理工作。
您使用了錯誤的數據類型和錯誤的函數。 這是關於如何改進的建議。 我想它將在幾秒鍾內運行。
工作的第一步是從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
圖像保留在矢量中,然后將所有圖像的直方圖提取為一個。
除其他有關代碼優化的答案外,請考慮處理圖像直方圖。 圖像中的幾個像素將具有完全相同的顏色,因此請首先計算直方圖,然后對圖像中的每種不同顏色進行處理。 那應該大大加快速度
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.