opencv裡的norm範數和影象裡的深度和通道數的理解和意義和相機標定後對內外引數的質量評估
阿新 • • 發佈:2019-02-19
CV_8UC1 是指一個8位無符號整型單通道矩陣,
CV_32FC2是指一個32位浮點型雙通道矩陣
CV_8UC1 CV_8SC1 CV_16U C1 CV_16SC1 CV_8UC2 CV_8SC2 CV_16UC2 CV_16SC2 CV_8UC3 CV_8SC3 CV_16UC3 CV_16SC3 CV_8UC4 CV_8SC4 CV_16UC4 CV_16SC4 CV_32SC1 CV_32FC1 CV_64FC1CV_32SC2 CV_32FC2 CV_64FC2CV_32SC3 CV_32FC3 CV_64FC3CV_32SC4 CV_32FC4 CV_64FC4
其中,通道表示每個點能存放多少個數,類似於RGB彩色圖中的每個畫素點有三個值,即三通道的。
圖片中的深度表示每個值由多少位來儲存,是一個精度問題,一般圖片是8bit(位)的,則深度是8.
範數
定義1. 設 ,滿足
1. 正定性:║x║≥0,║x║=0 iff x=0
2. 齊次性:║cx║=│c│║x║,
3. 三角不等式:║x+y║≤║x║+║y║
則稱Cn中定義了向量範數,║x║為向量x的範數.
可見向量範數是向量的一種具有特殊性質的實值函式.
常用向量範數有,令x=( x1,x2,…,xn)T
1-範數:║x║1=│x1│+│x2│+…+│xn│ //向量中的絕對值求和,
2-範數:║x║2=(│x1│2+│x2│2+…+│xn│2)^1/2 //就是歐幾里得距離,其跟勾股定理不太一樣
∞-範數:║x║∞=max(│x1│,│x2│,…,│xn│) //向量中的max
上面的就是c語言裡的norm範數求解函式,在opencv裡的則是過載了c的,可以看出opencv就只有三種範數,
跟上面的一樣,opencv裡其中的第二個範數可以作為多個點之間的差距誤差。如果想直接求
點之間的實際距離誤差,建議用:
for (size_t i = 0; i < prev_corner.size(); i++) { common_point.at<Vec2f>(0, i) = Vec2f(prev_corner[i].x,prev_corner[i].y); x = cur_corner[i].x*T.at<double>(0, 0) + cur_corner[i].y*T.at<double>(0, 1) + T.at<double>(0, 2); y = cur_corner[i].x*T.at<double>(1, 0) + cur_corner[i].y*T.at<double>(1, 1) + T.at<double>(1, 2); sumvalue += sqrt((x - prev_corner[i].x) *(x - prev_corner[i].x) + (y - prev_corner[i].y)*(y - prev_corner[i].y)); } sumvalue /= cur_corner.size();
其表示為:
評估出其內外參的質量,一般誤差值都很小,例程:
std::cout << "每幅影象的定標誤差:" << endl;
fout << "每幅影象的定標誤差:" << endl << endl;
for (int i = 0; i<image_count; i++)
{
/*object_Points是一個影象的vector,用於標定的其是初始化為三通道的,其中Z通道為0。其是實際的棋盤格的以左上角為原點的每個方塊角點的物理座標,方塊大小是12mm和12mm
*/
vector<Point3f> tempPointSet = object_Points[i];
/**通過得到的攝像機內外引數,對空間的三維點進行重新投影計算,得到新的投影點
這裡的tempPointSet把12mm乘12mm的物理棋盤格角點,image_points2是轉換後的影象畫素角點座標,
tempPointSet通過內外引數轉變為相機的影象畫素座標系,
然後與image_points2進行誤差計算,評估出其內外參的質量,一般誤差值都很小
問題:為什麼不進行影象畫素座標通過內外參轉換為實際物理座標?這是因為我們當把畫素座標轉換為物理 空間下時,其是一條射線,無法還原到深度Z **/
projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);
/* 把對應幀裡的影象的角點賦值給tempImagePoint,其是畫素座標*/
vector<Point2f> tempImagePoint = corners_Seq[i];
//這裡定義的是兩個通道的Mat矩陣,其表示每個點能表示兩個資料,這裡是分別表示棋盤格角點的X和Y,非常妙
Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
for (int j = 0; j < tempImagePoint.size(); j++)
{
image_points2Mat.at<Vec2f>(0, j) = Vec2f(image_points2[j].x, image_points2[j].y); //兩個通道同時賦值,如果三個通道則三個值同時賦值
tempImagePointMat.at<Vec2f>(0, j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
}
err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
total_err += err /= point_counts[i];
std::cout << "第" << i + 1 << "幅影象的平均誤差:" << err << "畫素" << endl;
fout << "第" << i + 1 << "幅影象的平均誤差:" << err << "畫素" << endl;
}
std::cout << "總體平均誤差:" << total_err / image_count << "畫素" << endl;
fout << "總體平均誤差:" << total_err / image_count << "畫素" << endl << endl;
std::cout << "評價完成!" << endl;
注意:opencv裡的norm函式其實把這裡的兩個通道分別分開來計算的(X1-X2)^2的值,然後統一求和,最後進行根號; 例如:
Mat common_point1 = Mat(1, 3, CV_32FC2);
Mat cur_point1 = Mat(1, 3, CV_32FC2);
for (size_t i = 0; i < 3; i++)
{
common_point1.at<Vec2f>(0, i) = Vec2f(6, 5);
cur_point1.at<Vec2f>(0, i) = Vec2f(4,4);
}
err = norm(common_point1, cur_point1, NORM_L2);
printf("err為 : %f個畫素 \n", err);
其計算時sqrt((6-4)^2+(5-4)^2+(6-4)^2+(5-4)^2+(6-4)^2+(5-4)^2)=3.872、其中求相機姿態的時候,一把使用的函式是solvePnP,其是對相機外參進行精確求解,其如下:
3.數學概念
參考文獻: