我有很多用鱼眼镜头拍摄的照片。当我想对照片进行一些图像处理(例如,边缘检测)时,我想消除桶形失真,这会严重影响我的结果。
经过研究和大量阅读文章,我找到了此页面:他们描述了一种解决此问题的算法(和一些公式)。
M = a * rcorr ^ 3 + b * rcorr ^ 2 + c * rcorr + d rsrc =(a * rcorr ^ 3 + b * rcorr ^ 2 + c * rcorr + d)* rcorr rsrc =像素距源图像中心的 距离rcorr =像素距校正图像中心的距离 a,b,c =图像失真d =图像的线性缩放
M = a * rcorr ^ 3 + b * rcorr ^ 2 + c * rcorr + d rsrc =(a * rcorr ^ 3 + b * rcorr ^ 2 + c * rcorr + d)* rcorr
rsrc =像素距源图像中心的 距离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)还有其他算法(例如,如何通过openCV模拟鱼眼镜头效果?),它们更好吗?
谢谢你的帮助!
您遇到的主要错误是该算法指定r_corr和r_src以min((xDim-1)/ 2,(yDim-1)/ 2)为单位。需要执行此操作以标准化计算,以便参数值不依赖于源图像的大小。有了代码,您将需要为paramB使用更小的值,例如,对于paramB =0.00000002(对于尺寸为2272 x 1704的图像),它对我来说可以正常工作。
在计算与中心的差异时,还存在一个错误,该错误会导致生成的图像与源图像相比旋转180度。
修复这两个错误应会为您提供以下信息:
protected static int[] correction2(int[] pixels, int width, int height) { int[] pixelsCopy = pixels.clone(); // parameters for correction double paramA = -0.007715; // affects only the outermost pixels of the image double paramB = 0.026731; // 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 < width; x++) { for (int y = 0; y < height; y++) { int d = Math.min(width, height) / 2; // radius of the circle // center of dst image double centerX = (width - 1) / 2.0; double centerY = (height - 1) / 2.0; // cartesian coordinates of the destination point (relative to the centre of the image) double deltaX = (x - centerX) / d; double deltaY = (y - centerY) / d; // distance or radius of dst image double dstR = Math.sqrt(deltaX * deltaX + deltaY * deltaY); // 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 + (deltaX * factor * d); double srcYd = centerY + (deltaY * factor * d); // no interpolation yet (just nearest point) int srcX = (int) srcXd; int srcY = (int) srcYd; if (srcX >= 0 && srcY >= 0 && srcX < width && srcY < height) { int dstPos = y * width + x; pixels[dstPos] = pixelsCopy[srcY * width + srcX]; } } } return pixels; }
使用此版本,您可以使用现有镜头数据库(例如LensFun)中的参数值(尽管您需要翻转每个参数的符号)。现在可以在http://mipav.cit.nih.gov/pubwiki/index.php/Barrel_Distortion_Correction中找到描述算法的页面