Im Spoiler die original Frage.
Spoiler anzeigen
Hallo Leute,
ich versuche momentan Bilder in "binär" umzuwandeln.
Versteht mich hier bitte nicht falsch, aus einem jpeg o. png eine Textdatei zu erstellen die aus 1 und 0 besteht ist kein Problem.
1 und 0 sind in meinem Fall Bitmaps (8x8 Pixel).
Bilder im Anhang als bin0.png und bin1.png.
Ein einzelner Pixel wird also in eine 8x8 große Bitmap übersetzt.
An und für sich funktioniert das auch... nur ist das Resultat ist schräg und versetzt (siehe Anhänge).
Ich komme hier momentan nicht weiter. Ich sehe den Wald vor lauter Bäumen nicht...
Code für das konvertieren von Pixel in 1 und 0 Bitmap
Spoiler anzeigen
Aufruf von CreateBinaryImage:
Spoiler anzeigen
@RodFromGermany
@Morrison
@exc-jdbi
@Mircosofter2206
Problem war lediglich die Indizierung der zu setzenden Bilder.
Weiter unten der neue Code der Funktioniert.
An alle die vielleicht sagen "Warum nicht einfach GetPixel() und SetPixel() verwenden?": Weil es unfassbar langsam ist!
ImageData Class:
Spoiler anzeigen
Test Class mit CreateBinaryImage() Implementation (Methode zum erstellen eines "Binär" Bildes)
Spoiler anzeigen
Hier ein Code, der das Prinzip des vorherigen Codes, etwas simpler darstellt und für manche evtl etwas einfacher zu verstehen ist:
Spoiler anzeigen
Hallo Leute,
ich versuche momentan Bilder in "binär" umzuwandeln.
Versteht mich hier bitte nicht falsch, aus einem jpeg o. png eine Textdatei zu erstellen die aus 1 und 0 besteht ist kein Problem.
1 und 0 sind in meinem Fall Bitmaps (8x8 Pixel).
Bilder im Anhang als bin0.png und bin1.png.
Ein einzelner Pixel wird also in eine 8x8 große Bitmap übersetzt.
An und für sich funktioniert das auch... nur ist das Resultat ist schräg und versetzt (siehe Anhänge).
Ich komme hier momentan nicht weiter. Ich sehe den Wald vor lauter Bäumen nicht...
Code für das konvertieren von Pixel in 1 und 0 Bitmap
C#-Quellcode
- private static Bitmap CreateBinaryImage(Bitmap zero, Bitmap one, Bitmap source)
- {
- // store all results and their location here
- var imageList = new List<KeyValuePair<Point, Bitmap>>();
- // new width and height
- int w = source.Width * zero.Width;
- int h = source.Height * zero.Height;
- // width and height of binary image
- int hbin = zero.Height;
- int wbin = zero.Width;
- // image position indexer
- int posX = 0;
- int posY = 0;
- // bitmap to draw on
- var canvas = new Bitmap(w, h, source.PixelFormat);
- using (var g = Graphics.FromImage(canvas))
- {
- // set background
- g.FillRectangle(Brushes.Black, 0, 0, canvas.Width, canvas.Height);
- unsafe
- {
- BitmapData lockBits = source.LockBits(
- new Rectangle(0, 0, source.Width, source.Height),
- ImageLockMode.ReadWrite,
- source.PixelFormat);
- try
- {
- // bits per pixel
- int bpp = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
- int hip = lockBits.Height;
- int wib = lockBits.Width;
- // pointer to first pixel
- byte* ptrPx = (byte*)lockBits.Scan0;
- // length of stride
- int bytes = Math.Abs(lockBits.Stride);
- for (int y = 0; y < hip; y++)
- {
- // get pointer to current scanline
- byte* scanLine = ptrPx + (y * lockBits.Stride);
- // iterate through pixels
- for (int x = 0; x < bytes; x+=bpp)
- {
- // calculate average to determine wether pixel will be 1 or 0
- float avg = ((scanLine[x + 2] & 0xff) / 255f +
- (scanLine[x + 1] & 0xff) / 255f +
- (scanLine[x] & 0xff) / 255f) / 3;
- avg = Math.Min(1f, .35f + .65f * avg);
- // set location and bitmap which will later be drawn
- imageList.Add(new KeyValuePair<Point, Bitmap>(
- new Point(posX, posY),
- avg < 0.5f ? one : zero));
- // increment or decrement the binary image location variables
- posX = posX >= w ? 0 : posX + wbin;
- posY = posX >= w ? posY + hbin : posY;
- }
- }
- // draw images on canvas bitmap
- for (int i=0; i<imageList.Count; i++) {
- g.DrawImage(imageList[i].Value, imageList[i].Key);
- }
- }
- finally
- {
- // release locked bitmap bits
- if (source != null) {
- source.UnlockBits(lockBits);
- }
- }
- return canvas;
- }
- }
- }
Aufruf von CreateBinaryImage:
C#-Quellcode
- static void Main(string[] args)
- {
- var source = (Bitmap)Load.FromFile(@"C:\Users\...\Pictures\240px-C_Sharp_wordmark.svg.png");
- var zero = (Bitmap)Load.FromFile("c:\\users\\...\\desktop\\bin0.jpeg");
- var one = (Bitmap)Load.FromFile("c:\\users\\...\\desktop\\bin1.jpeg");
- var binaryImage = CreateBinaryImage(zero, one, source);
- binaryImage.Save("c:\\users\\...\\desktop\\binaryImage_test.jpeg");
- Console.Write("Done... Press any key to exit");
- Console.ReadKey();
- }
@RodFromGermany
@Morrison
@exc-jdbi
@Mircosofter2206
Problem war lediglich die Indizierung der zu setzenden Bilder.
Weiter unten der neue Code der Funktioniert.
An alle die vielleicht sagen "Warum nicht einfach GetPixel() und SetPixel() verwenden?": Weil es unfassbar langsam ist!
ImageData Class:
C#-Quellcode
- using System;
- using System.Drawing;
- using System.Drawing.Imaging;
- namespace ImageConverter
- {
- public unsafe class ImageData : IDisposable
- {
- public Bitmap Bitmap { get; }
- public BitmapData Bits { get; }
- /// <summary>
- /// Width in Pixel
- /// </summary>
- public int Wip { get; }
- /// <summary>
- /// Height in Pixel
- /// </summary>
- public int Hip { get; }
- /// <summary>
- /// Byte per Pixel
- /// </summary>
- public int Bpp { get; }
- /// <summary>
- /// Pointer to first pixel of Image
- /// </summary>
- public unsafe byte* FirstPixel { get; }
- /// <summary>
- /// Stride of Image
- /// </summary>
- public int Stride { get; }
- /// <summary>
- /// Amount of Bytes per Pixel row (Math.Abs(Stride))
- /// </summary>
- public int Bytes { get; }
- public ImageData(Bitmap bitmap, ImageLockMode lockMode)
- {
- Bitmap = bitmap;
- Bits = bitmap.LockBits(
- new Rectangle(0, 0, bitmap.Width, bitmap.Height),
- lockMode,
- bitmap.PixelFormat);
- Bpp = Bitmap.GetPixelFormatSize(bitmap.PixelFormat) / 8;
- Hip = Bits.Height;
- Wip = Bits.Width;
- FirstPixel = (byte*)Bits.Scan0;
- Stride = Bits.Stride;
- Bytes = Math.Abs(Stride);
- }
- public Color GetPixel(int x, int y)
- {
- int px = Bpp * x + Stride * y;
- if (Bpp % 3 == 0)
- {
- return Color.FromArgb(
- FirstPixel[px + 2],
- FirstPixel[px + 1],
- FirstPixel[px + 0]);
- }
- else if (Bpp % 4 == 0)
- {
- return Color.FromArgb(
- FirstPixel[px + 3],
- FirstPixel[px + 2],
- FirstPixel[px + 1],
- FirstPixel[px + 0]);
- }
- return Color.Empty;
- }
- public void SetPixel(int x, int y, Color c)
- {
- int px = Bpp * x + Stride * y;
- if (Bpp % 3 == 0)
- {
- FirstPixel[px + 0] = c.B;
- FirstPixel[px + 1] = c.G;
- FirstPixel[px + 2] = c.R;
- }
- else if (Bpp % 4 == 0)
- {
- FirstPixel[px + 0] = c.B;
- FirstPixel[px + 1] = c.G;
- FirstPixel[px + 2] = c.R;
- FirstPixel[px + 3] = c.A;
- }
- }
- ~ImageData() { Dispose(false); }
- public void Dispose() { Dispose(true); }
- private void Dispose(bool disposing)
- {
- if (disposing)
- {
- GC.SuppressFinalize(this);
- }
- try { Bitmap.UnlockBits(Bits); }
- catch { }
- }
- }
- }
Test Class mit CreateBinaryImage() Implementation (Methode zum erstellen eines "Binär" Bildes)
C#-Quellcode
- using System;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Drawing.Imaging;
- namespace ImageConverter
- {
- class Program
- {
- static void Main(string[] args)
- {
- Bitmap source = (Bitmap)Image.FromFile(@"C:\data\resources\images\image.jpg");
- Bitmap zero = (Bitmap)Image.FromFile(@"c:\data\resources\images\bin_0_1024px_w.png");
- Bitmap one = (Bitmap)Image.FromFile(@"c:\data\resources\images\bin_1_1024px_w.png");
- zero = Resize(zero, 16, 16);
- one = Resize(one, 16, 16);
- var img = CreateBinaryImage(source, zero, one);
- img.Save("C:\\users\\[user]\\desktop\\test.png");
- Console.Write("Done... Press any key to exit");
- Console.ReadKey();
- }
- private static Bitmap Resize(Image source, int width, int height)
- {
- var destRect = new Rectangle(0, 0, width, height);
- var destImage = new Bitmap(width, height, source.PixelFormat);
- destImage.SetResolution(source.HorizontalResolution, source.VerticalResolution);
- using (var g = Graphics.FromImage(destImage))
- {
- g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
- g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
- g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
- g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
- g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
- using (var wrap = new ImageAttributes()) {
- wrap.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY);
- g.DrawImage(source, destRect, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel, wrap);
- }
- }
- return destImage;
- }
- private static Bitmap CreateBinaryImage(Bitmap source, Bitmap zero, Bitmap one, float threshold = 0.53f)
- {
- var canvas = new Bitmap(
- source.Width * zero.Width,
- source.Height * zero.Height,
- PixelFormat.Format24bppRgb);
- unsafe
- {
- var srcData = new ImageData(source, ImageLockMode.ReadOnly);
- var zData = new ImageData(zero, ImageLockMode.ReadOnly);
- var oData = new ImageData(one, ImageLockMode.ReadOnly);
- var cnvData = new ImageData(canvas, ImageLockMode.ReadWrite);
- try
- {
- /* Create lists of color arrays of the replacement images.
- ** Use the bpp property for incrementation to step through the individual pixel values.
- ** Stores each pixels RGB values as bytes. */
- var zPixel = new List<Color[]>();
- var oPixel = new List<Color[]>();
- for (int y=0; y<zData.Hip; y++)
- {
- /* Pointer to the desired row of pixels */
- byte* zScan = zData.FirstPixel + y * zData.Bytes;
- byte* oScan = oData.FirstPixel + y * oData.Bytes;
- /* We only want to store the Pixels color which is why we need to devide by Byte per pixel */
- Color[] z = new Color[zData.Bytes / zData.Bpp];
- Color[] o = new Color[oData.Bytes / oData.Bpp];
- int index = 0;
- for (int x=0; x<zData.Bytes; x+=zData.Bpp)
- {
- z[index] = Color.FromArgb(zScan[x + 2], zScan[x + 1], zScan[x + 0]);
- o[index] = Color.FromArgb(oScan[x + 2], oScan[x + 1], oScan[x + 0]);
- index++;
- }
- zPixel.Add(z);
- oPixel.Add(o);
- }
- int cx = 0; /* X-position on canvas */
- int cy = 0; /* Y-position on canvas */
- for (int y0=0; y0<srcData.Hip; y0++)
- {
- byte* srcScan = srcData.FirstPixel + y0 * srcData.Bytes;
- for (int x0=0; x0<srcData.Bytes; x0+=srcData.Bpp)
- {
- // calculate average to determine if pixel will be 1 or 0
- float avg = ((srcScan[x0 + 2] & 0xff) / 255f +
- (srcScan[x0 + 1] & 0xff) / 255f +
- (srcScan[x0 + 0] & 0xff) / 255f) / 3;
- avg = Math.Min(1f, .35f + .65f * avg);
- /* Determine which colors/pixels to use to reduce length of code */
- List<Color[]> pixels = avg < threshold ? oPixel : zPixel;
- /* Calculate start indizes on canvas */
- cx = (x0 / srcData.Bpp) * pixels[0].Length;
- cy = y0 * pixels.Count;
- int y1 = 0;
- while (y1 < pixels.Count && cy < canvas.Height)
- {
- int x1 = 0;
- while (x1 + zData.Bpp < pixels[y1].Length && cx < canvas.Width)
- {
- /* Increment the start indizes of the canvas with the current
- ** Pixel position of the replacement image. */
- cnvData.SetPixel(cx + x1, cy + y1, pixels[y1][x1]);
- x1++;
- }
- y1++;
- }
- }
- }
- }
- finally
- {
- srcData.Dispose();
- zData.Dispose();
- oData.Dispose();
- cnvData.Dispose();
- }
- return canvas;
- }
- }
- }
- }
Hier ein Code, der das Prinzip des vorherigen Codes, etwas simpler darstellt und für manche evtl etwas einfacher zu verstehen ist:
C#-Quellcode
- using System;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Drawing.Imaging;
- namespace ImageConverter
- {
- class Program
- {
- static void Main(string[] args)
- {
- Bitmap source = (Bitmap)Image.FromFile(@"C:\data\resources\images\image.jpg");
- Bitmap zero = (Bitmap)Image.FromFile(@"c:\data\resources\images\bin_0_1024px_w.png");
- Bitmap one = (Bitmap)Image.FromFile(@"c:\data\resources\images\bin_1_1024px_w.png");
- zero = Resize(zero, 16, 16);
- one = Resize(one, 16, 16);
- var sourceMap = GetBinaryMap(source, .625f);
- var testImage = GetParsedMap(sourceMap, zero, one);
- testImage.Save("c:\\users\\[user]\\desktop\\test.png");
- Console.Write("Done... Press any key to exit");
- Console.ReadKey();
- }
- private static Bitmap Resize(Image source, int width, int height)
- {
- var destRect = new Rectangle(0, 0, width, height);
- var destImage = new Bitmap(width, height, source.PixelFormat);
- destImage.SetResolution(source.HorizontalResolution, source.VerticalResolution);
- using (var g = Graphics.FromImage(destImage))
- {
- g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
- g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
- g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
- g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
- g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
- using (var wrap = new ImageAttributes())
- {
- wrap.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY);
- g.DrawImage(source, destRect, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel, wrap);
- }
- }
- return destImage;
- }
- private static Bitmap GetParsedMap(int[,] map, Bitmap z, Bitmap o)
- {
- var zMap = GetImageMap(z);
- var oMap = GetImageMap(o);
- Bitmap canvas = new Bitmap(map.GetLength(0) * z.Width, map.GetLength(1) * z.Width);
- int cx = 0;
- int cy = 0;
- for (int y0 = 0; y0 < map.GetLength(0); y0++)
- {
- for (int x0 = 0; x0 < map.GetLength(1); x0++)
- {
- List<Color[]> cMap = map[y0, x0] == 0 ? zMap : oMap;
- cx = x0 * cMap[0].Length;
- cy = y0 * cMap.Count;
- int y1 = 0;
- while (y1 < cMap.Count && cy < canvas.Height)
- {
- int x1 = 0;
- while (x1 < cMap[y1].Length && cx < canvas.Width)
- {
- canvas.SetPixel(cx + x1, cy + y1, cMap[y1][x1]);
- x1++;
- }
- y1++;
- }
- }
- }
- return canvas;
- }
- private static List<Color[]> GetImageMap(Bitmap map)
- {
- var bList = new List<Color[]>();
- unsafe
- {
- BitmapData lockBits = map.LockBits(
- new Rectangle(0, 0, map.Width, map.Height),
- ImageLockMode.ReadOnly,
- map.PixelFormat);
- try
- {
- int bpp = Bitmap.GetPixelFormatSize(map.PixelFormat) / 8;
- int hip = lockBits.Height;
- int wib = lockBits.Width;
- byte* ptrPx = (byte*)lockBits.Scan0;
- int bytes = Math.Abs(lockBits.Stride);
- for (int y = 0; y < hip; y++)
- {
- byte* scanLine = ptrPx + y * bytes;
- Color[] rowColors = new Color[bytes / bpp];
- int index = 0;
- for (int x = 0; x < bytes; x += bpp)
- {
- Color px = Color.FromArgb(
- scanLine[x + 2],
- scanLine[x + 1],
- scanLine[x]);
- rowColors[index] = px;
- index++;
- }
- bList.Add(rowColors);
- }
- return bList;
- }
- finally
- {
- map.UnlockBits(lockBits);
- }
- }
- }
- private static int[,] GetBinaryMap(Bitmap source, float threshold = 0.53f)
- {
- int[,] map;
- unsafe
- {
- BitmapData lockBits = source.LockBits(
- new Rectangle(0, 0, source.Width, source.Height),
- ImageLockMode.ReadWrite,
- source.PixelFormat);
- try
- {
- // byte per pixel
- int bpp = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
- int hip = lockBits.Height;
- int wib = lockBits.Width;
- // pointer to first pixel
- byte* ptrPx = (byte*)lockBits.Scan0;
- // length of stride
- int bytes = Math.Abs(lockBits.Stride);
- map = new int[hip + 1, wib + 1];
- for (int y = 0; y < hip; y++)
- {
- int x0 = 0;
- // get pointer to current scanline
- byte* scanLine = ptrPx + y * bytes;
- // iterate through pixels
- for (int x = 0; x < bytes; x += bpp)
- {
- // calculate average to determine wether pixel will be 1 or 0
- float avg = ((scanLine[x + 2] & 0xff) / 255f +
- (scanLine[x + 1] & 0xff) / 255f +
- (scanLine[x] & 0xff) / 255f) / 3;
- avg = Math.Min(1f, .35f + .65f * avg);
- map[y, x0] = avg < threshold ? 0 : 1;
- x0++;
- }
- }
- }
- finally
- {
- // release locked bitmap bits
- if (source != null)
- {
- source.UnlockBits(lockBits);
- }
- }
- return map;
- }
- }
Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Petersilie“ ()