ca

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <math.h>//
#include "bmp_loader.h"//
#include "calib.h"//

#define M_PI 3.141592653589793

//
// 模拟数据生成(参照、观测和模拟图像生成)dq
//
void gen_pts(
	char  *file,
	double ax, double ay, double az, 
	double tx, double ty, double tz,
	double alpha, double beta, double gamma, 
	double u0, double v0,
	double k1, double k2,
	int w, int h,
	data_t &data)
{
	int x, y;
	point_t wpt, cpt;//二维点坐标,double
	unsigned char *img;
	img = new unsigned char[3 * w * h];//存储图像

	memset(img, 0, 3 * w * h);

	gen_homography_2D(
		ax, ay, az,//旋转
		tx, ty, tz,//平移
		alpha, beta, gamma,
		u0, v0, //内参
		data.ref);//单应矩阵

	data.pts_num = 0;
	//
	for (x = -2 * w; x <= 2 * w; x += 50)//竖线
	{
		for (y = -2 * h; y <= 2 * h; y += 1)
		{
			wpt.x = x;//二维点坐标,实际是模拟的三维点
			wpt.y = y;
			//世界坐标系到照相机坐标系转换
			w2c_pt(wpt, cpt, data.ref, k1, k2, u0, v0);

			if (cpt.x > 0 && cpt.y > 0 && cpt.x < w && cpt.y < h)
			{
				int dx, dy;
				dx = cpt.x;
				dy = cpt.y;
				img[3 * (dx * w + dy) + 1] = 128;
			};
		};//y
	};//x
	for (x = -2 * w; x <= 2 * w; x += 1)//横线
	{
		for (y = -2 * h; y <= 2 * h; y += 50)
		{
			wpt.x = x;
			wpt.y = y;
			// 世界坐标系到照相机坐标系转换
			w2c_pt(wpt, cpt, data.ref, k1, k2, u0, v0);

			if (cpt.x > 0 && cpt.y > 0 && cpt.x < w && cpt.y < h)
			{
				int dx, dy;
				dx = cpt.x;
				dy = cpt.y;//得到横纵坐标
				img[3 * (dx * w + dy) + 1] = 128;
			};
		};//y
	};//x

	//
	for (x = -80; x <= 80; x += 40)//5(离散点)
	{
		for (y = -80; y <= 80; y += 40)//5,共25点
		{
			wpt.x = x;
			wpt.y = y;
			// 世界坐标系到照相机坐标系转换
			w2c_pt(wpt, cpt, data.ref, k1, k2, u0, v0);
			cpt.x += 0.0 * (rand() % 100) / 100.0;//加上噪声
			cpt.y += 0.0 * (rand() % 100) / 100.0;

			data.wpts[data.pts_num] = wpt;//三维点
			data.cpts[data.pts_num] = cpt;//二维点,相互匹配
			data.pts_num++;//计数

			if (cpt.x > 0 && cpt.y > 0 && cpt.x < w && cpt.y < h)
			{
				int dx, dy;
				dx = cpt.x;
				dy = cpt.y;
				img[3 * (dx * w + dy) + 0] = 255;
				img[3 * (dx * w + dy) + 1] = 255;
				img[3 * (dx * w + dy) + 2] = 255;
			};
		};//y
	};//x

	// 画像生成
	write_bmp_rgb(file, img, w, h);

	delete img;
};

//
// 模拟数据的制作。用它内部设计推测。
//
void test()
{
	int w, h;
	int i, j;
	double k1, k2, u0, v0;
	double alpha, beta, gamma;
	int img_n;
	char file[256];
	data_t data[10];

	img_n = 3;		// 图像数目
	w = h = 256;	// 图像长宽
	u0 = 128.0;		// 图像光轴中心
	v0 = 128.0;
	k1 = -0.2;	// 镜头失真系数
	k2 = 0.2;	//

	// 内部参数
	alpha = 512;
	beta = 512;
	gamma = 1.09083;

	printf("[***GEN SIMULATION DATA***]\nalpha=%f, beta=%f, gamma=%f\n", alpha, beta, gamma);
	printf("u0=%f, v0=%f\n", u0, v0);
	printf("k1=%f, k2=%f\n", k1, k2);

	//各图像生成
	for (i = 0; i < img_n; i++)
	{
		sprintf(file, "./img/test%d.bmp", i + 1);//屌屌的

		gen_pts(file,
			M_PI * (rand() % 20 - 10) / 180.0, M_PI * (rand() % 20 - 10) / 180.0, M_PI * (rand() % 40 - 20) / 180.0,
			rand() % 50 - 25, rand() % 50 - 25, 812 + rand() % 50,
			alpha, beta, gamma,
			u0, v0, k1, k2, w, h, data[i]);
		//
		sprintf(file, "./pt%d.txt", i + 1);
		FILE *fp = fopen(file, "w");
		for (int j = 0; j < data[i].pts_num; j++)
		{
			fprintf(fp, "%f %f\n", data[i].cpts[j].x, data[i].cpts[j].y);
		};
		fclose(fp);
		fp = fopen("./model.txt", "w");
		for (int j = 0; j < data[i].pts_num; j++)
		{
			fprintf(fp, "%f %f\n", data[i].wpts[j].x, data[i].wpts[j].y);
		};
		fclose(fp);
	};//图像生成结束

	// 线性方法,计算各图像的ホモグラフィ。镜头失真是不包含在内的。
	for (i = 0; i < img_n; i++)
	{
		estimate_homography(data[i].wpts,//世界坐标点 
							data[i].cpts, //相机坐标点
							data[i].pts_num, //点数目
							data[i].H);
	};

	// 复数图像内部参数推测。镜头失真推测等。
	estimate_intrinsic(data, img_n, alpha, beta, gamma, u0, v0, k1, k2);

	for (i = 0; i < img_n; i++)
	{
		unsigned char *img;
		unsigned char *out;
		sprintf(file, "./img/test%d.bmp", i + 1);
		load_bmp_rgb(file, &img, &w, &h);
		int x, y;
		double ix, iy, rx, ry;
		out = new unsigned char[3 * w * h];

		for (y = 0; y < h; y++)
		{
			for (x = 0; x < w; x++)
			{
				ix = (x - u0) / 512.0;
				iy = (y - v0) / 512.0;
				rx = x + (x - u0) * (k1 * (ix*ix + iy*iy) + k2 * (ix*ix + iy*iy) * (ix*ix + iy*iy));
				ry = y + (y - v0) * (k1 * (ix*ix + iy*iy) + k2 * (ix*ix + iy*iy) * (ix*ix + iy*iy));
				if (rx > 0 && rx < w && ry > 0 && ry < h)
				{
					int dx, dy;
					dx = rx; dy = ry;
					out[3 * (x + y * w) + 0] = img[3 * (dx + dy * w) + 0];
					out[3 * (x + y * w) + 1] = img[3 * (dx + dy * w) + 1];
					out[3 * (x + y * w) + 2] = img[3 * (dx + dy * w) + 2];
				}
				else {
					out[3 * (x + y * w) + 0] = 0;
					out[3 * (x + y * w) + 1] = 0;
					out[3 * (x + y * w) + 2] = 0;
				};
			};//x
		};//y

		sprintf(file, "./img/out%d.bmp", i + 1);
		write_bmp_rgb(file, out, w, h);
		delete out;
		delete img;
	};


};

