OpenCV图像处理技术(Python)——鼠标交互区域生长算法

©FuXianjun


图像分割与提取的概念

在图像处理的过程中, 经常需要从图像中将前景对象作为目标图像提取出来。例如无人驾驶技术, 我们关心的是周围的交通工具, 其他障碍物等, 而对于背景本身并不关注, 故而, 我们需要将这些东西从图片(视频)中提取出来, 而忽略那些只有背景的图像

分水岭算法的概念

图像的灰度空间很像地球表面的整个地理结构,每个像素的灰度值代表高度。其中的灰度值较大的像素连成的线可以看做山脊,也就是分水岭。

当水平面上升到一定高度时,水就会溢出当前山谷,可以通过在分水岭上修大坝,从而避免两个山谷的水汇集,这样图像就被分成2个像素集,一个是被水淹没的山谷像素集,一个是分水岭线像素集。最终这些大坝形成的线就对整个图像进行了分区,实现对图像的分割。

OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第1张图片

OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第2张图片

分水岭算法的步骤

在这里插入图片描述

鼠标交互

opencv的鼠标交互操作主要通过两个函数实现:
第一个是cv2.setMouseCallback(windowName, onMouse [, param])
第二个是setMouseCallback()的第二个参数,称为鼠标回调函数onMouse(event, x, y, flags, param)

鼠标交互函数

setMouseCallback()

cv2.setMouseCallback(windowName, onMouse [, param])

windowName:必需。类似于cv.imshow()函数,opencv具体操作哪个窗口以窗口名作为识别标识,这有点类似窗口句柄的概念。

onMouse()

onMouse:必需。鼠标回调函数。鼠标回调函数的定义是onMouse(event, x, y, flags, param),我们想要做什么鼠标操作,都是在这个函数内实现。
onMouse(event, x, y, flags,param)

event:由回调函数根据鼠标对图像的操作自动获得,内容包含左键点击,左键弹起,右键点击…等等等非常多的操作。
x,y:由回调函数自动获得,记录了鼠标当前位置的坐标,坐标以图像左上角为原点(0, 0),x方向向右为正,y方向向下为正。
flags:记录了一些专门的操作,下面有说明。
param:从setMouseCallback()里传递过来的参数。该参数在setMouseCallback()处是可选参数,所以可以不设置。

event类型

各个鼠标事件的含义(用时现查)
OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第3张图片

区域生长算法的概念

选取某个种子点(一般实际交互时就是鼠标点击的位置),从图像种子点位置开始,将种子点相邻的符合某个阈值范围内的像素添加到生长区域中,接着判断下一个像素点,直到没有可以符合条件的像素为止,此时分割完毕。

区域生长算法的步骤

OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第4张图片
OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第5张图片

区域生长算法的案例演示

OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第6张图片

实战

使用鼠标交互函数,实现图像数据标注

import cv2 

drawing = False # 是否开始画图
start = (-1,-1)

# 鼠标的回调函数的参数格式是固定的,不要随意更改
def mouse_event(event,x,y,flags,param):
    global start,drawing, mode
    
    #左键按下,开始画图
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        start = (x,y)
    # 鼠标移动,画图
    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing:
            cv2.circle(img,(x,y),5,(0,0,255),-1)
            cv2.imwrite("drawing.png",img)

img = cv2.imread("yiqing.png")

cv2.namedWindow(winname="drawing")
cv2.setMouseCallback("drawing",mouse_event)

while True:
    cv2.imshow("drawing",img)
    # 按 q 键推出
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break
        
cv2.destroyAllWindows()

OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第7张图片

鼠标画圆
import cv2 

# 编写回调函数
def draw_circle(event,x,y,flags,param):
    #鼠标左键按下去,实心圆
    if event == cv2.EVENT_LBUTTONDOWN:
        cv2.circle(img,center=(x,y),radius=5,
                  color=(0,255,0),thickness=-1)
    
    # 鼠标右键按下去,空心圆
    elif event == cv2.EVENT_MOUSEMOVE:
        cv2.circle(img,center=(x,y),radius=5,
                  color=(0,255,0),thickness=1)

img = cv2.imread("yiqing.png")

cv2.namedWindow(winname="drawing")
cv2.setMouseCallback("drawing",draw_circle)

while True:
    cv2.imshow("drawing",img)
    # 按 q 键推出
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break
        
cv2.destroyAllWindows()

OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第8张图片

区域生长算法

固定种子点的区域生长算法

定义Point类
import cv2
import numpy as np

class Point(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y
        
    def getX(self):
        return self.x
    def getY(self):
        return self.y
计算像素之间的偏差
def getGrayDiff(img,currentPoint,tmpPoint):
    return abs(int(img[currentPoint.x,currentPoint.y]) - int(img[tmpPoint.x,tmpPoint.y]))
设定八领域或四邻域
def selectConnects(p):
    if p == 8:
        connects = [Point(-1,-1),Point(0,-1),Point(1,-1),Point(1,0),Point(1,1), \
                   Point(0,1),Point(-1,1),Point(-1,0)]# 八邻域
    else:
        connects = [Point(0,-1),Point(1,0),Point(0,1),Point(-1,0)]# 四邻域
    return connects
定义生长函数
def regionGrow(img,seeds,thresh):
    # 读取图像的宽高,并建立一个和原图大小相同的seedMark
    height,width = img.shape
    seedMark = np.zeros(img.shape)
    #将定义的种子点放入种子点序列seedList
    seedList = []
    for seed in seeds:
        seedList.append(seed)
    label = 1
    # 选择邻域
    # connects = selectConnects(p)
    p=4
    connects = selectConnects(p)
    #逐个点开始生长,生长的结束条件为种子序列为空,既没有生长点
    while(len(seedList)>0):
        #弹出种子点序列的第一个点作为生长点
        currentPoint = seedList.pop(0)#弹出第一个元素
        # 并将生长点对应seedMark点赋值label(1),即为白色
        seedMark[currentPoint.x,currentPoint.y]= label
        #以种子点为中心,四邻域的像素进行比较
        for i in range(p):
            tmpX = currentPoint.x + connects[i].x
            tmpY = currentPoint.y + connects[i].y
            #判断是否为图像外的点,若是则跳过。如果种子点是图像的边界点,邻域点就会落在图像外
            if tmpX < 0 or tmpY < 0 or tmpX >= height or tmpY >=width:
                continue
            #判断邻域点和种子点的差值
            grayDiff = getGrayDiff(img,currentPoint,Point(tmpX,tmpY))
            # 如果邻域点和种子点的差值小于阈值并且是没有被分类的点,则认为是和种子点同类,赋值label
            # 并作为下一个种子点放入seedList
            if grayDiff < thresh and seedMark[tmpX,tmpY] == 0:
                seedMark[tmpX,tmpY] = label
                seedList.append(Point(tmpX,tmpY))
    return seedMark
应用区域生长
# 读入图像的灰度图像
img = cv2.imread("peppa.jpg",0)
cv2.namedWindow('gray')
# 选定种子点
seeds = [Point(251,208)]
binaryImg = regionGrow(img,seeds,5)
cv2.imshow("segment",binaryImg)
cv2.imshow("gray",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果

OpenCV图像处理技术(Python)——鼠标交互区域生长算法_第9张图片

你可能感兴趣的:(opencv)