Question

  

BOUNTY MISE À JOUR STATUT:

j'ai découvert comment cartographier une lentille linéaire , à partir des coordonnées destination à source coordonnées.

Comment calculez-vous la distance radiale du centre pour aller de fisheye rectiligne?

  • 1). Je lutte en fait à inverser et à la carte la source vers les coordonnées de destination. Quelle est l'inverse, dans le code dans le style des fonctions de conversion I posté?

  • .
  • 2) Je vois aussi que mon undistortion est imparfaite sur certains objectifs - vraisemblablement ceux qui ne sont pas strictement linéaire. Quel est l'équivalent de va-et-de la source et de destination coordonnées pour les lentilles? Encore une fois, plus de code que les formules mathématiques juste ... s'il vous plaît


  

Question initialement déclaré:

J'ai quelques points qui décrivent des positions dans une image prise avec un objectif fisheye.

Je veux convertir ces points en coordonnées rectilignes. Je veux undistort l'image.

Je l'ai trouvé cette description de la façon de générer un effet fisheye, mais pas comment l'inverser .

Il y a aussi un qui décrit comment utiliser les outils pour le faire; ces images sont de ce qui suit:

(1) : SOURCE href="http://photo.net/learn/fisheye/fe01.jpg" rel="noreferrer"> lien Photo originale < br>
Entrée:. Image originale avec une distorsion du poisson des yeux pour fixer

(2) : DESTINATION href="http://photo.net/learn/fisheye/fe04.jpg" rel="noreferrer"> lien Photo originale < br>
Sortie:. Correction d'image (technique aussi avec correction en perspective, mais c'est une étape distincte)

Comment calculer la distance radiale du centre pour aller de fisheye rectiligne?

regarde mon talon de fonction comme ceci:

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;
}

Sinon, je pouvais faire convertir l'image de fisheye rectiligne avant de trouver les points, mais je suis complètement embrouillé par le documentation OpenCV . Est-il un moyen simple de le faire dans OpenCV, et remplit-elle assez bien pour le faire à un flux vidéo en direct?

Était-ce utile?

La solution

href="http://wiki.panotools.org/Fisheye_Projection" vous mentionnez indique que la projection par une caméra sténopé (qui ne présente pas distorsion de l'objectif) est modélisé par

R_u = f*tan(theta)

et la projection par des caméras à lentille fisheye commun (soit déformé) est modélisé par

R_d = 2*f*sin(theta/2)

Vous savez déjà r_d et thêta et si vous saviez la distance focale (représentée par f) corriger alors l'image équivaudrait à calculer R_U en termes de r_d et thêta de l'appareil. En d'autres termes,

R_u = f*tan(2*asin(R_d/(2*f)))

est la formule que vous cherchez. L'estimation de la distance focale f peut être résolu par l'étalonnage de l'appareil photo ou d'autres moyens tels que permettant à l'utilisateur de fournir une rétroaction sur la façon dont l'image est corrigée en utilisant la connaissance ou de la scène originale.

Afin de résoudre le même problème en utilisant OpenCV, vous devez obtenir des paramètres intrinsèques et des coefficients de distorsion de l'objectif de l'appareil photo. Voir, par exemple, le chapitre 11 de Learning OpenCV (ne pas oublier de vérifier la correction ). Ensuite, vous pouvez utiliser un programme tel que celui-ci (écrit avec les liaisons Python pour OpenCV) afin d'inverser la distorsion de l'objectif:

#!/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)

Notez également que OpenCV utilise un modèle de distorsion de l'objectif très différent de celui de la page Web que vous lié.

Autres conseils

(Affiche originale, offrant une alternative)

La fonction suivante destination des cartes (rectiligne) Coordonnées de source (fisheye-déformée) coordonne. (je vous remercie de l'aide pour renverser)

Je suis arrivé à ce point par essais et erreurs: Je ne saisissais pas fondamentalement pourquoi ce code fonctionne, explications et une plus grande précision apprécié

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)))

Lorsqu'il est utilisé avec un facteur de 3,0, il undistorts avec succès les images utilisées comme exemples (j'ai fait aucune tentative d'interpolation de qualité):

lien mort

(ce qui est du poste de blog, à titre de comparaison:)

Utilisation Panotools

Si vous pensez que vos formules sont exactes, vous pouvez comput une formule exacte avec TRIG, comme suit:

Rin = 2 f sin(w/2) -> sin(w/2)= Rin/2f
Rout= f tan(w)     -> tan(w)= Rout/f

(Rin/2f)^2 = [sin(w/2)]^2 = (1 - cos(w))/2  ->  cos(w) = 1 - 2(Rin/2f)^2
(Rout/f)^2 = [tan(w)]^2 = 1/[cos(w)]^2 - 1