int main(int argc, char *argv[])
{

	if (argc == 1)
	{
		test();
		return 0;
	};

	double k1, k2, u0, v0;
	double alpha, beta, gamma;
	int    img_n;
	char file[256];
	data_t data[10];

	img_n = argc - 2;
	int i;


	for (i = 0; i < img_n; i++)
	{
		char file[256];
		char txt[1024];
		sprintf(file, "%s", argv[i + 2]);
		FILE *fp = fopen(file, "r");
		int n = 0, j;
		while (fgets(txt, 1024, fp))
		{
			sscanf(txt, "%lf %lf", &data[i].cpts[n].x, &data[i].cpts[n].y);
			n++;
		};
		fclose(fp);
		fp = fopen(argv[1], "r");
		n = 0;
		while (fgets(txt, 1024, fp))
		{
			sscanf(txt, "%lf %lf", &data[i].wpts[n].x, &data[i].wpts[n].y);
			n++;
		};
		fclose(fp);

		// 正規化
		if (0)
		{
			point_t mu1, mu2;
			point_t sig1, sig2;
			mu1.x = mu1.y = mu2.x = mu2.y = 0.0;
			sig1.x = sig1.y = sig2.x = sig2.y = 0.0;
			for (j = 0; j < n; j++)
			{
				mu1.x += data[i].cpts[j].x;
				mu1.y += data[i].cpts[j].y;
				mu2.x += data[i].wpts[j].x;
				mu2.y += data[i].wpts[j].y;
			};
			mu1.x /= (double)n;
			mu1.y /= (double)n;
			mu2.x /= (double)n;
			mu2.y /= (double)n;
			for (j = 0; j < n; j++)
			{
				sig1.x += (data[i].cpts[j].x - mu1.x)*(data[i].cpts[j].x - mu1.x);
				sig1.y += (data[i].cpts[j].y - mu1.y)*(data[i].cpts[j].y - mu1.y);
				sig2.x += (data[i].wpts[j].x - mu2.x)*(data[i].wpts[j].x - mu2.x);
				sig2.y += (data[i].wpts[j].y - mu2.y)*(data[i].wpts[j].y - mu2.y);
			};
			sig1.x = sqrt(sig1.x / (double)n);
			sig1.y = sqrt(sig1.y / (double)n);
			sig2.x = sqrt(sig2.x / (double)n);
			sig2.y = sqrt(sig2.y / (double)n);
			for (j = 0; j < n; j++)
			{
				data[i].cpts[j].x = (data[i].cpts[j].x - mu1.x) / sig1.x;
				data[i].cpts[j].y = (data[i].cpts[j].y - mu1.y) / sig1.y;
				data[i].wpts[j].x = (data[i].wpts[j].x - mu2.x) / sig2.x;
				data[i].wpts[j].y = (data[i].wpts[j].y - mu2.y) / sig2.y;
			};
		};

		data[i].pts_num = n;

	};
	// 复数图像内部参数推测。镜头失真推测等。
	alpha = beta = gamma = u0 = v0 = k1 = k2 = 0.0;
	// 线性方法,计算各图像的ホモグラフィ。镜头失真是不包含在内的。。
	for (i = 0; i < img_n; i++)
	{
		estimate_homography(data[i].wpts, data[i].cpts, data[i].pts_num, data[i].H);
	};

	estimate_intrinsic(data, img_n, alpha, beta, gamma, u0, v0, k1, k2);

	return 0;
};

 

calib.h

//
//  Zhangのキャリブレーション
//

#include "minpack.h"
#include "mat.h"
#include "gen_geometric_mat.h"

// LAPACK使用
extern "C"{
#include "f2c.h"
#include "clapack.h"
}

// 分群结构体
struct point_t
{
	double x, y;
};

// 对应点的结构体
struct data_t
{
	point_t wpts[100];//三维点
	point_t cpts[100];//二维点
	int     pts_num;//点数目
	double  H[9];
	double  ref[9];//单应矩阵
	double  Rt[9];
	double  R[9];
	double  t[3];
};


// 为了minpack global变数
point_t fcn_wpts[1000];
point_t fcn_cpts[1000];
double tmp_Rt[1000];
int fcn_pts_num;
int fcn_pts_list[1000];
int fcn_list_num;
double dRt[10][9];

