GUI Measuring Picture Size for Cropping - python

I am new to GUI programming. I want to create something that can load an image and then I can either measure the part of the picture I want and can load it into a cropping method or have to return the area of the crop. Does anyone have suggestions for accomplishing that?
I have a program with PySimpleGUI that can load an image, but I am not sure where to go from there to get the capacity to measure the item.

Using sg.Graph to load your image, and set drag_submits=True and enable_events=True to generate events when mouse click or drag. It will return the coordinate of mouse, then you can get the position of mouse or width/height of selected area.
following code to demo.
import base64
from io import BytesIO
from PIL import Image
import PySimpleGUI as sg
def update(x0, y0, x1, y1):
"""
Update rectangle information
"""
print(repr(x0), repr(y0), repr(x1), repr(y1))
window['-START-'].update(f'Start: ({x0}, {y0})')
window['-STOP-' ].update(f'Start: ({x1}, {y1})')
window['-BOX-' ].update(f'Box: ({abs(x1-x0+1)}, {abs(y1-y0+1)})')
# Generate an image with size (400, 400)
imgdata = base64.b64decode(sg.EMOJI_BASE64_HAPPY_LAUGH)
image = Image.open(BytesIO(imgdata))
im = image.resize((400, 400), resample=Image.CUBIC)
with BytesIO() as output:
im.save(output, format="PNG")
data = output.getvalue()
layout = [
[sg.Graph((400, 400), (0, 0), (400, 400), key='-GRAPH-',
drag_submits=True, enable_events=True, background_color='green')],
[sg.Text("Start: None", key="-START-"),
sg.Text("Stop: None", key="-STOP-"),
sg.Text("Box: None", key="-BOX-")],
]
window = sg.Window("Measure", layout, finalize=True)
graph = window['-GRAPH-']
graph.draw_image(data=data, location=(0, 400))
x0, y0 = None, None
x1, y1 = None, None
colors = ['blue', 'white']
index = False
figure = None
while True:
event, values = window.read(timeout=100)
if event == sg.WINDOW_CLOSED:
break
elif event in ('-GRAPH-', '-GRAPH-+UP'):
if (x0, y0) == (None, None):
x0, y0 = values['-GRAPH-']
x1, y1 = values['-GRAPH-']
update(x0, y0, x1, y1)
if event == '-GRAPH-+UP':
x0, y0 = None, None
if figure:
graph.delete_figure(figure)
if None not in (x0, y0, x1, y1):
figure = graph.draw_rectangle((x0, y0), (x1, y1), line_color=colors[index])
index = not index
window.close()

Related

How to draw with mouse over webcam in Tkinter?

I have an app that displays the webcam using OpenCV then this is converted to Tkinter (for GUI purposes). I can implement a mouse drawing function but the image update loop keeps covering it. I have tried raise/lower on canvas and labels but to no avail. Anyone got any ideas on this please?
Update Loop:
def update(self):
isTrue, frame = self.vid.getFrame()
#Convert frame to TK and put on canvas
if isTrue:
self.photo = ImageTk.PhotoImage(image=PIL.Image.fromarray(frame))
self.image = self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)
self.window.after(10, self.update)
Draw Function:
def paint(self, event):
white = (255, 255, 255)
x1, y1 = (event.x - 2), (event.y - 2)
x2, y2 = (event.x + 2), (event.y + 2)
self.canvas.create_oval(x1, y1, x2, y2, fill="white", outline="white")

How to use cursor to move video with OpenCV?

I am currently trying to implement a function that will allow me to use the cursor to "grab" a video and move it around. I want to be able to only move the video when the cursor is held down and moved. I have defined the mouse events, captured the coordinates of my cursor but I am not sure how to write the function to crop the video.
x1, x2, y1, y2 = 0, 0, 0, 0
mouse_down = False
def mouse_event_callback(event, x, y, flags, param):
global x1, x2, y1, y2, mouse_down
if event == cv2.EVENT_LBUTTONDOWN:
x1, y1 = x, y
mouse_down = True
elif event == cv2.EVENT_MOUSEMOVE:
if mouse_down:
x2, y2 = x, y
mouse_grab_video(x1, x2, y1, y2)
elif event == cv2.EVENT_LBUTTONUP:
mouse_down = False
def mouse_grab_video(x1, x2, y1, y2):
...
Any help would be much appreciated!
You can crop the image directly based on the coordinate you get from your mouse event.
#!/usr/bin/env python3
import argparse
import cv2
import numpy as np
from PIL import Image
drawing = False # true if mouse is pressed
ix,iy = -1,-1
refPt = []
img = ""
clone = ""
ROIRegion = []
# mouse callback function
def draw_rectangle(event,x,y,flags,param):
global ix,iy,drawing,img,clone,refPt, ROIRegion
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
refPt = [(x, y)]
ROIRegion.append(refPt)
#clone = img.copy()
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
img = clone.copy()
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),3)
a=x
b=y
if a != x | b != y:
cv2.rectangle(img,(ix,iy),(x,y),(0,0,0),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
refPt.append((x,y))
img = clone.copy()
cv2.rectangle(img, (ix,iy),(x,y), (0, 255, 0), 2)
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
img = cv2.imread(args["image"])
img = np.array(img)
clone = img.copy()
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_rectangle)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == ord("r"):
del ROIRegion[-1]
del refPt[-1]
img = clone.copy()
elif k == 27:
break
#Crop image to ROI
for region in range(len(ROIRegion)):
cv2.rectangle(img, ROIRegion[region][0],ROIRegion[region][1], (0, 255, 0), 2)
roi = clone[ROIRegion[region][0][1]:ROIRegion[region][1][1], ROIRegion[region][0][0]:ROIRegion[region][1][0]]
For zoom you may use EVENT_MOUSEWHEEL to increment scale and resize the image based on the scale. update imshow for latest image you scale. you can refer to this link

