欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

相机标定的原理、程序实现、畸变矫正(四,畸变矫正如何不丢失像素点)

程序员文章站 2023-12-27 09:02:45
...

一、原理
二、标定程序
三、畸变矫正(含opencv实现和自己实现)
四、不丢失原图像素点矫正

(有什么其他要补充的或者要提问,留言就行)
github工程:
有时候我们需要对图像进行矫正,但是不希望增加像素点。比如:原图是(256,64)的图像,希望矫正后得到的依然是256x64个像素点;如果用上一篇博客一样,不可避免的会导致有些像素点丢失了。
但是对于需要每个像素点的设备而言,这样的丢失像素点,会导致周边的像素丢失。

为什么点会丢失

相机标定的原理、程序实现、畸变矫正(四,畸变矫正如何不丢失像素点)
看过上一篇博客应该明白,畸变矫正的过程就是求解上方右图的a~p对应左图哪个位置的值,正常畸变矫正的过程是通过假设一幅与原图大小一样的图,然后求解每个像素点格子对应原图的像素格;然后将原图的像素值给矫正后的图。但是这样就会导致,原图中一个点对应矫正后的多个点,如下图所示,1、4、13、16出现多次,2、3、14、15丢失。
相机标定的原理、程序实现、畸变矫正(四,畸变矫正如何不丢失像素点)

不丢像素点的离散矫正图原理

相机标定的原理、程序实现、畸变矫正(四,畸变矫正如何不丢失像素点)
现在我们直接求解,原图中每一个像素点,对应的位置。这样就可以保证原图中的每个像素点都有对应的点。(适用于原图的每个点都要利用上的情况)
建议和代码一起看,比较好理解


#include "opencv.hpp"

#include <iostream>
#include <fstream>
#include <iostream>  
#include<io.h>
#include <string>  
#include<vector>
#include <sstream>
#include<direct.h>
#include<cmath>
using namespace cv;
using namespace std;

double f(double r, double k1, double k2, double b)
{
	return k2 * pow(r, 5) + k1 * pow(r, 3) + r - b;
}
//y'=5*k2*r^4+3*k1*r^2+1
double fg(double r, double k1, double k2)
{
	return 5 * k2 * pow(r, 4) + 3 * k1 * pow(r, 2) + 1;
}

//简化的高斯牛顿法计算求解x,y与x'与y'的对应关系
double lmm(double r, double k1, double k2, double b)
{
	double epsilon = 1e-8;
	int k = 10;
	double r_out;
	while (k)
	{
		double fr = f(r, k1, k2, b);
		double fgr = fg(r, k1, k2);
		double gk = fr * fgr;
		double dk = -gk / (fgr * fgr);
		if (abs(gk) < epsilon)
			break;
		int m = 0, mk = 0;
		while (m < 20)
		{
			double newf = 0.5 * pow(abs(f(r + pow(0.55, m) * dk, k1, k2, b)), 2);
			double oldf = 0.5 * pow(abs(f(r, k1, k2, b)), 2);
			if (newf < oldf + 0.4 * pow(0.55, m) * gk * gk)
			{
				mk = m;
				break;
			}
			++m;
		}
		r = r + pow(0.55, mk) * dk;
		--k;
	}
	r_out = r;

	double fr = f(r, k1, k2, b);
	return r_out;
}
//求解出(x,y)坐标
void calc_xy_point(int model, vector<Point2f>& undistort_point)
{
	//读取k1,k2,p1,p2,k3信息
	double fx = 112.18;
	double fy = 58.8;
	double cx = 131.8;
	double cy = 26.93;
	double k1 = -0.29;
	double k2 = 0.09;
	double k3 = 0;
	double p1 = 0;
	double p2 = 0;
	//原图大小
	int rows, cols;
	rows = 64;
	cols = 256;

	//Mat imageDistort = picMat[0];
	//求解f(r)=k2*r^5+k1*r^3+r-r0 = 0
	double diff = 0;
	for (int v = 0; v < rows; ++v)
		for (int u = 0; u < cols; ++u)
		{
			double x2 = (u - cx) / fx;//校正后畸变图像坐标为(x1,y1),原图为(x2,y2)其中x1=x/f,y1=y/f
			double y2 = (v - cy) / fy;
			double r0 = sqrt(pow(x2, 2) + pow(y2, 2));
			double b = r0;
			double r = lmm(r0, k1, k2, b);
			double x1 = x2 / (1.0 + k1 * pow(r, 2) + k2 * pow(r, 4));
			double y1 = y2 / (1.0 + k1 * pow(r, 2) + k2 * pow(r, 4));
			double del = x2 - x1;
			Point2f point;
			point.x = x1;
			point.y = y1;
			undistort_point.push_back(point);
			//误差分析
			//diff += f(r, k1, k2, b);

		}
	//cout << diff << endl;
}

得到的是x,y;再带回x=(u-cx)/fx;y=(v-cy)/fy。解出(u,v)才是像素点坐标,不过一般要不丢失像素点的应用,都是因为要使用(x,y)才用这种方法。注意:这里的(x,y)不是图像坐标系下的坐标,(x * f ,y * f)才是像素坐标系下的坐标。

上一篇:

下一篇: