1
votes

While using PIL draw rectangles on an image in the canvas. I wish to change the fill rectangle depending on the pixel color of my image in the canvas.

I have referred one of the cross posts (link pasted below) to create rectangles with mouse events in Tkinter.

create_rectangle fills the rectangle with a color specified with mouse events (example: the rectangle is filled with black in this example). Is there a way to logically change the fill color depending on the existing pixel color of the background image? I mean, while drawing a rectangle, I need only the white colored pixels of the background image to be turning red and the rest with a different color.

Drawing rectangle using mouse events in Tkinter

enter image description here

[1]: https://i.stack.imgur.com/W41kX.jpg

def rec_on_button_press(self,event):
    self.start_x = event.x
    self.start_y = event.y
    self.rect=self.image_canvas.create_rectangle(self.x, self.y, 1, 1,fill=self.python_red)
def rec_on_move(self, event):
    curX, curY = (event.x, event.y)
    imagenp= np.array(image)
    if imagenp[curY,curX]==255:
        self.python_red="#EE204D"
    else:
        self.python_red=None
    self.image_canvas.coords(self.rect, self.start_x, self.start_y, curX, curY)

def rec_on_button_release(self, event):
    pass
2
It sounds not very easy.What did you try ? - jizhihaoSAMA
I have used numpy to change the image to array and started reading each pixel of the mouse event. This, if statement actually picking the initial mouse position and changing the fill color but not reading all the pixels as mouse being dragged? - zym
Its not very clear what you want to do. Do you want to make a selection box? If not, can you please mock up an image using GIMP/Paint, etc - Edwin Clement
Can you create an image with the expected output of the area inside rectangle? - acw1668
I think your idea is not correct.According to your idea(from your code).It will finally generate a rectangle fill with white or fill with red which depends on the pixel where you pressed. - jizhihaoSAMA

2 Answers

1
votes

Principle: Crop the image you select,create it and show it.

The code need to be modified,the example of full code(the example is convert 255(white) to 0(black)):

import tkinter as tk # this is in python 3.4. For python 2.x import Tkinter
from PIL import Image, ImageTk
import numpy as np
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(2) # for windows 10

class ExampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.x = self.y = 0
        self.canvas = tk.Canvas(self, width=512, height=512, cursor="cross")
        self.canvas.pack(side="top", fill="both", expand=True)
        self.canvas.bind("<ButtonPress-1>", self.on_button_press)
        self.canvas.bind("<B1-Motion>", self.on_move_press)
        self.canvas.bind("<ButtonRelease-1>", self.on_button_release)

        self.rect = None

        self.start_x = None
        self.start_y = None
        self.python_red = None

        self.im = Image.open(r'ImagePath').convert("L")
        self.move_imageID = None
        self.move_image = None
        self.tk_im = ImageTk.PhotoImage(self.im)
        self.canvas.create_image(0,0,anchor="nw",image=self.tk_im)



    def on_button_press(self, event):
        # save mouse drag start position
        self.start_x = event.x
        self.start_y = event.y
        self.rect = self.canvas.create_rectangle(self.x, self.y,  0, 0, outline="black")

    def on_move_press(self, event):
        self.canvas.delete(self.move_imageID)
        crop_image = self.im.crop((self.start_x,self.start_y,event.x,event.y))
        imageArray = np.array(crop_image)
        if imageArray.shape:
            for i in range(imageArray.shape[0]):
                for j in range(imageArray.shape[1]): # convert  the white pixel to black
                    if imageArray[i,j] == 255:
                        imageArray[i,j] = 0
            self.move_image = Image.fromarray(imageArray)
            self.move_image = ImageTk.PhotoImage(self.move_image)
            self.move_imageID = self.canvas.create_image(self.start_x,self.start_y,anchor="nw",image=self.move_image)
            self.canvas.coords(self.rect,self.start_x,self.start_y,event.x,event.y)
            self.canvas.lift(self.rect)

    def on_button_release(self, event):
        pass


if __name__ == "__main__":
    app = ExampleApp()
    app.mainloop()

Now:

enter image description here

Select area:

enter image description here

-1
votes

Principle: Convert image to numpy array and use opencv to draw rectangles. After processing pixel colors convert back to image.

def rec_on_button_press(self,event):
        self.start_x = event.x
        self.start_y = event.y
        self.rect=self.image_canvas.create_rectangle(self.x, self.y, 1, 1,fill=self.python_red)
def rec_on_move(self, event):
        curX, curY = (event.x, event.y)
        cropimage=originalimage.crop((self.start_x,self.start_y,curX,curY))
        cropimagergb=cropimage.convert('RGB')
        cropimagergb.save('crop1.png')
        imagergbcv2=cv2.imread('crop1.png')
        if imagergbcv2.shape[:2]:
            for i in range(imagergbcv2.shape[0]):
                for j in range(imagergbcv2.shape[1]): 
                    color=imagergbcv2[i,j]
                    if (color[0]==255 and color[1]==255 and color[2]==255):
                        imagergbcv2[i,j]=(0,255,0)
        cv2.imwrite('crop2.png',imagergbcv2)
        croppedimage=cv2.imread('crop2.png')
        originalimage[self.start_y:self.start_y+croppedimage.shape[0],self.start_x:self.start_x+croppedimage.shape[1]]=croppedimage
        cv2.imwrite('originalpluscropped.png',originalimage)
    self.image_canvas.coords(self.rect, self.start_x, self.start_y, curX, curY)

def rec_on_button_release(self, event):
    pass
    self.image=Image.open('originalpluscropped.png')