I am trying to implement a NMS filter for labels in a Database.
NMS is a filter that removes redundant squares. On the image provided we can see there is only one tree, but there are three labels surrounding it.
The filter will acknowledge those squares share a big proportion of their areas and merge them or leave only one square.
Basically I have an image with squares and I need to pass from (1) to (2). the boxes are stored on a table called "Labels" and it has
string id //(uuid, is string for compatibility to sqlite),
int top,
int left,
int right,
int bottom
The picture shows 2 scenarios. The first one (1) is the current state, and the second one (2) is what I aim to get.
The table describing the first image data is the following (instead of uuid I'll just write the corresponding square's color)
id | top | left | right | bottom |
---|---|---|---|---|
orange | 10 | 15 | 29 | 60 |
red | 12 | 16 | 30 | 58 |
grey | 11 | 10 | 28 | 61 |
green | 20 | 23 | 45 | 44 |
blue | 22 | 25 | 44 | 41 |
and the second one (the one I aim to get) is
id | top | left | right | bottom |
---|---|---|---|---|
orange | 10 | 15 | 29 | 60 |
blue | 22 | 25 | 44 | 41 |
What I got so far:
I can get a combinatory of each label compared with each other.
select l1.id, l2.id, ..* from labels l1 left join labels l2 on l1.id =! l2.id
I can obtain the IoU score between the joined labels (IoU is IntersectionArea/UnionArea, an score that goes from 0 to 1, 1 being two squares that match perfectly, 0 meaning no match at all)
the area of the intersection can be described as the following:
greatest(least(l1.right,l2.right)-greatest(l1.left,l2.left),0) * greatest(least(l1.bottom,l2.bottom)-greatest(l1.top,l2.top),0)
and the area of the union is just the sume of the two independent areas minus the intersection area
I can remove the repeated redundant columns that the first query returns by joining the ids in an ordered way and grouping.
select concat(least(l1.id, l2.id),greatest(l1.id, l2.id)), min(l1.id) as id2, max(l2.id), min(IoU) from Labels as l1 left join Labels as l2 on l1.id!=l2.id group by concat(least(l1.id, l2.id),greatest(l1.id, l2.id)) where IoU > 0.85
with this I get only once the results of pairs like orange-grey and grey-orange (on both IoU should be the same).
the result is something like this
concat | id | id2 | IoU |
---|---|---|---|
grayorange | orange | gray | 0.9 |
orangered | orange | red | 0.91 |
grayred | gray | red | 0.88 |
bluegreen | green | blue | 0.86 |
Where I need help.
- this step should realize that squares orange, grey, and red are all related.
If I group the table 3 by id, I would be getting that the two first squares are related.
If I group the table 3 by id2, I would be getting that the two squares in the middle are related.
and by inspection, can see that the first an third register are also related (since gray appears on column id and id2)
How can I group together the three first registers on the table?
Is there a function on pgsql that can help on this problem?
Do any trick come to your mind?, like what I did to remove the duplicates using concat(least(id,id2),greatest(id,id2))?