# data[].attributes.attachment_link.readable_text
This course will help you take your very first steps in learning Computer Vision and AI using OpenCV. You will learn and get exposed to a wide range of exciting topics like Image & Video Manipulation, Image Enhancement, Filtering, Edge Detection, Object Detection and Tracking, Face Detection and the OpenCV Deep Learning Module.

Finally, hear from Dr Satya Mallick (CEO, OpenCV.org) where he shares his views on the limitless opportunities in the Computer Vision and AI job market and how to confidently prepare yourself in a structured manner for a fulfilling career in AI. For more advanced and detailed courses with structured learning paths, check out our offerings:

# data[].attributes.attachment_link.title
OpenCV Crash Course | Computer Vision Course with OpenCV and Python

# data[].attributes.attachment_link.description
This free course will help you take your first steps in learning Computer Vision and AI using OpenCV. You will learn from the Basics ( Image and Video Manipulation, Image Enhancement, Filtering, Edge Detection ) to Advanced topics ( Object Detection and Tracking, Face Detection, and the OpenCV Deep Learning Module ).

# data[].attributes.body
https://www.labri.fr/perso/nrougier/from-python-to-numpy/

# data[].attributes.attachment_link.readable_text
There are already a fair number of books about Numpy (see Bibliography) and a legitimate question is to wonder if another book is really necessary. As you may have guessed by reading these lines, my personal answer is yes, mostly because I think there is room for a different approach concentrating on the migration from Python to Numpy through vectorization. There are a lot of techniques that you don't find in books and such techniques are mostly learned through experience. The goal of this book is to explain some of these techniques and to provide an opportunity for making this experience in the process.

Disclaimer: All external pictures should have associated credits. If there are missing credits, please tell me, I will correct it. Similarly, all excerpts should be sourced (wikipedia mostly). If not, this is an error and I will correct it as soon as you tell me.

Nicolas P. Rougier is a full-time research scientist at Inria which is the French national institute for research in computer science and control. This is a public scientific and technological establishment (EPST) under the double supervision of the Research & Education Ministry, and the Ministry of Economy Finance and Industry. Nicolas P. Rougier is working within the Mnemosyne project which lies at the frontier between integrative and computational neuroscience in association with the Institute of Neurodegenerative Diseases, the Bordeaux laboratory for research in computer science ( LaBRI), the University of Bordeaux and the national center for scientific research ( CNRS).

He has been using Python for more than 15 years and numpy for more than 10 years for modeling in neuroscience, machine learning and for advanced visualization (OpenGL). Nicolas P. Rougier is the author of several online resources and tutorials (Matplotlib, numpy, OpenGL) and he's teaching Python, numpy and scientific visualization at the University of Bordeaux and in various conferences and schools worldwide (SciPy, EuroScipy, etc). He's also the author of the popular article Ten Simple Rules for Better Figures and a popular matplotlib tutorial.

This book has been written in restructured text format and generated using the rst2html.py command line available from the docutils python package.

If you want to rebuild the html output, from the top directory, type:

$ rst2html.py --link-stylesheet --cloak-email-addresses \
              --toc-top-backlinks --stylesheet=book.css \
              --stylesheet-dirs=. book.rst book.html

The sources are available from https://github.com/rougier/from-python-to-numpy.

If you want to contribute to this book, you can:

If you're an editor interested in publishing this book, you can contact me if you agree to have this version and all subsequent versions open access (i.e. online at this address), you know how to deal with restructured text (Word is not an option), you provide a real added-value as well as supporting services, and more importantly, you have a truly amazing latex book template (and be warned that I'm a bit picky about typography & design: Edward Tufte is my hero). Still here?

Note

You can execute any code below from the code folder using the regular python shell or from inside an IPython session or Jupyter notebook. In such a case, you might want to use the magic command%timeit instead of the custom one I wrote.

Numpy is all about vectorization. If you are familiar with Python, this is the main difficulty you'll face because you'll need to change your way of thinking and your new friends (among others) are named "vectors", "arrays", "views" or "ufuncs".

Let's take a very simple example, random walk. One possible object oriented approach would be to define a RandomWalker class and write a walk method that would return the current position after each (random) step. It's nice, it's readable, but it is slow:
Object oriented approach
Benchmarking gives us:
Procedural approach
For such a simple problem, we can probably save the class definition and concentrate only on the walk method that computes successive positions after each random step.

This new method saves some CPU cycles but not that much because this function is pretty much the same as in the object-oriented approach and the few cycles we saved probably come from the inner Python object-oriented machinery.
Vectorized approach
But we can do better using the itertools Python module that offers a set of functions creating iterators for efficient looping. If we observe that a random walk is an accumulation of steps, we can rewrite the function by first generating all the steps and accumulate them without any loop:

In fact, we've just vectorized our function. Instead of looping for picking sequential steps and add them to the current position, we first generated all the steps at once and used the accumulate function to compute all the positions. We got rid of the loop and this makes things faster:

We gained 85% of computation-time compared to the previous version, not so bad. But the advantage of this new version is that it makes numpy vectorization super simple. We just have to translate itertools call into numpy ones.

Not too difficult, but we gained a factor 500x using numpy:

This book is about vectorization, be it at the code or problem level. We'll see this difference is important before looking at custom vectorization.

Before heading to the next chapter, I would like to warn you about a potential problem you may encounter once you'll have become familiar with numpy. It is a very powerful library and you can make wonders with it but, most of the time, this comes at the price of readability. If you don't comment your code at the time of writing, you won't be able to tell what a function is doing after a few weeks (or possibly days). For example, can you tell what the two functions below are doing? Probably you can tell for the first one, but unlikely for the second (or your name is Jaime Fernández del Río and you don't need to read this book).

As you may have guessed, the second function is the vectorized-optimized-faster-numpy version of the first function. It is 10 times faster than the pure Python version, but it is hardly readable.

As explained in the Preface, you should have a basic experience with numpy to read this book. If this is not the case, you'd better start with a beginner tutorial before coming back here. Consequently I'll only give here a quick reminder on the basic anatomy of numpy arrays, especially regarding the memory layout, view, copy and the data type. They are critical notions to understand if you want your computation to benefit from numpy philosophy.

Let's consider a simple example where we want to clear all the values from an array which has the dtype np.float32. How does one write it to maximize speed? The below syntax is rather obvious (at least for those familiar with numpy) but the above question asks to find the fastest operation.

If you look more closely at both the dtype and the size of the array, you can observe that this array can be casted (i.e. viewed) into many other "compatible" data types. By compatible, I mean that Z.size * Z.itemsize can be divided by the new dtype itemsize.

Interestingly enough, the obvious way of clearing all the values is not the fastest. By casting the array into a larger data type such as np.float64, we gained a 25% speed factor. But, by viewing the array as a byte array ( np.int8), we gained a 50% factor. The reason for such speedup are to be found in the internal numpy machinery and the compiler optimization. This simple example illustrates the philosophy of numpy as we'll see in the next section below.

The numpy documentation defines the ndarray class very clearly:

An instance of class ndarray consists of a contiguous one-dimensional segment of computer memory (owned by the array, or by some other object), combined with an indexing scheme that maps N integers into the location of an item in the block.

Said differently, an array is mostly a contiguous block of memory whose parts can be accessed using an indexing scheme. Such indexing scheme is in turn defined by a shape and a data type and this is precisely what is needed when you define a new array:

Here, we know that Z itemsize is 2 bytes ( int16), the shape is (3,3) and the number of dimensions is 2 ( len(Z.shape)).

Furthermore and because Z is not a view, we can deduce the strides of the array that define the number of bytes to step in each dimension when traversing the array.

With all these information, we know how to access a specific item (designed by an index tuple) and more precisely, how to compute the start and end offsets:

Let's see if this is correct using the tobytes conversion method:

This array can be actually considered from different perspectives (i.e. layouts):
Item layout

               shape[1]
                 (=3)
            ┌───────────┐

         ┌  ┌───┬───┬───┐  ┐
         │  │ 0 │ 1 │ 2 │  │
         │  ├───┼───┼───┤  │
shape[0] │  │ 3 │ 4 │ 5 │  │ len(Z)
 (=3)    │  ├───┼───┼───┤  │  (=3)
         │  │ 6 │ 7 │ 8 │  │
         └  └───┴───┴───┘  ┘

Flattened item layout

┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘

└───────────────────────────────────┘
               Z.size
                (=9)

Memory layout (C order, big endian)

                         strides[1]
                           (=2)
                  ┌─────────────────────┐

          ┌       ┌──────────┬──────────┐ ┐
          │ p+00: │ 00000000 │ 00000000 │ │
          │       ├──────────┼──────────┤ │
          │ p+02: │ 00000000 │ 00000001 │ │ strides[0]
          │       ├──────────┼──────────┤ │   (=2x3)
          │ p+04  │ 00000000 │ 00000010 │ │
          │       ├──────────┼──────────┤ ┘
          │ p+06  │ 00000000 │ 00000011 │
          │       ├──────────┼──────────┤
Z.nbytes  │ p+08: │ 00000000 │ 00000100 │
(=3x3x2)  │       ├──────────┼──────────┤
          │ p+10: │ 00000000 │ 00000101 │
          │       ├──────────┼──────────┤
          │ p+12: │ 00000000 │ 00000110 │
          │       ├──────────┼──────────┤
          │ p+14: │ 00000000 │ 00000111 │
          │       ├──────────┼──────────┤
          │ p+16: │ 00000000 │ 00001000 │
          └       └──────────┴──────────┘

                  └─────────────────────┘
                        Z.itemsize
                     Z.dtype.itemsize
                           (=2)

If we now take a slice of Z, the result is a view of the base array Z:

Such view is specified using a shape, a dtype and strides because strides cannot be deduced anymore from the dtype and shape only:
Item layout

               shape[1]
                 (=2)
            ┌───────────┐

         ┌  ┌───┬╌╌╌┬───┐  ┐
         │  │ 0 │   │ 2 │  │            ┌───┬───┐
         │  ├───┼╌╌╌┼───┤  │            │ 0 │ 2 │
shape[0] │  ╎   ╎   ╎   ╎  │ len(Z)  →  ├───┼───┤
 (=2)    │  ├───┼╌╌╌┼───┤  │  (=2)      │ 6 │ 8 │
         │  │ 6 │   │ 8 │  │            └───┴───┘
         └  └───┴╌╌╌┴───┘  ┘

Flattened item layout

┌───┬╌╌╌┬───┬╌╌╌┬╌╌╌┬╌╌╌┬───┬╌╌╌┬───┐       ┌───┬───┬───┬───┐
│ 0 │   │ 2 │   ╎   ╎   │ 6 │   │ 8 │   →   │ 0 │ 2 │ 6 │ 8 │
└───┴╌╌╌┴───┴╌╌╌┴╌╌╌┴╌╌╌┴───┴╌╌╌┴───┘       └───┴───┴───┴───┘
└─┬─┘   └─┬─┘           └─┬─┘   └─┬─┘
  └───┬───┘               └───┬───┘
      └───────────┬───────────┘
               Z.size
                (=4)

Memory layout (C order, big endian)

              ┌        ┌──────────┬──────────┐ ┐             ┐
            ┌─┤  p+00: │ 00000000 │ 00000000 │ │             │
            │ └        ├──────────┼──────────┤ │ strides[1]  │
          ┌─┤    p+02: │          │          │ │   (=4)      │
          │ │ ┌        ├──────────┼──────────┤ ┘             │
          │ └─┤  p+04  │ 00000000 │ 00000010 │               │
          │   └        ├──────────┼──────────┤               │ strides[0]
          │      p+06: │          │          │               │   (=12)
          │            ├──────────┼──────────┤               │
Z.nbytes ─┤      p+08: │          │          │               │
  (=8)    │            ├──────────┼──────────┤               │
          │      p+10: │          │          │               │
          │   ┌        ├──────────┼──────────┤               ┘
          │ ┌─┤  p+12: │ 00000000 │ 00000110 │
          │ │ └        ├──────────┼──────────┤
          └─┤    p+14: │          │          │
            │ ┌        ├──────────┼──────────┤
            └─┤  p+16: │ 00000000 │ 00001000 │
              └        └──────────┴──────────┘

                       └─────────────────────┘
                             Z.itemsize
                          Z.dtype.itemsize
                                (=2)

