1.
Remove background
A recurring task is to remove the background from a portrait or picture of a person. You
can do this by hand, but that takes time.
1.1.
The Python script
There is a Python script, called
rembg
that removes the background from an image. Now, one of the problems of Python is
illustrated by
https://xkcd.com/1987/
and this script has quite a number of dependencies.
And the dependencies are not installed automatically. Some of the dependencie may interfere with
your global Python environment. The solution is to create a virtual environment for this script.
My virtual environment will be under
/home/ljm/src/python_venv
because I thought that was a good place. I
cd
-ed to that directory and created the virtual environment:
python3 -m venv rembg
Use
python3
because it is the only way that it is guaranteed to work.
Next, activate that environment:
rembg/bin/activate
Next step is to install the packages. You might expect that dependencies are installed.
No. This is Python. So, you should install:
pip install rembg
pip install onnxruntime
pip install click
pip install filetype
pip install watchdog
pip install aiohttp
pip install gradio
pip install asyncer
Run
rembg
by hand to see if I've missed some dependencies.
And, to see how great Python is,(1)
do
du -sh rembg
937M rembg
That's almost a gig for a single script to work normally.
Isn't Python great?
1.2.
A shell wrapper
To hide the horrors of the virtual Python environment, I created a script.
#!/bin/bash
#INSTALL@ /usr/local/bin/rembg
#INSTALLEDFROM verlaine:/home/ljm/src/python_venv
# Path to the virtual environment
# Adapt this to your own environment
VENV_PATH=/home/ljm/src/python_venv/rembg
# Activate the virtual environment
source "$VENV_PATH/bin/activate"
# Run the Python script
"$VENV_PATH/bin/rembg" i "$@"
# Deactivate the virtual environment
deactivate
1.3.
The GIMP plugin
To run it from GIMP, you need to create a GIMP plugin.
/*
#INSTALL_C@ ~/.config/GIMP/2.10/plug-ins/plugin_rembg
#MAKE gimptool-2.0 --install plugin_rembg.c
*/
#include <libgimp/gimp.h>
#include <glib.h> // For g_strdup_printf, g_spawn_command_line_sync
#include <unistd.h> // For unlink()
// Declare a global variable for the JPEG file path
char *jpegfile;
char *jpegfile2;
static void query(void);
static void run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals);
GimpPlugInInfo PLUG_IN_INFO = {
NULL, // Init function (optional)
NULL, // Quit function (optional)
query, // Query function (required)
run // Run function (required)
};
// Plugin query function
static void query(void) {
static GimpParamDef args[] = {
{ GIMP_PDB_INT32, "run_mode", "Run mode" },
{ GIMP_PDB_IMAGE, "image", "Input image" },
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
};
gimp_install_procedure(
"plug-in-rembg", // Procedure name
"Remove background", // Plugin description
"Saves the current image as a JPEG file, runs the external rembg script, and imports the result as a new layer", // Plugin help
"ljm", // Author
"ljm", // Copyright
"2025", // Date
"<Image>/Filters/Misc/Remove Background", // Menu path
"RGB*, GRAY*", // Image types this plugin works with
GIMP_PLUGIN, // Plugin type
G_N_ELEMENTS(args), // Number of input parameters
0, // Number of output parameters
args, // Input parameter definitions
NULL // No output parameters
);
}
// Plugin run function
static void run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) {
gint32 image_id, drawable_id, new_layer_id;
GError *error = NULL;
gchar *stdout_output = NULL;
gchar *stderr_output = NULL;
gint exit_status;
// Generate a unique temporary filename in /tmp
jpegfile = g_strdup_printf("/tmp/tempfile-%d.jpg", g_random_int());
jpegfile2 = g_strdup_printf("/tmp/tempfile2-%d.jpg", g_random_int());
// Get the image and drawable ID from the input parameters
image_id = param[1].data.d_int32;
drawable_id = param[2].data.d_int32;
// Save the image to the specified file using gimp_file_save
gboolean success = gimp_file_save(GIMP_RUN_NONINTERACTIVE, image_id, drawable_id, jpegfile, jpegfile);
if (!success) {
gimp_message("Error: Could not save the image as JPEG.");
g_free(jpegfile);
return;
}
// Run the external script with the JPEG files as an argument
gchar *cmd = g_strdup_printf("/usr/local/bin/rembg %s %s", jpegfile,jpegfile2);
// Execute the command and capture stdout and stderr
success = g_spawn_command_line_sync(cmd, &stdout_output, &stderr_output, &exit_status, &error);
// Check if the command ran successfully
if (!success) {
gimp_message("Error: Could not run the rembg script.");
} else {
// Display the output from stdout (if any) in the GIMP message bar
if (stdout_output && *stdout_output) {
gimp_message(stdout_output);
}
// Optionally, handle stderr output
if (stderr_output && *stderr_output) {
gimp_message(stderr_output);
}
// Load the enhanced JPEG as a new layer
new_layer_id = gimp_file_load_layer(GIMP_RUN_NONINTERACTIVE, image_id, jpegfile2);
if (new_layer_id != -1) {
// Add the new layer to the image
gimp_image_insert_layer(image_id, new_layer_id, -1, -1);
} else {
gimp_message("Error: Could not load the enhanced image as a new layer.");
}
// Delete the temporary file after importing the layer
unlink(jpegfile); // Use standard POSIX unlink to remove the file
unlink(jpegfile2); // Use standard POSIX unlink to remove the file
}
// Free resources
g_free(jpegfile);
g_free(cmd);
g_free(stdout_output);
g_free(stderr_output);
// No return values to set
*nreturn_vals = 0;
}
// Main entry point
MAIN();
(1)
I loath Python