Bilder zusammenfügen - Wie ARGB verrechnen?

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

M0rgenstern

Betreff: Bilder zusammenfügen - Wie ARGB verrechnen?

BeitragMi, Dez 14, 2011 15:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo Leute,
Ich bin gerade für nen Kumpel dabei ein Programm zu schreiben, mit dem man Bilder zusammenfügen kann.
Also ein kleineres Bild soll über ein größeres drübergelegt werden und das neue Bild abgespeichert werden.
Dazu lade ich die beiden Bilder als Pixmaps in den Speicher und mache folgendes:

Code: [AUSKLAPPEN]
Function AddImages:TPixmap(pPix1:TPixmap, pPix2:TPixmap)
   Local newPix:TPixmap = TPixmap.Create(pPix1.width, pPix1.height, pPix1.format)
   Local tsStream:TStream = WriteFile("Out.txt") 'Datei um Werte zu speichern
   For Local iX:Int = 0 To (newPix.width - 1)
      For Local iY:Int = 0 To (newPix.height - 1)
         If (iX < pPix2.width) And (iY < pPix2.height) Then
            Local argb1:Int = pPix2.ReadPixel(iX, iY)
            Local argb2:Int = pPix1.ReadPixel(iX, iY)
            Local added:Int = AddARGB(argb1, argb2, tsStream)
            newPix.WritePixel(iX, iY, added)
         Else
            newPix.WritePixel(iX, iY, pPix1.ReadPixel(iX, iY))
         EndIf
      Next
   Next
   
   Return newPix
End Function


BlitzMax: [AUSKLAPPEN]
Function AddARGB:Int(argb1:Int, argb2:Int, pStream:TStream = Null)
Local a1:Int = (argb1 & $FF000000) / $1000000
Local r1:Int = (argb1 & $FF0000) / $10000
Local g1:Int = (argb1 & $FF00) / $100
Local b1:Int = argb1 & $FF

Local a2:Int = (argb2 & $FF000000) / $1000000
Local r2:Int = (argb2 & $FF0000) / $10000
Local g2:Int = (argb2 & $FF00) / $100
Local b2:Int = argb2 & $FF

Local a3:Int' = (a1 + a2) Mod 101
Local r3:Int' = (r1 + r2) Mod 256
Local g3:Int' = (g1 + g2) Mod 256
Local b3:Int' = (b1 + b2) Mod 256

If(a1 < a2) Then
If (a1 < 0) Then
a3 = a2
Else
a3 = a1
EndIf
Else
If (a2 < 0) Then
a3 = a1
Else
a3 = a2
EndIf
EndIf

If(r1 > r2)
r3 = r1 - r2
Else
r3 = r2 - r1
EndIf

If(g1 > g2)
g3 = g1 - g2
Else
g3 = g2 - g1
EndIf

If(b1 > b2)
b3 = b1 - b2
Else
b3 = b2 - b1
EndIf

Local argb3:Int = a3 * $1000000 + r3 * $10000 + g3 * $100 + b3

'In Datei schreiben:
If (pStream <> Null)
pStream.WriteLine(a1 + "|" + r1 + "|" + b1 + "|" + g1 + " (argb: " + argb1 + ") AND " + a2 + "|" + r2 + "|" + b2 + "|" + g2 + " (argb: " + argb2 + ") = " + a3 + "|" + r3 + "|" + b3 + "|" + g3 + "(argb: " + argb3 + ")")
EndIf
Return argb3
End Function


Das Problem, das ich jetzt habe ist: In meinem Wasserzeichen ist schwarzer, halbtransparenter Text. Das heißt der hat einen RGB Wert von 0,0,0. So wie ich oben rechne wird also nur das andere Bild übernommen, und der Text wird nicht eingezeichnet.
Kann mir bitte jemand sagen, wie ich die beiden argb Werte miteinander verrechnen muss, damit das eine Bild (dessen Hintergrund transparent ist) über dem anderen liegt und die Transparent des oberen Bildes beachtet wird?

Lg, M0rgenstern

Xeres

Moderator

BeitragMi, Dez 14, 2011 15:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Frage: Warum zeichnest du das nicht einfach auf den Backbuffer und grabst dann das Ergebnis?
Arrow GrabImage
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

M0rgenstern