Views and copies are important concepts for the optimization of your numerical computations. Even if we've already manipulated them in the previous section, the whole story is a bit more complex.

First, we have to distinguish between indexing and fancy indexing. The first will always return a view while the second will return a copy. This difference is important because in the first case, modifying the view modifies the base array while this is not true in the second case:

Thus, if you need fancy indexing, it's better to keep a copy of your fancy index (especially if it was complex to compute it) and to work with it:

If you are unsure if the result of your indexing is a view or a copy, you can check what is the base of your result. If it is None, then you result is a copy:

Note that some numpy functions return a view when possible (e.g. ravel) while some others always return a copy (e.g. flatten):

As a conclusion, we'll make an exercise. Given two vectors Z1 and Z2. We would like to know if Z2 is a view of Z1 and if yes, what is this view ?

>>> Z1 = np.arange(10)
>>> Z2 = Z1[1:-1:2]

   ╌╌╌┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬╌╌
Z1    │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
   ╌╌╌┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴╌╌
   ╌╌╌╌╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌╌╌╌╌╌╌╌
Z2        │ 1 │   │ 3 │   │ 5 │   │ 7 │
   ╌╌╌╌╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌╌╌╌╌╌╌╌

First, we need to check if Z1 is the base of Z2

>>> print(Z2.base is Z1)
True

At this point, we know Z2 is a view of Z1, meaning Z2 can be expressed as Z1[start:stop:step]. The difficulty is to find start, stop and step. For the step, we can use the strides property of any array that gives the number of bytes to go from one element to the other in each dimension. In our case, and because both arrays are one-dimensional, we can directly compare the first stride only:

>>> step = Z2.strides[0] // Z1.strides[0]
>>> print(step)
2

Next difficulty is to find the start and the stop indices. To do this, we can take advantage of the byte_bounds method that returns a pointer to the end-points of an array.

  byte_bounds(Z1)[0]                  byte_bounds(Z1)[-1]
          ↓                                   ↓
   ╌╌╌┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬╌╌
Z1    │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
   ╌╌╌┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴╌╌

      byte_bounds(Z2)[0]      byte_bounds(Z2)[-1]
              ↓                       ↓
   ╌╌╌╌╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌╌╌╌╌╌╌╌
Z2        │ 1 │   │ 3 │   │ 5 │   │ 7 │
   ╌╌╌╌╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌╌╌╌╌╌╌╌

>>> offset_start = np.byte_bounds(Z2)[0] - np.byte_bounds(Z1)[0]
>>> print(offset_start) # bytes
8

>>> offset_stop = np.byte_bounds(Z2)[-1] - np.byte_bounds(Z1)[-1]
>>> print(offset_stop) # bytes
-16

Converting these offsets into indices is straightforward using the itemsize and taking into account that the offset_stop is negative (end-bound of Z2 is logically smaller than end-bound of Z1 array). We thus need to add the items size of Z1 to get the right end index.

>>> start = offset_start // Z1.itemsize
>>> stop = Z1.size + offset_stop // Z1.itemsize
>>> print(start, stop, step)
1, 8, 2

Last we test our results:

>>> print(np.allclose(Z1[start:stop:step], Z2))
True

As an exercise, you can improve this first and very simple implementation by taking into account:

Negative steps

Multi-dimensional arrays

Solution to the exercise.

Code vectorization means that the problem you're trying to solve is inherently vectorizable and only requires a few numpy tricks to make it faster. Of course it does not mean it is easy or straightforward, but at least it does not necessitate totally rethinking your problem (as it will be the case in the Problem vectorization chapter). Still, it may require some experience to see where code can be vectorized. Let's illustrate this through a simple example where we want to sum up two lists of integers. One simple way using pure Python is:

This first naive solution can be vectorized very easily using numpy:

Without any surprise, benchmarking the two approaches shows the second method is the fastest with one order of magnitude.

Not only is the second approach faster, but it also naturally adapts to the shape of Z1 and Z2. This is the reason why we did not write Z1 + Z2 because it would not work if Z1 and Z2 were both lists. In the first Python method, the inner+ is interpreted differently depending on the nature of the two objects such that if we consider two nested lists, we get the following outputs:

The first method concatenates the two lists together, the second method concatenates the internal lists together and the last one computes what is (numerically) expected. As an exercise, you can rewrite the Python version such that it accepts nested lists of any depth.

Uniform vectorization is the simplest form of vectorization where all the elements share the same computation at every time step with no specific processing for any element. One stereotypical case is the Game of Life that has been invented by John Conway (see below) and is one of the earliest examples of cellular automata. Those cellular automata can be conveniently regarded as an array of cells that are connected together with the notion of neighbours and their vectorization is straightforward. Let me first define the game and we'll see how to vectorize it.
Figure 4.1
Conus textile snail exhibits a cellular automaton pattern on its shell. Image by Richard Ling, 2005.

The Game of Life is a cellular automaton devised by the British mathematician John Horton Conway in 1970. It is the best-known example of a cellular automaton. The "game" is actually a zero-player game, meaning that its evolution is determined by its initial state, needing no input from human players. One interacts with the Game of Life by creating an initial configuration and observing how it evolves.

The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, live or dead. Every cell interacts with its eight neighbours, which are the cells that are directly horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:

1. Any live cell with fewer than two live neighbours dies, as if by needs caused by underpopulation.

2. Any live cell with more than three live neighbours dies, as if by overcrowding.

3. Any live cell with two or three live neighbours lives, unchanged, to the next generation.

4. Any dead cell with exactly three live neighbours becomes a live cell.

The initial pattern constitutes the 'seed' of the system. The first generation is created by applying the above rules simultaneously to every cell in the seed - births and deaths happen simultaneously, and the discrete moment at which this happens is sometimes called a tick. (In other words, each generation is a pure function of the one before.) The rules continue to be applied repeatedly to create further generations.

Note

We could have used the more efficient python array interface but it is more convenient to use the familiar list object.

In pure Python, we can code the Game of Life using a list of lists representing the board where cells are supposed to evolve. Such a board will be equipped with border of 0 that allows to accelerate things a bit by avoiding having specific tests for borders when counting the number of neighbours.

Taking the border into account, counting neighbours then is straightforward:

To iterate one step in time, we then simply count the number of neighbours for each internal cell and we update the whole board according to the four aforementioned rules:

The figure below shows four iterations on a 4x4 area where the initial state is a glider, a structure discovered by Richard K. Guy in 1970.

Starting from the Python version, the vectorization of the Game of Life requires two parts, one responsible for counting the neighbours and one responsible for enforcing the rules. Neighbour-counting is relatively easy if we remember we took care of adding a null border around the arena. By considering partial views of the arena we can actually access neighbours quite intuitively as illustrated below for the one-dimensional case:

               ┏━━━┳━━━┳━━━┓───┬───┐
        Z[:-2] ┃ 0 ┃ 1 ┃ 1 ┃ 1 │ 0 │ (left neighbours)
               ┗━━━┻━━━┻━━━┛───┴───┘
                     ↓︎
           ┌───┏━━━┳━━━┳━━━┓───┐
   Z[1:-1] │ 0 ┃ 1 ┃ 1 ┃ 1 ┃ 0 │ (actual cells)
           └───┗━━━┻━━━┻━━━┛───┘
                     ↑
       ┌───┬───┏━━━┳━━━┳━━━┓
Z[+2:] │ 0 │ 1 ┃ 1 ┃ 1 ┃ 0 ┃ (right neighbours)
       └───┴───┗━━━┻━━━┻━━━┛

Going to the two dimensional case requires just a bit of arithmetic to make sure to consider all the eight neighbours.

For the rule enforcement, we can write a first version using numpy's argwhere method that will give us the indices where a given condition is True.

Even if this first version does not use nested loops, it is far from optimal because of the use of the four argwhere calls that may be quite slow. We can instead factorize the rules into cells that will survive (stay at 1) and cells that will give birth. For doing this, we can take advantage of Numpy boolean capability and write quite naturally:

Note

We did no write Z = 0 as this would simply assign the value 0 to Z that would then become a simple scalar.

If you look at the birth and survive lines, you'll see that these two variables are arrays that can be used to set Z values to 1 after having cleared it.

Your browser does not support the video tag.

Reaction and diffusion of chemical species can produce a variety of patterns, reminiscent of those often seen in nature. The Gray-Scott equations model such a reaction. For more information on this chemical system see the article Complex Patterns in a Simple System (John E. Pearson, Science, Volume 261, 1993). Let's consider two chemical species U and V with respective concentrations u and v and diffusion rates Du and Dv. V is converted into P with a rate of conversion k. f represents the rate of the process that feeds U and drains U, V and P. This can be written as:

Based on the Game of Life example, try to implement such reaction-diffusion system. Here is a set of interesting parameters to test:

The figure below shows some animations of the model for a specific set of parameters.
Figure 4.4
Reaction-diffusion Gray-Scott model. From left to right, Bacteria 1, Coral and Spiral Dense.

Your browser does not support the video tag. Your browser does not support the video tag. Your browser does not support the video tag.

The Mandelbrot set is the set of complex numbers c for which the function does not diverge when iterated from z  = 0, i.e., for which the sequence , etc., remains bounded in absolute value. It is very easy to compute, but it can take a very long time because you need to ensure a given number does not diverge. This is generally done by iterating the computation up to a maximum number of iterations, after which, if the number is still within some bounds, it is considered non-divergent. Of course, the more iterations you do, the more precision you get.
Figure 4.5
Romanesco broccoli, showing self-similar form approximating a natural fractal. Image by Jon Sullivan, 2004.

