Shiran Yeyni
Shiran Yeyni

Reputation: 35

How can i convert bitmap array of rgbvalues 0 and 255 to 2d int array of 0 and 1?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

namespace ConvertBitmapToArray
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();

            Bitmap bitmap = new Bitmap(@"C:\Temp\Gimp Maps\Bitmaps\test1.bmp");
            CreateArray(bitmap);

            File.Create(@"C:\Temp\Gimp Maps\Maps.cs");
        }

        private void CreateArray(Bitmap bmp)
        {
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);

            IntPtr ptr = bmpData.Scan0;
            int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
            byte[] rgbValues = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
            System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

            bmp.UnlockBits(bmpData);

            for (int i = 0; i < rgbValues.Count(); i++)
            {

            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}

I have a bitmap of black and white size 8x8 or 800x800 and i get array of rgbValues. Now in the loop :

for (int i = 0; i < rgbValues.Count(); i++)
{

}

I want to create 2d array of int built from 0 and 1. For example like this:

int[,] map = new int[,] 
{
    {0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,},
    {1,1,1,1,0,0,0,0,},
    {0,0,0,1,0,0,0,0,},
    {0,0,1,1,0,0,0,0,},
    {0,0,0,0,1,1,1,0,},
    {0,0,0,0,0,0,0,1,},
};

So 255 will be 0 and 0 will be 1. In the int array example 1 is black and 0 white.

I tried this:

private void CreateArray(Bitmap bmp)
{
    int[] pix = new int[bmp.Width*bmp.Height];

    int x, y, rgb, val;
    for (y = 0; y < bmp.Height; y++)
    {
        for (x = 0; x < bmp.Width; x++)
        {
            Color c = bmp.GetPixel(x, y);
            rgb = c.ToArgb();
            if (rgb == 0xff000000) // if black
            { 
                val = 0;
            }
            else
                val = 1;
            pix[y * bmp.Width + x] = val;
        }
    }
}

But it's not good i'm not sure about the Color c and the rgb = c.ToArgb();

And on the if condition i get green line say:

Warning 1 Comparison to integral constant is useless; the constant is outside the range of type 'int'

How can i do it with LockBits or with GetPixel ? I want to know how different it is using each method.

This is what i did so far:

private void CreateArray(Bitmap bmp)
        {
            int[,] array = new int[,]
            {

            };

            // Lock the bitmap's bits.  
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                bmp.PixelFormat);

            // Get the address of the first line.
            IntPtr ptr = bmpData.Scan0;

            // Declare an array to hold the bytes of the bitmap. 
            int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;
            byte[] rgbValues = new byte[bytes];


            int x, y, rgb, val;
            for (y = 0; y < bmp.Height; y++)
            {
                for (x = 0; x < bmp.Width; x++)
                {
                    var row = ptr + (y * bmpData.Stride);
                    var pixel = row + x * ; // bpp will be 4 in your case

                    // A bit=0
                    // R bit=1
                    // G bit=2
                    // B bit=3
                    // (depending on your image pixel format)
                    for (var bit = 0; bit < bpp; bit++)
                    {
                        var pixelComponent = pixel[bit];
                    }
                }
            }
        }

Upvotes: 0

Views: 3110

Answers (1)

YoryeNathan
YoryeNathan

Reputation: 14502

To loop through the bytes of an image in a more logical fashion add the unsafe keyword to your function signature (private unsafe void ...) and make sure you enable unsafe code through your project properties.

var pt = (byte*)bmpData.Scan0;

Now you can easily loop through x and y:

var row = pt + (y * bmpData.Stride);
var pixel = row + x * bpp; // bpp will be 4 in your case

// A bit=0
// R bit=1
// G bit=2
// B bit=3
// (depending on your image pixel format)
for (var bit = 0; bit < bpp; bit++)
{
    var pixelComponent = pixel[bit];
}

If you really want the final results as a 2d array, you shoud use [,] or [][] instead of [] (single dimension array)


The huge difference between the LockBits approach vs the GetPixel approach is performance. The GetPixel actually locks the bits, retrieves a single pixel and unlocks the bits again - which means horrible performance when doing it over and over again for many times.


Edit

Here is a full code to work with:

private unsafe void CreateArray(Bitmap bmp)
{
    // Note that is it somewhat a standard
    // to define 2d array access by [y,x] (not [x,y])
    bool[,] bwValues = new bool[bmp.Height, bmp.Width];

    // Lock the bitmap's bits.  
    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    System.Drawing.Imaging.BitmapData bmpData =
        bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
        bmp.PixelFormat);

    // Get the address of the first line.
    byte* ptr = (byte*)bmpData.Scan0;

    // Declare an array to hold the bytes of the bitmap. 
    int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;

    for (int y = 0; y < bmp.Height; y++)
    {
        var row = ptr + (y * bmpData.Stride);

        for (int x = 0; x < bmp.Width; x++)
        {
            var pixel = row + x * 4; // ARGB has 4 bytes per pixel

            // A bit=0
            // R bit=1
            // G bit=2
            // B bit=3
            // (depending on your image pixel format)

            // Check if A = R = G = B = 255 (meaning the pixel is white)
            bool isWhite = (pixel[0] == 255 &&
                            pixel[1] == 255 &&
                            pixel[2] == 255 &&
                            pixel[3] == 255);

            // Assume that anything that isn't white is black
            bwValues[y, x] = isWhite;
        }
    }

    // Do whatever you want with vwValues here
}

Upvotes: 3

Related Questions