BeitragMi, Dez 14, 2011 16:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Hey Xeres, Danke.
Das scheint wirklich schneller und einfacher zu gehen.
Das Problem ist nur: Scheinbar werden halbtransparente Farben nicht beachtet. Also Teile im Bild die halbtransparent sind werden gar nicht gezeichnet, bzw. die schwarze Schrift wird total zerteilt.
Gibts da ne Möglichkeit das anders zu machen?

Lg, M0rgenstern

Xeres

Moderator

BeitragMi, Dez 14, 2011 16:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Nicht SetBlend(ALPHABLEND) vergessen!
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

Propellator

BeitragMi, Dez 14, 2011 16:36
Antworten mit Zitat
Benutzer-Profile anzeigen
Da du sowieso binäre Operationen vornimmst, wäre es eventuell empfehlenswert den PixelPtr der Pixmap zu nehmen und dann die einzelnen Bytes zu OR-en (mit |). Wobei ich mir beim Or unsicher bin. Razz
Propellator - Alles andere ist irrelephant.
Elefanten sind die Könige der Antarktis.
 

PhillipK

BeitragMi, Dez 14, 2011 16:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm, auf anhieb würde ich es wie das "Additive Blendingn mit alpha" aus OpenGl lösen.
falls du den befehl glBlendfunc Kennst:

GL_SRC_ALPHA, GL_ONE -> heißt im klartext, farbkomponenten von dem "oberen" bild (wasserzeichen?) werden mit dem ALPHAwert von dem oberen bild skaliert (bedenke: die werte sollten zwischen 0 und 1 liegen, am ende wieder *255 gerechnet werden^^)

Die farbkomponenten vom "unteren" bild werden nicht verändert ( bzw alle werden *1 genommen).
Auszug aus der DGL wiki:

Zitat:
Im folgenden sind Rq, Gq, Bq und Aq die Farbkomponenten des Fragmentes, dass neu dazukommt. Rz, Gz, Bz und Az sind die Farbkomponenten des bereits im Framebuffer enthaltenen Pixels und Rn, Gn, Bn und An sind die Farbkomponenten des sich ergebenden Fragmentes. Alle Werte sind skaliert auf einen Bereich von 0.0 bis 1.0, inklusive. Die Ergebnisswerte werden danach auf den Bereich 0.0 bis 1.0 geclampt.

(anmerkung: Fragment ist dein "oberes Bild", Framebuffer ist dein "unteres Bild")

Zitat:
Additives Blending (mit Alpha)

Das funktioniert eigentlich genauso wie das andere additive Blending, nur wird hier der Alphawert des neuen Fragmentes beachtet.

Rn = Rz + Rq * Aq;
Gn = Gz + Gq * Aq;
Bn = Bz + Bq * Aq;
An = Az + Aq * Aq;

Die beiden Konstanten hierfür sind GL_SRC_ALPHA und GL_ONE.



Ich hab dazu mal ein kleines beispiel geschrieben, hoffentlich verständlich.
Allerdings ist mir auf die schnelle nicht eingefallen, wie die farbwerte am ende miteinander verrechnet.
also hab ich von der DGL wiki die formel für Additives Blending mit alpha rausgekramt und hoffentlich richtig umgesetzt ^^

BlitzMax: [AUSKLAPPEN]
SuperStrict


Graphics(800, 600)


'erste pixmap:

Local src:TPixmap = CreatePixmap(256, 256, 6)

src.ClearPixels($00000000) ' schwarz, durchsichtig.

For Local x:Int = 0 Until 256 Step 20

For Local y:Int = 0 Until 256 Step 20

'rect durchgehen:
For Local x2:Int = x To x + 10
For Local y2:Int = y To y + 10
If x2 < 0 Or x2 >= 256 Then Continue
If y2 < 0 Or y2 >= 256 Then Continue

src.WritePixel(x2, y2, ARGBToIntcol([0.5, 0.0, 0.0, 0.0]))
Next
Next

Next

Next

'zweite pixmap:

Local dst:TPixmap = CreatePixmap(256, 256, 6)

dst.ClearPixels($FFFF0000) 'komplett rot!



'Output:

Local out:TPixmap = CreatePixmap(256, 256, 6)

For Local x:Int = 0 Until 256
For Local y:Int = 0 Until 256
Local srcCol:Float[] = IntcoltoFloat(src.ReadPixel(x, y))
Local dstCol:Float[] = intcoltofloat(dst.ReadPixel(x, y))

Local outCol:Float[]

srcCol[0]:*srcCol[3] 'mit dem alphawert skalieren.
srcCol[1]:*srcCol[3] 'mit dem alphawert skalieren.
srcCol[2]:*srcCol[3] 's.o