// 世界坐标系到照相机坐标系转换,径向失真矫正
void w2c_pt(point_t &in, point_t &out, double *H, double k1, double k2, double u0, double v0)
{
	double ix, iy, rx, ry, rz;//三维点[x,y,0,1]到[u,v,1]
	rz = (in.x * H[3 * 2 + 0] + in.y * H[3 * 2 + 1] + H[3 * 2 + 2]);//H*[x,y,1]T
	rx = (in.x * H[3 * 0 + 0] + in.y * H[3 * 0 + 1] + H[3 * 0 + 2]) / (rz);
	ry = (in.x * H[3 * 1 + 0] + in.y * H[3 * 1 + 1] + H[3 * 1 + 2]) / (rz);
	ix = (rx - u0) / 512.0;
	iy = (ry - v0) / 512.0;
	out.x = rx + (rx - u0) * (k1 * (ix*ix + iy*iy) + k2 * (ix*ix + iy*iy) * (ix*ix + iy*iy));//(11)
	out.y = ry + (ry - v0) * (k1 * (ix*ix + iy*iy) + k2 * (ix*ix + iy*iy) * (ix*ix + iy*iy));//(12)
};

// 投影误差计算
double calc_projection_err(doublereal * vvec)
{
	int i, j, n;
	double dx, dy;
	double x, y, z, mx, my, tx, ty, ix, iy;
	double H[10][9], Rt[9], dR[9];
	double A[9];
	double u0, v0, k1, k2;

	gen_intrinsic_mat(vvec[0], vvec[1], vvec[2], vvec[3], vvec[4], A);
	u0 = vvec[3];
	v0 = vvec[4];
	k1 = vvec[5];
	k2 = vvec[6];

	double err = 0.0;

	/*
	for(i = 0;i < fcn_list_num;i++)
	{
	for(j = 0;j < 9;j++)
	{
	Rt[j] = vvec[7 + i * 9 + j];
	};
	mat_mul(A, Rt, H[i], 3);
	};// i
	*/
	for (i = 0; i < fcn_list_num; i++)
	{
		gen_rot_mat(vvec[7 + i * 6], vvec[7 + i * 6 + 1], vvec[7 + i * 6 + 2], dR);
		mat_mul(dRt[i], dR, Rt, 3);
		Rt[3 * 0 + 2] = vvec[7 + i * 6 + 3];
		Rt[3 * 1 + 2] = vvec[7 + i * 6 + 4];
		Rt[3 * 2 + 2] = vvec[7 + i * 6 + 5];

		mat_mul(A, Rt, H[i], 3);
	};// i

	for (i = 0; i < fcn_pts_num; i++)
	{
		n = fcn_pts_list[i];
		x = H[n][0] * fcn_wpts[i].x + H[n][1] * fcn_wpts[i].y + H[n][2];
		y = H[n][3] * fcn_wpts[i].x + H[n][4] * fcn_wpts[i].y + H[n][5];
		z = H[n][6] * fcn_wpts[i].x + H[n][7] * fcn_wpts[i].y + H[n][8];
		mx = x / z;
		my = y / z;
		ix = (mx - u0) / 512.0;
		iy = (my - v0) / 512.0;

		tx = mx + (mx - u0) * (k1 * (ix*ix + iy*iy) + k2 * (ix*ix + iy*iy) * (ix*ix + iy*iy));
		ty = my + (my - v0) * (k1 * (ix*ix + iy*iy) + k2 * (ix*ix + iy*iy) * (ix*ix + iy*iy));

		err += sqrt((tx - fcn_cpts[i].x)*(tx - fcn_cpts[i].x) + (ty - fcn_cpts[i].y)*(ty - fcn_cpts[i].y));
	};// i

	return err / (double)fcn_pts_num;
};


//*************************************************************************
// minpack用优化过程
//
void fcn_homography(integer * fnum, integer * vnum,
	doublereal * vvec, doublereal * fvec, integer * iflag)
{
	int i;
	double dx, dy;
	double x, y, z, mx, my;
	for (i = 0; i < fcn_pts_num; i++)
	{
		x = vvec[0] * fcn_wpts[i].x + vvec[1] * fcn_wpts[i].y + vvec[2];
		y = vvec[3] * fcn_wpts[i].x + vvec[4] * fcn_wpts[i].y + vvec[5];
		z = vvec[6] * fcn_wpts[i].x + vvec[7] * fcn_wpts[i].y + vvec[8];
		mx = x / z;
		my = y / z;
		fvec[i] = mx - fcn_cpts[i].x;
		fvec[i + fcn_pts_num] = my - fcn_cpts[i].y;
	};// i
};

void fcn_homography_distortion(integer * fnum, integer * vnum,
	doublereal * vvec, doublereal * fvec, integer * iflag)
{
	int i, j, n;
	double dx, dy;
	double x, y, z, mx, my, tx, ty, ix, iy;
	double H[10][9], R[9], dR[9], Rt[9];
	double A[9];
	double u0, v0, k1, k2;

	gen_intrinsic_mat(vvec[0], vvec[1], vvec[2], vvec[3], vvec[4], A);
	u0 = vvec[3];
	v0 = vvec[4];
	k1 = vvec[5];
	k2 = vvec[6];


	for (i = 0; i < fcn_list_num; i++)
	{
		gen_rot_mat(vvec[7 + i * 6], vvec[7 + i * 6 + 1], vvec[7 + i * 6 + 2], dR);
		mat_mul(dRt[i], dR, Rt, 3);
		/*
		for(j = 0;j < 9;j++)
		{
		Rt[j] = vvec[7 + i * 9 + j];
		};
		*/
		Rt[3 * 0 + 2] = vvec[7 + i * 6 + 3];
		Rt[3 * 1 + 2] = vvec[7 + i * 6 + 4];
		Rt[3 * 2 + 2] = vvec[7 + i * 6 + 5];

		mat_mul(A, Rt, H[i], 3);
	};// i

	for (i = 0; i < fcn_pts_num; i++)
	{
		n = fcn_pts_list[i];
		x = H[n][0] * fcn_wpts[i].x + H[n][1] * fcn_wpts[i].y + H[n][2];
		y = H[n][3] * fcn_wpts[i].x + H[n][4] * fcn_wpts[i].y + H[n][5];
		z = H[n][6] * fcn_wpts[i].x + H[n][7] * fcn_wpts[i].y + H[n][8];
		mx = x / z;
		my = y / z;
		ix = (mx - u0) / 512.0;
		iy = (my - v0) / 512.0;

		tx = mx + (mx - u0) * (k1 * (ix*ix + iy*iy) + k2 * (ix*ix + iy*iy) * (ix*ix + iy*iy));
		ty = my + (my - v0) * (k1 * (ix*ix + iy*iy) + k2 * (ix*ix + iy*iy) * (ix*ix + iy*iy));

		fvec[i] = tx - fcn_cpts[i].x;
		fvec[i + fcn_pts_num] = ty - fcn_cpts[i].y;
	};// i
};
// minpack用优化过程
//*************************************************************************



