Wolfram Research

Function Repository Resource:

NonMaximumSuppression (1.0.0) current version: 1.0.1 »

Source Notebook

Filter regions based on their overlap

Contributed by: Giulio Alessandrini

ResourceFunction["NonMaximumSuppression"][{reg1,reg2,}]

keeps the rectangular regions regi with low overlap between each other.

ResourceFunction["NonMaximumSuppression"][{reg1,}{w1,}]

uses the weights wi to score the importance of each regi.

ResourceFunction["NonMaximumSuppression"][regions,property]

gives the specified property for the filtered regions.

Details and Options

ResourceFunction["NonMaximumSuppression"] is used to filter regions based on their mutual overlap and their weights.
Regions must be given in the form Rectangle[{xmin,ymin},{xmax,ymax}].
If the weights are not provided, regions are scored in linearly descending order with w1=1 and wn=1/n.
The following properties are supported:
"Index"position of the selected region
"Region"selected region
"Weight"the weight used to score the region
{prop1,}a list of properties
Allall the available properties
The following options are supported:
AcceptanceThresholdAutomaticregion acceptance threshold
MaxOverlapFractionAutomaticmaximum allowed overlap fraction
Method"Hard"method to use
Possible values for Method are:
"Hard"remove regions with overlap greater than the specified threshold
"Soft"iteratively rescore the regions based on their overlap

Examples

Basic Examples (2) 

Filter out rectangles from list that have a big overlap with other rectangles in the list:

In[1]:=
ResourceFunction[
 "NonMaximumSuppression"][{Rectangle[{0.1, 0.1}, {1, 1}], Rectangle[{0, 0}, {1, 1}], Rectangle[{0, 0}, {-2, -2}]}]
Out[1]=

Define and display a list of rectangle shapes:

