Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

stough 202-

Preview: Probability Distributions, Gaussian and Uniform

In the matplotlib tutorial we saw how to produce a histogram of color distribution in an image. These histograms represent the probability distribution on color; that is, the probability of a particular color in an image corresponds to the height of the histogram at that color (given the histogram of that image).

In this demo we’ll look at Uniform and Gaussian probability distributions, and what corresponding “random” images look like.

Imports

We’ll produce random numbers using numpy’s updated random-number-generation techniques. Read more about it here.

Generator(PCG64) at 0x7F880ADFCD60

At this point the object rng is our random number generator, and it has been seeded (with the current time for example) to produce different random sequences each run through this notebook. You could also seed the default random number generator to ensure the same random sequence (good for debugging).

Uniform Random Distribution

When you think of the word “random,” you probably mean that any outcome of the “random” process is equally likely. Let’s say we’re generating integers between 0 and 255 (inclusive). We would expect over many samples that no number is a lot more likely than any other.

<Figure size 600x300 with 1 Axes>
((1048576,), dtype('int64'), np.int64(0), np.int64(255))
np.float64(127.59317111968994)

In the above we generate about 1M samples in the range [0,255]. In fact we generate 220=10485762^{20} = 1048576 elements. Since these random numbers are split among 256=28256 = 2^{8} possibilites, that means on average we should get 212=40962^{12} = 4096 hits for each output integer. What makes the randomness uniform is that most of the bins have about the same number of outcomes, hovering near 4K as expected.

  • Little complication in generating the plot: plt.hist expects the bins argument to include both left end of the first bin and the right end of the last bin. Since arange provides the sequence [0,N)[0, N) exclusive, we call it with 257 to make sure we get all the way to [0,...,256][0,...,256].

Now let’s generate an image of uniform random colors

<Figure size 300x300 with 1 Axes>
((49152,), dtype('int64'), np.int64(0), np.int64(255))

The above is what a truly random image looks like.

  • Is it anyhing like the images we ourselves capture, communicate to each other, or attempt to study?

  • What is missing from it?

  • What does this say about the kinds of images that we actually care about?

Viewing in the Color Cube Space

If any possible color is equally likely to occur, as in the image above, what would that look like in the color cube visualization we saw in the matplotlib_tutorial? Think about it, then execute the next cell.

<Figure size 400x400 with 1 Axes>

Gaussian Random Distribution

There is a different kind of random that is more practically interesting in the world: the Gaussian, or Normal, Distribution, also called the Bell Curve. Many phenomena we deal with every day often closely follow the normal distribution, including heights, measurement errors, blood pressure, test scores. Here we’ll take a look a couple of Guassian-distributed samples.

As an aside, most everything that we try to model with a Gaussian is better modelled with some sort of skew normal, weibull, or pareto. These distributions have a heavier tail on one side than the other, common when there is some physical limit on the measurement. This is a complication we’ll concern ourselves with only when relevant.

<Figure size 600x300 with 1 Axes>
(np.float64(-0.0024453854048798935), np.float64(0.9937574389054398))

Above we sample from a standard_normal, which you can see has a mean of 0 and a variance (average square distance from the mean) of 1, symbolized with N(μ=0,σ2=1)\mathcal{N}(\mu = 0,\sigma^{2} = 1). We can reposition this kind of distribution anywhere we want by

  • adding a constant, to change the mean: C+N(μ,σ2)∼N(C+μ,σ2)C + \mathcal{N}(\mu,\sigma^{2}) \sim \mathcal{N}(C + \mu,\sigma^{2})

  • multiplying by a constant, to change the variance: K∗N(μ,σ2)∼N(μ,K2σ2)K*\mathcal{N}(\mu,\sigma^{2}) \sim \mathcal{N}(\mu,K^2\sigma^{2})

Using the above rules, we could make a Gaussian distributed image in the range [0,255][0,255]. We can also use numpy’s normal to do the same thing.

<Figure size 600x300 with 1 Axes>
<Figure size 800x300 with 2 Axes>

In the above cells, we plot the distribution of the Gaussian normal image (I_normal) and then show both the uniform (I_uniform) and normal images side by side.

You should immediately notice that the “Gauss Random” image is much more bland, or muted in its tones, than the “Uniform Random” image. This kind of difference is related to contrast. Contrast measures how distinguishable different image parts are from one another. In I_normal, most pixel intensities in red, green, and blue hover around 128. This results in a middling gray tone to the whole image, with neighboring pixels only mildly distinguishable from one another, especially compared to I_uniform.

Color Cube Again

So what would I_normal look like in the color cube space, with more pixels hovering in the middle of their component ranges rather than equally all over the place? Think about it, then execute the next cell.

<Figure size 400x400 with 1 Axes>

Plotting the two distributions together

A little bit of matplotlib-ary to show the two distributions together without y-axis.

<Figure size 700x300 with 1 Axes>

Here we looked into the difference between uniformly and normally-distributed randomness, and what that looks like in image data. Having this background will be critical in many later image processing and analysis topics, from contrast enhancement to compression and many others.