The trick is to search at each iteration values that have not yet diverged and update relevant information for these values and only these values. Because we start from Z = 0, we know that each value will be updated at least once (when they're equal to 0, they have not yet diverged) and will stop being updated as soon as they've diverged. To do that, we'll use numpy fancy indexing with the less(x1,x2) function that return the truth value of (x1 < x2) element-wise.

Here is the benchmark:

The gain is roughly a 5x factor, not as much as we could have expected. Part of the problem is that the np.less function implies tests at every iteration while we know that some values have already diverged. Even if these tests are performed at the C level (through numpy), the cost is nonetheless significant. Another approach proposed by Dan Goodman is to work on a dynamic array at each iteration that stores only the points which have not yet diverged. It requires more lines but the result is faster and leads to a 10x factor speed improvement compared to the Python version.

The benchmark gives us:

>>>  timeit ( "mandelbrot_numpy_2(xmin, xmax, ymin, ymax, xn, yn, maxiter)" , globals ())
1 loops, best of 3: 510 msec per loop

In order to visualize our results, we could directly display the N array using the matplotlib imshow command, but this would result in a "banded" image that is a known consequence of the escape count algorithm that we've been using. Such banding can be eliminated by using a fractional escape count. This can be done by measuring how far the iterated point landed outside of the escape cutoff. See the reference below about the renormalization of the escape count. Here is a picture of the result where we use recount normalization, and added a power normalized color map (gamma=0.3) as well as light shading.

Note

You should look at the ufunc.reduceat method that performs a (local) reduce with specified slices over a single axis.

We now want to measure the fractal dimension of the Mandelbrot set using the Minkowski-Bouligand dimension. To do that, we need to do box-counting with a decreasing box size (see figure below). As you can imagine, we cannot use pure Python because it would be way too slow. The goal of the exercise is to write a function using numpy that takes a two-dimensional float array and returns the dimension. We'll consider values in the array to be normalized (i.e. all values are between 0 and 1).

Spatial vectorization refers to a situation where elements share the same computation but are in interaction with only a subgroup of other elements. This was already the case for the game of life example, but in some situations there is an added difficulty because the subgroup is dynamic and needs to be updated at each iteration. This the case, for example, in particle systems where particles interact mostly with local neighbours. This is also the case for "boids" that simulate flocking behaviors.

Note

Excerpt from the Wikipedia entry Boids

Boids is an artificial life program, developed by Craig Reynolds in 1986, which simulates the flocking behaviour of birds. The name "boid" corresponds to a shortened version of "bird-oid object", which refers to a bird-like object.

As with most artificial life simulations, Boids is an example of emergent behavior; that is, the complexity of Boids arises from the interaction of individual agents (the boids, in this case) adhering to a set of simple rules. The rules applied in the simplest Boids world are as follows:

separation: steer to avoid crowding local flock-mates

alignment: steer towards the average heading of local flock-mates

cohesion: steer to move toward the average position (center of mass) of local flock-mates

As you might expect, the numpy implementation takes a different approach and we'll gather all our boids into a position array and a velocity array:

The first step is to compute the local neighborhood for all boids, and for this we need to compute all paired distances:

We could have used the scipy cdist but we'll need the dx and dy arrays later. Once those have been computed, it is faster to use the hypot method. Note that distance shape is(n, n) and each line relates to one boid, i.e. each line gives the distance to all other boids (including self).

From theses distances, we can now compute the local neighborhood for each of the three rules, taking advantage of the fact that we can mix them together. We can actually compute a mask for distances that are strictly positive (i.e. have no self-interaction) and multiply it with other distance masks.

Note

If we suppose that boids cannot occupy the same position, how can you compute mask_0 more efficiently?

Then, we compute the number of neighbours within the given radius and we ensure it is at least 1 to avoid division by zero.

We're ready to write our three rules:
Alignment Cohesion Separation
All three resulting steerings (separation, alignment & cohesion) need to be limited in magnitude. We leave this as an exercise for the reader. Combination of these rules is straightforward as well as the resulting update of velocity and position:

We finally visualize the result using a custom oriented scatter plot.

Your browser does not support the video tag.

We are now ready to visualize our boids. The easiest way is to use the matplotlib animation function and a scatter plot. Unfortunately, scatters cannot be individually oriented and we need to make our own objects using a matplotlib PathCollection. A simple triangle path can be defined as:

v= np.array([(-0.25, -0.25),
             ( 0.00,  0.50),
             ( 0.25, -0.25),
             ( 0.00,  0.00)])
c = np.array([Path.MOVETO,
              Path.LINETO,
              Path.LINETO,
              Path.CLOSEPOLY])

This path can be repeated several times inside an array and each triangle can be made independent.

n = 500
vertices = np.tile(v.reshape(-1), n).reshape(n, len(v), 2)
codes = np.tile(c.reshape(-1), n)

We now have a (n,4,2) array for vertices and a (n,4) array for codes representing n boids. We are interested in manipulating the vertices array to reflect the translation, scaling and rotation of each of the n boids.

Note

Rotate is really tricky.

How would you write the translate, scale and rotate functions ?

We've seen through these examples three forms of code vectorization:

Uniform vectorization where elements share the same computation unconditionally and for the same duration.

Temporal vectorization where elements share the same computation but necessitate a different number of iterations.

Spatial vectorization where elements share the same computation but on dynamic spatial arguments.

And there are probably many more forms of such direct code vectorization. As explained before, this kind of vectorization is one of the most simple even though we've seen it can be really tricky to implement and requires some experience, some help or both. For example, the solution to the boids exercise was provided by Divakar on stack overflow after having explained my problem.

Problem vectorization is much harder than code vectorization because it means that you fundamentally have to rethink your problem in order to make it vectorizable. Most of the time this means you have to use a different algorithm to solve your problem or even worse... to invent a new one. The difficulty is thus to think out-of-the-box.

To illustrate this, let's consider a simple problem where given two vectors X and Y, we want to compute the sum of X[i]*Y[j] for all pairs of indices i, j. One simple and obvious solution is to write:

However, this first and naïve implementation requires two loops and we already know it will be slow:

How to vectorize the problem then? If you remember your linear algebra course, you may have identified the expression X[i] * Y[j] to be very similar to a matrix product expression. So maybe we could benefit from some numpy speedup. One wrong solution would be to write:

This is wrong because the X*Y expression will actually compute a new vector Z such that Z[i] = X[i] * Y[i] and this is not what we want. Instead, we can exploit numpy broadcasting by first reshaping the two vectors and then multiply them:

Here we have Z[i,j] == X[i,0]*Y[0,j] and if we take the sum over each elements of Z, we get the expected result. Let's see how much speedup we gain in the process:

This is better, we gained a factor of ~150. But we can do much better.

If you look again and more closely at the pure Python version, you can see that the inner loop is using X[i] that does not depend on the j index, meaning it can be removed from the inner loop. Code can be rewritten as:

But since the inner loop does not depend on the i index, we might as well compute it only once:

Not so bad, we have removed the inner loop, meaning with transform a complexity into complexity. Using the same approach, we can now write:

Finally, having realized we only need the product of the sum over X and Y respectively, we can benefit from the np.sum function and write:

It is shorter, clearer and much, much faster:

We have indeed reformulated our problem, taking advantage of the fact that and we've learned in the meantime that there are two kinds of vectorization: code vectorization and problem vectorization. The latter is the most difficult but the most important because this is where you can expect huge gains in speed. In this simple example, we gain a factor of 150 with code vectorization but we gained a factor of 70,000 with problem vectorization, just by writing our problem differently (even though you cannot expect such a huge speedup in all situations). However, code vectorization remains an important factor, and if we rewrite the last solution the Python way, the improvement is good but not as much as in the numpy version:

This new Python version is much faster than the previous Python version, but still, it is 50 times slower than the numpy version:

Path finding is all about finding the shortest path in a graph. This can be split in two distinct problems: to find a path between two nodes in a graph and to find the shortest path. We'll illustrate this through path finding in a maze. The first task is thus to build a maze.
Figure 5.1
A hedge maze at Longleat stately home in England. Image by Prince Rurik, 2005.

There exist many maze generation algorithms but I tend to prefer the one I've been using for several years but whose origin is unknown to me. I've added the code in the cited wikipedia entry. Feel free to complete it if you know the original author. This algorithm works by creating n (density) islands of length p (complexity). An island is created by choosing a random starting point with odd coordinates, then a random direction is chosen. If the cell two steps in a given direction is free, then a wall is added at both one step and two steps in this direction. The process is iterated for n steps for this island. p islands are created. n and p are expressed as float to adapt them to the size of the maze. With a low complexity, islands are very small and the maze is easy to solve. With low density, the maze has more "big empty rooms".

Here is an animation showing the generation process.

Your browser does not support the video tag.

The breadth-first (as well as depth-first) search algorithm addresses the problem of finding a path between two nodes by examining all possibilities starting from the root node and stopping as soon as a solution has been found (destination node has been reached). This algorithm runs in linear time with complexity in (where V is the number of vertices, and E is the number of edges). Writing such an algorithm is not especially difficult, provided you have the right data structure. In our case, the array representation of the maze is not the most well-suited and we need to transform it into an actual graph as proposed by Valentin Bryukhanov.

Note

If we had used the depth-first algorithm, there is no guarantee to find the shortest path, only to find a path (if it exists).

Once this is done, writing the breadth-first algorithm is straightforward. We start from the starting node and we visit nodes at the current depth only (breadth-first, remember?) and we iterate the process until reaching the final node, if possible. The question is then: do we get the shortest path exploring the graph this way? In this specific case, "yes", because we don't have an edge-weighted graph, i.e. all the edges have the same weight (or cost).

The Bellman-Ford algorithm is an algorithm that is able to find the optimal path in a graph using a diffusion process. The optimal path is found by ascending the resulting gradient. This algorithm runs in quadratic time (where V is the number of vertices, and E is the number of edges). However, in our simple case, we won't hit the worst case scenario. The algorithm is illustrated below (reading from left to right, top to bottom). Once this is done, we can ascend the gradient from the starting node. You can check on the figure that this leads to the shortest path.

We start by setting the exit node to the value 1, while every other node is set to 0, except the walls. Then we iterate a process such that each cell's new value is computed as the maximum value between the current cell value and the discounted ( gamma=0.9 in the case below) 4 neighbour values. The process starts as soon as the starting node value becomes strictly positive.

The numpy implementation is straightforward if we take advantage of the generic_filter (from scipy.ndimage) for the diffusion process:

But in this specific case, it is rather slow. We'd better cook-up our own solution, reusing part of the game of life code:

Once this is done, we can ascend the gradient to find the shortest path as illustrated on the figure below:
Figure 5.5
Hydrodynamic flow at two different zoom levels, Neckar river, Heidelberg, Germany. Image by Steven Mathey, 2012.

In classical field theory, the Lagrangian specification of the field is a way of looking at fluid motion where the observer follows an individual fluid parcel as it moves through space and time. Plotting the position of an individual parcel through time gives the pathline of the parcel. This can be visualized as sitting in a boat and drifting down a river.

The Eulerian specification of the flow field is a way of looking at fluid motion that focuses on specific locations in the space through which the fluid flows as time passes. This can be visualized by sitting on the bank of a river and watching the water pass the fixed location.

In other words, in the Eulerian case, you divide a portion of space into cells and each cell contains a velocity vector and other information, such as density and temperature. In the Lagrangian case, we need particle-based physics with dynamic interactions and generally we need a high number of particles. Both methods have advantages and disadvantages and the choice between the two methods depends on the nature of your problem. Of course, you can also mix the two methods into a hybrid method.

However, the biggest problem for particle-based simulation is that particle interaction requires finding neighbouring particles and this has a cost as we've seen in the boids case. If we target Python and numpy only, it is probably better to choose the Eulerian method since vectorization will be almost trivial compared to the Lagrangian method.

I won't explain all the theory behind computational fluid dynamics because first, I cannot (I'm not an expert at all in this domain) and there are many resources online that explain this nicely (have a look at references below, especially tutorial by L. Barba). Why choose a computational fluid as an example then? Because results are (almost) always beautiful and fascinating. I couldn't resist (look at the movie below).

We'll further simplify the problem by implementing a method from computer graphics where the goal is not correctness but convincing behavior. Jos Stam wrote a very nice article for SIGGRAPH 1999 describing a technique to have stable fluids over time (i.e. whose solution in the long term does not diverge). Alberto Santini wrote a Python replication a long time ago (using numarray!) such that I only had to adapt it to modern numpy and accelerate it a bit using modern numpy tricks.

I won't comment the code since it would be too long, but you can read the original paper as well as the explanation by Philip Rideout on his blog. Below are some movies I've made using this technique.
Figure 5.6
Smoke simulation using the stable fluids algorithm by Jos Stam. Right most video comes from the glumpy package and is using the GPU (framebuffer operations, i.e. no OpenCL nor CUDA) for faster computations.

Your browser does not support the video tag. Your browser does not support the video tag. Your browser does not support the video tag.

Blue noise refers to sample sets that have random and yet uniform distributions with absence of any spectral bias. Such noise is very useful in a variety of graphics applications like rendering, dithering, stippling, etc. Many different methods have been proposed to achieve such noise, but the most simple is certainly the DART method.
Figure 5.7
Detail of "The Starry Night", Vincent van Gogh, 1889. The detail has been resampled using voronoi cells whose centers are a blue noise sample.

The DART method is one of the earliest and simplest methods. It works by sequentially drawing uniform random points and only accepting those that lie at a minimum distance from every previous accepted sample. This sequential method is therefore extremely slow because each new candidate needs to be tested against previous accepted candidates. The more points you accept, the slower the method is. Let's consider the unit surface and a minimum radius r to be enforced between each point.

I left as an exercise the vectorization of the DART method. The idea is to pre-compute enough uniform random samples as well as paired distances and to test for their sequential inclusion.

If the vectorization of the previous method poses no real difficulty, the speed improvement is not so good and the quality remains low and dependent on the k parameter. The higher, the better since it basically governs how hard to try to insert a new sample. But, when there is already a large number of accepted samples, only chance allows us to find a position to insert a new sample. We could increase the k value but this would make the method even slower without any guarantee in quality. It's time to think out-of-the-box and luckily enough, Robert Bridson did that for us and proposed a simple yet efficient method:

