一、什么是非极大值抑制
非极大值抑制(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库提供的分类器,从一张图像中检测到其中的人脸框,然后使用非极大值抑制方法,从中选择最突出、最明显的人脸框。最后,程序对图像中的每个人脸框进行标记,并在图像上显示标记后的结果。