In the last few days, I’ve been thinking a lot about how I could introduce a new function, as “generic” as possible, in the G’MIC mathematical expression evaluator, to do vector-to-vector transformation, including the stuffs that we don’t really have, such as:
- Value or color mapping (like what command
map
does). - Image warping, when the vector is seen as an image (like what command
warp
does). - Permutation of image axes (somehow like what command
permute
does).
Reimplementing all commands permute
, map
and warp
directly in the math parser seemed a bit overkill to me, so I tried to figure out what generic function could do all this at once (even if there are still very specific things that can’t be done).
I ended up implementing the function:
map(X,P,_nb_channelsX,_nb_channelsP,_boundary_conditions)
which is simple enough to use and does indeed allow very generic transformations on vectors.
Basically, this function does the same as command map
:
It considers that vector X
is an input image of size (size(X)/nb_channelsX,1,1,nb_channelsX)
, and P
is a palette, i.e., another image of size (size(P)/nb_channelsP,1,1,nb_channelsP)
, and it returns an image Y
of size (size(X)/nb_channelsX,1,1,nb_channelsX*nb_channelsP)
such that
Y[k] = P[X[x]], for each channel of Y.
Let me show how map()
can handles the three mentioned cases:
- Value or color mapping.
Obviously, map()
can be used just as the map
command. This is the simplest example:
map_for_map :
sp david,256 luminance n 0,255
palette hot
eval "
X = crop(#0);
P = crop(#1);
Y = map(X,P,1,3);
store('out',Y,w#0,h#0,1,s#1);
"
$out
map()
works exactly the same as command map
, so there are no limitations of using map()
compared the corresponding command.
- Image warping:
Amusingly, it turns out that you can also use map()
to warp images as well.
The idea is to convert the warping map into an offset map, which will be the X
image that we send to map()
:
map_for_warp :
sp david,256 # [0]: Color image to warp
100%,100%,1,2 rand. -1,1 b. 10%,0 n. -30,30 +. '[x,y]' # [1]: Random 2D warping map
+warp[0] [1] # [2]: Result using 'warp' command.
# Apply warp in math evaluator, using `map()` command:
eval "
P = crop(#0);
# Convert warp map into offset map.
X = round(crop(#1,0,0,0,1,w#1,h#1,d#1,1))*w#0 + round(crop(#1,0,0,0,0,w#1,h#1,d#1,1));
Y = map(X,P,1,3);
store('out',Y,w#0,h#0,1,s#0)"
$out
Here, there are some limitations of using map()
compared to the warp
command:
- Interpolation is restricted to the
nearest neighbors
mode. - boundary conditions works a bit differently, as it is just handled for vector indices that go outside
[0,size(P)]
, while commandwarp
is a bit smarter for managing boundary conditions.
- Permutation of images axes:
Same idea as for warp
here, we define an offset map corresponding to the desired permutation, and we are ready to go with map()
.
map_for_permute :
sp david,256
{[h,w]},1,1,"y + x*w#0 + c*wh#0" # Define offset map for permutation (invert x/y axes)
eval "
P = crop(#0);
X = crop(#1);
Y = map(X,P,1,3);
store('out',Y,w#1,h#1,1,s#0)"
$out
At this point, I can say that map()
is clearly a great addition to the G’MIC math evaluator!
It doesn’t require zillions of parameters, and it is capable of doing quite complicated things on vectors. Of course, it’s still more convenient to use the classical commands map
, warp
and permute
, but if you really need to perform such actions inside the math evaluator, you won’t have to write some slow loops to do so.