Step 0. Initialize an n-dimensional background grid for storing samples and accelerating spatial searches. We pick the cell size to be bounded by , so that each grid cell will contain at most one sample, and thus the grid can be implemented as a simple n-dimensional array of integers: the default −1 indicates no sample, a non-negative integer gives the index of the sample located in a cell.

Step 1. Select the initial sample, , randomly chosen uniformly from the domain. Insert it into the background grid, and initialize the "active list" (an array of sample indices) with this index (zero).

2 Step 2. While the active list is not empty, choose a random index from it (say i). Generate up to k points chosen uniformly from the spherical annulus between radius r and r around . For each point in turn, check if it is within distance r of existing samples (using the background grid to only test nearby samples). If a point is adequately far from existing samples, emit it as the next sample and add it to the active list. If after k attempts no such point is found, instead remove i from the active list.

Implementation poses no real problem and is left as an exercise for the reader. Note that not only is this method fast, but it also offers a better quality (more samples) than the DART method even with a high k parameter.

The last example we've been studying is indeed a nice example where it is more important to vectorize the problem rather than to vectorize the code (and too early). In this specific case we were lucky enough to have the work done for us but it won't be always the case and in such a case, the temptation might be high to vectorize the first solution we've found. I hope you're now convinced it might be a good idea in general to look for alternative solutions once you've found one. You'll (almost) always improve speed by vectorizing your code, but in the process, you may miss huge improvements.

One of the strengths of numpy is that it can be used to build new objects or to subclass the ndarray object. This later process is a bit tedious but it is worth the effort because it allows you to improve the ndarray object to suit your problem. We'll examine in the following section two real-world cases (typed list and memory-aware array) that are extensively used in the glumpy project (that I maintain) while the last one (double precision array) is a more academic case.

Typed list (also known as ragged array) is a list of items that all have the same data type (in the sense of numpy). They offer both the list and the ndarray API (with some restriction of course) but because their respective APIs may not be compatible in some cases, we have to make choices. For example, concerning the + operator, we'll choose to use the numpy API where the value is added to each individual item instead of expanding the list by appending a new item ( 1).

From the list API, we want our new object to offer the possibility of inserting, appending and removing items seamlessly.

Since the object is dynamic by definition, it is important to offer a general-purpose creation method powerful enough to avoid having to do later manipulations. Such manipulations, for example insertion/deletion, cost a lot of operations and we want to avoid them. Here is a proposal (among others) for the creation of a TypedList object.

This API allows creating an empty list or creating a list from some external data. Note that in the latter case, we need to specify how to partition the data into several items or they will split into 1-size items. It can be a regular partition (i.e. each item is 2 data long) or a custom one (i.e. data must be split in items of size 1, 2, 3 and 4 items).

At this point, the question is whether to subclass the ndarray class or to use an internal ndarray to store our data. In our specific case, it does not really make sense to subclass ndarray because we don't really want to offer the ndarray interface. Instead, we'll use an ndarray for storing the list data and this design choice will offer us more flexibility.

╌╌╌╌┬───┐┌───┬───┐┌───┬───┬───┐┌───┬───┬───┬───┬╌╌╌╌╌
    │ 0 ││ 1 │ 2 ││ 3 │ 4 │ 5 ││ 6 │ 7 │ 8 │ 9 │
 ╌╌╌┴───┘└───┴───┘└───┴───┴───┘└───┴───┴───┴───┴╌╌╌╌╌╌
   item 1  item 2    item 3         item 4

To store the limit of each item, we'll use an items array that will take care of storing the position (start and end) for each item. For the creation of a list, there are two distinct cases: no data is given or some data is given. The first case is easy and requires only the creation of the_data and _items arrays. Note that their size is not null since it would be too costly to resize the array each time we insert a new item. Instead, it's better to reserve some space.

First case. No data has been given, only dtype.

Second case. Some data has been given as well as a list of item sizes (for other cases, see full code below)

Once this is done, every list method requires only a bit of computation and playing with the different key when getting, inserting or setting an item. Here is the code for the __getitem__ method. No real difficulty but the possible negative step:

Modification of the list is a bit more complicated, because it requires managing memory properly. Since it poses no real difficulty, we left this as an exercise for the reader. For the lazy, you can have a look at the code below. Be careful with negative steps, key range and array expansion. When the underlying array needs to be expanded, it's better to expand it more than necessary in order to avoid future expansion.
setitem

╌╌╌╌┬───┬───┐┌───┬───┐┌───┬───┬╌╌╌╌╌
    │ 0 │ 0 ││ 1 │ 1 ││ 2 │ 2 │
 ╌╌╌┴───┴───┘└───┴───┘└───┴───┴╌╌╌╌╌╌
     item 1   item 2   item 3

╌╌╌╌┬───┬───┐┌───┬───┲━━━┓┌───┬───┬╌╌╌╌╌
    │ 0 │ 0 ││ 1 │ 1 ┃ 1 ┃│ 2 │ 2 │
 ╌╌╌┴───┴───┘└───┴───┺━━━┛└───┴───┴╌╌╌╌╌╌
     item 1     item 2     item 3

delitem

╌╌╌╌┬───┬───┐┏━━━┳━━━┓┌───┬───┬╌╌╌╌╌
    │ 0 │ 0 │┃ 1 ┃ 1 ┃│ 2 │ 2 │
 ╌╌╌┴───┴───┘┗━━━┻━━━┛└───┴───┴╌╌╌╌╌╌
     item 1   item 2   item 3

╌╌╌╌┬───┬───┐┌───┬───┬╌╌╌╌╌
    │ 0 │ 0 ││ 2 │ 2 │
 ╌╌╌┴───┴───┘└───┴───┴╌╌╌╌╌╌
     item 1    item 2

insert

╌╌╌╌┬───┬───┐┌───┬───┐┌───┬───┬╌╌╌╌╌
    │ 0 │ 0 ││ 1 │ 1 ││ 2 │ 2 │
 ╌╌╌┴───┴───┘└───┴───┘└───┴───┴╌╌╌╌╌╌
     item 1   item 2   item 3

╌╌╌╌┬───┬───┐┏━━━┳━━━┓┌───┬───┐┌───┬───┬╌╌╌╌╌
    │ 0 │ 0 │┃ 3 ┃ 3 ┃│ 1 │ 1 ││ 2 │ 2 │
 ╌╌╌┴───┴───┘┗━━━┻━━━┛└───┴───┘└───┴───┴╌╌╌╌╌╌
     item 1   item 2   item 3   item 4

Glumpy is an OpenGL-based interactive visualization library in Python whose goal is to make it easy to create fast, scalable, beautiful, interactive and dynamic visualizations.

Glumpy is based on a tight and seamless integration with numpy arrays. This means you can manipulate GPU data as you would with regular numpy arrays and glumpy will take care of the rest. But an example is worth a thousand words:

from glumpy import gloo

dtype = [("position", np.float32, 2),  # x,y
         ("color",    np.float32, 3)]  # r,g,b
V = np.zeros((3,3),dtype).view(gloo.VertexBuffer)
V["position"][0,0] = 0.0, 0.0
V["position"][1,1] = 0.0, 0.0

V is a VertexBuffer which is both a GPUData and a numpy array. When V is modified, glumpy takes care of computing the smallest contiguous block of dirty memory since it was last uploaded to GPU memory. When this buffer is to be used on the GPU, glumpy takes care of uploading the "dirty" area at the very last moment. This means that if you never use V, nothing will be ever uploaded to the GPU! In the case above, the last computed "dirty" area is made of 88 bytes starting at offset 0 as illustrated below:

Note

When a buffer is created, it is marked as totally dirty, but for the sake of illustration, just pretend this is not the case here.

Glumpy will thus end up uploading 88 bytes while only 16 bytes have been actually modified. You might wonder if this optimal. Actually, most of the time it is, because uploading some data to a buffer requires a lot of operations on the GL side and each call has a fixed cost.

As explained in the Subclassing ndarray documentation, subclassing ndarray is complicated by the fact that new instances of ndarray classes can come about in three different ways:

Explicit constructor call

View casting

New from template

However our case is simpler because we're only interested in the view casting. We thus only need to define the __new__ method that will be called at each instance creation. As such, the GPUData class will be equipped with two properties:

extents: This represents the full extent of the view relatively to the base array. It is stored as a byte offset and a byte size.

pending_data: This represents the contiguous dirty area as (byte offset, byte size) relatively to theextents property.

One extra difficulty is that we don't want all the views to keep track of the dirty area but only the base array. This is the reason why we don't instantiate the self._pending_data in the second case of the __array_finalize__ method. This will be handled when we need to update some data as during a__setitem__ call for example:

As explained on the numpy website, numpy is the fundamental package for scientific computing with Python. However, as illustrated in this chapter, the usage of numpy strengths goes far beyond a mere multi-dimensional container of generic data. Using ndarray as a private property in one case ( TypedList) or directly subclassing the ndarray class ( GPUData) to keep track of memory in another case, we've seen how it is possible to extend numpy's capabilities to suit very specific needs. The limit is only your imagination and your experience.

You've almost reached the end of the book and, hopefully, you've learned that numpy is a very versatile and powerful library. However in the meantime, remember that Python is also quite a powerful language. In fact, in some specific cases, it might be more powerful than numpy. Let's consider, for example, an interesting exercise that has been proposed by Tucker Balch in his Coursera's Computational Investing course. The exercise is written as:

Write the most succinct code possible to compute all "legal" allocations to 4 stocks such that the allocations are in 1.0 chunks, and the allocations sum to 10.0.

Yaser Martinez collected the different answers from the community and the proposed solutions yield surprising results. But let's start with the most obvious Python solution:

This solution is the slowest solution because it requires 4 loops, and more importantly, it tests all the different combinations (11641) of 4 integers between 0 and 10 to retain only combinations whose sum is 10. We can of course get rid of the 4 loops using itertools, but the code remains slow:

One of the best solution that has been proposed by Nick Popplas takes advantage of the fact we can have intelligent imbricated loops that will allow us to directly build each tuple without any test as shown below:

The best numpy solution by Yaser Martinez uses a different strategy with a restricted set of tests:

If we benchmark these methods, we get:

The numpy solution is the fastest but the pure Python solution is comparable. But let me introduce a small modification to the Python solution:

If we benchmark it, we get:

You read that right, we have gained a factor of 100 just by replacing square brackets with parenthesis. How is that possible? The explanation can be found by looking at the type of the returned object:

The solution_3_bis() returns a generator that can be used to generate the full list or to iterate over all the different elements. In any case, the huge speedup comes from the non-instantiation of the full list and it is thus important to wonder if you need an actual instance of your result or if a simple generator might do the job.

Beyond numpy, there are several other Python packages that are worth a look because they address similar yet different class of problems using different technology (compilation, virtual machine, just in time compilation, GPU, compression, etc.). Depending on your specific problem and your hardware, one package may be better than the other. Let's illustrate their usage using a very simple example where we want to compute an expression based on two float vectors:

If there are several additional packages for numpy, there are a trillion additional packages for scipy. In fact, every domain of science probably has its own package and most of the examples we've been studying until now could have been solved in two or three calls to a method in the relevant package. But of course, that was not the goal and programming things yourself is generally a good exercise if you have some spare time. The biggest difficulty at this point is to find these relevant packages. Here is a very short list of packages that are well-maintained, well-tested and may simplify your scientific life (depending on your domain). There are of course many more and depending on your specific needs, chances are you do not have to program everything by yourself. For an extensive list, have a look at the Awesome python list.

Numpy is a very versatile library but still, it does not mean you have to use it in every situation. In this chapter, we've seen some alternatives (including Python itself) that are worth a look. As always, the choice belongs to you. You have to consider what is the best solution for you in term of development time, computation time and effort in maintenance. On the one hand, if you design your own solution, you'll have to test it and to maintain it, but in exchange, you'll be free to design it the way you want. On the other hand, if you decide to rely on a third-party package, you'll save time in development and benefit from community-support even though you might have to adapt the package to your specific needs. The choice is up to you.

