Friday, February 19, 2021

Morphological Transformations

I started playing around with the OpenCV library in Python ("cv2"). Here are some of the mathematical morphological operations that can be done on an image of your choosing:

Here is an example of an "erosion" operation done on an image of a gradient. First, here is the input image that I used, of a gradient I also generated programmatically via Python:

And here is the processed image, using the erosion operation with a 3 x 3 kernel of 1s:

As I said, I've been playing around with these mathematical morphological operations, of erosion, dilation, edge detection and sharpening of images, all using the OpenCV library. The functions are pretty simple to use. The library is really powerful, giving you everything you need at the touch of a simple function. One can also use function composition to use a function on top of a function. I wrote some helper functions to facilitate the task of using the morphological transformation functions.

Monday, February 15, 2021

Generating a Gradient Programmatically

I've posted many times on this blog, my experiments in image generation through Python. I've been working on what I call my "Noisefield" project, where I generated a bitmap with random black and white pixels. I have now done something similar, except this time I generated a black to white gradient, using the PIL library in Python.

The idea is pretty simple. You create a vector or array of values from 0 to 255, then you repeat that 256 times, to make a square matrix, or bitmap (because Python puts in the pixels from top-left downwards and towards the right, line by line). So that way you get a gradient. I took the "LINE" variable that I created with a for loop and range() function and then multiplied it by 256 in a variable called MATRIX. I then used an iterator function on the Matrix which I called in the image-generation function by calling next(MATRIX). The result is a smooth matrix.

ADDENDUM: I have found a simpler way of generating a black to white gradient, using the np.linspace function in Numpy.

FOR YOUR INFORMATION: I have written a few blog posts in the past about generating bitmaps with random black and white pixel values, or grey values between 0 and 255. I found a much quicker way to do this using the OpenCV library (cv2). (In passing, this np.random.randint() function gives the same results as the uniform_noise function below, in the second Gist below:

Here's another way to generate noise, Gaussian noise in this case, via OpenCV (cv2). The Gaussian distribution is "smoother" in appearance, as it has mean 128 and standard deviation 20:

With mean 0 and standard deviation 256, we get a "coarser" noise distribution:

As stated, the uniform_noise "randu" function gives the same result as the previous np.random.randint() function, a uniform noise distribution:

If I add the following, "ret,thresh1 = cv2.threshold(uniform_noise,64,255,cv2.THRESH_BINARY)" and then write "cv2.imwrite("Noise.jpg",thresh1)", I get a noisy distribution with many more whites, because of the threshold value being at 64. For every pixel, the same threshold value is applied. If the pixel value is smaller than the threshold, it is set to 0, otherwise it is set to a maximum value, in this case 255, which is pure white. This way it is possible to adjust the parseness if you will of the noisy distribution using the threshold function:

The opposite would be true if we set the treshold higher, to say 250. Then it's mostly black, or at a pixel value of 0:

Friday, February 12, 2021

Finding The Mean Part II

A short while ago, I wrote a blog post called "Finding The Mean" where I gave code of a function I wrote which generates an array of n random real numbers between 0 and 1 inclusively. I wrote the function in Python, in R, and in GNU Octave. My goal was to write the function in as many programming languages as possible. I have now written a version in C.

I will be trying to write the same function in various other programming languages, probably including Ruby, Javascript, Scala, and many others, potentially in some functional programming languages like Haskell or SML (Standard ML). Stay tuned!

In passing, the main idea behind this program is the fact that as an array or list of random real numbers between 0 and 1 grows in size, the average will technically converge on 0.50. It's just a mathematical fact. I think it's called the Law of Large Numbers. "According to the law, the average of the results obtained from a large number of trials should be close to the expected value and will tend to become closer to the expected value as more trials are performed."

Here is a mathematical representation of the Law of Large Numbers:

ADDENDUM: Here is some Scala code that does the same thing, but only seems to work in the REPL. I'm not familiar enough with writing actual scala programs, but as I said it works in the REPL. Just change the value of n.

I was also able to translate the code into Ruby. This works in the REPL and worked as a simple Ruby program, though I think it lacks some of the usual formalism of Ruby programs. I tried to turn it into a function (via function definition) but it said there was an "undefined method", not recognizing the .sum method for arrays. But I got it to work in the following way, decomposed into different lines of code. You just have to change the value of n. Remember, this is all to prove the Law of Large Numbers:

The idea behind this proof of the Law of Large Numbers is simply that given an array of random real numbers (floats) between 0 and 1, the larger the length n of the array, the closer the mean of the values of the array will become to 0.50. That is, the mean of a large number of such random numbers, or the expected value, is 0.50. And if you try these functions with 10,000 or more values in the array, you'll see that it converges on 0.50. This is my so-called "proof" of the Law of Large Numbers.