dstCol[0]:*(1.0 - srcCol[3]) 'mit 1-src_alpha skalieren!
dstCol[1]:*(1.0 - srcCol[3])
dstCol[2]:*(1.0 - srcCol[3])

'mal additives blending:
outCol = New Float[4]
outCol[0] = dstCol[0] + srcCol[0] * srcCol[3]
outCol[1] = dstCol[1] + srcCol[1] * srcCol[3]
outCol[2] = dstCol[2] + srcCol[2] * srcCol[3]
outCol[3] = dstCol[3] + srcCol[3] * srcCol[3]

'zusammenfügen:
outCol = [1.0, ..
srcCol[0] + dstCol[0], ..
srcCol[1] + dstCol[1], ..
srcCol[2] + dstCol[2]]
'anmerkung: outcol ist nun ARGB aufgebaut (nichtmehr RGBA!)

Local col:Int = ARGBToIntcol(outcol)

out.WritePixel(x, y, col)
Next
Next


Local img:TImage = LoadImage(out)

While Not KeyHit(KEY_ESCAPE)
Cls
DrawImage(img, 200, 200)
Flip 1
Wend


Function ARGBToIntcol:Int(c:Float[])
Local a:Byte = Max(0, Min(c[0] * 255, 255))
Local r:Byte = Max(0, Min(c[1] * 255, 255))
Local g:Byte = Max(0, Min(c[2] * 255, 255))
Local b:Byte = Max(0, Min(c[3] * 255, 255))

Return (a Shl 24) | (r Shl 16) | (g Shl 8) | b
End Function

Function IntColToFloat:Float[] (col:Int)
Local a:Float = ((col & $ff000000) Shr 24) / 255.0 'zwischen 0 und 1 bringen!
Local r:Float = ((col & $00ff0000) Shr 16) / 255.0 'zwischen 0 und 1 bringen!
Local g:Float = ((col & $0000ff00) Shr 8) / 255.0 'zwischen 0 und 1 bringen!
Local b:Float = ((col & $000000ff)) / 255.0 'zwischen 0 und 1 bringen!

Return[r, g, b, a]
End Function



Edit:

Was? Oh schreck oO
Da war ich aber mal langsam!

Bist du vorher nicht auf die idee gekommen, es auf den Backbuffer zu zeichnen und zu Grabben? *g* Ich dachte, das hat einen besonderen grund, warum du das selbst machen willst ^^
Naja, ich lass mein gekritzel stehen.

M0rgenstern

BeitragMi, Dez 14, 2011 16:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Xeres hat Folgendes geschrieben:
Nicht SetBlend(ALPHABLEND) vergessen!


Ha, das wars.
Habs zwar ganz am Anfang so eingestellt, habe aber zwischendurch Graphics() aufgerufen und da wars dann natürlich wieder weg.

Vielen Dank an alle.
Klappt jetzt.

@PhillipK: Nein ich hab wirklich nicht an GrabImage gedacht.

Lg, M0rgenstern.

klin

BeitragMi, Dez 14, 2011 21:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Für diejenigen, wo auf grafische Obefläche verzichten müssen:
https://www.blitzforum.de/foru...hp?t=27981

hatte es bei mir probiert und es funktioniert 1A =)
Ist halt eine elegante Lösung. Man kann auch einfach pixmap.Paste() machen. Aber dann wird oft, wegen Transperenz, ein Loch rein gemacht.

Klin

Jan_

Ehemaliger Admin

BeitragDo, Dez 15, 2011 17:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich möchte Kurz die Theorie dahinter erläutern, falls das hier jemand mal in der Suche mal findet.

zuerst müssen alle Ebenen sotiert werden, d.H. die hinterste ebne zuerst.
weiterhin sollte man unbedingt mit Floats rechnen und es am ende in einen integer umwandeln.
Es kann verschiedene hintergrundfarben geben!

weiter geht man dann alle ebenen von hinten nach vorne durch.

Code: [AUSKLAPPEN]
farber=(unterefarber*(255.0-alpha)+(oberefarber*alpha)/(255.0))
farbeg=(unterefarbeg*(255.0-alpha)+(oberefarbeg*alpha)/(255.0))
farbeb=(unterefarbeb*(255.0-alpha)+(oberefarbeb*alpha)/(255.0))


Damit können Farbtöne gegeben werden oder auch komplett überdeckt.

Lg. Jan_
between angels and insects

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group