This code
def process_hero_box_annotations(post_to_boxes):
for box in post_to_boxes:
k = box
a = post_to_boxes.get(box)
new = ()
post_to_processed_box = {}
if len(a) != 0:
x0 = a[0][0]
y0 = a[0][1]
x1 = a[0][2]
y1 = a[0][3]
if len(a) == 2:
if a[0][0] < a[1][0]:
x0 = a[0][0]
else:
x0 = a[1][0]
if a[0][1] < a[1][1]:
y0 = a[0][1]
else:
y0 = a[1][1]
if a[0][2] > a[1][2]:
x1 = a[0][2]
else:
x1 = a[1][2]
if a[0][3] > a[1][3]:
y1 = a[0][3]
else:
y1 = a[1][3]
new = (x0, y0, x1, y1)
print(new)
post_to_processed_box[k] = new
return post_to_processed_box
gives me
{
384121: (10, 20, 100, 300)
}
when I want
{
149321: (14, 10, 503, 545),
384121: (10, 20, 100, 300)
}
Why is one item not adding?
CodePudding user response:
Move the following statement @ line 6 outside of the loop
post_to_processed_box = {}
So it would look more similar to the following
def process_hero_box_annotations(post_to_boxes):
post_to_processed_box = {}
for box in post_to_boxes:
k = box
a = post_to_boxes.get(box)
new = ()
if len(a) != 0:
x0 = a[0][0]
y0 = a[0][1]
x1 = a[0][2]
y1 = a[0][3]
if len(a) == 2:
if a[0][0] < a[1][0]:
x0 = a[0][0]
else:
x0 = a[1][0]
if a[0][1] < a[1][1]:
y0 = a[0][1]
else:
y0 = a[1][1]
if a[0][2] > a[1][2]:
x1 = a[0][2]
else:
x1 = a[1][2]
if a[0][3] > a[1][3]:
y1 = a[0][3]
else:
y1 = a[1][3]
new = (x0, y0, x1, y1)
print(new)
post_to_processed_box[k] = new
return post_to_processed_box
with your current code you are setting post_to_processed_box
to an empty dictionary each iteration of the loop.
CodePudding user response:
@Jadon's answer definitely solves your problem.
I want to offer this as another way of thinking of the problem of getting a "hero box" (a union of two rectangles):
- It uses some different logic, which I think might be easier to follow as it avoids nested if-blocks.
- I chose to use the
min()
andmax()
functions to find the minimums and maximums for X and Y. - I'm also using the
items()
method on the dict of boxes passed in, to get both the key and value/object in one statement.
import pprint
def union(box_a, box_b):
'''Return a box that both minimally & fully covers box_a and box_b.
A box is a 4-part tuple: (minX, minY, maxX, maxY)
'''
min_x = min(box_a[0], box_b[0])
min_y = min(box_a[1], box_b[1])
max_x = max(box_a[2], box_b[2])
max_y = max(box_a[3], box_b[3])
return (min_x, min_y, max_x, max_y)
def process_hero_box_annotations(post_to_boxes):
post_to_processed_box = {}
for key, boxes in post_to_boxes.items():
if len(boxes) > 2:
raise ValueError(f'Expected 0, 1, or 2 boxes, got {len(boxes)} boxes')
if len(boxes) == 0:
post_to_processed_box[key] = ()
continue # move on to the next set of key/boxes, if there is one
box_a = boxes[0]
hero_box = (box_a[0], box_a[1], box_a[2], box_a[3])
if len(boxes) == 2:
box_b = boxes[1]
hero_box = union(box_a, box_b)
post_to_processed_box[key] = hero_box
return post_to_processed_box
I mocked up some input that should produce the expected output you shared:
boxes = {
149321: [(14, 10, 500, 500), (20, 20, 503, 545)],
384121: [(10, 20, 100, 300), (50, 50, 90, 250)]
}
When I run it , I get your expected result:
hero_boxes = process_hero_box_annotations(boxes)
expected = {
149321: (14, 10, 503, 545),
384121: (10, 20, 100, 300)
}
assert hero_boxes == expected
pprint.pprint(hero_boxes, width=30)
{149321: (14, 10, 503, 545),
384121: (10, 20, 100, 300)}