Add custom libgmic C++ filter to gmic-qt

Is there any tutorial explaining how to extend “gmic-qt” application with a custom filter written in compiled Cpp language and which would call either “gmic.h” library or “CImg.h” library ? I could find none.

Example of such filter is provided in page G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processing - Libgmic : filter “foo2.cpp”.

  • The targeted goal is to be able to apply high performance compiled routines (potentially fortran codes) on images from either Gimp or Krita, through the use of gmic plugin.
  • Using the predefined gmic language is too restrictive for the targeted use.

The cited Cpp compiled code “foo2.cpp” is:

//----- File 'foo2.cpp' -----
        #include "gmic.h"
        #include <cstdio>
        #include <cmath>

        int main() {
        gmic_list<float> image_list;
        image_list.assign(2); // Tell 'image_list' it has 2 images.

        for (unsigned int i = 0; i<image_list._width; ++i) { // 2 input images.

        // Initialize each image of 'image_list' to a 320x200x1x3 (color) image.
        gmic_image<float>& img = image_list[i];
        img.assign(320,200,1,3);

        // Fill image buffer with random sinus waves.
        float *ptr = img;
        for (unsigned int c = 0; c<img._spectrum; ++c) // 3 channels.
        for (unsigned int y = 0; y<img._height; ++y) // 200 rows.
        for (unsigned int x = 0; x<img._width; ++x) // 320 columns.
        *(ptr++) = (float)(128 + 127*std::cos(x/(5. + 10*i))*std::sin(y/(5. + 10*i + c)));
        }

        gmic_list<char> image_names; // We don't care about image names here, let this empty.
        try {
        gmic("water[0] 20 flower[1] 20 blend vividlight",
        image_list,image_names);
        } catch (gmic_exception &e) { // In case something went wrong.
        std::fprintf(stderr,"ERROR : %s\n",e.what());
        return -1;
        }

        // Here, 'image_list' now contains only 1 (color) image of size 320x200x1x3.
        // You can retrieve the image data from the buffer at 'image_list[0]._data',
        // as well as the image dimensions 'image_list[0]._xxxx', where
        // 'xxxx' can be 'width', 'height', 'depth' or 'spectrum'.

        (...)  // Do whatever you want with the image data here.

        image_list.assign(0); // Deallocate images, if you want to do it before the destructor.
        return 0;
        }

The key element in this code is the explicit triple loop: which ranges on width, height and color channels of the image.

Thanks for answers or help.

Although I do have experience with c++, I had not touched this yet. Pinging @David_Tschumperle as he does this task often.

Not that I’m aware of - I certainly haven’t written any.
As you probably know, the tutorial you did use has taken you off to one side. What you want to do is write a highly performant command, one that appears to be a “native” G’MIC command in the G’MIC interpreter framework, which is what libgmic exposes to you. What you want to find in that interpreter framework are the ways to set up hooks to call into your custom code, and, I suppose, a mapping to a “command name” which, when the interpreter encounters such in a string its parsing, hooks into your code. To my knowledge, libgmic doesn’t furnish that kind of access. You have access to image list and image API’s, so you can set up image lists and put images on them, and you can call the interpreter to operate on the images on those lists via the commands you cite in the string you hand off to the interpreter. I believe that is it. Though you have custom code also operating on those images in parallel, I am aware of no mechanism that you can employ to expose your custom code through the gmic interpreter framework so that gmic-qt can find it. The tutorial you followed basically set you up as a co-consumer of the libgmic API, in parallel with gmic-qt, which also consumes the same API. I believe the standard path to extent libgmic is to extend CImg.h, which houses the mechanisms to expose the new custom command to libgmic, which wraps CImg.h and implements an interpreter to whatever CImg.h provides. Perhaps David could furnish additional insights. Good luck.

Edit: Addendum
Looking at your custom code, (“Fill image buffer with random sinus waves”), that is the kind of thing a G’MIC scripter would write a Math Expression for, the kind of thing an image -fill command would take as a parameter. Not as performant as natively compiled code, but not that much slower, (Math Expressions are JIT compiled and bytecode interpreted) and it follows a well-established pathway to gmic-qt.

Thanks a lot for your detailed answer, and the positioning of the elements.
Indeed that would be a possible goal: having defined a custom command, which gmic-qt would find.
And indeed, I was trying to escape working directly in CImg.h
Being more on the fortran hpc side (fluid mech.), experience is that linking to Cpp templating framework is both challenging and difficult to maintain. While passing a C pointer to Fortran is manageable.
Anyway, thanks for all your insights.

Another solution would be to have a compiled binary besides the plug-in, and create a custom filter that would basically call the binary executable with exec.
Not that portable, as your user must have the extra binary compiled for their architecture, but at least you could do everything you want.

I think that Math expressions are compiled for parallelized execution using OpenMP, on the fly. I am unsure. See the “Multi-threaded and in-place evaluation:” paragraph in the Math expression page.
You could see how fast your algorithm works in the G’MIC language for now, then implement it in C++/fortran. Note that @David_Tschumperle writes many new filters and experiments in the G’MIC language first, before deciding to implement it in C++ if necessary.