//********************************************************************************
//    应对分开始内部パラメタ和镜头失真,パラメタ非线性优化调整。data初期解决。
//********************************************************************************
void optimize_homography_distortion(
	double & alpha, double & beta, double & gamma,
	double & u0, double & v0, double & k1, double & k2,
	data_t * data, int N
	)
{
	int i, j;
	integer m, n;
	doublereal vvec[1000] = { 0 }, fvec[1000] = { 0 }, *wa, tol;
	integer info = 0, lwa = 0;
	integer *iwa;

	n = 0;				// 应优化矢量的角度
	m = 0;		        // 目的函数的项数
	for (i = 0; i < N; i++)
	{
		m += 2 * data[i].pts_num;
	};


	vvec[n++] = alpha;
	vvec[n++] = beta;
	vvec[n++] = gamma;
	vvec[n++] = u0;
	vvec[n++] = v0;
	vvec[n++] = k1;
	vvec[n++] = k2;

	for (i = 0; i < N; i++)
	{
		/*
		for(j = 0;j < 9;j++)
		{
		vvec[n++] = 0.0;//data[i].Rt[j];
		};// j
		*/
		vvec[n++] = 0.0;
		vvec[n++] = 0.0;
		vvec[n++] = 0.0;
		vvec[n++] = data[i].t[0];
		vvec[n++] = data[i].t[1];
		vvec[n++] = data[i].t[2];
		memcpy(dRt[i], data[i].R, sizeof(double)* 9);
	};// i

	fcn_pts_num = 0;
	fcn_list_num = N;
	for (i = 0; i < N; i++)
	{
		for (j = 0; j < data[i].pts_num; j++)
		{
			fcn_wpts[fcn_pts_num] = data[i].wpts[j];
			fcn_cpts[fcn_pts_num] = data[i].cpts[j];
			fcn_pts_list[fcn_pts_num] = i;
			fcn_pts_num++;
		}; // j
	};// i


	lwa = m*n + 5 * n + m;
	wa = new doublereal[lwa];
	iwa = new integer[lwa];
	tol = 10e-10;

	double e1, e2;

	e1 = calc_projection_err(vvec);
	printf("optimizing....");
	lmdif1_((U_fp)(fcn_homography_distortion), &m, &n, vvec, fvec, &tol, &info, iwa, wa, &lwa);
	printf("ok\n");
	e2 = calc_projection_err(vvec);

	alpha = vvec[0];
	beta = vvec[1];
	gamma = vvec[2];
	u0 = vvec[3];
	v0 = vvec[4];
	k1 = vvec[5];
	k2 = vvec[6];
	// print log
	printf("[***RESULT***]\nerr=%f[pix](initial) ---> %f[pix](after non-linear optimize)\n", e1, e2);
	printf("[***ESTIMATED PARAMETER***]\nalpha=%f, beta=%f, gamma=%f\n", alpha, beta, gamma);
	printf("u0=%f, v0=%f\n", u0, v0);
	printf("k1=%f, k2=%f\n", k1, k2);

	delete wa;
	delete iwa;

}

//********************************************************************************
//    从非线性ホモグラフィ对应点,调整优化。h是初期解决。
//********************************************************************************
void optimize_homography(double *h, point_t *wpts, point_t *cpts, int N)
{
	int i;
	integer m, n;
	doublereal vvec[10000] = { 0 }, fvec[10000] = { 0 }, wa[10000] = { 0 }, tol;
	integer info = 0, lwa = 0;
	integer iwa[10000] = { 0 };

	n = 9;	    // 应优化矢量的角度
	m = 2 * N;	// 目的函数的项数

	lwa = m*n + 5 * n + m;
	tol = 10e-10;

	for (i = 0; i < 9; i++)
	{
		vvec[i] = h[i];
	};

	fcn_pts_num = N;
	for (i = 0; i < N; i++)
	{
		fcn_wpts[i] = wpts[i];
		fcn_cpts[i] = cpts[i];
	};
	/*     the purpose of lmdif1 is to minimize the sum of the squares of */
	/*     m nonlinear functions in n variables by a modification of the */
	/*     levenberg-marquardt algorithm.*/
	lmdif1_((U_fp)(fcn_homography), &m, &n, vvec, fvec, &tol, &info, iwa, wa, &lwa);
	for (i = 0; i < 9; i++)
	{
		h[i] = vvec[i];
	};

};


