Wednesday, January 25, 2017

Generating a cube in Python

Check out this cool image!
enter image description here

I generated it with the following python code:

import numpy as np
import matplotlib.pyplot as plt
plt.imsave(
    'outfile.png',
    np.histogramdd(
        np.dot(
            np.random.random((10000000,3))-.5,
            np.array([[0.4,0],[0.1,0.4],[-0.2,0.3]])),
        bins=(500,500),
        range=((-.5,.5),(-.5,.5)))[0],
    cmap='gray')

How it works

The image consists of 10 million random 3D points which have been projected into 2D, and then turned into an image.

I start with generating 10 million random 3D points where each component can vary uniformly from -0.5 to 0.5. Notice that these points will form a 1x1x1 cube centered at the origin. This is done with the line np.random.random((10000000,3))-.5. This is a 10000000x3 numpy array.

In order to turn these 3D points into 2D points, I use an isometric projection. An isometric projection is not as realistic as a perspective projection, but it is simpler to compute. All that needs to be done is a linear projection (or an affine projection, in case you don’t want the origin to project on the origin). In this case, the center of the projected cube will be at the origin. To perform the isometrix projection, I multiply the 10000000x3 matrix of points on the right with the 3x2 matrix np.array([[0.4,0],[0.1,0.4],[-0.2,0.3]]). I chose this matrix arbitrarily, just so that the picture looks nice at the end. This now results in a 10000000x2 matrix, containing 10 million 2D points, representing a projected cube centered at the origin.

Now I have a bunch of points, but what I really need in order to make an image is a 2D array of pixel intensities. To obtain this, I used np.histogramdd, which computes a multidimensional histogram of the data we computed. Pretty much, I am partitioning the 2D space from -0.5 to 0.5 in each dimension into 500x500 “bins”, and counting how many points in each bin. Each bin will then correspond to a pixel, and the pixel intensity should be proportional to the count of its bin.

Finally, I use plt.imsave to save the image as a PNG. Neat!

Written with StackEdit.

No comments:

Post a Comment