【发布时间】:2012-09-19 03:48:55
【问题描述】:
我有大量使用鱼眼镜头拍摄的照片。因为我想对照片进行一些图像处理(例如边缘检测),所以我想消除严重影响结果的桶形失真。
经过一些研究和大量阅读文章后,我发现了这个page:他们描述了一种算法(和一些公式)来解决这个问题。
M = a *rcorr^3 + b * rcorr^2 + c * rcorr + d
rsrc = (a * rcorr^3 + b * rcorr^2 + c * rcorr + d) * rcorrrsrc = 像素到源图像中心的距离
rcorr = 校正后图像中像素到中心的距离
a,b,c = 图像失真 d = 图像的线性缩放
我使用了这些公式并尝试在 Java 应用程序中实现它。不幸的是,它不起作用,我没能使它起作用。 “更正”的图像看起来与原始照片完全不同,而是在中间显示了一些神秘的圆圈。看这里:
http://imageshack.us/f/844/barreldistortioncorrect.jpg/ (这曾经是一头白牛在蓝墙前的照片)
这是我的代码:
protected int[] correction(int[] pixels) {
//
int[] pixelsCopy = pixels.clone();
// parameters for correction
double paramA = 0.0; // affects only the outermost pixels of the image
double paramB = -0.02; // most cases only require b optimization
double paramC = 0.0; // most uniform correction
double paramD = 1.0 - paramA - paramB - paramC; // describes the linear scaling of the image
//
for(int x = 0; x < dstView.getImgWidth(); x++) {
for(int y = 0; y < dstView.getImgHeight(); y++) {
int dstX = x;
int dstY = y;
// center of dst image
double centerX = (dstView.getImgWidth() - 1) / 2.0;
double centerY = (dstView.getImgHeight() - 1) / 2.0;
// difference between center and point
double diffX = centerX - dstX;
double diffY = centerY - dstY;
// distance or radius of dst image
double dstR = Math.sqrt(diffX * diffX + diffY * diffY);
// distance or radius of src image (with formula)
double srcR = (paramA * dstR * dstR * dstR + paramB * dstR * dstR + paramC * dstR + paramD) * dstR;
// comparing old and new distance to get factor
double factor = Math.abs(dstR / srcR);
// coordinates in source image
double srcXd = centerX + (diffX * factor);
double srcYd = centerY + (diffX * factor);
// no interpolation yet (just nearest point)
int srcX = (int)srcXd;
int srcY = (int)srcYd;
if(srcX >= 0 && srcY >= 0 && srcX < dstView.getImgWidth() && srcY < dstView.getImgHeight()) {
int dstPos = dstY * dstView.getImgWidth() + dstX;
pixels[dstPos] = pixelsCopy[srcY * dstView.getImgWidth() + srcX];
}
}
}
return pixels;
}
我的问题是:
1) 这个公式正确吗?
2) 把这个公式变成一个软件是不是我犯了一个错误?
3) 还有其他算法(例如How to simulate fisheye lens effect by openCV? 或 wiki/Distortion_(optics)),它们更好吗?
感谢您的帮助!
【问题讨论】:
-
边缘附近的方形像素网格可以说明问题可能是什么。你的算法是否适用于任何照片,我不知道。它不起作用的一个可能原因是您可能过度校正了失真。
-
正如我在下面提到的,我尝试将 b 设置为无限小的值。它给出了不同的结果(不再进行球面校正),但仍然不显示相同的图像。见这里:imageshack.us/f/191/barreldistortioncorrect.jpg
-
可能无限小的 b 值在 other 方向上过度校正?
-
尝试制作一个动画,当您将参数值从一个极端滑动到另一个极端时,图像会发生什么;这可以说明你的问题。如果您可以使用 Wolfram Mathematica 之类的工具,这将非常简单,但即使没有这些,您也可以让它为不同的参数值生成大量图像并将它们拼接成动画。
-
另外,试着用铅笔在纸上复习所有数学,看看图像像素实际发生了什么,以确保你的数学是正确的。
标签: java algorithm image-processing distortion fisheye