//********************************************************************************
// 参照和观测分cpts wpts分ホモグラフィ队伍从eH推测
//********************************************************************************
void estimate_homography(point_t *wpts, 
						 point_t *cpts,
						 int pts_num,//点数
						 double *eH)
{
	double B[10000];
	double BB[81];
	int i, j, k, n;

	// 论文的公式:附录A
	for (i = 0; i < pts_num; i++)
	{
		n = 2 * i;
		B[n * 9 + 0] = wpts[i].x;             
		B[n * 9 + 1] = wpts[i].y;             
		B[n * 9 + 2] = 1.0;
		B[n * 9 + 3] = 0.0;                   
		B[n * 9 + 4] = 0.0;                   
		B[n * 9 + 5] = 0.0;
		B[n * 9 + 6] = -cpts[i].x * wpts[i].x; 
		B[n * 9 + 7] = -cpts[i].x * wpts[i].y; 
		B[n * 9 + 8] = -cpts[i].x;

		n = 2 * i + 1;
		B[n * 9 + 0] = 0.0;                   
		B[n * 9 + 1] = 0.0;                   
		B[n * 9 + 2] = 0.0;
		B[n * 9 + 3] = wpts[i].x;             
		B[n * 9 + 4] = wpts[i].y;             
		B[n * 9 + 5] = 1.0;
		B[n * 9 + 6] = -cpts[i].y * wpts[i].x; 
		B[n * 9 + 7] = -cpts[i].y * wpts[i].y; 
		B[n * 9 + 8] = -cpts[i].y;
	};// i

	// B^T B
	for (i = 0; i < 9; i++)
	{
		for (j = 0; j < 9; j++)
		{
			double sum = 0.0;
			for (k = 0; k < 2 * pts_num; k++)
			{
				sum += B[k * 9 + i] * B[k * 9 + j];
			};// k
			BB[i * 9 + j] = sum;
		};//j
	};// i


	long N = 9;
	double wr[1000], wi[2], work[1000], vl[1000], vr[1000];
	long lda = N, ldvl = N, ldvr = N, lwork = 3 * N, info, ldvt = 5;

	// 线性解法:固有方程解决
	// A 为BB
	//computes all eigenvalues and, optionally, eigenvectors of a real symmetric matrix A
	// 'V':  Compute eigenvalues and eigenvectors;
	// 'U':  Upper triangle of A is stored;
	// The order of the matrix A
	// lda: The leading dimension of the array A
	// lwork: The length of the array WORK
	dsyev_("V", "U", &N, BB, &lda, wr, work, &lwork, &info);
	double h[9];
	for (i = 0; i < 9; i++)
	{
		h[i] = BB[i];
	};
	// 非线性解法:马尔卡丁车法调整
	optimize_homography(h, wpts, cpts, pts_num);

	// 结果的表格
	eH[3 * 0 + 0] = h[0]; 
	eH[3 * 0 + 1] = h[1]; 
	eH[3 * 0 + 2] = h[2];
	eH[3 * 1 + 0] = h[3]; 
	eH[3 * 1 + 1] = h[4]; 
	eH[3 * 1 + 2] = h[5];
	eH[3 * 2 + 0] = h[6]; 
	eH[3 * 2 + 1] = h[7]; 
	eH[3 * 2 + 2] = h[8];
};




//********************************************************************************
// 复数图像的观测分的对应,内部パラメタ推测
//********************************************************************************
void estimate_intrinsic(
	data_t * data,		// 对应点数据
	int N,				// 画像枚数
	double & alpha, double & beta, double & gamma,
	double & u0, double & v0, double & k1, double & k2
	)
{
	int n, i, j, k;
	double V[1000], VV[1000], v[2][2][6];

	// 行列V作成:Zhang論文の式(9)
	for (n = 0; n < N; n++)
	{
		for (i = 0; i < 2; i++)
		{
			for (j = 0; j < 2; j++)
			{
				v[i][j][0] = data[n].H[i + 3 * 0] * data[n].H[j + 3 * 0];
				v[i][j][1] = data[n].H[i + 3 * 0] * data[n].H[j + 3 * 1] + data[n].H[i + 3 * 1] * data[n].H[j + 3 * 0];
				v[i][j][2] = data[n].H[i + 3 * 1] * data[n].H[j + 3 * 1];
				v[i][j][3] = data[n].H[i + 3 * 2] * data[n].H[j + 3 * 0] + data[n].H[i + 3 * 0] * data[n].H[j + 3 * 2];
				v[i][j][4] = data[n].H[i + 3 * 2] * data[n].H[j + 3 * 1] + data[n].H[i + 3 * 1] * data[n].H[j + 3 * 2];
				v[i][j][5] = data[n].H[i + 3 * 2] * data[n].H[j + 3 * 2];
			};//j
		};//i
		for (j = 0; j < 6; j++)
		{
			V[(2 * n) * 6 + j] = v[0][1][j];
			V[(2 * n + 1) * 6 + j] = v[0][0][j] - v[1][1][j];
		};
	};// n

	// V^T V
	for (i = 0; i < 6; i++)
	{
		for (j = 0; j < 6; j++)
		{
			double sum = 0.0;
			for (k = 0; k < 2 * N; k++)
			{
				sum += V[k * 6 + i] * V[k * 6 + j];
			};// k
			VV[i * 6 + j] = sum;
		};//j
	};// i


	long P = 6;
	double wr[1000], wi[2], work[1000], vl[1000], vr[1000];
	long lda = P, ldvl = P, ldvr = P, lwork = 3 * P, info, ldvt = 6;

	// 固有方程式解开
	dsyev_("V", "U", &P, VV, &lda, wr, work, &lwork, &info);

	// 求めた固有ベクトルから行列Bを構成:Zhang論文の式(6)
	double B[9];

	B[3 * 0 + 0] = VV[0];
	B[3 * 0 + 1] = B[3 * 1 + 0] = VV[1];
	B[3 * 1 + 1] = VV[2];
	B[3 * 0 + 2] = B[3 * 2 + 0] = VV[3];
	B[3 * 1 + 2] = B[3 * 2 + 1] = VV[4];
	B[3 * 2 + 2] = VV[5];

	// 内部参数推测:漳论文的附录B
	double lambda;
	v0 = (B[3 * 0 + 1] * B[3 * 0 + 2] - B[3 * 0 + 0] * B[3 * 1 + 2]) / (B[3 * 0 + 0] * B[3 * 1 + 1] - B[3 * 0 + 1] * B[3 * 0 + 1]);
	lambda = B[3 * 2 + 2] - (B[3 * 0 + 2] * B[3 * 0 + 2] + v0 * (B[3 * 0 + 1] * B[3 * 0 + 2] - B[3 * 0 + 0] * B[3 * 1 + 2])) / B[3 * 0 + 0];
	alpha = sqrt(lambda / B[3 * 0 + 0]);
	beta = sqrt(lambda * B[3 * 0 + 0] / (B[3 * 0 + 0] * B[3 * 1 + 1] - B[3 * 0 + 1] * B[3 * 0 + 1]));
	gamma = -B[3 * 0 + 1] * alpha * alpha * beta / lambda;
	u0 = gamma * v0 / beta - B[3 * 0 + 2] * alpha * alpha / lambda;
	// 内部行列の逆
	double invA[9];
	invA[0] = 1.0 / alpha;
	invA[1] = -gamma / (alpha * beta);
	invA[2] = (gamma * v0 - u0 * beta) / (alpha * beta);
	invA[3] = 0.0; invA[4] = 1.0 / beta; invA[5] = -v0 / beta;
	invA[6] = 0.0; invA[7] = 0.0;       invA[8] = 1.0;
	// invAとホモグラフィから各画像でのRt行列を求める
	for (i = 0; i < N; i++)
	{
		gen_Rt_from_AH(invA, data[i].H, data[i].R, data[i].t);
	};
	k1 = k2 = 0.0;
	// 非线性解法:马尔卡丁车法调整
	optimize_homography_distortion(alpha, beta, gamma, u0, v0, k1, k2, data, N);

};

 

