Entwickler-Ecke
Algorithmen, Optimierung und Assembler - Bild/Pixel Interpolation
Aya - Di 09.01.07 23:39
Titel: Bild/Pixel Interpolation
Hi,
weiß jemand wie ich ein Bild, bzw Pixel Interpolieren kann?
Sagen wir, ich habe ein Bild der größe 512x512 und möchte bei dem das Pixel an der stelle 128.7x63.2 haben, sprich kein ganzes Pixel, sondern den Farbwert zwischen 4 Pixeln.
Ich bräuchte also etwas á la:
function GetInterpolatedColor(Bitmap: TBitmap; X, Y: Single): TColor;
Hat da jemand was, bzw weiß wie das geht?
Aya~
PS: Ich brauche es nicht um ein Bild zu resizen o.Ä. mir geht es wirklich nur um einige spezielle X,Y koordinaten.
UGrohne - Di 09.01.07 23:47
Ich kenn mich mit Interpolation nicht so genau aus, aber hast Du schon mal versucht, einen gewichteten Durchschnitt der RGB-Komponenten der Pixel zu nehmen? Also in Deinem Beispiel in etwa so
P1 = 128x63
P2 = 128x64
P3 = 129x63
P4 = 129x64
Quelltext
1:
| Rneu = (8 x R1 + 2 x R2 + 7 x R4 + 3 x R3) / 20 |
Entsprechendes für die anderen Farbkomponenten.
jaenicke - Mi 10.01.07 00:04
Ich würde mal sagen bei der Betrachtung von nur 4 Pixeln ist eine ungewichtete Betrachtung sinnvoller. Also ein ganz normales arithmetisches Mittel.
Lediglich bei einer "echten" Interpolation würde man gewichtet vorgehen, dabei die Gewichte aber aus einer größeren Anzahl von Pixeln (ich habe wahlweise 16 oder 36 genommen) berechnen. Nur dann kann man ja versuchen Kontrastverläufe etc. mit in die Berechnung einfließen zu lassen, wofür Gewichte bspw. sinnvoll sind. Aber das ist in diesem Fall ja unwichtig...
Aya - Mi 10.01.07 02:17
Hi,
UGrohne hat folgendes geschrieben: |
Quelltext 1:
| Rneu = (8 x R1 + 2 x R2 + 7 x R4 + 3 x R3) / 20 |
Entsprechendes für die anderen Farbkomponenten. |
Ne, das geht nicht.. weil du so nur jeweils 2 pixel einbeziehst... aber du mußt ja zwischen allen 4 interpolieren.
jaenicke hat folgendes geschrieben: |
Ich würde mal sagen bei der Betrachtung von nur 4 Pixeln ist eine ungewichtete Betrachtung sinnvoller. Also ein ganz normales arithmetisches Mittel. |
Wie, was? Ob sinnvoller oder nicht ist halt ne frage wofür man es brauch.. ich würde nicht fragen wie ich interpoliere wenn ich es nicht brauche ;)
Aya~
jaenicke - Mi 10.01.07 04:00
Aya hat folgendes geschrieben: |
Hi,
UGrohne hat folgendes geschrieben: | Quelltext 1:
| Rneu = (8 x R1 + 2 x R2 + 7 x R4 + 3 x R3) / 20 |
Entsprechendes für die anderen Farbkomponenten. |
Ne, das geht nicht.. weil du so nur jeweils 2 pixel einbeziehst... aber du mußt ja zwischen allen 4 interpolieren. |
Mit R1 bis R4 sind doch alle vier Rotwerte der vier Pixel einbezogen. Und genauso geht es dann doch mit grün und blau.
Aya hat folgendes geschrieben: |
jaenicke hat folgendes geschrieben: | Ich würde mal sagen bei der Betrachtung von nur 4 Pixeln ist eine ungewichtete Betrachtung sinnvoller. Also ein ganz normales arithmetisches Mittel. |
Wie, was? Ob sinnvoller oder nicht ist halt ne frage wofür man es brauch.. ich würde nicht fragen wie ich interpoliere wenn ich es nicht brauche ;) |
Ich wollte damit lediglich sagen, dass mit nur 4 Pixeln die Werte relativ ungenau sein dürften. Sorry, wenn es anders rüberkam. Da ist dann die Frage, ob etwas besseres herauskommt, wenn man die benachbarten Pixel entsprechend ihrem Anstand zum gesuchten Punkt bewertet als wenn man so tut, als wären die genauso weit vom gesuchten Punkt entfernt.
Aber bei starken Kontrasten ist das sicherlich so am besten. Bei meinen Experimenten hat es aber nur die Berechnung verlangsamt, die Ergebnisse waren bei gewichteten Werten jedoch praktisch identisch zu ungewichteten, als ich nur 4 Pixel betrachtet habe.
Egal, jedenfalls ist doch das von
UGrohne genau so gemeint, wie eine solche exakte Interpolation unter Einbeziehung aller vier Pixel entsprechend ihres Abstandes zum gesuchten Punkt aussehen müsste. Es fehlt allerdings noch die genaue Berechnung der Gewichte.
Die würde ich folgendermaßen machen:
Ich nummeriere mal die Pixel von P1 bis P4 zeilenweise, P1 und P2 sind also die beiden oberen Pixel. R1 bis R4 sind die daszugehörigen Rotwerte. P ist der gesuchte Punkt. R der dazugehörige Rotwert.
Delphi-Quelltext
1:
| R := R1 + ((P.x - P1) * (R2 - R1) + ((P.x - P1) * (P.x - P1) + (P.y - P1) * (P.y - P1)) * (R4 - R1) + (P.y - P1) * (R3 - R1)) div 3; |
Das wäre eine mögliche Berechnung. Ich verrechne den linken oberen Pixel mit den anderen dreien, wobei jeweils der Abstand des gesuchten Punkts zum linken oberen das Entscheidende Kriterium für die Gewichtung ist.
Ich hoffe ich habe mich jetzt nicht vertan. Ich bin schon etwas müde.
Es gibt allerdings noch viele andere Algorithmen. Die meisten funktionieren jedoch erst mit mehr als 4 Pixeln, weil sie beispielsweise auch Bildfehler korrigieren, indem einzelne "stark abweichende" Pixel gering gewichtet werden.
Reinhard Kern - Mi 10.01.07 07:02
jaenicke hat folgendes geschrieben: |
[
...
Es gibt allerdings noch viele andere Algorithmen. Die meisten funktionieren jedoch erst mit mehr als 4 Pixeln, weil sie beispielsweise auch Bildfehler korrigieren, indem einzelne "stark abweichende" Pixel gering gewichtet werden. |
Hallo,
korrekt ist meiner Meinung nach, die Pixel als Quadrate zu betrachten und den gesuchten Pixel über die vorhandenen zu legen nach folgender Skizze. Die Gewichtung ergibt sich dann aus dem Flächenanteil des gesuchten Quadrats, der auf jedes der 4 überdeckten Quadrate fällt. Das ist auch ganz einfach zu berechnen, mit den Zahlen in der Skizze sind die Koeffizienten
0,06 0,14
0,24 0,56
was automatisch 1,0 ergibt.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| | | | -------------------------------------- | 100/100 | 101/100 | | | | | | | | | | | | | | .....|............ | | . | . | | . | . | ------------.------------------------- | . | . | | . | # <<<<<<<<<<<<<<< gesuchter Pixel | . | . | 101,7 / 101,8 | . | . | | . | . | | .....|............ | | | | | 100/101 | 101/101 | -------------------------------------- | | | | | | |
Bitte um Verzeihung wegen der Vergewaltigung des Delphi-Tags.
Gruss Reinhard
Phantom1 - Mi 10.01.07 12:38
Ich stimme "Reinhard Kern" zu, die flächenmäßige Gewichtung ist gut, hab mal versucht das ganze in delphi umzusetzen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| function GetInterpolatedColor(Bitmap: TBitmap; X, Y: Single): TColor; type PRGBArray = ^TRGBArray; TRGBArray = array[0..0] of TRGBQuad; var p: PRGBArray; TruncX, TruncY: Integer; FracX, FracY: Single; TopLeft, TopRight, BottomLeft, BottomRight: Single; r, g, b: Single; begin if x<0 then x:=0 else if x>Bitmap.Width-2 then x:=Bitmap.Width-2; if y<0 then y:=0 else if y>Bitmap.Height-2 then y:=Bitmap.Height-2; Bitmap.PixelFormat:=pf32bit; TruncX:=Trunc(X); TruncY:=Trunc(Y); FracX:=X-TruncX; FracY:=Y-TruncY; TopLeft := (1-FracX) * (1-FracY); TopRight := (FracX) * (1-FracY); BottomLeft := (1-FracX) * (FracY); BottomRight:= (FracX) * (FracY); p:=Bitmap.ScanLine[TruncY]; r:=p^[TruncX].rgbRed * TopLeft + p^[TruncX+1].rgbRed * TopRight; g:=p^[TruncX].rgbGreen * TopLeft + p^[TruncX+1].rgbGreen * TopRight; b:=p^[TruncX].rgbBlue * TopLeft + p^[TruncX+1].rgbBlue * TopRight; p:=Bitmap.ScanLine[TruncY+1]; r:=r + p^[TruncX].rgbRed * BottomLeft + p^[TruncX+1].rgbRed * BottomRight; g:=g + p^[TruncX].rgbGreen * BottomLeft + p^[TruncX+1].rgbGreen * BottomRight; b:=b + p^[TruncX].rgbBlue * BottomLeft + p^[TruncX+1].rgbBlue * BottomRight; Result:=RGB(Round(r), Round(g), Round(b)); end; |
mfg
Aya - Mi 10.01.07 20:41
Hi,
danke für die antworten :)
Der Code von Phantom1 sieht in etwa so aus wie das was ich mir zusammengebastelt hatte, aber ich hab im netz dashier gefunden:
Interpolating Bitmap Resampler v.1.2 [
http://www.torry.net/quicksearchd.php?String=resampler&Title=Yes]
das ist zwar für nen komplettes Bild zum resamplen, aber ich hab mir einfach das was ich brauchte rausgesucht.. dadurch ist das ganze jetzt nur ~10 zeilen lang und ich hab die möglichkeit zwischen allen möglichen Filtern auszuwählen für's resampling :)
Aber tausend dank trotzdem~ :D
Aya~
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!