pixel-farbe aus raw datein bestimmen

  • "DAS" RAW-Format gibts nicht, das wird je nach Gutdünken desjenigen festgelegt, der es erstellt. Bei Digitalkameras also der Hersteller. Du öffnest auch in Photoshop kein RAW, sondern das RAW deines Kameramodells! Einige Hersteller legen ihr Format offen und liefern sogar ein SDK, andere Verschlüsseln ihre Daten sogar.
    Daher ist eine universelle Lösung garnicht möglich...

  • das meine ich nicht
    was ich meine ist eine hight map datei
    in der die höhe für eine map abgepeichert ist
    je dunkler der farbton um so häher ist das gelände
    das ganze ist dann nur in schwarz weis

  • SOWAS? MAP-Formate gibts genausoviele wie RAW. Häng doch einfach mal eine Beispiel-Datei an.

  • Hi, hab mal etwas gebastelt....die RAW (131*131) wird angezeigt und ein Array mit allen Graustufenwerten wird ausgegeben. Du kannst es ja noch etwas umbauen....

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    $gdi32 = DllOpen("gdi32.dll")
    $user32 = DllOpen("user32.dll")
    Dim $farbcodes[131][131]

    [/autoit] [autoit][/autoit] [autoit]

    $hgui = GUICreate("RAW-Viewer", 400, 300, -1, -1)
    $gui_DC = getdc(WinGetHandle($hgui))
    $load_btn = GUICtrlCreateButton("RAW-Datei laden", 300, 20)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    If GUIGetMsg() = $load_btn Then _loadfile()
    If GUIGetMsg() = -3 Then Exit
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _loadfile()

    [/autoit] [autoit][/autoit] [autoit]

    $file = FileOpenDialog("RAW öffnen", @DesktopDir & "\", "(*.raw)", 1)
    If @error Then
    MsgBox(0, "RAW-Viewer", "RAW-Datei konnte nicht gefunden werden")
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $datei = FileOpen($file, 16) ;binärmodus lesen
    $bindata = (FileRead($datei))
    FileClose($datei)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $bindata = ' & $bindata & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $bindata = BinaryToString($bindata)
    $max = 0
    $min = 0xFFFFFF

    [/autoit] [autoit][/autoit] [autoit]

    For $zeile = 0 To 130
    For $spalte = 0 To 130 ;2 Byte = ein pixel
    $highbyte = Asc(StringMid($bindata, 262 * $zeile + $spalte * 2 + 1, 1)) ;byte aus dem binärstring holen
    $lowbyte = Asc(StringMid($bindata, 262 * $zeile + $spalte * 2 + 2, 1))
    $bit16 = ($highbyte + 256 * $lowbyte) ;aus high und lowbyte ein 16-Bit-Wort machen
    ;16 Bit in 5/6/5 Bits splitten
    $g1 = BitShift($bit16, 11) ;erste 5 bit holen
    $g2 = BitShift(BitAND($bit16, 2016), 5) ;6 bit holen
    $g3 = BitAND($bit16, 31) ;letzte 5 bit holen
    $c = Int((8.22 * $g1 + 4 * $g2 + 8.22 * $g3) / 3) ;5 Bit nach 8 bit näherung
    $col = 256 * 256 * $c + 256 * $c + $c ; Grau ist, wenn R=G=B
    If $col > $max Then $max = $col ;größte Farbe
    If $col < $min Then $min = $col ;kleinste Farbe
    $farbcodes[$zeile][$spalte] = Hex($col, 6) ;farben ins array schreiben
    setpixel($gui_DC, $spalte * 2, $zeile * 2, $col)
    setpixel($gui_DC, $spalte * 2 + 1, $zeile * 2, $col)
    setpixel($gui_DC, $spalte * 2, $zeile * 2 + 1, $col)
    setpixel($gui_DC, $spalte * 2 + 1, $zeile * 2 + 1, $col)
    Next
    Next
    _ArrayDisplay($farbcodes)
    MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @LF & '$max' & @LF & @LF & 'Return:' & @LF & Hex($max)) ;### Debug MSGBOX
    MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @LF & '$min' & @LF & @LF & 'Return:' & @LF & Hex($min)) ;### Debug MSGBOX
    EndFunc ;==>_loadfile

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func setpixel($dc, $x, $y, $color) ;pixel mit farbe an koordinaten setzen
    DllCall($gdi32, "long", "SetPixel", "long", $dc, "long", $x, "long", $y, "long", $color)
    EndFunc ;==>setpixel

    [/autoit] [autoit][/autoit] [autoit]

    Func GetDC($handle)
    $dc = DllCall($user32, "int", "GetDC", "hwnd", $handle)
    Return $dc[0]
    EndFunc ;==>GetDC

    [/autoit]

    /EDIT/ Script angepasst

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    3 Mal editiert, zuletzt von Andy (21. April 2010 um 00:45)

  • vielen vielen dank
    das anzeigen im gui hätte ich garnicht gebraucht
    aber kann es sein das er das als 8 bit ausliest
    ich brauche:
    [Blockierte Grafik: http://img704.imageshack.us/img704/7270/unbenanntdhu.jpg]
    das ist wichtig

    und könntest du mir bitte das mal erklären:

    [autoit]

    $c = Int((8 * $g1 + 4 * $g2 + 8 * $g3) / 3) ;5 Bit nach 8 bit näherung
    $col = 256 * 256 * $c + 256 * $c + $c
    If $col > $max Then $max = $col
    If $col < $min Then $min = $col

    [/autoit]

    Einmal editiert, zuletzt von HansWurrst (20. April 2010 um 23:03)

  • Hi,
    die Datei besteht aus 34322 Byte. Geteilt durch 131 Pixel Breite, geteilt durch 131 Pixel Höhe ergibt 2. Das bedeutet, jedes "Pixel" besteht aus 2 Byte = 16 Bit
    Aus diesen 16 Bit muss man, um "normale" Graustufen (RGB=RotGrünBlau) in einer Bitmap zu erzeugen, 3 Byte machen. Wenn jeder Farbwert für R,G, und B gleich ist, dann hat man einen "Grauton". Also ist "grau" immer dann, wenn R=G=B

    Wie bekommt man nun aus 16 Bit ein "GRAU" aus 3 Byte RGB?
    Es gibt verschiedene Möglichkeiten, man teilt z.B. die 16 Bit in 3x5 Bit (5/5/5) oder in 5Bit,6Bit,5Bit (5/6/5) oder oder auf. Ich hab das einfach mit IrfanView ausprobiert, das Programm bietet beim Einlesen verschiedenste Filter an.

    Beispiel:
    Aus den ersten 2 Byte=16 Bit ( Hexcodes FB B8 ) der Datei einen Grauton erstellen:
    IBM PC soll wohl auf das Intel-Format little Endian hinweisen. Das bedeutet, daß das niederwertigste Byte am Anfang steht, also B8FB.
    Mit Hilfe des Windowstaschenrechners (wissenschaftliche Darstellung ^^) kann man aus den beiden Bytes B8FB die Binärdarstellung machen:
    1011100011111011
    wird zerlegt in 5/6/5 Bit
    10111 000111 11011
    die ersten 5 Bit für Rot, die nächsten 6 Bit für Grün und die letzten 5 Bit für Blau
    Umformen in dezimal:
    10111 = 23 ROT
    000111 = 7 GRÜN
    11011 = 27 BLAU

    Um jetzt die 5-Bit-Zahl zu einer 8-Bit-Zahl zu machen (wir brauchen ja einen regulären 8-Bit-Wert für Rot), schauen wir uns den Zahlenbereich an. Die größte Zahl, die man mit 5 Bit darstellen kann ist 31, die grösste Zahl, die man mit 8 Bit darstellen kann ist 255 also ist der Faktor 255/31 = 8,22. Das heisst, um eine 5-Bit-Zahl in eine 8-Bit-Zahl zu transformieren, muss man sie mit 8,22 multiplizieren.
    Das heisst, um eine 6-Bit-Zahl in eine 8-Bit-Zahl zu transformieren, muss man sie mit 255/63 = 4 multiplizieren.

    Wie oben beschrieben, ist "GRAU", wenn R=G=B
    Also zählt man R+G+B zusammen und teilt durch 3, das ergibt den Durchschnitt dieser "Farbe", also den Grauton
    Rgrau=Ggrau=Bgrau= (R + G + B)/3
    Rgrau=Ggrau=Bgrau= (5-Bit-Zahl * 8,22 + 6-Bit-Zahl * 4 + 5-Bit-Zahl * 8,22)/3
    Rgrau=Ggrau=Bgrau= (23 * 8,22 + 7 * 4 + 27 * 8,22)/3
    Rgrau=Ggrau=Bgrau= 146 = 0x92 also ist unser "Grau" die Farbe 0x929292 und so stehts als erste Farbe auch im Array^^

    damit 0x929292 entsteht, muss man 0x920000 + 0x009200 + 0x000092 addieren
    0x920000 = 0x92 * 256 * 256 (16 Bit nach links schieben)
    0x009200 = 0x92 * 256 (8 Bit nach links schieben)

    BTW, habe das Script nun angepasst, und oben editiert! Wie gesagt ist das eine der Möglichkeiten, wie man die Graustufen bestimmen KANN, ob Photoshop das genauso macht, weiß ich nicht ^^. IrfanView hat jedenfalls ähnlich importiert, das Bild sieht genauso aus....

    Ich weiss jetzt nicht genau was du mit "wichtig" meinst....

    /EDIT/ ersetze oben im script mal $c = round((4.632 * $g1 + 7.627 * $g2 + 4.632 * $g3) / 3) ;5 Bit nach 8 bit Näherung
    Damit wirds noch ein Stück besser

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    3 Mal editiert, zuletzt von Andy (21. April 2010 um 01:37)

  • ok nochmal danke
    jetzt siehts schon besser aus
    Mit Photoshop siehts zwar immer noch etwas anderst aus
    aber so wies jetzt ist reichts
    es ist wichtig das es so genau wie möglich ist weil ich einen map editor bastel
    der die objeckte auf einene bestimmte höhe setzen muss
    und dies ist halt in der height.raw gespeichert
    nochmal zum vergleich:
    Photoshop:
    [Blockierte Grafik: http://img255.imageshack.us/img255/2151/height.png]
    RAW-Viewer:
    [Blockierte Grafik: http://img96.imageshack.us/img96/494/30828679.jpg]

  • Hi,
    wenn ich das jetzt richtig verstanden habe, dann ist das "Bild" eigentlich egal. Wichtig ist einzig die "Höhe" (als 16-Bit-Wort) in der RAW-Datei?
    Was Photoshop da genau macht, kann ich auch nicht sagen, habe den Import jetzt mit einigen Programmen gemacht, immer sieht das Ergebnis so aus wie beim RAW-Viewer. Da der Kontrast beim Photoshop-Bild ziemlich flau ist, vermute ich irgendeinen bestimmten Algorithmus 16Bit --> Graustufen
    Wenn du das "Objekt" an einer bestimmten Stelle plazieren möchtest, dann brauchst du doch nur an dieser Koordinate den dazugehörenden Wert des 16-Bit-Worts in der RAW Datei zu bestimmen?!
    Angenommen, dein Objekt steht an der Position zeile=80, spalte=50 (1.Pixel oben links ist 0,0) dann kannst du die 3 Zeilen aus dem Script benutzen um die Höhe aus der RAW-Datei auszulesen:

    [autoit]

    $highbyte = Asc(StringMid($bindata, 262 * $zeile + $spalte * 2 + 1, 1)) ;byte aus dem binärstring holen
    $lowbyte = Asc(StringMid($bindata, 262 * $zeile + $spalte * 2 + 2, 1))
    $bit16 = ($highbyte + 256 * $lowbyte) ;aus high und lowbyte ein 16-Bit-Wort machen

    [/autoit]

    In $Bit16 steht dann die "Höhe", sollte das nicht klappen, High- und Lowbyte tauschen. Hast du die richtige Reihenfolge der beiden Bytes gefunden, gehts dann natürlch direkt mit nur einer Zeile (direkt die 2 Bytes auslesen)

  • ja das hab ich schon
    es geht ja jetzt auch
    das war nur so aus reiner interesse
    und wie wäre es jetzt wenn ich es mit 8 bit auslesen möchte ?
    achso wenn mans mit irfan view 12bpp not normalized öffnet dann siehts auch besser aus

    Einmal editiert, zuletzt von HansWurrst (21. April 2010 um 15:52)

  • genauso, Datei binär einlesen (soweit hast du es schon) , FOR/TO Schleife bis len(binstring) und die Bytes auslesen....

  • ersetz mal

    [autoit]

    $c=round($bit16/256)

    [/autoit]

    auf die einfachsten Sachen kommt man nicht ^^