mat.h

//
//  娙堈峴楍墘嶼
//

#ifndef _MAT_
#define _MAT_

// 峴楍偺妡偗嶼丗 C = A * B
void mat_mul(double *A, double *B, double *C, int N)
{
	int i, j, k;
	double sum;

	for(i = 0;i < N;i++)
	{
		for(j = 0;j < N;j++)
		{
			sum = 0.0;
			for(k = 0;k < N;k++)
			{
				sum += A[i * N + k] * B[k * N + j];
			};
			C[i * N + j] = sum;
		};//j
	};//i
};


// 峴楍偲儀僋僩儖偺妡偗嶼丗b = A . v
void mat_vec(double *A, double *v, double *b, int N)
{
	int i, k;
	double sum;

	for(i = 0;i < N;i++)
	{
		sum = 0.0;
		for(k = 0;k < N;k++)
		{
			sum += A[i * N + k] * v[k];
		};
		b[i] = sum;
	};//i

};


// 撪愊丗<a, b>
double dot(double *a, double *b, int N)
{
	double sum = 0.0;
	int i;

	for(i = 0;i < N;i++)
		sum += a[i] * b[i];

	return sum;
};

// 奜愊丗a 亊 b
void cross3(double *a, double *b, double *c)
{
	c[0] =   a[1] * b[2] - a[2] * b[1];
	c[1] = -(a[0] * b[2] - a[2] * b[0]);
	c[2] =   a[0] * b[1] - a[1] * b[0];
};
void normalize(double *a, int N)
{
	int i;
	double d = sqrt(dot(a, a, N));
	for(i = 0;i < N;i++)
		a[i] /= d;

};

#endif

 

gen_mat.h

//
//  几何变换用的队伍生成
//

#ifndef _GEN_GEOMETRIC_MAT_
#define _GEN_GEOMETRIC_MAT_


#include "mat.h"

// 内部行列 A 生成
void gen_intrinsic_mat(double alpha, double beta, double gamma, double u0, double v0, double *A)
{
	A[0 * 3 + 0] = alpha; //搞定
	A[0 * 3 + 1] = gamma; 
	A[0 * 3 + 2] = u0;
	A[1 * 3 + 0] = 0.0; 
	A[1 * 3 + 1] = beta; 
	A[1 * 3 + 2] = v0;
	A[2 * 3 + 0] = 0.0; 
	A[2 * 3 + 1] = 0.0; 
	A[2 * 3 + 2] = 1.0;
};

// 旋转队伍R生成(3个延展而成角开始生成)
void gen_rot_mat(double x, double y, double z, double *R)
{
	double Rx[9], Ry[9], Rz[9], tmp[9];

	Rz[0 * 3 + 0] = cos(z); Rz[0 * 3 + 1] = -sin(z); Rz[0 * 3 + 2] = 0.0;
	Rz[1 * 3 + 0] = sin(z); Rz[1 * 3 + 1] = cos(z); Rz[1 * 3 + 2] = 0.0;
	Rz[2 * 3 + 0] = 0.0;   Rz[2 * 3 + 1] = 0.0; Rz[2 * 3 + 2] = 1.0;

	Ry[0 * 3 + 0] = cos(y); Ry[0 * 3 + 1] = 0.0; Ry[0 * 3 + 2] = sin(y);
	Ry[1 * 3 + 0] = 0.0; Ry[1 * 3 + 1] = 1.0; Ry[1 * 3 + 2] = 0.0;
	Ry[2 * 3 + 0] = -sin(y); Ry[2 * 3 + 1] = 0.0; Ry[2 * 3 + 2] = cos(y);

	Rx[0 * 3 + 0] = 1.0; Rx[0 * 3 + 1] = 0.0; Rx[0 * 3 + 2] = 0.0;
	Rx[1 * 3 + 0] = 0.0; Rx[1 * 3 + 1] = cos(x); Rx[1 * 3 + 2] = -sin(x);
	Rx[2 * 3 + 0] = 0.0; Rx[2 * 3 + 1] = sin(x); Rx[2 * 3 + 2] = cos(x);

	mat_mul(Ry, Rx, tmp, 3);//矩阵乘法N*N
	mat_mul(Rz, tmp, R, 3);
};

