In Tkinter, when I create an image on a canvas and find the coordinates of it, it only returns two coordinates, so the find_overlapping method doesn't work with it (naturally). Is there an alternative?
You should be able to get the image's bounding box (bbox) by calling bbox = canvas.bbox(imageID). Then you can use canvas.find_overlapping(*bbox).
The coordinates it returns should be the coordinates of the top left corner of the image. So if the coordinates you got were (x, y), and your image object (assuming it's a PhotoImage) is img, then you can do:
w, h = img.width(), img.height()
find_overlapping(x, y, x + w, y + h)
Related
I am doing an object detection task and annotated my image using labelme. The images were annotated with rectangle bounding boxes in the labelme too. The JSON file of the annotation just shows two-point coordinates instead of four (required to define a rectangle). I need all the four coordinates or two coordinates with the width and height of the rectangle latest so I can prepare the mask. Can someone help me with that
You only need two points to define a bounding box.
Let's say that the 4 point coordinates that form the bounding box are the following:
(x, y)
(x + w, y)
(x, y + h)
(x + w, y + h)
What LabelMe is showing you the xmin, ymin, xmax and ymax. So, using the example, LabelMe would show you:
<bndbox>
<xmin>x</xmin>
<ymin>y</ymin>
<xmax>x+w</xmax>
<ymax>y+h</ymax>
</bndbox>
Which is enough to get the other 2 point coordinates.
I'm working on an project where I would like to take a bounding box already drawn on a subject and select it (via mouse click) so I can have something like a text dialogue box hover above the image, so I can then type in a label. I'm already using OpenCV to detect the object and draw an initial bounding box on it using the Haar Cascade classifier, but so far I can't find the right combination of OpenCV directives to be able to select that bounding box and then annotate it. The relevant code is below.
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
)
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
Would appreciate some good pointers. Thanks.
You can take the x/y position of the mouse and compare that to the bounding boxes.
The code below descibes how you could do that.
First, to be able to process mouse input, you have to crate a namedWindow. You can then attach a mouseCallback to that window:
# create window
cv2.namedWindow("Frame")
# attach a callback to the window, that calls 'getFace'
cv2.setMouseCallback("Frame", getFace)
In the getFace method, you check for button press, then loop through the faces and check if the x/y of the mouse is within the bounds of the bounding box of a face. If so, return the index of the face.
def getFace(event, x,y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
# if mousepressed
for i in range(len(faces)):
# loop through faces
(face_x,face_y,w,h) = faces[i]
# unpack variables
if x > face_x and x < face_x + w:
# if x is within x-range of face
if y > face_y and y < face_y + h:
# if y is also in y-range of face
return i
# then return the index of the face
This is a very rudimentary question and I'm sure that there's some part of the Pillow library/documentation I've missed...
Let's say you have a 128x128 image, and you want to save the "chunk" of it that is "x" pixels right from the top-left corner of the original image, and "y" pixels down from the top left corner of the original image (so the top left corner of this "chunk" is located at (x,y). If you know that the chunk you want is "a" pixels wide and "b" pixels tall (so the four corners of the chunk you want are known, and they're (x,y),(x+a,y),(x,y+b),(x+a,y+b)) - how would you save this "chunk" of the original image you're given as a separate image file?
More concisely, how can I save pieces of images given their pixel-coordinates using PIL? any help/pointers are appreciated.
Came up with:
"""
The function "crop" takes in large_img, small_img, x, y, w, h and returns the image lying within these restraints:
large_img: the filename of the large image
small_img: the desired filename of the smaller "sub-image"
x: x coordinate of the upper left corner of the bounding box
y: y coordinate of the upper left corner of the bounding box
w: width of the bounding box
h: height of the bounding box
"""
def crop(large_img, small_img, x, y, w, h):
img = Image.open(large_img)
box = (x, y, x+w, y+h)
area = img.crop(box)
area.save(small_img, 'jpeg')
import cairo
import math
w = 2000
h = 2000
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
ctx = cairo.Context(surface)
ctx.scale(w, h)
surface_path = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
ctx_path = cairo.Context(surface_path)
ctx_path.scale(w, h)
surface_circle = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
ctx_circle = cairo.Context(surface_circle)
ctx_circle.scale(w, h)
""" Lots of function calls that draw paths to surface_path and circles to surface_circle """
ctx.set_source_surface(surface_path, 0, 0)
ctx.paint()
ctx.set_source_surface(surface_circle, 0, 0)
ctx.paint()
surface_path.write_to_png("example.png")
surface_circle.write_to_png("example2.png")
surface.write_to_png("result.png")
Imgur link to saved images
I am attempting to compile two surfaces (one with lines, one with circles) onto one separate surface, then save that to a file.
Despite following what the documentation suggests should work, the final image ends up blank. I also tried calling flush() on surface_path and surface_circle, but that seemed to do nothing.
How could I combine the image info in surface_circle (example2.png) on top of surface_path (example.png), then output it to a file?
Try calling ctx.identity_matrix() before your last few paint() calls.
As is right-now, thanks to your call to ctx.scale(w, h), you only get the top-left pixels of those other surfaces scaled up to fill all of the target surface.
I seem to be having some trouble getting this code to work:
import Image, ImageDraw
im = Image.open("1.jpg")
draw = ImageDraw.Draw(im)
draw.ellipse((60, 60, 40, 40), fill=128)
del draw
im.save('output.png')
im.show()
This should draw an ellipse at (60,60) which is 40 by 40 pixels. The image returns nothing.
This code works fine however:
draw.ellipse ((0,0,40,40), fill=128)
It just seems that when i change the first 2 co-ords (for where the ellipse should be placed) it won't work if they are larger than the size of the ellipse to be drawn. For example:
draw.ellipse ((5,5,15,15), fill=128)
Works, but only shows part of the rect. Whereas
draw.ellipse ((5,5,3,3), fill=128)
shows nothing at all.
This happens when drawing a rectangle too.
The bounding box is a 4-tuple (x0, y0, x1, y1) where (x0, y0) is the top-left bound of the box and (x1, y1) is the lower-right bound of the box.
To draw an ellipse to the center of the image, you need to define how large you want your ellipse's bounding box to be (variables eX and eY in my code snippet below).
With that said, below is a code snippet that draws an ellipse to the center of an image:
from PIL import Image, ImageDraw
im = Image.open("1.jpg")
x, y = im.size
eX, eY = 30, 60 #Size of Bounding Box for ellipse
bbox = (x/2 - eX/2, y/2 - eY/2, x/2 + eX/2, y/2 + eY/2)
draw = ImageDraw.Draw(im)
draw.ellipse(bbox, fill=128)
del draw
im.save("output.png")
im.show()
This yields the following result (1.jpg on left, output.png on right):
The ellipse function draws an ellipse within a bounding box. So you need to use draw.ellipse((40,40,60,60)) or other coordinates where the top left is smaller than the bottom right.