您的位置:

非极大值抑制

一、什么是非极大值抑制

非极大值抑制(Non-Maximum Suppression,简称NMS)是一种用于边缘检测和目标检测中的常用技术,其作用是对检测到的边缘或目标进行筛选和过滤,只保留最明显、最显著的部分。

在边缘检测中,Canny算法常常会产生较多的细节边缘,而非极大值抑制可以将这些边缘过滤掉,只保留最明显的边缘;同样,在目标检测中,非极大值抑制有助于消除重复或遮盖的目标,并只留下一些最突出的目标。

二、非极大值抑制的原理

非极大值抑制的原理非常简单:对于检测到的每个边缘点或目标,取其周围一个窗口内的所有相邻点的灰度值,如果该点的灰度值最大,那么就将其保留,否则将其丢弃。

以边缘检测为例,当Canny算法对图像进行边缘检测后,会得到很多边缘点。由于像素点的灰度值往往会出现较大的变化,我们可以将这些边缘点看作是局部的"山峰",其周围的边缘点则是"山峰"的"山峰麓"。我们希望保留的是"山峰"最高、最明显的点,而将其他点抑制掉。

三、非极大值抑制的实现

下面是一个使用Python实现的非极大值抑制的代码示例:

import cv2

def non_max_suppression(boxes, overlapThresh):
    # 如果框的数量为空,直接返回空列表
    if len(boxes) == 0:
        return []

    # 如果输入的框的数据类型为整数,将其转换为浮点数
    if boxes.dtype.kind == "i":
        boxes = boxes.astype("float")

    # 初始化选择框的列表
    pick = []

    # 分别获取框的坐标轴信息
    startX = boxes[:, 0]
    startY = boxes[:, 1]
    endX = boxes[:, 2]
    endY = boxes[:, 3]

    # 计算矩形框的面积和排序
    area = (endX - startX + 1) * (endY - startY + 1)
    idxs = np.argsort(endY)

    # 循环遍历排序后的框的索引
    while len(idxs) > 0:
        # 取出框列表中的最后一个索引,并将其添加到已选择的列表中
        last = len(idxs) - 1
        i = idxs[last]
        pick.append(i)

        # 寻找其他矩形与当前矩形交叉的面积
        xx1 = np.maximum(startX[i], startX[idxs[:last]])
        yy1 = np.maximum(startY[i], startY[idxs[:last]])
        xx2 = np.minimum(endX[i], endX[idxs[:last]])
        yy2 = np.minimum(endY[i], endY[idxs[:last]])

        # 计算矩形框之间的交叉面积
        w = np.maximum(0, xx2 - xx1 + 1)
        h = np.maximum(0, yy2 - yy1 + 1)

        # 计算交叉面积比
        overlap = (w * h) / area[idxs[:last]]

        # 将交叉面积比小于给定阈值的索引从列表中删除
        idxs = np.delete(idxs, np.concatenate(([last],np.where(overlap > overlapThresh)[0])))

    # 返回选择框的列表
    return boxes[pick].astype("int")

该代码实现了一个基于IoU重叠度的非极大值抑制算法,其中的参数boxes代表一组含有x、y、w、h四个坐标的框,overlapThresh代表给定的IoU重叠度阈值。该算法会对输入的框进行遍历,依次计算每个框和其他框的IoU重叠度,并选择IoU大于给定阈值的框保留。

四、非极大值抑制的应用

在实际应用中,非极大值抑制被广泛应用于目标检测、人脸识别、OCR等领域。例如,当我们要对一组人脸图像进行检测时,非极大值抑制可以帮助我们消除重复或遮盖的人脸,并只保留一些最明显、最突出的人脸。

下面是一个基于非极大值抑制算法的人脸检测示例代码:

import cv2

def detect_faces(image, face_cascade):
    # 将图像转灰度
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # 使用分类器检测图像中的人脸
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=5)

    # 对检测到的矩形框进行非极大值抑制,保留最突出的人脸
    faces = non_max_suppression(faces, 0.3)

    # 返回人脸框的坐标信息及图像
    return faces, image

# 初始化人脸检测器
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")

# 读取输入图像
image = cv2.imread("test.jpg")

# 检测图像中的人脸
faces, image = detect_faces(image, face_cascade)

# 循环遍历检测到的人脸,并在图像上进行标注
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)

# 显示标注后的图像
cv2.imshow("Faces found", image)
cv2.waitKey(0)

该代码利用OpenCV库提供的分类器,从一张图像中检测到其中的人脸框,然后使用非极大值抑制方法,从中选择最突出、最明显的人脸框。最后,程序对图像中的每个人脸框进行标记,并在图像上显示标记后的结果。