// ホモグラフィ(斜影変換)+平行移動 行列 H 生成(2D用)
void gen_homography_2D(double x, double y, double z, double tx, double ty, double tz,
	double alpha, double beta, double gamma, double u0, double v0, double *H
	)
{
	double R[9];//旋转矩阵
	double A[9];//内参
	double T[9];//
	gen_rot_mat(x, y, z, R);//生成旋转矩阵
	gen_intrinsic_mat(alpha, beta, gamma, u0, v0, A);//生成内参矩阵
	//[r1,r2,t]
	T[3 * 0 + 0] = R[3 * 0 + 0]; T[3 * 0 + 1] = R[3 * 0 + 1]; T[3 * 0 + 2] = tx;
	T[3 * 1 + 0] = R[3 * 1 + 0]; T[3 * 1 + 1] = R[3 * 1 + 1]; T[3 * 1 + 2] = ty;
	T[3 * 2 + 0] = R[3 * 2 + 0]; T[3 * 2 + 1] = R[3 * 2 + 1]; T[3 * 2 + 2] = tz;
	mat_mul(A, T, H, 3);//H单应矩阵
};

// A ^ - 1和H开始生成旋转队伍
void gen_Rt_from_AH(double *invA, double *H, double * R, double * t)
{
	double lambda;
	double r1[3], r2[3], r3[3], r4[3];
	double h1[3], h2[3], h3[3];
	double Rt[9];
	int i;

	h1[0] = H[0];
	h1[1] = H[3];
	h1[2] = H[6];
	h2[0] = H[1];
	h2[1] = H[4];
	h2[2] = H[7];
	h3[0] = H[2];
	h3[1] = H[5];
	h3[2] = H[8];

	mat_vec(invA, h1, r1, 3);
	mat_vec(invA, h2, r2, 3);
	mat_vec(invA, h3, t, 3);

	lambda = 1.0 / sqrt(dot(r1, r1, 3));

	for (i = 0; i < 3; i++)
	{
		r1[i] *= lambda;
		r2[i] *= lambda;
		t[i] *= lambda;
	};
	normalize(r1, 3);
	normalize(r2, 3);
	cross3(r1, r2, r3);
	cross3(r1, r3, r4);
	if (r4[0] * r2[0] < 0)
	{
		r2[0] = -r4[0];
		r2[1] = -r4[1];
		r2[2] = -r4[2];
	}
	else {
		r2[0] = r4[0];
		r2[1] = r4[1];
		r2[2] = r4[2];
	};

	double d1 = dot(r1, r1, 3);
	double d2 = dot(r2, r2, 3);
	double d12 = dot(r1, r2, 3);

	for (i = 0; i < 3; i++)
	{
		R[3 * i + 0] = r1[i];
		R[3 * i + 1] = r2[i];
		R[3 * i + 2] = r3[i];
	};
	for (i = 0; i < 3; i++)
	{
		Rt[3 * i + 0] = r1[i];
		Rt[3 * i + 1] = r2[i];
		Rt[3 * i + 2] = t[i];
	};

};

#endif

 

bmp_loader.h

//
//  bit图读入 g.koutaki 2012
//

#ifndef _BMP_LOADER_
#define _BMP_LOADER_

typedef unsigned long   DWORD;
typedef unsigned short  WORD;
typedef long		    LONG;

typedef struct tagBITMAPCOREHEADER{
	DWORD   bcSize;
	WORD    bcWidth;
	WORD    bcHeight;
	WORD    bcPlanes;
	WORD    bcBitCount;
} BITMAPCOREHEADER;//未使用

typedef struct tagBITMAPINFOHEADER{
	DWORD      biSize;
	LONG       biWidth;
	LONG       biHeight;
	WORD       biPlanes;
	WORD       biBitCount;
	DWORD      biCompression;
	DWORD      biSizeImage;
	LONG       biXPelsPerMeter;
	LONG       biYPelsPerMeter;
	DWORD      biClrUsed;
	DWORD      biClrImportant;
} BITMAPINFOHEADER;//位图信息头

typedef struct tagBITMAPFILEHEADER {
	WORD    bfType;
	DWORD   bfSize;
	WORD    bfReserved1;
	WORD    bfReserved2;
	DWORD   bfOffBits;
} BITMAPFILEHEADER;//位图文件头

typedef struct tagBITMAPINFO {
	BITMAPINFOHEADER    bmiHeader;
	DWORD               bmiColors[1];
} BITMAPINFO;//彩色表/调色板

void load_bmp_rgb(char *filename, unsigned char **img, int *w, int *h)
{

	FILE *fp = fopen(filename, "rb");
	BITMAPINFOHEADER BmpInfoH;//位图信息头
	BITMAPFILEHEADER BmpFileH;//位图文件头
	int x, y, pitch;
	unsigned char line[3 * 9096];
	int s = sizeof(BITMAPINFOHEADER);

	if (fp)//打开成功
	{
		fread(&BmpFileH, 1, 14, fp);//文件头
		fread(&BmpInfoH, 1, 40, fp);//信息头
		//位图的幅度要求
		*w = BmpInfoH.biWidth;
		*h = BmpInfoH.biHeight;
		printf("load %s:%dx%d\n", filename, *w, *h);//打印信息
		(*img) = new unsigned char[*w * *h * 3];//C++的
		pitch = (*w * 3 + 3) & ~3;//对齐?
		//ビットマップデータ为止文件点移动
		fseek(fp, 54, SEEK_SET);//偏移到数据
		for (y = *h - 1; y >= 0; y--)//从最后一行读??
		{
			fread(line, pitch, 1, fp);
			for (x = 0; x < *w; x++)
			{
				(*img)[(x + y * *w) * 3 + 0] = line[x * 3 + 2];	// R
				(*img)[(x + y * *w) * 3 + 1] = line[x * 3 + 1];	// G
				(*img)[(x + y * *w) * 3 + 2] = line[x * 3 + 0];	// B
			};
		};
		fclose(fp);
	};
};


