OpenCV_11图像分割与修复

前言:总纲《计算机视觉学习路》

图像分割

概念:将前景物体从背景中分离出来

分类:传统的图像分割和基于深度学习的图像分割,本章主要介绍传统图像分割方法。

分水岭法

其基本原理为:

存在的问题:当图像存在过多的极小区域时,会产生许多小的集水盆

处理步骤:

1.标记背景:灰度化-二值化-开运算-膨胀

2.标记前景:距离变换-二值化

3.标记未知区域 : 背景减去前景

4.创建marker : 求前景的连通域,背景像素值设为1,位置区域设为0

5.进行分割  watershed(img , masker)  # masker:前景、背景设置不同的值用以区分

还需要了解两个函数:

距离变换

distanceTransform(img , distanceType , maskSize) # 计算非零值到零值的距离

distanceType : DIST_L1   DIST_L2

maskSize  : L1用3x3   L2用5x5

 求连通域

connectedComponents(img , connectivity)  # 求图像中所有非零元素的连通域

connectivity : 4 、8(默认) 连通域

import cv2
import numpy as np
import matplotlib.pyplot as mp

img = cv2.imread('../img/water_coins.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 获取背景
# 1. 二值化  , 这里的阈值设置0,其实是用到了OTSU自适应阈值,不需要我们自己设置
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# 得到背景为黑色,硬币为白色的图
cv2.imshow('thresh', thresh)
# 2. 形态学获取背景
kernel = np.ones((3, 3), np.uint8)
# 开运算去除噪点
open_ = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 膨胀  得到背景
bg = cv2.dilate(open_, kernel, iterations=1)
cv2.imshow('bg', bg)

# 获取前景物体
dist = cv2.distanceTransform(open_, cv2.DIST_L2, 5)
# fg 前景
ret1, fg = cv2.threshold(dist, 0.7 * dist.max(), 255, cv2.THRESH_BINARY)
cv2.imshow('fg', fg)

# mp.imshow(dist, cmap='gray')  # 使用matplotlib显示出梯度
# mp.show()
# exit()

# 获取未知区域
fg = np.uint8(fg)
unknow = cv2.subtract(bg, fg)
cv2.imshow('unknow', unknow)

# 创建marker
# 创建连通域
ret2,marker = cv2.connectedComponents(fg)
marker = marker + 1  # 将所有的背景用1表示,前景255+1没什么影响
marker[unknow==255] = 0  # 设置未知区域的值为0

#进行图像分割
result = cv2.watershed(img , marker)

img[result == -1] = [0,0,255]
cv2.imshow('img',img)

cv2.waitKey(0)

GrabCut

通过交互的方式获取前景物体

原理:

  • 用户指定前景的大体区域,剩下的为背景区域
  • 用户明确指定某些地方为前景或背景
  • GrabCut采用分段迭代的方法分析前景物体形成模型树
  • 最后根据权重决定某个像素是前景还是背景

1.定义主体结构(类) 

2.鼠标事件处理

3.调用GrabCut实现前景与背景的分离

小衣服真不错,哈哈哈哈还是用PS吧

import cv2
import numpy as np


class App:
    flag_rect = False
    rect = (0, 0, 0, 0)
    startX = 0
    startY = 0

    def onmouse(self, event, x, y, flags, param):

        if event == cv2.EVENT_LBUTTONDOWN:
            self.flag_rect = True
            self.startX = x
            self.startY = y
            print("LBUTTIONDOWN")
        elif event == cv2.EVENT_LBUTTONUP:
            self.flag_rect = False
            cv2.rectangle(self.img,
                          (self.startX, self.startY),
                          (x, y),
                          (0, 0, 255),
                          3)
            self.rect = (min(self.startX, x), min(self.startY, y),
                         abs(self.startX - x),
                         abs(self.startY - y))

            print("LBUTTIONUP")
        elif event == cv2.EVENT_MOUSEMOVE:
            if self.flag_rect == True:
                self.img = self.img2.copy()
                cv2.rectangle(self.img,
                              (self.startX, self.startY),
                              (x, y),
                              (255, 0, 0),
                              3)
            print("MOUSEMOVE")

        print("onmouse")

    def run(self):
        print("run...")

        cv2.namedWindow('input')
        cv2.setMouseCallback('input', self.onmouse)

        self.img = cv2.imread('../img/cat.jpg')
        self.img2 = self.img.copy()
        self.mask = np.zeros(self.img.shape[:2], dtype=np.uint8)
        self.output = np.zeros(self.img.shape, np.uint8)

        while (1):
            cv2.imshow('input', self.img)
            cv2.imshow('output', self.output)
            k = cv2.waitKey(100)
            if k == 113:  # q退出
                break

            if k == ord('g'):  # g抠图
                bgdmodel = np.zeros((1, 65), np.float64)
                fgdmodel = np.zeros((1, 65), np.float64)
                cv2.grabCut(self.img2, self.mask, self.rect,
                            bgdmodel, fgdmodel,
                            1,
                            cv2.GC_INIT_WITH_RECT)
            mask2 = np.where((self.mask == 1) | (self.mask == 3), 255, 0).astype('uint8')
            self.output = cv2.bitwise_and(self.img2, self.img2, mask=mask2)


App().run()

MeanShift

原理:色彩平滑,相近的颜色形成一片区域,以图像任意一点p为圆心,半径为sp,色彩幅值为sr进行不断迭代。

pyMeanShiftFiltering(img , double sp , doule sr)

可以自己调节sp和sr看看效果 。色彩平滑后就可以进行边缘提取和轮廓提取然后绘制。

import cv2
import numpy as np

img = cv2.imread('../img/flower.png')

m_img = cv2.pyrMeanShiftFiltering(img, 20, 30)

canny = cv2.Canny(m_img, 150, 300)

contours, h = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cv2.imshow('img', img)
cv2.imshow('m_img', m_img)
cv2.imshow('canny', canny)
cv2.drawContours(img, contours, -1, (0, 0, 255, 2))
cv2.imshow('result',img)

cv2.waitKey(0)

视频背景抠除

视频背景抠除的原理:在某一组帧中,背景几乎是不变的

MOG

混合高斯模型为基础的前景/背景分离算法

mog = cv2.bgsegm.createBackgroundSubtratorMOG( )

result_frame = mog.apply(视频帧)

import cv2
import numpy as np

cap = cv2.VideoCapture('../img/vtest.avi')
mog = cv2.bgsegm.createBackgroundSubtractorMOG()

while(True):
    ret, frame = cap.read()
    fgmask = mog.apply(frame)

    cv2.imshow('img',fgmask)

    k = cv2.waitKey(10)
    if k ==113:  # q 退出
        break

cap.release()
cv2.destroyAllWindows()

 MOG2

与MOG类似,对亮度产生的阴影有更好的识别

mog2 = cv2.createBackgroundSubtracorMOG2(history,detectShadows )

history : 默认500毫秒

detectShadows : True检测阴影, false不检测

 可以看到人有阴影。缺点是会产生很多噪点

import cv2
import numpy as np

cap = cv2.VideoCapture('../img/vtest.avi')
# mog = cv2.bgsegm.createBackgroundSubtractorMOG()
mog = cv2.createBackgroundSubtractorMOG2()

while (True):
    ret, frame = cap.read()
    fgmask = mog.apply(frame)

    cv2.imshow('img', fgmask)

    k = cv2.waitKey(10)
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()

GMG

静态背景图像估计和每个像素的贝叶斯分割,抗噪性强

cv2.bgsegm.createBackgroundSubtractorGMG( initializationFrames...)  # 初始帧数默认120

 刚开始会有很长时间的黑屏。因为默认初始帧数为120,可以自己设置为10

import cv2
import numpy as np

cap = cv2.VideoCapture('../img/vtest.avi')
# mog = cv2.bgsegm.createBackgroundSubtractorMOG()
# mog = cv2.createBackgroundSubtractorMOG2()
mog = cv2.bgsegm.createBackgroundSubtractorGMG(10)

while (True):
    ret, frame = cap.read()
    fgmask = mog.apply(frame)

    cv2.imshow('img', fgmask)

    k = cv2.waitKey(10)
    if k == 113:
        break

cap.release()
cv2.destroyAllWindows()

图像修复

inpaint(img , mask , inpaintRadius , flags)

inpaintRadius : 每个点的圆形领域半径

flags: INPAINT_NS ,  INPAINT_TELEA

import cv2
import numpy as np

img = cv2.imread('../img/inpaint.png')
mask = cv2.imread('../img/inpaint_mask.png', 0)

dst = cv2.inpaint(img, mask, 5, cv2.INPAINT_TELEA)

cv2.imshow('dst', dst)
cv2.imshow('img', img)

cv2.waitKey()

可以看到只要有掩码图像,就可以恢复原图。

那么怎么找到掩码图片呢?可以自己定义一个函数,定义鼠标事件,圈出图片中需要还原的位置。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
OpenCV_contrib 3.4.1 是OpenCV 的一个附加模块版本。OpenCV_contrib 是一个由OpenCV 的社区和开发人员提供的一些额外的功能和算法的集合,它扩展了OpenCV 的功能。 OpenCV_contrib 3.4.1 版本包括了一些新的特性和改进,如: 1. DNN 模块的改进:包括了对新的深度学习模型和框架的支持,例如 TensorFlow、Caffe2 等。 2. 超像素模块的改进:添加了一些新的超像素分割算法,提供了更精确的图像分割结果。 3. 特征检测和描述子模块的改进:增加了一些新的特征检测器和描述子,提供更丰富的特征提取能力。 4. 目标检测和跟踪模块的改进:包括了一些新的目标检测和跟踪算法,如 TLD、GOTURN 等。 5. 3D 模块的改进:提供了更多的 3D 建模和重建算法,支持从 2D 图像中恢复 3D 物体的形状和纹理信息。 此外,OpenCV_contrib 还包括了一些其他的功能和算法,如图像分割、图像修复计算机视觉工具等。 OpenCV_contrib 3.4.1 版本的发布主要目的是为了提供一个更完善和强大的库,使用户能够更方便地使用和开发计算机视觉应用程序。它为开发人员提供了更多的选择和灵活性,可以根据自己的需求选择和使用合适的算法和功能。 为了使用OpenCV_contrib 3.4.1,需要先下载和安装该版本的OpenCVOpenCV_contrib 源码,然后编译和构建对应的库和模块。在代码中,可以通过导入相应的模块来使用OpenCV_contrib 中提供的功能和算法。 总之,OpenCV_contrib 3.4.1 是OpenCV 的一个扩展版本,集成了一些新的功能和算法,为开发人员提供了更多的选择和灵活性,可以帮助他们更方便地构建和开发计算机视觉应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Goafan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值