You've reached the end of this book. I hope you've learned something while reading it, I sure learned a lot writing it. Trying to explain something is a generally a good exercise to test for your knowledge of this thing. Of course, we only scratched the surface of numpy and there are many things left to discover. Have a look at the bibliography for books written by true experts, at the documentation written by people making numpy and don't hesitate to ask your questions on the mailing lists because the numpy community is very friendly.

If there's a single message to retain from this book it is "premature optimization is the root of all evil". We've seen that code vectorization can drastically improve your computation, with several orders of magnitude in some cases. Still, problem vectorization is generally much more powerful. If you write code vectorization too early in your design process, you won't be able to think out-of-the-box and you'll certainly miss some really powerful alternatives because you won't be able to identify your problem properly as we've seen in the problem vectorization chapter. This requires some experience and you have to be patient: experience is not an overnight process.

Finally, custom vectorization is an option worth considering once you've looked at the alternatives to numpy. When nothing works for you, numpy still offers you a clever framework to forge your own tools. And who knows, this can be the start of an exciting adventure for you and the community as it happened to me with the glumpy and the vispy packages.

bool, int, float, and complex are understood, but named np.bool_ with an additional underscore in NumPy. Additionally the names such as intc, long, or double used in the C programming language are defined.

┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘

┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 1 │ 1 │ 1 │ 1 │ 1 │ 1 │ 1 │ 1 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘

┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 1 │ 0 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘

┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘

┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘

┌───┐
│ 0 │
├───┤
│ 1 │
├───┤
│ 2 │
├───┤
│ 3 │
├───┤
│ 4 │
├───┤
│ 5 │
├───┤
│ 6 │
├───┤
│ 7 │
├───┤
│ 8 │
└───┘

┌───┬───┬───┐
│ 0 │ 1 │ 2 │
├───┼───┼───┤
│ 3 │ 4 │ 5 │
├───┼───┼───┤
│ 6 │ 7 │ 8 │
└───┴───┴───┘

┌───┬───┬───┐
│ 4 │ 5 │ 7 │
├───┼───┼───┤
│ 0 │ 2 │ 6 │
├───┼───┼───┤
│ 8 │ 4 │ 0 │
└───┴───┴───┘

┌──────┬──────┬──────┬──────┬──────┐
│ 0.00 │ 0.25 │ 0.50 │ 0.75 │ 1.00 │
└──────┴──────┴──────┴──────┴──────┘

┌───┬───┬───┐   ┌───┬───┬───┐
│ 0 │ 0 │ 0 │   │ 0 │ 1 │ 2 │
├───┼───┼───┤   ├───┼───┼───┤
│ 1 │ 1 │ 1 │   │ 0 │ 1 │ 2 │
├───┼───┼───┤   ├───┼───┼───┤
│ 2 │ 2 │ 2 │   │ 0 │ 1 │ 2 │
└───┴───┴───┘   └───┴───┴───┘

┏━━━┓───┬───┐   ┏━━━┓
┃ 0 ┃ 1 │ 2 │ → ┃ 0 ┃ (scalar)
┗━━━┛───┼───┤   ┗━━━┛
│ 3 │ 4 │ 5 │
├───┼───┼───┤
│ 6 │ 7 │ 8 │
└───┴───┴───┘

┌───┬───┬───┐
│ 0 │ 1 │ 2 │
├───┼───┼───┤
│ 3 │ 4 │ 5 │
├───┼───┏━━━┓   ┏━━━┓
│ 6 │ 7 ┃ 8 ┃ → ┃ 8 ┃ (scalar)
└───┴───┗━━━┛   ┗━━━┛

┌───┬───┬───┐
│ 0 │ 1 │ 2 │
┏━━━┳━━━┳━━━┓   ┏━━━┳━━━┳━━━┓
┃ 3 ┃ 4 ┃ 5 ┃ → ┃ 3 ┃ 4 ┃ 5 ┃
┗━━━┻━━━┻━━━┛   ┗━━━┻━━━┻━━━┛
│ 6 │ 7 │ 8 │      (view)
└───┴───┴───┘

┌───┬───┏━━━┓   ┏━━━┓
│ 0 │ 1 ┃ 2 ┃   ┃ 2 ┃
├───┼───┣━━━┫   ┣━━━┫
│ 3 │ 4 ┃ 5 ┃ → ┃ 5 ┃ (view)
├───┼───┣━━━┫   ┣━━━┫
│ 6 │ 7 ┃ 8 ┃   ┃ 8 ┃
└───┴───┗━━━┛   ┗━━━┛

┌───┬───┬───┐
│ 0 │ 1 │ 2 │    (view)
├───┏━━━┳━━━┓   ┏━━━┳━━━┓
│ 3 ┃ 4 ┃ 5 ┃   ┃ 4 ┃ 5 ┃
├───┣━━━╋━━━┫ → ┣━━━╋━━━┫
│ 6 ┃ 7 ┃ 8 ┃   ┃ 7 ┃ 8 ┃
└───┗━━━┻━━━┛   ┗━━━┻━━━┛

┏━━━┓───┏━━━┓   ┏━━━┳━━━┓
┃ 0 ┃ 1 ┃ 2 ┃   ┃ 0 ┃ 2 ┃
┗━━━┛───┗━━━┛ → ┣━━━╋━━━┫
│ 3 │ 4 │ 5 │   ┃ 6 ┃ 8 ┃
┏━━━┓───┏━━━┓   ┗━━━┻━━━┛
┃ 6 ┃ 7 ┃ 8 ┃    (view)
┗━━━┛───┗━━━┛

┏━━━┓───┬───┐
┃ 0 ┃ 1 │ 2 │
┗━━━┛───┏━━━┓   ┏━━━┳━━━┓
│ 3 │ 4 ┃ 5 ┃ → ┃ 0 ┃ 5 ┃
├───┼───┗━━━┛   ┗━━━┻━━━┛
│ 6 │ 7 │ 8 │    (copy)
└───┴───┴───┘

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┏━━━┓───┐
│ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 ┃ 1 ┃ 0 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┗━━━┛───┘

┌───┐
│ 0 │
├───┤
│ 0 │
├───┤
│ 0 │
├───┤
│ 0 │
├───┤
│ 0 │
├───┤
│ 0 │
├───┤
│ 0 │
├───┤
│ 0 │
├───┤
│ 0 │
├───┤
│ 0 │
┏━━━┓
┃ 1 ┃
┗━━━┛
│ 0 │
└───┘

┌───┬───┬───┬───┐
│ 0 │ 0 │ 0 │ 0 │
├───┼───┼───┼───┤
│ 0 │ 0 │ 0 │ 0 │
├───┼───┏━━━┓───┤
│ 0 │ 0 ┃ 1 ┃ 0 │
└───┴───┗━━━┛───┘

┌───┬───┬───┐
│ 0 │ 0 │ 0 │
├───┼───┼───┤
│ 0 │ 0 │ 0 │
├───┼───┼───┤
│ 0 │ 0 │ 0 │
├───┏━━━┓───┤
│ 0 ┃ 1 ┃ 0 │
└───┗━━━┛───┘

┌───┬───┐
│ 0 │ 0 │
├───┼───┤
│ 0 │ 0 │
├───┼───┤
│ 0 │ 0 │
├───┼───┤
│ 0 │ 0 │
├───┼───┤
│ 0 │ 0 │
┏━━━┓───┤
┃ 1 ┃ 0 │
┗━━━┛───┘

┌───┬───┬───┬───┬───┬───┐
│ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │
├───┼───┼───┼───┏━━━┓───┤
│ 0 │ 0 │ 0 │ 0 ┃ 1 ┃ 0 │
└───┴───┴───┴───┗━━━┛───┘

┌───┬───┬───┐   ┌───┐   ┌───┬───┬───┐   ┏━━━┓───┬───┐   ┌───┬───┬───┐
│ 0 │ 1 │ 2 │ + │ 1 │ = │ 0 │ 1 │ 2 │ + ┃ 1 ┃ 1 │ 1 │ = │ 1 │ 2 │ 3 │
├───┼───┼───┤   └───┘   ├───┼───┼───┤   ┗━━━┛───┼───┤   ├───┼───┼───┤
│ 3 │ 4 │ 5 │           │ 3 │ 4 │ 5 │   │ 1 │ 1 │ 1 │   │ 4 │ 5 │ 6 │
├───┼───┼───┤           ├───┼───┼───┤   ├───┼───┼───┤   ├───┼───┼───┤
│ 6 │ 7 │ 8 │           │ 6 │ 7 │ 8 │   │ 1 │ 1 │ 1 │   │ 7 │ 8 │ 9 │
└───┴───┴───┘           └───┴───┴───┘   └───┴───┴───┘   └───┴───┴───┘

┌───┬───┬───┐   ┌───┐   ┌───┬───┬───┐   ┏━━━┓───┬───┐   ┌───┬───┬───┐
│ 0 │ 1 │ 2 │ + │ 2 │ = │ 0 │ 1 │ 2 │ + ┃ 2 ┃ 2 │ 2 │ = │ 2 │ 3 │ 4 │
├───┼───┼───┤   ├───┤   ├───┼───┼───┤   ┣━━━┫───┼───┤   ├───┼───┼───┤
│ 3 │ 4 │ 5 │   │ 1 │   │ 3 │ 4 │ 5 │   ┃ 1 ┃ 1 │ 1 │   │ 4 │ 5 │ 6 │
├───┼───┼───┤   ├───┤   ├───┼───┼───┤   ┣━━━┫───┼───┤   ├───┼───┼───┤
│ 6 │ 7 │ 8 │   │ 0 │   │ 6 │ 7 │ 8 │   ┃ 0 ┃ 0 │ 0 │   │ 6 │ 7 │ 8 │
└───┴───┴───┘   └───┘   └───┴───┴───┘   ┗━━━┛───┴───┘   └───┴───┴───┘

┌───┬───┬───┐   ┌───┬───┬───┐   ┌───┬───┬───┐   ┏━━━┳━━━┳━━━┓   ┌───┬───┬───┐
│ 0 │ 1 │ 2 │ + │ 2 │ 1 │ 0 │ = │ 0 │ 1 │ 2 │ + ┃ 2 ┃ 1 ┃ 0 ┃ = │ 2 │ 2 │ 2 │
├───┼───┼───┤   └───┴───┴───┘   ├───┼───┼───┤   ┗━━━┻━━━┻━━━┛   ├───┼───┼───┤
│ 3 │ 4 │ 5 │                   │ 3 │ 4 │ 5 │   │ 2 │ 1 │ 0 │   │ 5 │ 5 │ 5 │
├───┼───┼───┤                   ├───┼───┼───┤   ├───┼───┼───┤   ├───┼───┼───┤
│ 6 │ 7 │ 8 │                   │ 6 │ 7 │ 8 │   │ 2 │ 1 │ 0 │   │ 8 │ 8 │ 8 │
└───┴───┴───┘                   └───┴───┴───┘   └───┴───┴───┘   └───┴───┴───┘

┌───┐   ┌───┬───┬───┐   ┏━━━┓───┬───┐   ┏━━━┳━━━┳━━━┓   ┌───┬───┬───┐
│ 0 │ + │ 0 │ 1 │ 2 │ = ┃ 0 ┃ 0 │ 0 │ + ┃ 0 ┃ 1 ┃ 2 ┃ = │ 0 │ 1 │ 2 │
├───┤   └───┴───┴───┘   ┣━━━┫───┼───┤   ┗━━━┻━━━┻━━━┛   ├───┼───┼───┤
│ 1 │                   ┃ 1 ┃ 1 │ 1 │   │ 0 │ 1 │ 2 │   │ 1 │ 2 │ 3 │
├───┤                   ┣━━━┫───┼───┤   ├───┼───┼───┤   ├───┼───┼───┤
│ 2 │                   ┃ 2 ┃ 2 │ 2 │   │ 0 │ 1 │ 2 │   │ 2 │ 3 │ 4 │
└───┘                   ┗━━━┛───┴───┘   └───┴───┴───┘   └───┴───┴───┘