void load_bmp_gray(char *filename, unsigned char **img, int *w, int *h){

	FILE *fp = fopen(filename, "rb");
	BITMAPINFOHEADER BmpInfoH;
	BITMAPFILEHEADER BmpFileH;
	int x, y, pitch;
	unsigned char line[3 * 9096];
	int s = sizeof(BITMAPINFOHEADER);

	if (fp){
		fread(&BmpFileH, 1, 14, fp);
		fread(&BmpInfoH, 1, 40, fp);
		//位图的幅度要求
		*w = BmpInfoH.biWidth;
		*h = BmpInfoH.biHeight;
		printf("load %s:%dx%d\n", filename, *w, *h);
		(*img) = new unsigned char[*w * *h * 3];
		pitch = (*w * 3 + 3) & ~3;
		//ビットマップデータ为止文件点移动
		fseek(fp, 54, SEEK_SET);
		for (y = *h - 1; y >= 0; y--)
		{
			fread(line, pitch, 1, fp);
			for (x = 0; x < *w; x++)
			{
				(*img)[(x + y * *w)] = line[x * 3 + 0];	// R
			};
		};
		fclose(fp);
	};
};

void write_bmp_rgb( char *filename, //文件名
					unsigned char *img, //图像数据
					int w, //宽
					int h) //高
{

	FILE *fp = fopen(filename, "wb");
	BITMAPINFOHEADER BmpInfoH;//长宽大小等信息
	BITMAPINFO		 BmpInfo;
	BITMAPFILEHEADER BmpFileH;
	int x, y, pitch;
	unsigned char line[3 * 9096];
	int s = sizeof(BITMAPFILEHEADER);

	if (fp){
		//位图的幅度要求
		pitch = (w * 3 + 3) & ~3;
		memset(&BmpFileH, 0, 14);
		memset(&BmpInfo, 0, 40);
		memset(&BmpInfoH, 0, 40);
		//位图信息头
		BmpInfo.bmiHeader.biHeight = h;
		BmpInfo.bmiHeader.biWidth = w;
		BmpInfo.bmiHeader.biSize = 40;
		BmpInfo.bmiHeader.biSizeImage = pitch * h;
		BmpInfo.bmiHeader.biPlanes = 1;
		BmpInfo.bmiHeader.biBitCount = 24;
		BmpInfo.bmiHeader.biCompression = 0;
		BmpInfo.bmiHeader.biClrUsed = 0;
		BmpInfo.bmiHeader.biXPelsPerMeter = 0;
		BmpInfo.bmiHeader.biYPelsPerMeter = 0;
		BmpInfo.bmiHeader.biClrImportant = 0;
		BmpInfoH = BmpInfo.bmiHeader;
		//位图文件头
		BmpFileH.bfOffBits = 3435921408;
		BmpFileH.bfSize = pitch * h + BmpFileH.bfOffBits;
		BmpFileH.bfType = 19778;
		BmpFileH.bfReserved1 = 0;
		BmpFileH.bfReserved2 = 54;
		printf("write %s:%dx%d\n", filename, w, h);

		fwrite(&BmpFileH, 14, 1, fp);
		fwrite(&BmpInfoH, 40, 1, fp);
		for (y = h - 1; y >= 0; y--){
			for (x = 0; x < w; x++){
				line[x * 3 + 2] = img[(x + y * w) * 3 + 0];
				line[x * 3 + 1] = img[(x + y * w) * 3 + 1];
				line[x * 3 + 0] = img[(x + y * w) * 3 + 2];
			};
			fwrite(line, pitch, 1, fp);
		};
		fclose(fp);
	};
};

void write_bmp_gray(char *filename, unsigned char *img, int w, int h)
{
	FILE *fp = fopen(filename, "wb");
	BITMAPINFOHEADER BmpInfoH;
	BITMAPINFO		 BmpInfo;
	BITMAPFILEHEADER BmpFileH;
	int x, y, pitch;
	unsigned char line[3 * 9096];
	int s = sizeof(BITMAPFILEHEADER);

	if (fp)
	{
		// 位图的幅度要求
		pitch = (w * 3 + 3) & ~3;
		memset(&BmpFileH, 0, 14);
		memset(&BmpInfo, 0, 40);
		memset(&BmpInfoH, 0, 40);
		BmpInfo.bmiHeader.biHeight = h;
		BmpInfo.bmiHeader.biWidth = w;
		BmpInfo.bmiHeader.biSize = 40;
		BmpInfo.bmiHeader.biSizeImage = pitch * h;
		BmpInfo.bmiHeader.biPlanes = 1;
		BmpInfo.bmiHeader.biBitCount = 24;
		BmpInfo.bmiHeader.biCompression = 0;
		BmpInfo.bmiHeader.biClrUsed = 0;
		BmpInfo.bmiHeader.biXPelsPerMeter = 0;
		BmpInfo.bmiHeader.biYPelsPerMeter = 0;
		BmpInfo.bmiHeader.biClrImportant = 0;
		BmpInfoH = BmpInfo.bmiHeader;
		BmpFileH.bfOffBits = 3435921408;
		BmpFileH.bfSize = pitch * h + BmpFileH.bfOffBits;
		BmpFileH.bfType = 19778;
		BmpFileH.bfReserved1 = 0;
		BmpFileH.bfReserved2 = 54;
		printf("write %s:%dx%d\n", filename, w, h);

		fwrite(&BmpFileH, 14, 1, fp);
		fwrite(&BmpInfoH, 40, 1, fp);
		for (y = h - 1; y >= 0; y--)
		{
			for (x = 0; x < w; x++)
			{
				line[x * 3 + 2] = img[(x + y * w)];
				line[x * 3 + 1] = img[(x + y * w)];
				line[x * 3 + 0] = img[(x + y * w)];
			};
			fwrite(line, pitch, 1, fp);
		};
		fclose(fp);
	};
};
#endif


posted @ 2016-06-14 00:41  _木头人  阅读(270)  评论(0编辑  收藏  举报