Suche einen Algorithmus zum entfernen des Fischaugeneffekts
-
Wie meinst du das?
Du berechnest vorwärts? Rechne lieber rückwärts
Ich rechne nach den zwei Formeln. Wie gebe ich da eine Richtung an?
-
Denis103 schrieb:
@ __HIRSCH_H__
Es lag am Vorzeichen. Bei postiven Kappa zieht er es auseinander und die Kurven werden zu Geraden und bei negativen Kappa erzeugt er diesen Fischaugeneffekt.
Ich bin aber nicht so ganz zufrieden damit, weil das Bild gezogen wird, wodurch Stellen entstehen an denen keine Pixel mehr vorhanden sind. Gibts dafür noch eine Lösung? Vielleicht eine Art Filter?
Genau wie Jester gesagt hat, rechne rückwärts, das heisst du musst dein Zielbild sampeln, nicht das Ausgangsbild. Die Farben für das Zielbild kannste dann mit einer beliebigen Funktion (nearest-neigbour, linear oder quadratisch) aus den berechneten float Koordinaten interpolieren.
-
Denis103 schrieb:
Wie meinst du das?
Du berechnest vorwärts? Rechne lieber rückwärts
Ich rechne nach den zwei Formeln. Wie gebe ich da eine Richtung an?
Ein codebeispiel:
const int nW2 = from.width()/2; const int nH2 = from.height()/2; for(int nY=0; nY<to.height(); ++nY) { const int nYC = nY - nH2; for(int nX=0; nX<to.width(); ++nX) { const int nXC = nX - nW2; const float fR = nXC*nXC + nYC*nYC; const float fX = nXC/(1.0f+fKappa*fR) + nW2; const float fY = nYC/(1.0f+fKappa*fR) + nH2; if (fX >= 0 && fX < from.width() && fY >= 0 && fY < from.height()) to(nX, nY) = interpolate(fX, fY); } }
-
ich mach das so:
:: Ist ne BCB- Variante !!! (VCL)
:: ist auf 24Bit Farbtiefe getrimmt !!!
:: Interpolator ist entfernt !!!:: Berechnet 4 verschiedene FishEye- Geometrien wahlweise
:: Kann das Bild dabei Skalieren
Die Bildabmessungen werden gehalten, nur der Inhalt wird "gezoomt":: Zu jedem Punkt im ERGEBNIS- Bild wird die Koordinate im AUSGANGS- Bild
berechnet und Der Farbwert von dort geholt
Die Berechnungen erfolgen deshalb mit double, um vernünftig interpolieren
zu können.Die Funktion ist in einem fertigen Programm integriert und klappt !!
(Da ist dann allerdings eine Interpolation drin, die abhängig von der Perspektive jedes Pixel passend berechnet)Die Formeln sind gemäss Prof. Dersch !!!
(siehe vorigen Link)//Funktion zum Entzerren von FishEye- Bildern //Parameter: //Originalbild //Zielbild //Brennweite //Cropfaktor //Skalierfaktor //FishEye- Methode void __fastcall FishEyePicNoInterpolate(Graphics::TBitmap *OrgBM,Graphics::TBitmap *DestBM,double Aperture, double LensFactor, double FishEyeZoom, int FishEyeMode) { double FCorrVal=1; FCorrVal=FCorrVal * max(OrgBM->Height,OrgBM->Width) / 36.0; // FCorrVal=FCorrVal * min(OrgBM->Height,OrgBM->Width) / 24.0; double F=Aperture * FCorrVal * LensFactor; int ImgW=OrgBM->Width; int ImgH=OrgBM->Height; double ImgW_2=ImgW / 2.0; double ImgH_2=ImgH / 2.0; double RBQ,RB; double ROrg; TPoint MP; MP.x=(ImgW - 1) / 2.0;// + 1; MP.y=(ImgH - 1) / 2.0;// + 1; int X,Y; int XOrg,YOrg; double XOrgDbl,YOrgDbl,XSrcDbl,YSrcDbl; PRGBTriple Row; PRGBTriple OrgRow; PRGBTriple *POrgRow=NULL; DestBM->Width=ImgW; DestBM->Height=ImgH; DestBM->PixelFormat=pf24bit; OrgBM->PixelFormat=pf24bit; POrgRow=(PRGBTriple*)malloc(sizeof(PRGBTriple) * ImgH); if (POrgRow!=NULL) { for (int Zeile=0;Zeile<ImgH;Zeile++) POrgRow[Zeile]=(PRGBTriple)OrgBM->ScanLine[Zeile]; try { for (Y=0;Y<ImgH;Y++) { Row=(PRGBTriple)DestBM->ScanLine[Y]; YSrcDbl=ImgH_2 - Y; for (X=0;X<ImgW;X++) { XSrcDbl=-ImgW_2 + X; XOrgDbl=XSrcDbl; YOrgDbl=YSrcDbl; XOrgDbl=XOrgDbl / FishEyeZoom; YOrgDbl=YOrgDbl / FishEyeZoom; RBQ=XOrgDbl * XOrgDbl + YOrgDbl * YOrgDbl; RB=sqrt(RBQ); switch (FishEyeMode) { case 0: ROrg=2 * F * sin(atan(RB / F) / 2); if (RB>0) { XOrgDbl=XOrgDbl * ROrg / RB; YOrgDbl=YOrgDbl * ROrg / RB; } break; case 1: ROrg=F * atan(RB / F); if (RB>0) { XOrgDbl=XOrgDbl * ROrg / RB; YOrgDbl=YOrgDbl * ROrg / RB; } break; case 2: ROrg=F * sin(atan(RB / F)); if (RB>0) { XOrgDbl=XOrgDbl * ROrg / RB; YOrgDbl=YOrgDbl * ROrg / RB; } break; case 3: ROrg=2 * F * tan(atan(RB / F) / 2); if (RB>0) { XOrgDbl=XOrgDbl * ROrg / RB; YOrgDbl=YOrgDbl * ROrg / RB; } break; } YOrgDbl=ImgH_2 - YOrgDbl; XOrgDbl=ImgW_2 + XOrgDbl; YOrg=int(YOrgDbl); if ((YOrg<0)||(YOrg>=ImgH)) continue; OrgRow=POrgRow[YOrg]; XOrg=XOrgDbl; if (XOrgDbl<0) XOrgDbl=0; if (YOrgDbl<0) YOrgDbl=0; if ((XOrg>=0)&&(XOrg<ImgW)) { //Hier sollte eine Interpolation stattfinden !!! Row[X].rgbtRed=OrgRow[XOrg].rgbtRed; Row[X].rgbtGreen=OrgRow[XOrg].rgbtGreen; Row[X].rgbtBlue=OrgRow[XOrg].rgbtBlue; } } } } catch(...) { Application->MessageBox("Sie haben ungültige Werte gewählt\r\nDie Berechnung ist nicht möglich.\r\n\r\nErhöhen Sie die Brennweite oder\r\nsetzen Sie den Horizont mehr zur Bildmitte.","Geometriefehler!!!",MB_OK + MB_ICONEXCLAMATION); } free(POrgRow); } } //--------------------------------------------------------------------------- //Aufruf der Funktion void __fastcall DeFishEyeClick(TObject *Sender) { FishEyePicNoInterpolate(Origin->Bitmap, //Ausgangsbild Recti->Picture->Bitmap, //Entzerrtes Bild FL->Caption.ToDouble(), //Brennweite 1, //Crop- Faktor (Standard sollte 1 sein) 1, //Zoom- faktor (Vergrösserungsfaktor = beliebig, positiv) 1); //FishEye- Modus (0 .. 3) }
Origin und Recti sind BCB- TImage elemente, die die Graphic als TBitmap kapseln.
TBitmap hat Scanline zum schnellen Zugriff auf Pixel- Zeile
-
Das klappt rückwärts super. Jetzt verstehe ich auch wie ihr das meintet.
Habt nochmal vielen Dank für eure tolle Unterstützung!