Click here to Skip to main content
15,890,123 members
Articles / Desktop Programming / WPF
Tip/Trick

Generative Art II

Rate me:
Please Sign up or sign in to vote.
4.45/5 (7 votes)
1 Jan 2015CPOL2 min read 13.1K   335   13  
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:

Image 1

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
C#
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.

C#
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:

C#
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.

C#
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:

C#
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:

Image 2

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

Image 3

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

Image 4

Image 5

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
schoder.uk
United Kingdom United Kingdom
generative artist: schoder.uk

Comments and Discussions

 
-- There are no messages in this forum --