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`
來表示其對應的編碼值,但是一些特殊的符號還是需要記一下。對常用的記錄如下:
Key | Code |
---|---|
q鍵 | ‘q’ |
esc | 27 |
enter | 13 |
space | 8 |
深度資料統計
評估時選取中心區域和興趣區域進行統計,需要完成無效點過濾,
核心程式碼展示
// 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
(Xi−EX)2/N
標準差公式:
s
q
r
t
(
(
X
i
−
E
X
)
2
/
(
N
−
1
)
)
sqrt((X_i - EX)^2 / (N-1))
sqrt((Xi−EX)2/(N−1))
延伸: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資料儲存方式: