gimp python - how to change pixel color?

3.6k views Asked by At

I would like to load 2 jpg images with Gimp Python. Then the pictures should be compared pixel by pixel. If the pixel in picture 2 has a certain rgb value, the pixel in picture 1 should be colored. Before that, a user input should be made in which the start value can be entered.

I'm unsure if gimp python can do it all?

Primarily I search the commands:
- Load a picture
- User input
- Load pixel RGB value
- Change pixel RGB value
- Save image

Many thanks in advance

I first tried c ++, but handling pictures is not that easy. My teacher advised me to gimp. Schematic it should look like this:

#include <iostream>
using namespace std;

int main()
{
unsigned long long int startPixelBreite;
unsigned long long int startPixelHoehe;
int prozent;


//EDIT: Load pic 1
//EDIT: load pic 2


//startpixel bestimmen durch usereingabe
    cout << "Startpixel Höhe" << endl;
    cin >> startPixelBreite;
    cout << "Startpixel Höhe" << endl;
    cin >> startPixelHoehe;

//breite + Höhe von bild 1 auslesen
        endpixelBreite = startPixelBreite + bildBreite1
        endpixelHoehe = startPixelHoehe + bildHoehe1

    //ANFANG: Schleife für pixelzeile
        aktuellerPixelX = 0;
        //ANFANG schleife für pixel pixelreihe


             //pixelfarbebild1 einlesen
                /*
                pixelfarbebild1[0]  = //rot
                pixelfarbebild1[1]  = //grün
                pixelfarbebild1[2]  = //blau
                */

            //pixelfarbebild2 einlesen
                /*
                pixelfarbebild2[0]  = //rot
                pixelfarbebild2[1]  = //grün
                pixelfarbebild2[2]  = //blau
                */

            if (aktuellerPixelX > startPixelBreite & aktuellerPixelX< endpixelBreite)
            {
                if pixelfarbe[0] = 102 & pixelfarbe[1] = 102 & pixelfabre [2] = 102 //grau
                {
                    prozent = 60
                    neuerpixel[0] = (pixelfarbebild1[0]*prozent-100*pixelfarbebild1[0]+100*pixelfarbebild2[0])/prozent  //rot
                    neuerpixel[1] = (pixelfarbebild1[1]*prozent-100*pixelfarbebild1[1]+100*pixelfarbebild2[1])/prozent  //grün
                    neuerpixel[2] = (pixelfarbebild1[2]*prozent-100*pixelfarbebild1[2]+100*pixelfarbebild2[2])/prozent  //blau
                }
                else if pixelfarbe[0] = 237 & pixelfarbe[1] = 136 & pixelfabre [2] = 196 //pink
                {
                    prozent = 70
                    neuerpixel[0] = (pixelfarbebild1[0]*prozent-100*pixelfarbebild1[0]+100*pixelfarbebild2[0])/prozent  //rot
                    neuerpixel[1] = (pixelfarbebild1[1]*prozent-100*pixelfarbebild1[1]+100*pixelfarbebild2[1])/prozent  //grün
                    neuerpixel[2] = (pixelfarbebild1[2]*prozent-100*pixelfarbebild1[2]+100*pixelfarbebild2[2])/prozent  //blau
                }
                else if pixelfarbe[0] = 175 & pixelfarbe[1] = 167 & pixelfabre [2] = 172 //hellgrau
                {
                    prozent = 67
                    neuerpixel[0] = (pixelfarbebild1[0]*prozent-100*pixelfarbebild1[0]+100*pixelfarbebild2[0])/prozent  //rot
                    neuerpixel[1] = (pixelfarbebild1[1]*prozent-100*pixelfarbebild1[1]+100*pixelfarbebild2[1])/prozent  //grün
                    neuerpixel[2] = (pixelfarbebild1[2]*prozent-100*pixelfarbebild1[2]+100*pixelfarbebild2[2])/prozent  //blau
                }
                else
                {
                    neuerpixel[0] = pixelfarbebild2[0]  //rot
                    neuerpixel[1] = pixelfarbebild2[1]  //grün
                    neuerpixel[2] = pixelfarbebild2[2]  //blau
                }

                //pixel in bild schreiben
            }
            else{
                neuerpixel[0] = pixelfarbebild2[0]  //rot
                neuerpixel[1] = pixelfarbebild2[1]  //grün
                neuerpixel[2] = pixelfarbebild2[2]  //blau
            }

            aktuellerPixelX++;

        //ENDE schleife für pixel pixelreihe

    //ENDE: Schleife für pixelzeile
//ausgabe

}
4

There are 4 answers

0
Tasos Papastylianou On