Problem with pyglet drawing black lines instead of green pixels

So I'm a beginner programmer with Python I have been playing with pyglet and I've discovered a problem if you run this code:
from pyglet.gl import *
window = pyglet.window.Window(1000,500,"App",resizable=True)
window.set_minimum_size(500,250)
image =pyglet.resource.image("logo.png")
intt = None
def pixel(x1,y1):
color = []
size = []
for x in range(x1):
for y in range(y1):
size.append(x)
size.append(y)
color.append(0)
color.append(255)
color.append(0)
vertex_list = pyglet.graphics.vertex_list(x1 * y1,('v2i', size ),
('c3B', color ))
return vertex_list
#window.event
def on_draw():
window.clear()
#vertex_list = pixel(600,500)
#vertex_list.draw(GL_POINTS)
color = []
size = []
for x in range(100):
for y in range(500):
size.append(x+504)
size.append(y)
color.append(0)
color.append(255)
color.append(0)
vertex_list = pyglet.graphics.vertex_list(100 * 500, ('v2i', size),
('c3B', color))
vertex_list.draw(GL_POINTS)
pyglet.app.run()
You will find that the area shown has black lines in it. I've tried to fix it but it does not work and because pyglet is not pretty famous there aren't videos that describe that problem. I hope you know how to fix it because you are my last hope.
If you want to draw a filled area then draw a rectangular GL_POLYGON primitive instead of multiple GL_POINT primitives. That will be much faster and ensures that the area is completely filled:
from pyglet.gl import *
window = pyglet.window.Window(1000,500,"App",resizable=True)
window.set_minimum_size(500,250)
def pixel(x1, y1, x2, y2):
size = [x1, y1, x2, y1, x2, y2, x1, y2]
color = []
for _ in range(4):
color += [0, 255, 0]
vertex_list = pyglet.graphics.vertex_list(4, ('v2i', size ), ('c3B', color ))
return vertex_list
#window.event
def on_draw():
window.clear()
vertex_list = pixel(500, 0, 600, 500)
vertex_list.draw(GL_POLYGON)
pyglet.app.run()
If you want to draw an pyglet.image, then generate a texture and a pyglet.graphics.Batch:
from pyglet.gl import *
window = pyglet.window.Window(1000,500,"App",resizable=True)
window.set_minimum_size(500,250)
def quadTexture(x, y, w, h, texture):
vertex = [x, y, x+w, y, x+w, y+h, x, y+h]
tex = [0, 0, 1, 0, 1, 1, 0, 1]
batch = pyglet.graphics.Batch()
batch.add(4, GL_QUADS, texture, ('v2i', vertex ), ('t2f', tex ))
return batch
#window.event
def on_draw():
window.clear()
batch.draw()
file = "logo.png"
image = pyglet.image.load(file)
tex = pyglet.graphics.TextureGroup(image.get_texture())
batch = quadTexture(20, 20, image.width, image.height, tex)
pyglet.app.run()
Much easier is to use a pyglet.sprite. e.g:
from pyglet.gl import *
window = pyglet.window.Window(1000,500,"App",resizable=True)
window.set_minimum_size(500,250)
#window.event
def on_draw():
window.clear()
sprite.draw()
file = "logo.png"
image = pyglet.image.load(file)
sprite = pyglet.sprite.Sprite(image, x=20, y=20)
pyglet.app.run()

unable to capture window title python

The following code snippet should look for a window "Notes.txt - Notepad" and capture a screen-shot of that window.
import pyautogui
import win32gui
def screenshot(window_title="Notes.txt - Notepad"):
if window_title:
hwnd = win32gui.FindWindow(window_title, None)
if hwnd:
win32gui.SetForegroundWindow(hwnd)
x, y, x1, y1 = win32gui.GetClientRect(hwnd)
x, y = win32gui.ClientToScreen(hwnd, (x, y))
x1, y1 = win32gui.ClientToScreen(hwnd, (x1 - x, y1 - y))
im = pyautogui.screenshot(region=(x, y, x1, y1))
return im
else:
print('Window not found!')
else:
im = pyautogui.screenshot()
return im
im = screenshot('Calculator')
if im:
im.show()
The issues here is that no matter what I pass as window_title it always return:
Window not found!
When I print(hwnd) it evaluate to 0
File title:
The issue lies here - hwnd = win32gui.FindWindow(window_title, None).
Replace it with win32gui.FindWindowEx(None, None, None, window_title) and it should work.
Docs
EDIT:
win32gui.FindWindow(None, window_title) should also work.

Tkinter update polygon points on mouse click

I want to update the polygon on each mouse click. The below code redraw new polygon when new position is obtained from mouse click. I want to update the polygon or get new one (delete old one). How to do it. Here is the complete as suggested. Tkinter library of python is used.
import math
from Tkinter import *
from PIL import Image, ImageDraw
import Image, ImageTk
coord=[] # for saving coord of each click position
Dict_Polygons={} # Dictionary for saving polygons
list_of_points=[]
# Function to get the co-ordianates of mouse clicked position
def draw_polygons(event):
mouse_xy = (event.x, event.y)
func_Draw_polygons(mouse_xy)
# Function to draw polygon
def func_Draw_polygons(mouse_xy):
center_x, center_y = mouse_xy
#draw dot over position which is clicked
x1, y1 = (center_x - 1), (center_y - 1)
x2, y2 = (center_x + 1), (center_y + 1)
canvas.create_oval(x1, y1, x2, y2, fill='green', outline='green', width=5)
# add clicked positions to list
list_of_points.append(mouse_xy)
numberofPoint=len(list_of_points)
# Draw polygon
if numberofPoint>2:
poly=canvas.create_polygon(list_of_points, fill='', outline='green', width=2)
canvas.coords(poly,)
elif numberofPoint==2 :
print('line')
canvas.create_line(list_of_points)
else:
print('dot')
# ImageDraw.ImageDraw.polygon((list_of_points), fill=None, outline=None)
print(list_of_points)
##########################################################################
# Main function
if __name__ == '__main__':
root = tk.Tk()
# Input image
img = Image.open("e.png")
# Draw canvas for input image to pop up image for clicks
filename = ImageTk.PhotoImage(img)
canvas = Canvas(root,height=img.size[0],width=img.size[0])
canvas.image = filename
canvas.create_image(0,0,anchor='nw',image=filename)
canvas.pack()
# bind function to canvas to generate event
canvas.bind("<Button 3>", draw_polygons)
root.mainloop()
Does this get you any closer to your solution? It re-draws based on the list of points each time a new point is added to the list.
import math
#change to tkinter for python3
from Tkinter import *
#from PIL import Image, ImageDraw
#import Image, ImageTk
coord=[] # for saving coord of each click position
Dict_Polygons={} # Dictionary for saving polygons
list_of_points=[]
poly = None
# Function to get the co-ordianates of mouse clicked position
def draw_polygons(event):
mouse_xy = (event.x, event.y)
func_Draw_polygons(mouse_xy)
# Function to draw polygon
def func_Draw_polygons(mouse_xy):
global poly, list_of_points
center_x, center_y = mouse_xy
canvas.delete(ALL)
list_of_points.append((center_x, center_y))
for pt in list_of_points:
x, y = pt
#draw dot over position which is clicked
x1, y1 = (x - 1), (y - 1)
x2, y2 = (x + 1), (y + 1)
canvas.create_oval(x1, y1, x2, y2, fill='green', outline='green', width=5)
# add clicked positions to list
numberofPoint=len(list_of_points)
# Draw polygon
if numberofPoint>2:
poly=canvas.create_polygon(list_of_points, fill='', outline='green', width=2)
elif numberofPoint==2 :
print('line')
canvas.create_line(list_of_points)
else:
print('dot')
# ImageDraw.ImageDraw.polygon((list_of_points), fill=None, outline=None)
print(list_of_points)
##########################################################################
# Main function
if __name__ == '__main__':
root = Tk()
canvas = Canvas(root,height=200,width=200)
canvas.pack()
# bind function to canvas to generate event
canvas.bind("<Button 3>", draw_polygons)
root.mainloop()

Categories

Resources