# data[].attributes.attachment_link.description
There are already a fair number of books about Numpy (see Bibliography) and a legitimate question is to wonder if another book is really necessary. As you may have guessed by reading these lines, my personal answer is yes, mostly because I think there is room for a different approach concentrating on the migration from Python to Numpy through vectorization.

# data[].attributes.body
https://www.w3schools.com/python/python_intro.asp

# data[].attributes.attachment_link.readable_text
What is Python?

Python is a popular programming language. It was created by Guido van Rossum, and released in 1991.

It is used for:

web development (server-side),

software development,

mathematics,

system scripting.

What can Python do?

Python can be used on a server to create web applications.

Python can be used alongside software to create workflows.

Python can connect to database systems. It can also read and modify files.

Python can be used to handle big data and perform complex mathematics.

Python can be used for rapid prototyping, or for production-ready software development.

Why Python?

Python works on different platforms (Windows, Mac, Linux, Raspberry Pi, etc).

Python has a simple syntax similar to the English language.

Python has syntax that allows developers to write programs with fewer lines than some other programming languages.

Python runs on an interpreter system, meaning that code can be executed as soon as it is written. This means that prototyping can be very quick.

Python can be treated in a procedural way, an object-oriented way or a functional way.

Good to know

The most recent major version of Python is Python 3, which we shall be using in this tutorial. However, Python 2, although not being updated with anything other than security updates, is still quite popular.

In this tutorial Python will be written in a text editor. It is possible to write Python in an Integrated Development Environment, such as Thonny, Pycharm, Netbeans or Eclipse which are particularly useful when managing larger collections of Python files.

Python Syntax compared to other programming languages

Python was designed for readability, and has some similarities to the English language with influence from mathematics.

Python uses new lines to complete a command, as opposed to other programming languages which often use semicolons or parentheses.

Python relies on indentation, using whitespace, to define scope; such as the scope of loops, functions and classes. Other programming languages often use curly-brackets for this purpose.

Video: Python Introduction

# data[].attributes.attachment_link.description
W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

# data[].attributes.body
https://scikit-image.org/

# data[].attributes.attachment_link.title
scikit-image: Image processing in Python - scikit-image

# data[].attributes.attachment_link.description
If you find this project useful, please cite: Stéfan van der Walt, Johannes L. Schönberger, Juan Nunez-Iglesias, François Boulogne, Joshua D. Warner, Neil Yager, Emmanuelle Gouillart, Tony Yu and the scikit-image contributors.scikit-image: Image processing in Python. PeerJ 2:e453 (2014) http://dx.doi.org/10.7717/peerj.453

# data[].attributes.body
https://www.youtube.com/watch?v=aVwxzDHniEw

# data[].attributes.body
https://mypad.northampton.ac.uk/uonai/

# data[].attributes.attachment_link.readable_text
Hello and welcome to the Artificial Intelligence and Data Science programme at the University of Northampton.

Along with our internal NILE course sites and social media updates, this website provides useful course information for current students at different stages of their study. You can also find tech blogs written by tutors and students.

The programme is supported by a core team of Lecturers, Classroom Assistants, Technician Demonstrators, PhD researchers and External Advisors. We share a passion for AI and data science teaching and research while each of us focuses on one or multiple subject specialities. To know more about our cutting-edge research, please visit here.

If you are a prospective student who wishes to study with us, please visit the University's programme guide.

About the programme

This programme will equip you with a range of knowledge and practical skills required to establish your career. They can aid many career paths, such as a machine learning software engineer, solution architect, project manager or AI research scientist. You will learn the fundamentals and applications of data science and machine learning progressively over the course period.

Year 1
During your first year of this programme, you will study common computer science modules which give you the foundation and flexibility to specialise in your second and third years. Additionally, you'll study a specialised module that is tailored for artificial intelligence and data science programme students.

Year 2
In your second year, you will continue your journey with more specialised modules. These include the Introduction to AI, Cloud Computing and Big Data, and Relational Databases along with other computer science modules. You will also complete a group project where you will be a part of a small design team working to produce an innovative and bespoke AI solution to a real-world challenge.

Year 3
In your final year of the degree, you will acquire comprehensive AI skills in advanced modules. These modules include such as Advanced AI and Applications, Natural Language Processing, Modern Databases, and Media Technology. You will be able to develop AI applications using computer vision and neural networks and deploy the solutions in the cloud. You'll have an opportunity to complete an independent dissertation on a specialist topic of your choice in the field of artificial intelligence.

Accreditation
We are part of Amazon Web Services (AWS) Academy. Students joining the programme will have the chance to take part in AWS-accredited cloud computing courses to prepare students for industry-recognised certifications and the most in-demand careers in the cloud industry.

# data[].attributes.attachment_link.title
AI and Data Science research at the University of Northampton

# data[].attributes.attachment_link.description
Hello and welcome to the Artificial Intelligence and Data Science programme at the University of Northampton. Along with our internal NILE course sites and social media updates, this website provides useful course information for current students at different stages of their study. You can also find tech blogs written by tutors and students.

# data[].attributes.headline
FFMPEG - A complete, cross-platform solution to record, convert and stream audio and video.

# data[].attributes.subject
FFMPEG - A complete, cross-platform solution to record, convert and stream audio and video.

# data[].attributes.body
https://ffmpeg.org/

# data[].attributes.attachment_link.readable_text
Converting video and audio has never been so easy.

$ ffmpeg -i input.mp4 output.avi

June 19th, 2021, IRC

We have a new IRC home at Libera Chat now! Feel free to join us at #ffmpeg and #ffmpeg-devel. More info at contact#IRCChannels

April 8th, 2021, FFmpeg 4.4 "Rao"

FFmpeg 4.4 "Rao", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

June 15th, 2020, FFmpeg 4.3 "4:3"

FFmpeg 4.3 "4:3", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

October 5th, 2019, Bright Lights

FFmpeg has added a realtime bright flash removal filter to libavfilter.

Note that this filter is not FDA approved, nor are we medical professionals. Nor has this filter been tested with anyone who has photosensitive epilepsy. FFmpeg and its photosensitivity filter are not making any medical claims.

That said, this is a new video filter that may help photosensitive people watch tv, play video games or even be used with a VR headset to block out epiletic triggers such as filtered sunlight when they are outside. Or you could use it against those annoying white flashes on your tv screen. The filter fails on some input, such as the Incredibles 2 Screen Slaver scene. It is not perfect. If you have other clips that you want this filter to work better on, please report them to us on our trac.

See for yourself. Example was made with -vf photosensitivity=20:0.8

We are not professionals. Please use this in your medical studies to advance epilepsy research. If you decide to use this in a medical setting, or make a hardware hdmi input output realtime tv filter, or find another use for this, please let me know. This filter was a feature request of mine since 2013.

August 5th, 2019, FFmpeg 4.2 "Ada"

FFmpeg 4.2 "Ada", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

November 6th, 2018, FFmpeg 4.1 "al-Khwarizmi"

FFmpeg 4.1 "al-Khwarizmi", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

April 20th, 2018, FFmpeg 4.0 "Wu"

FFmpeg 4.0 "Wu", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

October 15th, 2017, FFmpeg 3.4 "Cantor"

FFmpeg 3.4 "Cantor", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

April 13th, 2017, FFmpeg 3.3 "Hilbert"

FFmpeg 3.3 "Hilbert", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

October 30th, 2016, Results: Summer Of Code 2016.

This has been a long time coming but we wanted to give a proper closure to our participation in this run of the program and it takes time. Sometimes it's just to get the final report for each project trimmed down, others, is finalizing whatever was still in progress when the program finished: final patches need to be merged, TODO lists stabilized, future plans agreed; you name it.

Without further ado, here's the silver-lining for each one of the projects we sought to complete during this Summer of Code season:

FFv1 (Mentor: Michael Niedermayer)

Stanislav Dolganov designed and implemented experimental support for motion estimation and compensation in the lossless FFV1 codec. The design and implementation is based on the snow video codec, which uses OBMC. Stanislav's work proved that significant compression gains can be achieved with inter frame compression. FFmpeg welcomes Stanislav to continue working beyond this proof of concept and bring its advances into the official FFV1 specification within the IETF.

Self test coverage (Mentor: Michael Niedermayer)

Petru Rares Sincraian added several self-tests to FFmpeg and successfully went through the in-some-cases tedious process of fine tuning tests parameters to avoid known and hard to avoid problems, like checksum mismatches due to rounding errors on the myriad of platforms we support. His work has improved the code coverage of our self tests considerably.

MPEG-4 ALS encoder implementation (Mentor: Thilo Borgmann)

Umair Khan updated and integrated the ALS encoder to fit in the current FFmpeg codebase. He also implemented a missing feature for the ALS decoder that enables floating-point sample decoding. FFmpeg support for MPEG-4 ALS has been improved significantly by Umair's work. We welcome him to keep maintaining his improvements and hope for great contributions to come.

Tee muxer improvements (Mentor: Marton Balint)

Ján Sebechlebský's generic goal was to improve the tee muxer so it tolerated blocking IO and allowed transparent error recovery. During the design phase it turned out that this functionality called for a separate muxer, so Ján spent his summer working on the so-called FIFO muxer, gradually fixing issues all over the codebase. He succeeded in his task, and the FIFO muxer is now part of the main repository, alongside several other improvements he made in the process.

TrueHD encoder (Mentor: Rostislav Pehlivanov)

Jai Luthra's objective was to update the out-of-tree and pretty much abandoned MLP (Meridian Lossless Packing) encoder for libavcodec and improve it to enable encoding to the TrueHD format. For the qualification period the encoder was updated such that it was usable and throughout the summer, successfully improved adding support for multi-channel audio and TrueHD encoding. Jai's code has been merged into the main repository now. While a few problems remain with respect to LFE channel and 32 bit sample handling, these are in the process of being fixed such that effort can be finally put in improving the encoder's speed and efficiency.

Motion interpolation filter (Mentor: Paul B Mahol)

Davinder Singh investigated existing motion estimation and interpolation approaches from the available literature and previous work by our own: Michael Niedermayer, and implemented filters based on this research. These filters allow motion interpolating frame rate conversion to be applied to a video, for example, to create a slow motion effect or change the frame rate while smoothly interpolating the video along the motion vectors. There's still work to be done to call these filters 'finished', which is rather hard all things considered, but we are looking optimistically at their future.

And that's it. We are happy with the results of the program and immensely thankful for the opportunity of working with such an amazing set of students. We can be a tough crowd but our mentors did an amazing job at hand holding our interns through their journey. Thanks also to Google for this wonderful program and to everyone that made room in their busy lives to help making GSoC2016 a success. See you in 2017!

September 24th, 2016, SDL1 support dropped.

Support for the SDL1 library has been dropped, due to it no longer being maintained (as of January, 2012) and it being superseded by the SDL2 library. As a result, the SDL1 output device has also been removed and replaced by an SDL2 implementation. Both the ffplay and opengl output devices have been updated to support SDL2.

August 9th, 2016, FFmpeg 3.1.2 "Laplace"

FFmpeg 3.1.2, a new point release from the 3.1 release branch, is now available! It fixes several bugs.

We recommend users, distributors, and system integrators, to upgrade unless they use current git master.

July 10th, 2016, ffserver program being dropped

After thorough deliberation, we're announcing that we're about to drop the ffserver program from the project starting with the next release. ffserver has been a problematic program to maintain due to its use of internal APIs, which complicated the recent cleanups to the libavformat library, and block further cleanups and improvements which are desired by API users and will be easier to maintain. Furthermore the program has been hard for users to deploy and run due to reliability issues, lack of knowledgable people to help and confusing configuration file syntax. Current users and members of the community are invited to write a replacement program to fill the same niche that ffserver did using the new APIs and to contact us so we may point users to test and contribute to its development.

July 1st, 2016, FFmpeg 3.1.1 "Laplace"

FFmpeg 3.1.1, a new point release from the 3.1 release branch, is now available! It mainly deals with a few ABI issues introduced in the previous release.

