计算NMS
在进行测试的时候我们需要进行NMS,把没有必要的框去除掉,以保证我们的输出效果。
在把数据输入到检测网络中时,输出的为PreBoxes(Shape=(B,A,4)),PreIds(Shape=(B,A,NUMClass)),PreScores(Shape=(B,A,NUMClass)),在此我真对一张图片进行求解NMS。首先我们要明白PreBoxes包含的是所有Decoder以后的Boxes,那么PreScore是每一个Anchor的SoftMax,PreIds为每一个Anchor的真实ID,若不是该类则为-1。如下所示,下面分别是介绍BboxEncoder、ClassEncoder以及NMS(单张图片)。
BboxEncoder:
目标检测预测的Bbox是Anchor的Offset,因此在输出之前,我们先要进行Encoder,即将坐标转换为绝对坐标。计算公式为
p = nd.split(x, axis=-1, num_outputs=4)
ox = nd.broadcast_add(nd.broadcast_mul(p[0] * 0.1, a[2]), a[0])
oy = nd.broadcast_add(nd.broadcast_mul(p[1] * 0.1, a[3]), a[1])
tw = nd.exp(p[2]*0.2)
th = nd.exp(p[3]*0.2)
ow = nd.broadcast_mul(tw, a[2]) / 2
oh = nd.broadcast_mul(th, a[3]) / 2
ClassEncoder:
import mxnet as mx
#mx.nd.where(mx.nd.array([0,1,2]),mx.nd.array([12,11,13]),mx.nd.array([15,16,17]))
#mx.nd.ones_like(mx.nd.array([0,1,2]))*-1
def ClassEncoder(Data):
Template=mx.nd.zeros_like(Data.slice_axis(begin=0,end=1,axis=-1))
Score=Data.slice_axis(begin=1,end=Data.shape[-1],axis=-1)
ClassIds=[]
for i in range(Data.shape[-1]-1):
ClassIds.append(Template+i)
class_id=mx.nd.concatenate(ClassIds,axis=2)
mask=Score>0.5
print(mask)
print(class_id)
print(mx.nd.ones_like(class_id)*-1)
class_id=mx.nd.where(mask,class_id,mx.nd.ones_like(class_id)*-1)
Score=mx.nd.where(mask,Score,mx.nd.zeros_like(class_id))
return class_id,Score
Data=mx.nd.random.uniform(shape=(4,5,6))###Data的Shape格式为(B,A,classNum+1)
ClassEncoder(Data)
NMS:
import numpy as np
import mxnet as mx
def bboxes_iou(PreBoxes,GtBoxes):
assert PreBoxes.shape[1]==4 or GtBoxes.shape[1]==4,print('PreBoxes or GtBoxes shape must be (N,4)')
TopLeft=np.maximum(PreBoxes[:,None,:2],GtBoxes[:,:2])##N*1*2,与M*2,maximum有广播机制
DownRight=np.minimum(PreBoxes[:,None,2:],GtBoxes[:,2:])##输出Shape为N*M*4
Intersection=np.prod(DownRight-TopLeft,axis=2)*(TopLeft<DownRight).all(axis=2)##Shpae为N*M
AreaPre=np.prod(PreBoxes[:,2:]-PreBoxes[:,:2],axis=1)#Shape为N
AreaGt=np.prod(GtBoxes[:,2:]-GtBoxes[:,:2],axis=1)#Shape为M
IOUs=Intersection/(AreaPre[:,None]+AreaGt[:]-Intersection)
return IOUs
###输入PreBoxes Shape为(B,A,4) A为Anchor数目,PreIDs Shape为(B,A,NumClass),PreScores Shape为(B,A,NumClass)
def NMS(PreBoxes,PreIds,PreScores,NumClass,Thresh):
PickBoxes=[]
PickScores=[]
if isinstance(PreBoxes,mx.nd.NDArray):
PreBoxes=PreBoxes.asnumpy()
for i in range(NumClass):
PickBox=[]
PickScore=[]
PreId=PreIds.slice_axis(axis=-1,begin=i,end=i+1)
PreScore=PreScores.slice_axis(axis=-1,begin=i,end=i+1)
if isinstance(PreId,mx.nd.NDArray) or isinstance(PreScore,mx.nd.NDArray):
PreId=PreId.asnumpy()
PreScore=PreScore.asnumpy()
IdMask=PreId.flat==i
PreScore=PreScore.flat[IdMask]
PreBox=PreBoxes[IdMask]
#print(PreBox)
order=PreScore.argsort()[::-1]
#PreScore=PreScore[order]
#PreBox=PreBox[order]
while order.size>0:
PickBox.append(PreBox[order[0]])
PickScore.append(PreScore[order[0]])
IOUS=bboxes_iou(PreBox[order[0]].reshape((1,4)),PreBox[order])
IOUMask=IOUS<Thresh
order=order[IOUMask.flat]
#PickBoxes.append(PickBox)
PickBoxes.append([PickBox,PickScore])
PickScores.append(PickScore)
return PickBoxes,PickScores
PreBoxes=mx.nd.array([[1,1,4,4],[3,2,4,6],[4,4,5,6],[8,6,10,8]])
PreIds=mx.nd.array([[0,1],[0,1],[0,1],[0,1]])
PreScores=mx.nd.array([[0.6,0.4],[0.7,0.3],[0.8,0.2],[0,1]])
NMS(PreBoxes,PreIds,PreScores,2,0.5)