1. 程式人生 > 其它 >opencv滑鼠互動與模組深度資料評估

opencv滑鼠互動與模組深度資料評估

技術標籤:OpenCV

前言

主要涉及到兩個方面的內容:一是預處理環節,通過滑鼠互動在彩色/灰度圖上框選出需要評估的畫面範圍;二是在上一步選出的區域上完成深度資料統計環節,這部分主要實際到有效點佔比,平均值,方差(標準差),精度(標準差/均值)的計算。

滑鼠互動選擇待評估區域

因為這本身就是一個很簡單且幾乎是一次性的工作,所以程式設計上,沒有設計成"在每個深度下可以多次選擇評估框直至滿意"。

核心程式碼展示

// preprocessor.cpp
cv::Rect roi_rect;
bool g_drawbox = false;
void on_mousehandle(int
event, int x, int y, int flags, void* param) { switch (event) { case cv::EVENT_LBUTTONDOWN: //按下左鍵 { g_drawbox = true; roi_rect = cv::Rect(x, y, 0, 0); break; } case cv::EVENT_MOUSEMOVE: //滑鼠移動 { if (g_drawbox) {
roi_rect.width = x - roi_rect.x; roi_rect.height = y - roi_rect.y; } break; } case cv::EVENT_LBUTTONUP: //滑鼠左鍵抬起 { if (roi_rect.width < 0) { roi_rect.x += roi_rect.width; roi_rect.
width *= -1; } if (roi_rect.height < 0) { roi_rect.y += roi_rect.height; roi_rect.height *= -1; } std::cout << roi_rect.tl() << " " << roi_rect.br() << std::endl; g_drawbox = false; cv::waitKey(0); break; } default: { break; } } } int main(int argc, char const *argv[]) { std::string data_set = "dataset_folder_path"; std::vector<std::string> depth_values{"60", "120", "180", "240", "300", "360"}; for (int i = 0; i < depth_values.size(); ++i) { std::string depth_file = data_set + "/" + depth_values[i] + "/depth.png"; std::string img_file = data_set + "/" + depth_values[i] + "/image.png"; cv::Mat img = cv::imread(img_file, CV_LOAD_IMAGE_UNCHANGED); cv::namedWindow("選擇評估區域", cv::WINDOW_AUTOSIZE); cv::setMouseCallback("選擇評估區域", on_mousehandle); std::cout << "按'enter'鍵確認當前選擇區域." << std::endl; while (true) { cv::Mat draw_img_show; cvtColor(img, draw_img_show, cv::COLOR_GRAY2BGR); if (g_drawbox) { cv::rectangle(draw_img_show, roi_rect.tl(), roi_rect.br(), cv::Scalar(0,0,255)); cv::imwrite(depth_values[i] + "_left.png", draw_img_show); } cv::imshow("選擇評估區域", draw_img_show); if (cv::waitKey(10) == 13) // enter { break; } } } return 0; }

滑鼠互動涉及到的變數需設計成全域性變數。

顯示滑鼠互動畫面,需要while (true)迴圈,在左鍵抬起條件下加入cv::waitKey(0),是保證最終選擇方案停駐畫面,以便press enter並進入下一個。

滑鼠與影象顯示視窗的互動,opencv主要用setMouseCallback()這個函式來實現,該函式是與顯示視窗的名字繫結的。

void setMousecallback(const string& winname, MouseCallback onMouse, void* userdata=0);
// winname:視窗的名字
// onMouse:滑鼠響應回撥函式。指定窗口裡每次滑鼠時間發生的時候被呼叫的函式指標。
// userdata:傳給回撥函式的引數,可選引數

// on_Mouse函式原型
void on_Mouse(int event, int x, int y, int flags, void* param);
// event是 CV_EVENT_*變數之一
// x和y是滑鼠指標在影象座標系的座標(不是視窗座標系) 
// flags是CV_EVENT_FLAG的組合, param是使用者定義的傳遞到setMouseCallback函式呼叫的引數。

延伸:switch case語句括號規範

建議switch 語句中的每個 case 塊可以使用大括號。避免switch-case中定義區域性變數引起的編譯錯誤

如果case不加大括號,此時switch中包含的整個程式碼屬於同一個程式碼塊,而不是每個case表示一個程式碼塊。程式將會順序執行,直至遇到break跳出。不同case之間定義的同一個名字的區域性變數,將可能由於執行多個case或者跳過某些case,而會出現"重複定義"或者"引用未定義的變數"錯誤。

延伸:常用按鍵對應的編碼值

針對字母、陣列等符號可以採用`a`來表示其對應的編碼值,但是一些特殊的符號還是需要記一下。對常用的記錄如下:

KeyCode
q鍵‘q’
esc27
enter13
space8

深度資料統計

評估時選取中心區域和興趣區域進行統計,需要完成無效點過濾,

核心程式碼展示

// evaluation.cpp

void evaluation(std::string depth_file)
{
    // .....
    // 深度資料獲取
    float data[img_width * img_height];
    char s;
    FILE* file;
    file = fopen(depth_file.c_str(), "r");
    int i = 0;
    while (fscanf(file,"%f,%s",data+i,s)!=EOF)
    {
        ++i;
    }
    fclose(file);

    // 中心區域深度評估: 有效點佔比,平均值,方差
    std::vector<float> center_depth;  // 有效點陣列
    // ....
    float center_valid_ratio = 1 - float(center_zero_num) / (10 * 10);
    double center_sum = accumulate(center_depth.begin(), center_depth.end(), 0.0);
    double center_mean = center_sum / center_depth.size();
    double center_accum = 0.0;
    std::for_each (center_depth.begin(), center_depth.end(), [&](const double d) {
        center_accum += (d - center_mean) * (d - center_mean);
    });
    double stdev = center_accum / center_depth.size();
    std::cout << "有效點佔比,平均值,方差: " 
              << center_valid_ratio << "  "
              << center_mean << "  "
              << center_accum << std::endl;
     // ....
}

方差公式:
( X i − E X ) 2 / N (X_i - EX)^2 / N (XiEX)2/N

標準差公式:
s q r t ( ( X i − E X ) 2 / ( N − 1 ) ) sqrt((X_i - EX)^2 / (N-1)) sqrt((XiEX)2/(N1))

延伸:cv::Mat元素型別與訪問

cv::Mat的型別表示了矩陣中元素的型別以及矩陣的通道個數,它是一系列的預定義的常量,其命名規則為:
CV_(位數)+(資料型別)+(通道數)
資料型別有7種類型:CV_8U、CV_8S、CV_16U、CV_16S、CV_32S、CV_32F、CV_64F。

通道數有4種類型,針對上述7種資料型別,依次對應型別編碼為:C1通道數 (0-6)、C2通道數 (8-14)、C3通道數 (16-22)、C4通道數 (24-30).

在進行元素訪問時,針對上述7種資料型別,依次需設定模板函式typename為uchar、char、ushort、short、 int、float、double。

row == height == Point.y

col == width == Point.x

cv::Mat::at(Point(x, y)) == Mat::at(y,x)

opencv中mat資料儲存方式:

img

參考資料

opencv畫框記錄座標