Tengo una gran cantidad de fotografías tomadas con una lente ojo de pez. Como quiero hacer algo de procesamiento de imágenes (por ejemplo, detección de bordes) en las fotos, quiero eliminar la distorsión del cañón que afecta mucho a mis resultados.Algoritmo de corrección de distorsión de barril para corregir la lente de ojo de pez: no se ha implementado con Java
Después de algunas investigaciones y muchos artículos de lectura encontré esto page: Describen un algoritmo (y algunas fórmulas) para resolver este problema.
M = a * Rcorr^3 + b * Rcorr^2 + c * Rcorr + d
rsrc = (a * Rcorr^3 + b * Rcorr^2 + c * Rcorr + d) * Rcorrrsrc = distancia de un píxel del centro de la imagen de origen
Rcorr = distancia de un píxel del centro en la imagen corregida
a, b, c = distorsión de la imagen d = escalado lineal de la imagen
He utilizado estos fórmulas y trató de implementar esto en una aplicación Java. Lamentablemente, no funciona y no pude hacerlo funcionar. La imagen "corregida" no se parece en nada a la fotografía original y en su lugar muestra algunos círculos misteriosos en el medio. Mira aquí:
http://imageshack.us/f/844/barreldistortioncorrect.jpg/ (esto solía ser una fotografía de una vaca blanca delante de una pared azul)
Aquí está mi código:
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;
}
Mis preguntas son:
1) ¿Es esta fórmula correcta?
2) ¿He cometido un error al convertir esa fórmula en una pieza de software?
3) Existen otros algoritmos (por ejemplo, How to simulate fisheye lens effect by openCV? o wiki/Distortion_ (óptica)), ¿son mejores?
Gracias por su ayuda!
La cuadrícula de píxeles cerca del borde dice mucho sobre cuál es el problema. Ya sea que su algoritmo funcione o no para cualquier foto, no tengo ni idea. Una posible razón por la que no funciona es que es posible que esté sobre-corrigiendo la distorsión. – AJMansfield
Como mencioné a continuación intenté establecer b en un valor infinitamente pequeño. Da un resultado diferente (ya no hay corrección esférica) pero aún no muestra la misma imagen. Vea aquí: http://imageshack.us/f/191/barreldistortioncorrect.jpg/ – Lucas
¿Podría un valor infinitamente pequeño b estar sobrecorrigiendo en la _otra dirección? – AJMansfield