Autor Beitrag
dom19
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Fr 13.05.16 14:27 
Hallo,
ich bin hier neu im Forum und hoffe hier kann mir jemand von euch weiter Helfen. Ich habe in einem C# Software-Projket das ich gerade im Bereich eines Studienprojektes entwickle ein Problem. Die Software bekommt von einer Kamera direkt 12 Bit Bilddaten uebermittelt was schon sehr gut Funktioniert. Das Problem das ich habe und bis jetzt nicht leosen konnte besteht darin diese Bilddaten in ein 16 Bit Tiff Bild umzuwandeln und ab zuspeichern. Ich habe mir dazu schon eine entsprechende Library (LibTiff von bitmiracle) heruntergeladen und die entsprechende Funktion fuer meine Zwecke umgeschrieben. Allerdings bekomme ich nach dem Speichern entweder ein verzerrtes Bild oder ein gesplittetes Bild. Den entsprechenden Quellcode habe ich unten mit angefuegt. Ich wuerde mich sehr freuen wenn mir jemand einen Tipp geben koennte oder helfen koennte falls ich etwas falsch oder vergessen habe, da ich so langsam mit meinem Latein am Ende bin da es auch fuer mich auch etwas neu Land ist.

Code Snippet:

ausblenden volle Höhe C#-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:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
// Der Funktion wird der Speicherpfad und die aktuellen Bilddaten von der Kamera uebergeben. 

public Bitmap saveRoutine(string fileName, byte[] iData)
        {
            // Bitmap for current Image 
            Bitmap akImage;
            
            byte[] buffer = null;
            ushort[] bufi = null;

            // Frame size 
            int width = 2560
            int height = 2160;
            // counter 
            int rowMultiplier = 0;
            int counterWidth = 0
            byte[] _imageData = iData; // 12 Bit frame data 
            unsafe
            {
                // Bitmap save between the current Image. 
                akImage = new Bitmap(25602160, PixelFormat.Format16bppGrayScale);
                Rectangle dimension2 = new Rectangle(00, akImage.Width, akImage.Height);
                BitmapData picData2 = akImage.LockBits(dimension2, ImageLockMode.ReadWrite, PixelFormat.Format16bppGrayScale);
                IntPtr pixelStartAddress2 = picData2.Scan0;
                System.Runtime.InteropServices.Marshal.Copy(_imageData, 0, pixelStartAddress2, _imageData.Length);
                akImage.UnlockBits(picData2);
               
                Tiff outputImage;
                using (outputImage = Tiff.Open(fileName, "w"))
                { 
                    bufi = new ushort[akImage.Width * akImage.Height];

                    // LibTiff settings 
                    outputImage.SetField(TiffTag.IMAGEWIDTH, width);
                    outputImage.SetField(TiffTag.IMAGELENGTH, height);
                    outputImage.SetField(TiffTag.SAMPLESPERPIXEL, 1);
                    outputImage.SetField(TiffTag.BITSPERSAMPLE, 16);
                    outputImage.SetField(TiffTag.ORIENTATION, BitMiracle.LibTiff.Classic.Orientation.TOPLEFT);
                    outputImage.SetField(TiffTag.ROWSPERSTRIP, height);
                    outputImage.SetField(TiffTag.XRESOLUTION, 2560);
                    outputImage.SetField(TiffTag.YRESOLUTION, 2160);
                    outputImage.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.CENTIMETER);
                    outputImage.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
                    outputImage.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
                    outputImage.SetField(TiffTag.COMPRESSION, Compression.LZW);
                    outputImage.SetField(TiffTag.FILLORDER, FillOrder.MSB2LSB);
                  
                    // run through the row (y) line 
                    for (int row = 0; row < akImage.Height; ++row)
                    {
                        ushort* ptr = (ushort*)picData2.Scan0+(row *picData2.Stride); 
                        rowMultiplier = row + 1;
                        counterWidth = 0;

                        // run through the (x) line 
                        for (int x = (akImage.Width * rowMultiplier) - akImage.Width; x < (akImage.Width * rowMultiplier); ++x ,++ptr)
                        {
                            // write the current pixel in the buffer 
                            bufi[counterWidth] = (ushort)ptr;
                            counterWidth++;
                        }
                        buffer = new byte[bufi.Length * sizeof(ushort)];
                        Buffer.BlockCopy(bufi, 0, buffer, 0, buffer.Length);
                        // create the 16 bit frame tiff
                        outputImage.WriteScanline(buffer, row);
                        bufi = new ushort[akImage.Width * akImage.Height];
                    }
                }
                akImage.Dispose();
                outputImage.Dispose();
            }
            return akImage; 
        }


