Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Generative Art II

0.00/5 (No votes)
1 Jan 2015 1  
Read and analyse pixels: fundamental C# classes and methods for the artwork production in the area of generative art.

Introduction

This second part of the series deals with generative art based on images as input.

Background

The basis of the representational example in this tip is the following photo:

Alida Altemburg (model), Robert Anthony (photographer), Vanee Pham (makeup), Crown Casino Melbourne

Basic Approach

For producing an artwork based on an input image, you have to accomplish the following tasks:

  • Read all pixels of the input image
  • Create a canvas with the appropriate size
  • Generate something influenced by the pixels of the input image
  • Sign the result
  • Save the artwork
var inputImage = new InputImage(currentDirectory + inputFile);
var canvas = new GenArtCanvas(inputImage.Width * zoom, inputImage.Height * zoom, backgroundColor);

canvas.Generate(zoom, inputImage, margin);
canvas.Sign(zoom, signature, margin);
canvas.Save(currentDirectory + title + format);

Read Input Image

Creating a new InputImage reads all Pixels of the image into an array of bytes.

public class InputImage
{
    public byte[] Pixels;
    public int Width, Height;

    public InputImage(string InputFileName)
    {
        using (FileStream inStream = 
            new FileStream(InputFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            BitmapSource Image = new JpegBitmapDecoder
            (inStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default).Frames[0];
            Width = Image.PixelWidth;
            Height = Image.PixelHeight;
            int stride = Width * ((Image.Format.BitsPerPixel + 7) / 8);
            Pixels = new byte[Height * stride];
            Image.CopyPixels(Pixels, stride, 0);
        }
    }
}

The InputImage itself is not stored in memory. Only the Pixels are kept for further processing and the Width and Height are taken as ratio for the creation of the empty canvas of the new generative artwork:

var canvas = new GenArtCanvas(inputImage.Width * zoom, inputImage.Height * zoom, backgroundColor);

Generate Artwork

This algorithm takes every single pixel of each 40th row and each 40th column of the InputImage. Then it adds a shape (Ellipse or Rectangle) to the canvas filling the shape with the color of the specific pixel (PixelColor). Each shape is set to its corresponding position from the InputImage.

public void Generate(int Zoom, InputImage InputImage, double Margin)
{
    Generator.ImageBaseShapes(this, InputImage, Zoom, Margin);
}

public static void ImageBaseShapes(Canvas Canvas, InputImage InputImage, int Zoom, double Margin)
{
    for (var row = Margin; row <= InputImage.Height - Margin; row += 5)
        for (var column = Margin; column <= InputImage.Width - Margin; column += 5)
        {
            var shape = new Ellipse() // new Rectangle()
            {
                Width = Zoom * 3,
                Height = Zoom * 3,
                Fill = new SolidColorBrush(InputImage.PixelColor(new Point(column, row)))
                //Fill = InputImage.RedValue(new Point(column, row)) > 128 ? 
            Brushes.LightGray : Brushes.Black
            };
            Canvas.Children.Add(shape);
            Canvas.SetLeft(shape, column * Zoom - shape.Width / 2);
            Canvas.SetTop(shape, row * Zoom - shape.Height / 2);
        }
}

The method PixelColor analyses the red, green and blue portion (RGB) of a certain pixel:

public byte RedValue(Point Point)
{
    return Pixels[PixelPos(Point, 2)];
}
public byte GreenValue(Point Point)
{
    return Pixels[PixelPos(Point, 1)];
}
public byte BlueValue(Point Point)
{
    return Pixels[PixelPos(Point)];
}
private int PixelPos(Point Point, int RgbDelta = 0)
{
    return (int)(3 * ((int)Point.Y * Width + (int)Point.X) + RgbDelta);
}
public Color PixelColor(Point Point)
{
    if (Point.X >= Width || Point.Y >= Height || Point.X < 0 || Point.Y < 0) return Colors.White;

    return Color.FromRgb(RedValue(Point), GreenValue(Point), BlueValue(Point));
}

The generated result looks like this:

Limiting the color of the shapes to light gray and black produces a new result:

Adjustments of the step size and shape size lead to additional results:

Points of Interest

This approach was also used by human painters in the late 1880s, see "Pointillism".

History

  • 1st January, 2015 - Published
  • 11th January, 2015 - Links to other articles in the series added

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here