We strongly recommend users, distributors, and system integrators, especially those who experienced issues upgrading from 3.0, to upgrade unless they use current git master.

June 27th, 2016, FFmpeg 3.1 "Laplace"

FFmpeg 3.1 "Laplace", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

March 16th, 2016, Google Summer of Code

FFmpeg has been accepted as a Google Summer of Code open source organization. If you wish to participate as a student see our project ideas page. You can already get in contact with mentors and start working on qualification tasks as well as register at google and submit your project proposal draft. Good luck!

February 15th, 2016, FFmpeg 3.0 "Einstein"

FFmpeg 3.0 "Einstein", a new major release, is now available! Some of the highlights:

We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

January 30, 2016, Removing support for two external AAC encoders

We have just removed support for VisualOn AAC encoder (libvo-aacenc) and libaacplus in FFmpeg master.

Even before marking our internal AAC encoder as stable, it was known that libvo-aacenc was of an inferior quality compared to our native one for most samples. However, the VisualOn encoder was used extensively by the Android Open Source Project, and we would like to have a tested-and-true stable option in our code base.

When first committed in 2011, libaacplus filled in the gap of encoding High Efficiency AAC formats (HE-AAC and HE-AACv2), which was not supported by any of the encoders in FFmpeg at that time.

The circumstances for both have changed. After the work spearheaded by Rostislav Pehlivanov and Claudio Freire, the now-stable FFmpeg native AAC encoder is ready to compete with much more mature encoders. The Fraunhofer FDK AAC Codec Library for Android was added in 2012 as the fourth supported external AAC encoder, and the one with the best quality and the most features supported, including HE-AAC and HE-AACv2.

Therefore, we have decided that it is time to remove libvo-aacenc and libaacplus. If you are currently using libvo-aacenc, prepare to transition to the native encoder ( aac) when updating to the next version of FFmpeg. In most cases it is as simple as merely swapping the encoder name. If you are currently using libaacplus, start using FDK AAC ( libfdk_aac) with an appropriate profile option to select the exact AAC profile that fits your needs. In both cases, you will enjoy an audible quality improvement and as well as fewer licensing headaches.

Enjoy!

January 16, 2016, FFmpeg 2.8.5, 2.7.5, 2.6.7, 2.5.10

We have made several new point releases (2.8.5,2.7.5,2.6.7,2.5.10). They fix various bugs, as well as CVE-2016-1897 and CVE-2016-1898. Please see the changelog for each release for more details.

We recommend users, distributors and system integrators to upgrade unless they use current git master.

December 5th, 2015, The native FFmpeg AAC encoder is now stable!

After seven years the native FFmpeg AAC encoder has had its experimental flag removed and declared as ready for general use. The encoder is transparent at 128kbps for most samples tested with artifacts only appearing in extreme cases. Subjective quality tests put the encoder to be of equal or greater quality than most of the other encoders available to the public.

Licensing has always been an issue with encoding AAC audio as most of the encoders have had a license making FFmpeg unredistributable if compiled with support for them. The fact that there now exists a fully open and truly free AAC encoder integrated directly within the project means a lot to those who wish to use accepted and widespread standards.

The majority of the work done to bring the encoder up to quality was started during this year's GSoC by developer Claudio Freire and Rostislav Pehlivanov. Both continued to work on the encoder with the latter joining as a developer and mainainer, working on other parts of the project as well. Also, thanks to Kamedo2 who does comparisons and tests, the original authors and all past and current contributors to the encoder. Users are suggested and encouraged to use the encoder and provide feedback or breakage reports through our bug tracker.

A big thank you note goes to our newest supporters: MediaHub and Telepoint. Both companies have donated a dedicated server with free of charge internet connectivity. Here is a little bit about them in their own words:

Telepoint is the biggest carrier-neutral data center in Bulgaria. Located in the heart of Sofia on a cross-road of many Bulgarian and International networks, the facility is a fully featured Tier 3 data center that provides flexible customer-oriented colocation solutions (ranging from a server to a private collocation hall) and a high level of security.

MediaHub Ltd. is a Bulgarian IPTV platform and services provider which uses FFmpeg heavily since it started operating a year ago. "Donating to help keep FFmpeg online is our way of giving back to the community" .

Thanks Telepoint and MediaHub for their support!

September 29th, 2015, GSoC 2015 results

FFmpeg participated to the latest edition of the Google Summer of Code Project. FFmpeg got a total of 8 assigned projects, and 7 of them were successful.

We want to thank Google, the participating students, and especially the mentors who joined this effort. We're looking forward to participating in the next GSoC edition!

Below you can find a brief description of the final outcome of each single project.

Basic servers for network protocols, mentee: Stephan Holljes, mentor: Nicolas George

Stephan Holljes's project for this session of Google Summer of Code was to implement basic HTTP server features for libavformat, to complement the already present HTTP client and RTMP and RTSP server code.

The first part of the project was to make the HTTP code capable of accepting a single client; it was completed partly during the qualification period and partly during the first week of the summer. Thanks to this work, it is now possible to make a simple HTTP stream using the following commands:

    ffmpeg -i /dev/video0 -listen 1 -f matroska \
    -c:v libx264 -preset fast -tune zerolatency http://:8080
    ffplay http://localhost:8080/

The next part of the project was to extend the code to be able to accept several clients, simultaneously or consecutively. Since libavformat did not have an API for that kind of task, it was necessary to design one. This part was mostly completed before the midterm and applied shortly afterwards. Since the ffmpeg command-line tool is not ready to serve several clients, the test ground for that new API is an example program serving hard-coded content.

The last and most ambitious part of the project was to update ffserver to make use of the new API. It would prove that the API is usable to implement real HTTP servers, and expose the points where more control was needed. By the end of the summer, a first working patch series was undergoing code review.

Browsing content on the server, mentee: Mariusz Szczepańczyk, mentor: Lukasz Marek

Mariusz finished an API prepared by the FFmpeg community and implemented Samba directory listing as qualification task.

During the program he extended the API with the possibility to remove and rename files on remote servers. He completed the implementation of these features for file, Samba, SFTP, and FTP protocols.

At the end of the program, Mariusz provided a sketch of an implementation for HTTP directory listening.

Directshow digital video capture, mentee: Mate Sebok, mentor: Roger Pack

Mate was working on directshow input from digital video sources. He got working input from ATSC input sources, with specifiable tuner.

The code has not been committed, but a patch of it was sent to the ffmpeg-devel mailing list for future use.

The mentor plans on cleaning it up and committing it, at least for the ATSC side of things. Mate and the mentor are still working trying to finally figure out how to get DVB working.

Implementing full support for 3GPP Timed Text Subtitles, mentee: Niklesh Lalwani, mentor: Philip Langdale

Niklesh's project was to expand our support for 3GPP Timed Text subtitles. This is the native subtitle format for mp4 containers, and is interesting because it's usually the only subtitle format supported by the stock playback applications on iOS and Android devices.

ffmpeg already had basic support for these subtitles which ignored all formatting information - it just provided basic plain-text support.

Niklesh did work to add support on both the encode and decode side for text formatting capabilities, such as font size/colour and effects like bold/italics, highlighting, etc.

The main challenge here is that Timed Text handles formatting in a very different way from most common subtitle formats. It uses a binary encoding (based on mp4 boxes, naturally) and stores information separately from the text itself. This requires additional work to track which parts of the text formatting applies to, and explicitly dealing with overlapping formatting (which other formats support but Timed Text does not) so it requires breaking the overlapping sections into separate non-overlapping ones with different formatting.

Finally, Niklesh had to be careful about not trusting any size information in the subtitles - and that's no joke: the now infamous Android stagefright bug was in code for parsing Timed Text subtitles.

All of Niklesh's work is committed and was released in ffmpeg 2.8.

libswscale refactoring, mentee: Pedro Arthur, mentors: Michael Niedermayer, Ramiro Polla

Pedro Arthur has modularized the vertical and horizontal scalers. To do this he designed and implemented a generic filter framework and moved the existing scaler code into it. These changes now allow easily adding removing, splitting or merging processing steps. The implementation was benchmarked and several alternatives were tried to avoid speed loss.

He also added gamma corrected scaling support. An example to use gamma corrected scaling would be:

    ffmpeg -i input -vf scale=512:384:gamma=1 output

Pedro has done impressive work considering the short time available, and he is a FFmpeg committer now. He continues to contribute to FFmpeg, and has fixed some bugs in libswscale after GSoC has ended.

AAC Encoder Improvements, mentee: Rostislav Pehlivanov, mentor: Claudio Freire

Rostislav Pehlivanov has implemented PNS, TNS, I/S coding and main prediction on the native AAC encoder. Of all those extensions, only TNS was left in a less-than-usable state, but the implementation has been pushed (disabled) anyway since it's a good basis for further improvements.

PNS replaces noisy bands with a single scalefactor representing the energy of that band, gaining in coding efficiency considerably, and the quality improvements on low bitrates are impressive for such a simple feature.

TNS still needs some polishing, but has the potential to reduce coding artifacts by applying noise shaping in the temporal domain (something that is a source of annoying, notable distortion on low-entropy bands).

Intensity Stereo coding (I/S) can double coding efficiency by exploiting strong correlation between stereo channels, most effective on pop-style tracks that employ panned mixing. The technique is not as effective on classic X-Y recordings though.

Finally, main prediction improves coding efficiency by exploiting correlation among successive frames. While the gains have not been huge at this point, Rostislav has remained active even after the GSoC, and is polishing both TNS and main prediction, as well as looking for further improvements to make.

In the process, the MIPS port of the encoder was broken a few times, something he's also working to fix.

Animated Portable Network Graphics (APNG), mentee: Donny Yang, mentor: Paul B Mahol

Donny Yang implemented basic keyframe only APNG encoder as the qualification task. Later he wrote interframe compression via various blend modes. The current implementation tries all blend modes and picks one which takes the smallest amount of memory.

Special care was taken to make sure that the decoder plays correctly all files found in the wild and that the encoder produces files that can be played in browsers that support APNG.

During his work he was tasked to fix any encountered bug in the decoder due to the fact that it doesn't match APNG specifications. Thanks to this work, a long standing bug in the PNG decoder has been fixed.

For latter work he plans to continue working on the encoder, making it possible to select which blend modes will be used in the encoding process. This could speed up encoding of APNG files.

September 9th, 2015, FFmpeg 2.8

We published release as new major version. It contains all features and bug fixes of the git master branch from September 8th. Please see the for a list of the most important changes.

We recommend users, distributors and system integrators to upgrade unless they use current git master.

August 1st, 2015, A message from the FFmpeg project

Dear multimedia community,

The resignation of Michael Niedermayer as leader of FFmpeg yesterday has come by surprise. He has worked tirelessly on the FFmpeg project for many years and we must thank him for the work that he has done. We hope that in the future he will continue to contribute to the project. In the coming weeks, the FFmpeg project will be managed by the active contributors.

The last four years have not been easy for our multimedia community - both contributors and users. We should now look to the future, try to find solutions to these issues, and to have reconciliation between the forks, which have split the community for so long.

Unfortunately, much of the disagreement has taken place in inappropriate venues so far, which has made finding common ground and solutions difficult. We aim to discuss this in our communities online over the coming weeks, and in person at the VideoLAN Developer Days in Paris in September: a neutral venue for the entire open source multimedia community.

The FFmpeg project.

July 4th, 2015, FFmpeg needs a new host

UPDATE: We have received more than 7 offers for hosting and servers, thanks a lot to everyone!

After graciously hosting our projects ( FFmpeg, MPlayer and rtmpdump) for 4 years, Arpi (our hoster) has informed us that we have to secure a new host somewhere else immediately.

If you want to host an open source project, please let us know, either on ffmpeg-devel mailing list or irc.freenode.net #ffmpeg-devel.

We use about 4TB of storage and at least 4TB of bandwidth / month for various mailing lists, trac, samples repo, svn, etc.

March 16, 2015, FFmpeg 2.6.1