Moderiert von user profile iconChristian S.: C#-Tags hinzugefügt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 13.05.16 14:44 
Hallo und :welcome:

ohne deinen Code genau angesehen zu haben, aber "verzerrtes Bild" klingt nach Nichtbeachtung von "bitmap stride".

Handelt es sich denn um Graubilder oder Farbbilder (und welches Format genau)?
Und sind die verzerrten Bilder denn farblich richtig?
dom19 Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Sa 14.05.16 12:52 
Hallo Th69,

es handelt sich um Graubilder die in 16 Bit große Tiff Bilder abgespeichert werden sollen also Bilder die keine 0-255 Farbwerte annehmen sondern Farbwerte von 0-65536 umfassen.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 14.05.16 14:12 
Meine Frage bezog sich mehr auf das Kameraformat (d.h. die 12 Bit), d.h. wie sind diese denn abgespeichert (immer in 2 Byte)? Denn bisher behandelst du diese ja direkt so (mittels Marshal.Copy). Dieses Bitmap wird also bei dir richtig dargestellt?

Dann brauchst du doch nur diese Bilddaten direkt in das TIFF zu kopieren.
Besteht deine Schwierigkeit also darin das byte[] in ein ushort[] zu transferieren? Dann siehe z.B. Convert byte array to ushort array in C# .Net Microframework:
ausblenden C#-Quelltext
1:
2:
3:
4:
var input = byte[1024];
var output = ushort[1024 / 2]; // every ushort is 2 bytes

Buffer.BlockCopy(input, 0, output, 01024);
dom19 Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Mo 16.05.16 18:00 
Ja die 12 Bit werden in einem Byte-Array gespeichert also wie du schon geschrieben hast immer in 2 Byte. Ja ich habe festgestellt das dieses Bitmap-Format was ich momentan benutzte noch nicht richtig Unterstüzt wird. Die Bitmap wird mir nur richtig angezeigt wenn ich 8 Bit Bitmap verwende. Das wäre aber keine gute Lösung für mich wegen dem Informationsverlust den ich erhalte wenn ich die Werte von der 8 Bit Bitmap in ein 16 Bit Tiff Bild schreiben möchte oder liege ich da Falsch ?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 17.05.16 09:19 
Hallo,

dann brauchst du das temporäre Bitmap ja auch nicht und du kannst direkt die Daten in das TIFF reinkopieren (s. meinen obigen Code).
Wenn du dann von 12-bit auf 16-bit skalieren mußt (d.h. von 4096 auf 65536 Grauwerte), dann multipliziere jeden einzelnen ushort-Wert mit 4 / 3:
ausblenden C#-Quelltext
1:
2:
for (int n = 0; n < output.Length; n++)
    output[n] = (ushort)(output[n] * 4 / 3);

Für diesen Beitrag haben gedankt: dom19
dom19 Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 17.05.16 12:36 
Also ich konnte nun mal das testen was Du mir vorgeschlagen hast. In dem Zuge habe ich auch nochmal ein anderes Manuel des Kamerahersteller gefunden und habe endlich die eigentliche Funktionweise einer Methode herausfinden können. Damit ist es mir nun möglich die 12 Bit Werte direkt in 16 Bit Werte durch die Methode zu konvertieren. Allerdings bekomme ich das Bild trotzdem nicht korregt abgespeichert.

hier ist auch nochmal der Quellcode und ich habe zwei Bilder das eine wie es momentan aussieht und wie es eigentlich aussehen sollte.


bufi = new ushort[width * height];

Tiff outputImage;
using (outputImage = Tiff.Open(fileName, "w"))
{

// LibTiff settings
----------------
----------------
// LibTiff settings end


for (int row = 0; row < height; row++)
{
bufi = new ushort[width];
// run through the (x) line
for (int x = 0; x < width; x++)
// write the current pixel in the buffer
bufi[x] = _imageData[x];

buffer = new byte[bufi.Length * sizeof(ushort)];
Buffer.BlockCopy(bufi, 0, buffer, 0, buffer.Length);
// create the 16 bit frame tiff
outputImage.WriteScanline(buffer, row);

}


So endlich hat es geklappt nochmal vielen Dank für die Hilfe. Falls erwünscht kann ich noch meine Lösung reinpacken wenn jemand eine ähnliches Problem hat :)
Einloggen, um Attachments anzusehen!