In[2]:=
SeedRandom[123];
Short[(boxes = Flatten@Array[
     Rectangle[2 {##} + RandomVariate[NormalDistribution[], 2], 2 {##} + RandomReal[{3, 9}, 2]] &, {5, 3}]), 2]
Out[2]=
In[3]:=
g = Graphics[{Opacity[.05], EdgeForm[Black], boxes}, ImageSize -> Small]
Out[3]=

Delete rectangles with high overlap and display the results in red along with the original rectangles in black:

In[4]:=
ResourceFunction["NonMaximumSuppression"][boxes];
Show[g, Graphics[{Opacity[0.3], Red, EdgeForm[Red], %}]]
Out[4]=

Only keep non-overlapping rectangles:

In[5]:=
ResourceFunction["NonMaximumSuppression"][boxes, MaxOverlapFraction -> 0];
Show[g, Graphics[{Opacity[0.3], Red, EdgeForm[Red], %}]]
Out[5]=

Scope (4) 

Perform non-max suppression on a list of regions:

In[6]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
Length[boxes]
Out[6]=
In[7]:=
ResourceFunction["NonMaximumSuppression"][boxes] // Short
Out[7]=
In[8]:=
Graphics[{Opacity[0.05], EdgeForm[Black], boxes, Opacity[0.3], Red, EdgeForm[Red], %}, ImageSize -> Small]
Out[8]=

Provide an explicit list of weights:

In[9]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
scores = {0.18372941641066354`, 0.7792523485576668, 0.7552787064436872, 0.20397739818471128`, 0.29873901258951774`, 0.5385959520846411, 0.0019547594798015044`, 0.7158017739163653, 0.16959589408147346`, 0.8582668907417819, 0.21215626418505606`, 0.304448649385447, 0.33974292946852325`, 0.4268902847722864, 0.3182413575132059};
Length[boxes]
Out[11]=

Performing non-maximum suppression eliminated some of the rectangles:

In[12]:=
result = ResourceFunction["NonMaximumSuppression"][boxes -> scores];
Length[result]
Out[13]=

Show the result:

In[14]:=
Graphics[{Opacity[0.05], EdgeForm[Black], boxes, Opacity[0.3], Red, EdgeForm[Red], result}, ImageSize -> Small]
Out[14]=

Ask for a specific property:

In[15]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
scores = {0.18372941641066354`, 0.7792523485576668, 0.7552787064436872, 0.20397739818471128`, 0.29873901258951774`, 0.5385959520846411, 0.0019547594798015044`, 0.7158017739163653, 0.16959589408147346`, 0.8582668907417819, 0.21215626418505606`, 0.304448649385447, 0.33974292946852325`, 0.4268902847722864, 0.3182413575132059};
ResourceFunction["NonMaximumSuppression"][boxes -> scores, "Index"]
Out[15]=

The index is determined by the order of the scores for rectangles that contained in the result:

In[16]:=
Reverse@Ordering[scores]
Out[16]=

Ask for a list of properties:

In[17]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
scores = {0.18372941641066354`, 0.7792523485576668, 0.7552787064436872, 0.20397739818471128`, 0.29873901258951774`, 0.5385959520846411, 0.0019547594798015044`, 0.7158017739163653, 0.16959589408147346`, 0.8582668907417819, 0.21215626418505606`, 0.304448649385447, 0.33974292946852325`, 0.4268902847722864, 0.3182413575132059};
ResourceFunction["NonMaximumSuppression"][
 boxes -> scores, {"Index", "Region"}]
Out[19]=

Ask for all properties:

In[20]:=
ResourceFunction["NonMaximumSuppression"][boxes -> scores, All]
Out[20]=

Options (6) 

AcceptanceThreshold (2) 

Specify an AcceptanceThreshold for the regions:

In[21]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
scores = {0.18372941641066354`, 0.7792523485576668, 0.7552787064436872, 0.20397739818471128`, 0.29873901258951774`, 0.5385959520846411, 0.0019547594798015044`, 0.7158017739163653, 0.16959589408147346`, 0.8582668907417819, 0.21215626418505606`, 0.304448649385447, 0.33974292946852325`, 0.4268902847722864, 0.3182413575132059};
ResourceFunction["NonMaximumSuppression"][boxes -> scores, AcceptanceThreshold -> .5]
Out[21]=
In[22]:=
Graphics[{Opacity[0.05], EdgeForm[Black], boxes, Opacity[0.3], Red, EdgeForm[Red], %}, ImageSize -> Small]
Out[22]=

Specify values to use before and after the overlap filtering:

In[23]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
scores = {0.18372941641066354`, 0.7792523485576668, 0.7552787064436872, 0.20397739818471128`, 0.29873901258951774`, 0.5385959520846411, 0.0019547594798015044`, 0.7158017739163653, 0.16959589408147346`, 0.8582668907417819, 0.21215626418505606`, 0.304448649385447, 0.33974292946852325`, 0.4268902847722864, 0.3182413575132059};
ResourceFunction["NonMaximumSuppression"][boxes -> scores, Method -> "Soft", AcceptanceThreshold -> {.2, .5}]
Out[23]=
In[24]:=
Graphics[{Opacity[0.05], EdgeForm[Black], boxes, Opacity[0.3], Red, EdgeForm[Red], %}, ImageSize -> Small]
Out[24]=

MaxOverlapFraction (2) 

Use MaxOverlapFractionf to only keep regions with an overlap smaller than f:

In[25]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
scores = {0.18372941641066354`, 0.7792523485576668, 0.7552787064436872, 0.20397739818471128`, 0.29873901258951774`, 0.5385959520846411, 0.0019547594798015044`, 0.7158017739163653, 0.16959589408147346`, 0.8582668907417819, 0.21215626418505606`, 0.304448649385447, 0.33974292946852325`, 0.4268902847722864, 0.3182413575132059};
ResourceFunction["NonMaximumSuppression"][boxes -> scores] // Length
Out[25]=
In[26]:=
ResourceFunction["NonMaximumSuppression"][boxes -> scores, MaxOverlapFraction -> .2] // Length
Out[26]=

If soft NMS is used, MaxOverlapFraction is used to defined the scaling behaviour:

In[27]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
scores = {0.18372941641066354`, 0.7792523485576668, 0.7552787064436872, 0.20397739818471128`, 0.29873901258951774`, 0.5385959520846411, 0.0019547594798015044`, 0.7158017739163653, 0.16959589408147346`, 0.8582668907417819, 0.21215626418505606`, 0.304448649385447, 0.33974292946852325`, 0.4268902847722864, 0.3182413575132059};
ResourceFunction["NonMaximumSuppression"][boxes -> scores, MaxOverlapFraction -> 0, Method -> "Soft"] // Length
Out[27]=

If the a scaling value is given explicitly, the option is ignored:

In[28]:=
ResourceFunction["NonMaximumSuppression"][boxes -> scores, MaxOverlapFraction -> 0, Method -> {"Soft", 1}] // Length
Out[28]=

Method (2) 

By default, regions are removed using a hard overlap threshold:

In[29]:=
boxes = {
Rectangle[{3.241549223388991, 1.8258945791733319`}, {
    10.659287859633295`, 10.773294493394275`}], 
Rectangle[{0.4869914284730348, 4.321183643750274}, {5.369829888721986,
     9.31386702637484}], 
Rectangle[{2.2334201426158136`, 4.721638979849482}, {
    5.291543408030995, 12.769601273219152`}], 
Rectangle[{5.349846089859113, 2.8592299264608263`}, {
    12.259520398084739`, 5.65464262378527}], 
Rectangle[{5.419709227350725, 3.2032779499946393`}, {
    8.019495864892848, 7.597470779871912}], 
Rectangle[{2.9916342183590716`, 6.701712853508063}, {
    12.82951197826295, 10.889573073474823`}], 
Rectangle[{5.716124755621678, 4.016397691332317}, {
    12.634485498683249`, 9.030579596384047}], 
Rectangle[{4.318687518098674, 4.086673071150529}, {
    12.377658857900416`, 10.295175285987018`}], 
Rectangle[{5.254646844539921, 5.048321499467785}, {
    11.505305608427992`, 13.227130047971752`}], 
Rectangle[{8.231089286494171, 1.8404075028314466`}, {16.2229662869946,
     8.789967125833199}], 
Rectangle[{6.7403064092133205`, 4.533063177477215}, {
    14.410877169797764`, 9.89745177054213}], 
Rectangle[{9.862402933845159, 5.563175394985179}, {
    11.276877537331307`, 11.97757563169206}], 
Rectangle[{11.180782570286068`, 2.0918187606070013`}, {
    15.93179551146674, 5.471116257515766}], 
Rectangle[{9.160598972568872, 3.0721821586970166`}, {
    16.105158304284622`, 11.003417304165653`}], 
Rectangle[{9.199084080623214, 6.486880587531073}, {
    18.967352233543956`, 13.733293159109362`}]};
scores = {0.18372941641066354`, 0.7792523485576668, 0.7552787064436872, 0.20397739818471128`, 0.29873901258951774`, 0.5385959520846411, 0.0019547594798015044`, 0.7158017739163653, 0.16959589408147346`, 0.8582668907417819, 0.21215626418505606`, 0.304448649385447, 0.33974292946852325`, 0.4268902847722864, 0.3182413575132059};
result = ResourceFunction["NonMaximumSuppression"][boxes -> scores]
Out[31]=
In[32]:=
Graphics[{Opacity[0.05], EdgeForm[Black], boxes, Opacity[0.3], Red, EdgeForm[Red], result}, ImageSize -> Small]
Out[32]=

Filter boxes using a soft NMS that scales the weights based on the overlap:

In[33]:=
ResourceFunction["NonMaximumSuppression"][boxes -> scores, Method -> "Soft"];
Graphics[{Opacity[0.05], EdgeForm[Black], boxes, Opacity[0.3], Red, EdgeForm[Red], %}, ImageSize -> Small]
Out[33]=

Specify the scaling value used to update the regions weights:

In[34]:=
ResourceFunction["NonMaximumSuppression"][boxes -> scores, Method -> {"Soft", .05}];
Graphics[{Opacity[0.05], EdgeForm[Black], boxes, Opacity[0.3], Red, EdgeForm[Red], %}, ImageSize -> Small]
Out[34]=

Soft NMS can become very slow if boxes are not removed:

In[35]:=
test = Rectangle[First[#], Total[#] + 1] & /@ RandomReal[10, {5000, 2, 2}];
In[36]:=
ResourceFunction["NonMaximumSuppression"][test, AcceptanceThreshold -> 0, Method -> "Hard"] // RepeatedTiming // First
Out[36]=
In[37]:=
ResourceFunction["NonMaximumSuppression"][test, AcceptanceThreshold -> 0, Method -> "Soft"] // RepeatedTiming // First
Out[37]=

Even a small threshold can significantly speed-up the computation:

In[38]:=
ResourceFunction["NonMaximumSuppression"][test, AcceptanceThreshold -> .1, Method -> "Soft"] // RepeatedTiming // First
Out[38]=

Version History

  • 1.0.1 – 06 December 2023
  • 1.0.0 – 14 December 2021

Source Metadata

License Information