-> (Rout/f)^2 = 1/(1-2[Rin/2f]^2)^2 - 1

Cependant, comme @jmbr dit, la distorsion de la caméra réelle dépendra de l'objectif et le zoom. Plutôt que de compter sur une formule fixe, vous pouvez essayer une expansion polynomiale:

Rout = Rin*(1 + A*Rin^2 + B*Rin^4 + ...)

Par peaufinage premier A, coefficients d'ordre supérieur, vous pouvez calculer une fonction locale raisonnable (la forme de l'expansion tire profit de la symétrie du problème). En particulier, il devrait être possible de calculer les coefficients initiaux pour rapprocher la fonction théorique ci-dessus.

En outre, pour de bons résultats, vous devez utiliser un filtre d'interpolation pour générer votre image corrigée. Tant que la distorsion est pas trop grande, vous pouvez utiliser le type de filtre que vous utilisez pour redimensionner l'image linéaire sans trop de problème.

Edit: selon votre demande, le facteur d'échelle équivalent pour la formule ci-dessus:

(Rout/f)^2 = 1/(1-2[Rin/2f]^2)^2 - 1
-> Rout/f = [Rin/f] * sqrt(1-[Rin/f]^2/4)/(1-[Rin/f]^2/2)

Si vous tracez la formule ci-dessus à côté tan (Rin / f), vous pouvez voir qu'ils sont très similaires en forme. Fondamentalement, la distorsion de la tangente devient sévère avant sin (w) devient très différent de w.

La formule inverse doit être quelque chose comme:

Rin/f = [Rout/f] / sqrt( sqrt(([Rout/f]^2+1) * (sqrt([Rout/f]^2+1) + 1) / 2 )

Je aveuglément mis à exécution les formules de , donc je ne peux pas garantir qu'il ferait ce que vous avez besoin.

Utilisez auto_zoom pour obtenir la valeur du paramètre zoom.


def dist(x,y):
    return sqrt(x*x+y*y)

def fisheye_to_rectilinear(src_size,dest_size,sx,sy,crop_factor,zoom):
    """ returns a tuple of dest coordinates (dx,dy)
        (note: values can be out of range)
 crop_factor is ratio of sphere diameter to diagonal of the source image"""  
    # convert sx,sy to relative coordinates
    rx, ry = sx-(src_size[0]/2), sy-(src_size[1]/2)
    r = dist(rx,ry)

    # focal distance = radius of the sphere
    pi = 3.1415926535
    f = dist(src_size[0],src_size[1])*factor/pi

    # calc theta 1) linear mapping (older Nikon) 
    theta = r / f

    # calc theta 2) nonlinear mapping 
    # theta = asin ( r / ( 2 * f ) ) * 2

    # calc new radius
    nr = tan(theta) * zoom

    # back to absolute coordinates
    dx, dy = (dest_size[0]/2)+rx/r*nr, (dest_size[1]/2)+ry/r*nr
    # done
    return (int(round(dx)),int(round(dy)))


def fisheye_auto_zoom(src_size,dest_size,crop_factor):
    """ calculate zoom such that left edge of source image matches left edge of dest image """
    # Try to see what happens with zoom=1
    dx, dy = fisheye_to_rectilinear(src_size, dest_size, 0, src_size[1]/2, crop_factor, 1)

    # Calculate zoom so the result is what we wanted
    obtained_r = dest_size[0]/2 - dx
    required_r = dest_size[0]/2
    zoom = required_r / obtained_r
    return zoom

Je pris ce que JMBR a fait et essentiellement renoncé à cette solution. Il a pris le rayon de l'image déformée (Rd, qui est, la distance en pixels à partir du centre de l'image) et a trouvé une formule pour Ru, le rayon de l'image non déformée.

Vous voulez aller dans l'autre sens. Pour chaque pixel de la non faussée (image traitée), vous voulez savoir ce que le pixel correspondant est dans l'image déformée. En d'autres termes, étant donné (xu, yu) -> (xd, yd). Vous remplacez alors chaque pixel de l'image non déformée avec son pixel correspondant de l'image déformée.

À partir où JMBR a fait, je fais l'inverse, trouver Rd en fonction de Ru. Je reçois:

Rd = f * sqrt(2) * sqrt( 1 - 1/sqrt(r^2 +1))

où f est la distance focale en pixels (je vous expliquerai plus tard), et r = Ru/f.

La distance focale pour mon appareil photo était de 2,5 mm. La taille de chaque pixel sur mon CCD était 6 carré um. f est donc 2500/6 = 417 pixels. Cela peut être trouvé par tâtonnement.

Trouver Rd vous permet de trouver le pixel correspondant dans l'image déformée en coordonnées polaires.

L'angle de chaque pixel à partir du point central est le même:

theta = arctan( (yu-yc)/(xu-xc) ) où xc, sont les points Yc du centre.

Alors,

xd = Rd * cos(theta) + xc
yd = Rd * sin(theta) + yc

Assurez-vous que vous savez quel quadrant vous êtes.

Voici le code C # je

 public class Analyzer
 {
      private ArrayList mFisheyeCorrect;
      private int mFELimit = 1500;
      private double mScaleFESize = 0.9;

      public Analyzer()
      {
            //A lookup table so we don't have to calculate Rdistorted over and over
            //The values will be multiplied by focal length in pixels to 
            //get the Rdistorted
          mFisheyeCorrect = new ArrayList(mFELimit);
            //i corresponds to Rundist/focalLengthInPixels * 1000 (to get integers)
          for (int i = 0; i < mFELimit; i++)
          {
              double result = Math.Sqrt(1 - 1 / Math.Sqrt(1.0 + (double)i * i / 1000000.0)) * 1.4142136;
              mFisheyeCorrect.Add(result);
          }
      }

      public Bitmap RemoveFisheye(ref Bitmap aImage, double aFocalLinPixels)
      {
          Bitmap correctedImage = new Bitmap(aImage.Width, aImage.Height);
             //The center points of the image
          double xc = aImage.Width / 2.0;
          double yc = aImage.Height / 2.0;
          Boolean xpos, ypos;
            //Move through the pixels in the corrected image; 
            //set to corresponding pixels in distorted image
          for (int i = 0; i < correctedImage.Width; i++)
          {
              for (int j = 0; j < correctedImage.Height; j++)
              {
                     //which quadrant are we in?
                  xpos = i > xc;
                  ypos = j > yc;
                     //Find the distance from the center
                  double xdif = i-xc;
                  double ydif = j-yc;
                     //The distance squared
                  double Rusquare = xdif * xdif + ydif * ydif;
                     //the angle from the center
                  double theta = Math.Atan2(ydif, xdif);
                     //find index for lookup table
                  int index = (int)(Math.Sqrt(Rusquare) / aFocalLinPixels * 1000);
                  if (index >= mFELimit) index = mFELimit - 1;
                     //calculated Rdistorted
                  double Rd = aFocalLinPixels * (double)mFisheyeCorrect[index]
                                        /mScaleFESize;
                     //calculate x and y distances
                  double xdelta = Math.Abs(Rd*Math.Cos(theta));
                  double ydelta = Math.Abs(Rd * Math.Sin(theta));
                     //convert to pixel coordinates
                  int xd = (int)(xc + (xpos ? xdelta : -xdelta));
                  int yd = (int)(yc + (ypos ? ydelta : -ydelta));
                  xd = Math.Max(0, Math.Min(xd, aImage.Width-1));
                  yd = Math.Max(0, Math.Min(yd, aImage.Height-1));
                     //set the corrected pixel value from the distorted image
                  correctedImage.SetPixel(i, j, aImage.GetPixel(xd, yd));
              }
          }
          return correctedImage;
      }
}

J'ai trouvé ce fichier pdf et je l'ai prouvé que les mathématiques sont correctes (sauf pour la ligne vd = *xd**fv+v0 which should say vd = **yd**+fv+v0).

http://perception.inrialpes.fr/CAVA_Dataset/Site/files /Calibration_OpenCV.pdf

Il n'utilise toutes les dernières co-que OpenCV a coefficients disponible mais je suis sûr qu'il pourrait être adapté assez facilement.

double k1 = cameraIntrinsic.distortion[0];
double k2 = cameraIntrinsic.distortion[1];
double p1 = cameraIntrinsic.distortion[2];
double p2 = cameraIntrinsic.distortion[3];
double k3 = cameraIntrinsic.distortion[4];
double fu = cameraIntrinsic.focalLength[0];
double fv = cameraIntrinsic.focalLength[1];
double u0 = cameraIntrinsic.principalPoint[0];
double v0 = cameraIntrinsic.principalPoint[1];
double u, v;


u = thisPoint->x; // the undistorted point
v = thisPoint->y;
double x = ( u - u0 )/fu;
double y = ( v - v0 )/fv;

double r2 = (x*x) + (y*y);
double r4 = r2*r2;

double cDist = 1 + (k1*r2) + (k2*r4);
double xr = x*cDist;
double yr = y*cDist;

double a1 = 2*x*y;
double a2 = r2 + (2*(x*x));
double a3 = r2 + (2*(y*y));

double dx = (a1*p1) + (a2*p2);
double dy = (a3*p1) + (a1*p2);

double xd = xr + dx;
double yd = yr + dy;

double ud = (xd*fu) + u0;
double vd = (yd*fv) + v0;

thisPoint->x = ud; // the distorted point
thisPoint->y = vd;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top