使用Python和OpenCV检测图像中的多个亮点

使用Python和OpenCV检测图像中的多个亮点)

今天是2021春节的最后一个工作日,同事已陆续离开,鉴于我回家没什么事,so 学习一篇博客再回家。

这篇博客是上一篇 使用Python,OpenCV查找图像中的最亮点 的进阶,将介绍如何使用Python和OpenCV检测图像中的多个亮的区域。

主要通过应用阈值化显示图像中最亮的区域来完成。

关键是阈值化步骤——如果阈值化后的图像非常嘈杂,无法使用轮廓属性或连接组件分析进行过滤,那么将无法定位图像中的每个明亮区域。

因此,应该首先通过应用各种阈值技术(如简单阈值,大津阈值,自适应阈值,甚至是GrabCut)来评估输入图像,并可视化结果。只要可以合理地从图像的较暗,不相关的区域中分割出较亮的区域,那么这个方法将非常有用;

1. 效果图

原始图 VS 效果图:
可以看到图左原始图中有多个亮的灯泡,在图右效果图中每个亮的区域都被成功标记。

在这里插入图片描述
下一个效果图将每一步的步骤图如下图所示:

在这里插入图片描述

原始图如下,图中有5个电灯泡,目标是检测图中的5个电灯泡并进行唯一标记
在这里插入图片描述
转换为灰度图,平滑后如图:
在这里插入图片描述
阈值化图像,以显示出亮的区域,效果图如下左图thresh1
对于小的噪点,运用一系列腐蚀、膨胀操作消除,效果图如下右图thresh2:可以看到干净了许多,但仍有一些噪点要消除**
在这里插入图片描述
thresh2中遗留的小的分离噪点,可应用连接组件分析去除。然后应用轮廓检测,检测到每一个亮的区域,并展示如下:
在这里插入图片描述
原图 VS 效果图如下:
在这里插入图片描述

2. 源码

# USAGE
# python detect_bright_spots.py --image images/lights_01.png

# 导入必要的包
from imutils import contours
from skimage import measure
import numpy as np
import argparse
import imutils
import cv2

dict = {
    
    }


def imageShow(name, image, end=False):
    cv2.imshow(name, image)
    cv2.waitKey(0)
    # dict[name] = image
    # if end:
    #     for i, j in enumerate(dict.items()):
    #         name = str("image/" + str(i + 1) + j[0] + ".jpg")
    #         print(name)
    #         cv2.imshow(name, j[1])
    #         cv2.waitKey(0)
    #         cv2.imwrite(str("image/" + str(i + 1) + ".jpg"), j[1])


# 构建命令行参数及解析
# --image 原始图像路径
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
                help="path to the image file")
args = vars(ap.parse_args())

# 从磁盘加载图像,将其转换为灰度图,平滑(即模糊)以减少高频噪声:
image = cv2.imread(args["image"])
origin = image.copy()
imageShow("origin", origin)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (11, 11), 0)
imageShow("gray", gray)
imageShow("blurred", blurred)
imageShow("gray VS blurred", np.hstack([gray, blurred]))

# 要显示模糊图像中最亮的区域,需要应用阈值
# 对平滑后的图像应用阈值化方法,以显示出亮的区域
# 对任何像素值p> = 200并将其设置为255(白色)。 <200的像素值设置为0(黑色)。
thresh = cv2.threshold(blurred, 200, 255, cv2.THRESH_BINARY)[1]
imageShow("thresh1", thresh)

# 图像中还存在一些噪点(即小斑点),可通过执行一系列腐蚀和扩张来对其进行清理:
# 应用一系列腐蚀、膨胀来消除小的噪点
thresh = cv2.erode(thresh, None, iterations=2)
thresh = cv2.dilate(thresh, None, iterations=4)
imageShow("thresh2", thresh)

# 应用腐蚀膨胀操作后,阈值图像要干净得多,但仍有一些斑点要清除
# 该项目的关键步骤是在上图中标记每个区域。但是,即使在应用侵蚀和膨胀之后,仍然希望过滤掉所有剩余的“嘈杂”区域。一个很好的方法是执行连接组件分析:
# 在阈值化的图像上应用连接组件分析,初始化mask来存储最大的元素
# 使用scikit-image库执行实际的连接组件分析
labels = measure.label(thresh, neighbors=8, background=0)
mask = np.zeros(thresh.shape, dtype="uint8")

# 遍历唯一的组件
for (i, label) in enumerate(np.unique(labels)):
    # 如果是黑色标记,过滤
    if label == 0:
        continue
    # 否则,构建组件mask并计数像素数
    labelMask = np.zeros(thresh.shape, dtype="uint8")
    labelMask[labels == label] = 255
    numPixels = cv2.countNonZero(labelMask)

    # 如果组件足够大,超过300个像素则加入大斑点蒙版中
    if numPixels > 300:
        mask = cv2.add(mask, labelMask)
        imageShow("mask" + str(i), mask)

# 请注意,如何过滤掉所有小斑点,并且仅保留大斑点。
# 找到蒙版图像中的轮廓,并从左到右排序
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
                        cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = contours.sort_contours(cnts)[0]

# 遍历所有轮廓
for (i, c) in enumerate(cnts):
    # 绘制图像中亮的光点
    # 计算轮廓的最小包围圆,代表图像中亮的区域
    (x, y, w, h) = cv2.boundingRect(c)
    ((cX, cY), radius) = cv2.minEnclosingCircle(c)
    cv2.circle(image, (int(cX), int(cY)), int(radius),
               (0, 0, 255), 3)
    cv2.putText(image, "#{}".format(i + 1), (x, y - 15),
                cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255), 2)

# 展示输出图像
imageShow("ResImage", image, True)
imageShow("origin VS ResImage", np.hstack([origin, image]))
cv2.destroyAllWindows()

参考

猜你喜欢

转载自blog.csdn.net/qq_40985985/article/details/113769432