How is this for "performance portability?" I use this solution in C when the function is very expensive, therefore a little extra indirection really won't make any difference - but can potentially improve the reusability a lot. Is inlining calls to function via a pointer a very basic optimization that any self respecting compiler should be able to do, or is it a very advanced optimization that I can't count on working across platforms? Given the possibility of dynamic libraries I don't see how it could be inlined in all cases, therefore at least some kind of analysis must be done before trying it.
Of course, my statement if far from being complete and definitive answer, it's a mere suggestion of another method to add to OP's list.
If the functions are defined in different binaries which are dynamically linked, the chances of inlining are approaching zero [0], although this method may work across binaries in contrast to all techniques from the article. To enable compiler to inline the argument-function, the compiler must have definitions of both functions. To enable this in library/library-consumer scenario the higher level function [1] can be placed in header file and marked as static, this will guarantee that they are in the same module.
Inlining function pointers doesn't seem to be advanced optimization technique (it is not that different from constants propagation). GCC 4.5 does this for same module functions even in -O1 [2].
Personally, I prefer to emphasize modularity in my code and move to other solutions when something is identified as a bottle-neck (which seems to be nice rule of the thumb for all optimizations).
[0] I would love to be proven wrong, by some kind of JIT-ing dynamic linker.
[1] ie. function accepting other functions as arguments.
Inlining a call to a function via a pointer, if the function is static and implemented in the same .c file or an included header, is a basic optimization.
I'm less sure about the compiler figuring out that the user wants (in that case) process_image to be inlined into each of the wrapper functions. However, if you don't mind a bit of nonportability, it's easy to force it to do so: mark the function to be inlined __forceinline on MSVC, __attribute__((always_inline)) on GCC/Clang/ICC/etc.