In matlab / octave this is very straightforward. No need for gimp, and integrates well with C++ if you absolutely must have c++ code integration. E.g., say you want to change Image2 pixels to R: 50, G: 60, B:70, whenever Image1 has pixels R:10, G: 20, B:30. Then:

% Alle kommentierure im lingula obfuscatis fur demonstraru how rude it looks

Im1 = imread('im1.jpg');  Im2 = imread('im2.jpg'); % readure imagurine
 R1 = Im1(:,:,1);          R2 = Im2(:,:,1);        % selectu 'red'   layeru piripitsi
 G1 = Im1(:,:,2);          G2 = Im2(:,:,2);        % selectu 'green' layeru piripitsi
 B1 = Im1(:,:,3);          B2 = Im2(:,:,3);        % selectu 'blue'  layeru piripitsi

Mask = (R1 == 10) & (G1 == 20) & (B1 == 30); % криеит маск фром чаннелз
R2(Mask) = 50; % πουτ 50 γουεαρ Mask ηζ True!
G2(Mask) = 60; % πουτ 60 γουεαρ Mask ηζ True!
B2(Mask) = 70; % πουτ 70 γουεαρ Mask ηζ True!

NewIm2 = cat(3, R2, G2, B2); % Sukasumeseleba! Habibi chan! Uleleleleleeeeeeeh!!!!!

You can read and compare images similarly in python using scipy.imread, numpy, etc if you prefer python over matlab. No need for gimp.


PS. As you may have realised from my sarcastic code comments, please consider writing code exclusively in English when asking an international audience such as SO. It's very frustrating and tiresome to read such 'mixed' code and therefore it comes across as rude and inconsiderate; (and this holds true even for someone like me personally, despite the fact that I happen to speak a reasonable amount of German and English is not my native language.). Not to mention that you risk needlessly limiting your audience to only German speakers by doing so!

3
Valentino On

In GIMP, check the gimp_drawable_get_pixel and gimp_drawable_set_pixel procedures. You can find all the procedures you can use in a python plug-in in the Filters -> Python Fu -> Console.

A very basic code, just to give you an idea, may be:

color_to_edit = (102, 102, 102) #or whatever color you wish to edit, this is an RGB value without alpha channel
new_color = (200, 200, 200) #the new color
for i in range(x_size):
    for j in range(y_size):
        num_channels, pixel = pdb.gimp_drawable_get_pixel(drawable, i, j)
        if all([p == q for p, q in zip(pixel, color_to_edit)]):
            pdb.gimp_drawable_set_pixel(drawable, i, j, 3, new_color)
pdb.gimp_displays_flush() #this will update the image.

Here drawable should be a gimp layer with your image.

1
xenoid On

You can/should use "pixel regions" to export/import layers to/from python arrays. A script of mine uses this to transfer Gimp's pixels into a numpy array:

# Returns NP array (N,bpp) (single vector of triplets)
def channelData(layer):
    w,h=layer.width,layer.height
    region=layer.get_pixel_rgn(0, 0, w,h)
    pixChars=region[:,:]
    bpp=region.bpp
    return np.frombuffer(pixChars,dtype=np.uint8).reshape(w,h,bpp)

This is Gimp 2.8 code, might need some changes to support higher bit depths in 2.10.

In the opposite direction:

def createResultLayer(image,name,result):
    rlBytes=np.uint8(result).tobytes();
    rl=gimp.Layer(image,name,image.width,image.height,
                  image.active_layer.type,100,NORMAL_MODE)
    region=rl.get_pixel_rgn(0, 0, rl.width,rl.height,True)
    region[:,:]=rlBytes
    image.add_layer(rl,0)
    gimp.displays_flush()

You can of course drop the numpy part, but if you can express your problem as global array ops things can be very fast. On Windows (or using a flatpak version on Linux), you have to add numpy to the Python runtime used by Gimp. See here for some hints. You'll find the full script here, that can also be used as an example of how to get at the image and layer.

See here for the Python-specific API documentation.

0
xenoid On

A completely different answer, that avoids extracting the pixels from Gimp

So we have the "image" layer (where you color pixels) and the "map" layer (where a given color you indicates which pixels should be colored). Then:

  • Do a color selection of the color on the "map" layer (gimp_by_color_select(maplayer,...))
  • Using that selection (which is global in the image and so applies to any layer), color the pixels on the image layer (bucket-fill selection, for a uniform color: gimp_edit_bucket_fill(imagelayer,...)).
  • For more complicated color schemes, you can paint a 3rd layer, insert it below the "image" layer, and delete the selected pixels to make it visible through, then merge the image layer on it.

All this is done with Gimp operators, and is very fast. It is also usable as manual procedure, so you can try it in Gimp first without writing a single line of code.