Wil*_*ill 49 math graphics geometry projection
BOUNTY STATUS UPDATE:
我发现了如何绘制线性镜头,从destination
坐标到source
坐标.
你如何计算从中心到鱼眼到直线的径向距离?
1).我实际上很难逆转它,并将源坐标映射到目标坐标.在我发布的转换函数风格的代码中有什么反转?
2).我也看到我的失真在一些镜头上是不完美的 - 大概是那些不是严格线性的镜头.这些镜头的源和目标坐标是等价的?再说一遍,代码不仅仅是数学公式,请...
最初提出的问题:
我有一些观点描述用鱼眼镜头拍摄的照片中的位置.
我想将这些点转换为直线坐标.我想不要失真的形象.
我发现这个描述的如何生成鱼眼效果,但不知道如何扭转这种局面.
还有一篇博客文章描述了如何使用工具来完成它; 这些照片来自:
(1):SOURCE
原始照片链接
输入:修复鱼眼失真的原始图像.
(2):DESTINATION
原始照片链接
输出:校正图像(技术上也有透视校正,但这是一个单独的步骤).
你如何计算从中心到鱼眼到直线的径向距离?
我的函数存根看起来像这样:
Point correct_fisheye(const Point& p,const Size& img) {
// to polar
const Point centre = {img.width/2,img.height/2};
const Point rel = {p.x-centre.x,p.y-centre.y};
const double theta = atan2(rel.y,rel.x);
double R = sqrt((rel.x*rel.x)+(rel.y*rel.y));
// fisheye undistortion in here please
//... change R ...
// back to rectangular
const Point ret = Point(centre.x+R*cos(theta),centre.y+R*sin(theta));
fprintf(stderr,"(%d,%d) in (%d,%d) = %f,%f = (%d,%d)\n",p.x,p.y,img.width,img.height,theta,R,ret.x,ret.y);
return ret;
}
Run Code Online (Sandbox Code Playgroud)
或者,我可以在找到点之前以某种方式将图像从鱼眼转换为直线,但我完全被OpenCV文档迷惑了.有没有一种直接的方法在OpenCV中做到这一点,它是否能够很好地运行到实时视频源?
jmb*_*mbr 33
您提到的描述表明,针孔相机(不引入镜头失真的投影)的投影是通过建模的
R_u = f*tan(theta)
Run Code Online (Sandbox Code Playgroud)
普通鱼眼镜头相机(即失真)的投影由模拟
R_d = 2*f*sin(theta/2)
Run Code Online (Sandbox Code Playgroud)
你已经知道了R_d和theta,如果你知道相机的焦距(用f表示)那么校正图像将相当于用R_d和theta计算R_u.换一种说法,
R_u = f*tan(2*asin(R_d/(2*f)))
Run Code Online (Sandbox Code Playgroud)
是你正在寻找的公式.估计焦距f可以通过校准相机或其他装置来解决,例如让用户提供关于图像校正程度的反馈或使用来自原始场景的知识的反馈.
为了使用OpenCV解决相同的问题,您必须获得相机的内部参数和镜头失真系数.例如,参见学习OpenCV的第11章(不要忘记检查校正).然后你可以使用像这样的程序(用OpenCV的Python绑定编写)来反转镜头失真:
#!/usr/bin/python
# ./undistort 0_0000.jpg 1367.451167 1367.451167 0 0 -0.246065 0.193617 -0.002004 -0.002056
import sys
import cv
def main(argv):
if len(argv) < 10:
print 'Usage: %s input-file fx fy cx cy k1 k2 p1 p2 output-file' % argv[0]
sys.exit(-1)
src = argv[1]
fx, fy, cx, cy, k1, k2, p1, p2, output = argv[2:]
intrinsics = cv.CreateMat(3, 3, cv.CV_64FC1)
cv.Zero(intrinsics)
intrinsics[0, 0] = float(fx)
intrinsics[1, 1] = float(fy)
intrinsics[2, 2] = 1.0
intrinsics[0, 2] = float(cx)
intrinsics[1, 2] = float(cy)
dist_coeffs = cv.CreateMat(1, 4, cv.CV_64FC1)
cv.Zero(dist_coeffs)
dist_coeffs[0, 0] = float(k1)
dist_coeffs[0, 1] = float(k2)
dist_coeffs[0, 2] = float(p1)
dist_coeffs[0, 3] = float(p2)
src = cv.LoadImage(src)
dst = cv.CreateImage(cv.GetSize(src), src.depth, src.nChannels)
mapx = cv.CreateImage(cv.GetSize(src), cv.IPL_DEPTH_32F, 1)
mapy = cv.CreateImage(cv.GetSize(src), cv.IPL_DEPTH_32F, 1)
cv.InitUndistortMap(intrinsics, dist_coeffs, mapx, mapy)
cv.Remap(src, dst, mapx, mapy, cv.CV_INTER_LINEAR + cv.CV_WARP_FILL_OUTLIERS, cv.ScalarAll(0))
# cv.Undistort2(src, dst, intrinsics, dist_coeffs)
cv.SaveImage(output, dst)
if __name__ == '__main__':
main(sys.argv)
Run Code Online (Sandbox Code Playgroud)
另请注意,OpenCV使用与您链接的网页中的镜头失真模型截然不同的镜头失真模型.
(原创海报,提供替代方案)
以下函数将目标(直线)坐标映射到源(鱼眼失真)坐标. (我很感激帮助扭转它)
我通过反复试验达到了这一点:我没有从根本上理解为什么这个代码有效,解释和提高准确性赞赏!
def dist(x,y):
return sqrt(x*x+y*y)
def correct_fisheye(src_size,dest_size,dx,dy,factor):
""" returns a tuple of source coordinates (sx,sy)
(note: values can be out of range)"""
# convert dx,dy to relative coordinates
rx, ry = dx-(dest_size[0]/2), dy-(dest_size[1]/2)
# calc theta
r = dist(rx,ry)/(dist(src_size[0],src_size[1])/factor)
if 0==r:
theta = 1.0
else:
theta = atan(r)/r
# back to absolute coordinates
sx, sy = (src_size[0]/2)+theta*rx, (src_size[1]/2)+theta*ry
# done
return (int(round(sx)),int(round(sy)))
Run Code Online (Sandbox Code Playgroud)
当使用因子3.0时,它成功地不使用作为示例的图像(我没有尝试质量插值):
死链接
(这是来自博客文章,为了比较:)
归档时间: |
|
查看次数: |
51967 次 |
最近记录: |