1. 程式人生 > 其它 >相機標定——數學原理及公式推導篇

相機標定——數學原理及公式推導篇

當然這個東西不常考,學一點基本的就行

叉積

\(\vec a\times \vec b\),或者簡寫成 axb。

\[a*b=x_1y_2-x_2y_1 \]

並不滿足交換律。

這個可以這樣理解,將 \(a\) 逆時針旋轉到 \(b\) 的角度。所以如果 \(>0\) 那麼 \(a\) 就在 \(b\) 的下方,否則就在上方。

判斷一個點在直線的哪邊

設這個直線是 \(PQ\),而且我要求 \(A\) 在直線的哪邊。計算出直線的方向向量 \(v=PQ\),那麼判斷 \(v*PA\) 的正負性即可(\(>0\) 在下方,\(<0\) 在上方)。

求點集的凸包

用 Andrew 演算法求出 \(n\)

個點的凸包。

首先將它們以 \(x\) 為第一關鍵字,\(y\) 為第二關鍵字排序。那麼最左邊和最右邊的點就一定會在凸包中。我們依次求出上凸包和下凸包。

用一個棧維護現在的凸包點集,如果我們現在要加入一個新點 \(a\),我們就看加入它後可以彈出棧頂多少個點。用叉積去計算斜率,比較 \(s_{top},s_{top-1}\) 的斜率,和 \(a,s_{top-1}\) 的斜率即可,若凹下去了就彈棧。

while(top>1 && cross(vet(sak[top-1],sak[top]),vet(sak[top-1],i))<0 )top--;

求一個點是否在一個三角形內

對於三角形 \(\bigtriangledown ABC\),和點 \(N\),我們看,是否 \(A,N\) 在直線 \(BC\) 同側; \(B,N\) 在直線 \(AC\) 同側;\(C,N\) 在直線 \(AB\) 同側。三個都滿足就是,否則就不在三角形內。

求多邊形的周長與面積

周長:直接相鄰兩個點算距離,最後再加起來。

面積:\(\Large S=\frac{1}2 |\sum\limits_{i=1}^np_i\times p_{i+1}|\)(如果 \(i=n\)\(i+1=1\)

平衡樹維護凸包

CF70D。(當然下面的程式碼不是這一題的 233)

#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x;i<=y;++i)
#define per(i,x,y) for(int i=x;i>=y;--i)
#define lon long long
#define lod long double
#define iter set <drop> :: iterator
using namespace std;
const int n7=201234,inf=2e9;
const lod eps=1e-12;
struct drop{
	lod x,y;
	friend bool operator == (drop p,drop q){return p.x==q.x&&p.y==q.y;}
	friend bool operator != (drop p,drop q){return !(p==q);}
	friend bool operator < (drop p,drop q){return p.x==q.x?p.y<q.y:p.x<q.x;}
	friend drop operator - (drop p,drop q){return (drop){p.x-q.x,p.y-q.y};}
	friend lod operator * (drop p,drop q){return p.x*q.y-p.y*q.x;}
}a[n7],infl,infr;
struct iron{char typ;int t,l,r;}qt[n7];
int n,T,vis[n7],ans[n7],xmax,ymax;
set <drop> sut;

int rd(){
	int shu=0;bool fu=0;char ch=getchar();
	while( !isdigit(ch) ){if(ch=='-')fu=1;ch=getchar();}
	while( isdigit(ch) )shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar();
	return fu?-shu:shu;
}

lod getK(drop p,drop q){
	if(p.x==q.x)return inf;
	return (p.y-q.y)/(p.x-q.x);
}

void print(iter it=sut.end()){
	puts("------");
	if(it==sut.end()){
		it=sut.begin();
		while(it!=sut.end())printf("%.0Lf %.0Lf\n",(*it).x,(*it).y),++it;
	}
	else printf("%.0Lf %.0Lf\n",(*it).x,(*it).y);
}

bool check(drop x,iter it){
	if( *prev(it)==infl || *it==infr )return 1;
	drop p=*prev(it),q=*it;
	drop z1=p-q,z2=x-p;
	return z1*z2+eps<0;
}

void work(drop x){
	if( sut.count(x) )return;
	iter it=sut.lower_bound(x);
	if( !check(x,it) )return;
	while( *it!=infr && *next(it)!=infr ){
		if( getK(*it,x)<=getK(*next(it),x) )++it,sut.erase( prev(it) );
		else break;
	}
	it=--sut.lower_bound(x);
	while( *it!=infl && *prev(it)!=infl ){
		if( getK(*it,x)>=getK(*prev(it),x) )--it,sut.erase( next(it) );
		else break;		
	}
	sut.insert(x);
}

int main(){
	n=rd();
	rep(i,1,n)a[i]=(drop){rd(),rd()};
	T=rd();
	rep(i,1,T){
		char sys=getchar();
		while( !isalpha(sys) )sys=getchar();
		if(sys=='c')qt[i]=(iron){'c',rd(),rd(),rd()};
		if(sys=='q')qt[i]=(iron){'q',rd()},vis[ qt[i].t ]=1;
	}
	infl=(drop){-inf,-inf},infr=(drop){inf,-inf};
	sut.insert(infl),sut.insert(infr);
	rep(i,1,n){
		if(vis[i])continue;
		work(a[i]);
		if(a[i].y>ymax)xmax=a[i].x,ymax=a[i].y;
	}
	per(i,T,1){
		if(qt[i].typ=='c'){
			drop z=(drop){qt[i].l*1.0/qt[i].t,qt[i].r*1.0/qt[i].t};
			if(z.x<=xmax&&z.y<=ymax)ans[i]=1;
			else if( sut.count(z) )ans[i]=1;
			else{
				iter it=sut.lower_bound(z);
				ans[i]=!check(z,it);
			}
		}
		if(qt[i].typ=='q'){
			work(a[ qt[i].t ]);
			if(a[ qt[i].t ].y>ymax)xmax=a[ qt[i].t ].x,ymax=a[ qt[i].t ].y;
		}
	}
	rep(i,1,T)if(qt[i].typ=='c')puts(ans[i]?"no":"yes");
	return 0;
}

旋轉卡殼

雙指標維護兩個端點即可。

詳細一點:設定兩個指標 \(i,j\),如果 \(dis(i,j)<dis(i,j+1)\) 那麼 \(j++\),否則 \(i++\)