opencv里的norm范数和图像里的深度和通道数的理解和意义和相机标定后对内外参数的质量评估

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_64FC1
CV_32SC2         CV_32FC2         CV_64FC2
CV_32SC3         CV_32FC3         CV_64FC3
CV_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.87


2、其中求相机姿态的时候,一把使用的函数是solvePnP,其是对相机外参进行精确求解,其如下:

3.数学概念






参考文献:


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值