// which is opposite of what you would normally expect.
// So we invert the transformation before passing it to scipy.
// Otherwise, a scaling of (3, 3) would actually shrink the image contents by a factor 3.
matrix = np.linalg.inv(matrix)
// Scipy also has the origin of linear transformations at the *center* of pixel (0, 0).
// We need to adjust, because that"s insane.
// We want the origin precisely at the top left corner of the image.
matrix = change_transform_origin(matrix, (-0.5, -0.5))
// The first axis of an image stored as numpy array is the Y axis.
// The matrix has to be adjusted to match that convention.
matrix[:2, :2] = matrix[1::-1, 1::-1]
matrix[:2, 2] = matrix[1::-1, 2]
// Apply the transformation to each channel separately.
// For that we need the first axis to represent the channels so we can loop over them.
image = np.moveaxis(image, params.channel_axis, 0)