We have made a new major release () and now one week afterward 2.6.1. It contains all features and bugfixes of the git master branch from the 6th March. Please see the Release Notes for a list of note-worthy changes.

We recommend users, distributors and system integrators to upgrade unless they use current git master.

March 4, 2015, Google Summer of Code

FFmpeg has been accepted as a Google Summer of Code Project. If you wish to participate as a student see our project ideas page. You can already get in contact with mentors and start working on qualification tasks. Registration at Google for students will open March 16th. Good luck!

March 1, 2015, Chemnitzer Linux-Tage

We happily announce that FFmpeg will be represented at Chemnitzer Linux-Tage (CLT) in Chemnitz, Germany. The event will take place on 21st and 22nd of March.

More information can be found here

We demonstrate usage of FFmpeg, answer your questions and listen to your problems and wishes. If you have media files that cannot be processed correctly with FFmpeg, be sure to have a sample with you so we can have a look!

For the first time in our CLT history, there will be an FFmpeg workshop! You can read the details here. The workshop is targeted at FFmpeg beginners. First the basics of multimedia will be covered. Thereafter you will learn how to use that knowledge and the FFmpeg CLI tools to analyse and process media files. The workshop is in German language only and prior registration is necessary. The workshop will be on Saturday starting at 10 o'clock.

We are looking forward to meet you (again)!

December 5, 2014, FFmpeg 2.5

We have made a new major release () It contains all features and bugfixes of the git master branch from the 4th December. Please see the Release Notes for a list of note-worthy changes.

We recommend users, distributors and system integrators to upgrade unless they use current git master.

October 10, 2014, FFmpeg is in Debian unstable again

We wanted you to know there are FFmpeg packages in Debian unstable again. A big thank-you to Andreas Cadhalpun and all the people that made it possible. It has been anything but simple.

Unfortunately that was already the easy part of this news. The bad news is the packages probably won't migrate to Debian testing to be in the upcoming release codenamed jessie. Read the argumentation over at Debian.

However things will come out in the end, we hope for your continued remarkable support!

October 8, 2014, FFmpeg secured a place in OPW!

Thanks to a generous 6K USD donation by Samsung (Open Source Group), FFmpeg will be welcoming at least 1 "Outreach Program for Women" intern to work with our community for an initial period starting December 2014 (through March 2015).

We all know FFmpeg is used by the industry, but even while there are countless products building on our code, it is not at all common for companies to step up and help us out when needed. So a big thank-you to Samsung and the OPW program committee!

If you are thinking on participating in OPW as an intern, please take a look at our OPW wiki page for some initial guidelines. The page is still a work in progress, but there should be enough information there to get you started. If you, on the other hand, are thinking on sponsoring work on FFmpeg through the OPW program, please get in touch with us at opw@ffmpeg.org. With your help, we might be able to secure some extra intern spots for this round!

September 15, 2014, FFmpeg 2.4

We have made a new major release () It contains all features and bugfixes of the git master branch from the 14th September. Please see the Release Notes for a list of note-worthy changes.

We recommend users, distributors and system integrators to upgrade unless they use current git master.

August 20, 2014, FFmpeg 2.3.3, 2.2.7, 1.2.8

We have made several new point releases (2.3.3,2.2.7,1.2.8). They fix various bugs, as well as CVE-2014-5271 and CVE-2014-5272. Please see the changelog for more details.

We recommend users, distributors and system integrators to upgrade unless they use current git master.

July 29, 2014, Help us out securing our spot in OPW

Following our previous post regarding our participation on this year's OPW (Outreach Program for Women), we are now reaching out to our users (both individuals and companies) to help us gather the needed money to secure our spot in the program.
We need to put together 6K USD as a minimum but securing more funds would help us towards getting more than one intern.
You can donate by credit card using Click&Pledge and selecting the "OPW" option. If you would like to donate by money transfer or by check, please get in touch by e-mail and we will get back to you with instructions.
Thanks!

July 20, 2014, New website

The FFmpeg project is proud to announce a brand new version of the website made by db0. While this was initially motivated by the need for a larger menu, the whole website ended up being redesigned, and most pages got reworked to ease navigation. We hope you'll enjoy browsing it.

July 17, 2014, FFmpeg 2.3

We have made a new major release () It contains all features and bugfixes of the git master branch from the 16th July. Please see the Release Notes for a list of note-worthy changes.

We recommend users, distributors and system integrators to upgrade unless they use current git master.

July 3, 2014, FFmpeg and the Outreach Program For Women

FFmpeg has started the process to become an OPW includer organization for the next round of the program, with internships starting December 9. The OPW aims to "Help women (cis and trans) and genderqueer to get involved in free and open source software". Part of the process requires securing funds to support at least one internship (6K USD), so if you were holding on your donation to FFmpeg, this is a great chance for you to come forward, get in touch and help both the project and a great initiative!

We have set up an email address you can use to contact us about donations and general inquires regarding our participation in the program. Hope to hear from you soon!

June 29, 2014, FFmpeg 2.2.4, 2.1.5, 2.0.5, 1.2.7, 1.1.12, 0.10.14

We have made several new point releases (). They fix a security issue in the LZO implementation, as well as several other bugs. See the git log for details.

We recommend users, distributors and system integrators to upgrade unless they use current git master.

May 1, 2014, LinuxTag

Once again FFmpeg will be represented at LinuxTag in Berlin, Germany. The event will take place from 8th to 10th of May. Please note that this year's LinuxTag is at a different location closer to the city center.

We will have a shared booth with XBMC and VideoLAN. If you have media files that cannot be processed correctly with FFmpeg, be sure to have a sample with you so we can have a look!

More information about LinuxTag can be found here

We are looking forward to see you in Berlin!

April 18, 2014, OpenSSL Heartbeat bug

Our server hosting the Trac issue tracker was vulnerable to the attack against OpenSSL known as "heartbleed". The OpenSSL software library was updated on 7th of April, shortly after the vulnerability was publicly disclosed. We have changed the private keys (and certificates) for all FFmpeg servers. The details were sent to the mailing lists by Alexander Strasser, who is part of the project server team. Here is a link to the user mailing list archive .

We encourage you to read up on "OpenSSL heartbleed". It is possible that login data for the issue tracker was exposed to people exploiting this security hole. You might want to change your password in the tracker and everywhere else you used that same password.

April 11, 2014, FFmpeg 2.2.1

We have made a new point releases (2.2.1). It contains bug fixes for Tickets #2893, #3432, #3469, #3486, #3495 and #3540 as well as several other fixes. See the git log for details.

March 24, 2014, FFmpeg 2.2

We have made a new major release (2.2) It contains all features and bugfixes of the git master branch from 1st March. A partial list of new stuff is below:

    - HNM version 4 demuxer and video decoder
    - Live HDS muxer
    - setsar/setdar filters now support variables in ratio expressions
    - elbg filter
    - string validation in ffprobe
    - support for decoding through VDPAU in ffmpeg (the -hwaccel option)
    - complete Voxware MetaSound decoder
    - remove mp3_header_compress bitstream filter
    - Windows resource files for shared libraries
    - aeval filter
    - stereoscopic 3d metadata handling
    - WebP encoding via libwebp
    - ATRAC3+ decoder
    - VP8 in Ogg demuxing
    - side & metadata support in NUT
    - framepack filter
    - XYZ12 rawvideo support in NUT
    - Exif metadata support in WebP decoder
    - OpenGL device
    - Use metadata_header_padding to control padding in ID3 tags (currently used in
    MP3, AIFF, and OMA files), FLAC header, and the AVI "junk" block.
    - Mirillis FIC video decoder
    - Support DNx444
    - libx265 encoder
    - dejudder filter
    - Autodetect VDA like all other hardware accelerations

We recommend users, distributors and system integrators to upgrade unless they use current git master.

February 3, 2014, Chemnitzer Linux-Tage

We happily announce that FFmpeg will be represented at `Chemnitzer Linux-Tage' in Chemnitz, Germany. The event will take place on 15th and 16th of March.

More information can be found here

We invite you to visit us at our booth located in the Linux-Live area! There we will demonstrate usage of FFmpeg, answer your questions and listen to your problems and wishes.

If you have media files that cannot be processed correctly with FFmpeg, be sure to have a sample with you so we can have a look!

We are looking forward to meet you (again)!

February 9, 2014, trac.ffmpeg.org / trac.mplayerhq.hu Security Breach

The server on which FFmpeg and MPlayer Trac issue trackers were installed was compromised. The affected server was taken offline and has been replaced and all software reinstalled. FFmpeg Git, releases, FATE, web and mailinglists are on other servers and were not affected. We believe that the original compromise happened to a server, unrelated to FFmpeg and MPlayer, several months ago. That server was used as a source to clone the VM that we recently moved Trac to. It is not known if anyone used the backdoor that was found.

We recommend all users to change their passwords. Especially users who use a password on Trac that they also use elsewhere, should change that password at least elsewhere.

November 12, 2013, FFmpeg RFP in Debian

Since the splitting of Libav the Debian/Ubuntu maintainers have followed the Libav fork. Many people have requested the packaging of ffmpeg in Debian, as it is more feature-complete and in many cases less buggy.

Rogério Brito, a Debian developer, has proposed a Request For Package (RFP) in the Debian bug tracking system.

Please let the Debian and Ubuntu developers know that you support packaging of the real FFmpeg! See Debian ticket #729203 for more details.

October 28, 2013, FFmpeg 2.1

We have made a new major release (2.1) It contains all features and bugfixes of the git master branch from 28th October. A partial list of new stuff is below:

    - aecho filter
    - perspective filter ported from libmpcodecs
    - ffprobe -show_programs option
    - compand filter
    - RTMP seek support
    - when transcoding with ffmpeg (i.e. not streamcopying), -ss is now accurate
    even when used as an input option. Previous behavior can be restored with
    the -noaccurate_seek option.
    - ffmpeg -t option can now be used for inputs, to limit the duration of
    data read from an input file
    - incomplete Voxware MetaSound decoder
    - read EXIF metadata from JPEG
    - DVB teletext decoder
    - phase filter ported from libmpcodecs
    - w3fdif filter
    - Opus support in Matroska
    - FFV1 version 1.3 is stable and no longer experimental
    - FFV1: YUVA(444,422,420) 9, 10 and 16 bit support
    - changed DTS stream id in lavf mpeg ps muxer from 0x8a to 0x88, to be
    more consistent with other muxers.
    - adelay filter
    - pullup filter ported from libmpcodecs
    - ffprobe -read_intervals option
    - Lossless and alpha support for WebP decoder
    - Error Resilient AAC syntax (ER AAC LC) decoding
    - Low Delay AAC (ER AAC LD) decoding
    - mux chapters in ASF files
    - SFTP protocol (via libssh)
    - libx264: add ability to encode in YUVJ422P and YUVJ444P
    - Fraps: use BT.709 colorspace by default for yuv, as reference fraps decoder does
    - make decoding alpha optional for prores, ffv1 and vp6 by setting
    the skip_alpha flag.
    - ladspa wrapper filter
    - native VP9 decoder
    - dpx parser
    - max_error_rate parameter in ffmpeg
    - PulseAudio output device
    - ReplayGain scanner
    - Enhanced Low Delay AAC (ER AAC ELD) decoding (no LD SBR support)
    - Linux framebuffer output device
    - HEVC decoder, raw HEVC demuxer, HEVC demuxing in TS, Matroska and MP4
    - mergeplanes filter

We recommend users, distributors and system integrators to upgrade unless they use current git master.

# data[].attributes.attachment_link.description
ffmpeg -i input.mp4 output.avi We have a new IRC home at Libera Chat now! Feel free to join us at #ffmpeg and #ffmpeg-devel. More info at contact#IRCChannels FFmpeg 4.4 "Rao", a new major release, is now available! Some of the highlights: We strongly recommend users, distributors, and system integrators to upgrade unless they use current git master.

# data[].attributes.body
https://www.youtube.com/watch?v=XkY2DOUCWMU

# data[].attributes.attachment_link.title
Matrix multiplication as composition | Chapter 4, Essence of linear algebra