OpenCV(11)-图像的分割与修复

图像的分割与修复

图像分割的基本概念

  • 图像分割定义:将前景物体从背景中分离出来

  • 图像分割方法:

    • 传统的图像分割方法
      • 分水岭法
      • GrabCut法
      • MeanShift法
      • 背景扣除
  • 基于深度学习的图像分割方法

分水岭法

  • 问题:图像存在过多的极小区域而产生许多小的集水盆,使得图像分割太碎,不利于处理

  • 处理步骤:

    • 标记背景
    • 标记前景
    • 标记未知域
    • 进行分割
  • watershed(img,masker)

    • masker 标记数据,前景、背景使用不同的值用以区分它们
  • 矩离变换:distanceTransform(img,distanceType,maskSize)

    • distanceType:DIST_L1、DIST_L2
    • maskSize:L1用3、L2用5
  • 求连通域:connectedComponents(img,connectivity,…)

    • connectivity:4,8(默认)
import cv2
import numpy as np
import matplotlib import pyplot as plt

#获取背景
#1.通过二值化得到黑白图片
#2.通过形态学获取背景

img = cv2.imread('water.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY_INV + cv2.THRESH_OTSU)

ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)

#开运算
kernel = np.ones((3,3),np.int8)
open1 = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2)

#膨胀
bg = cv2.dilate(open1, kernel, iteratons = 1)

#获取前景物体
dist = cv2.distanceTransform(open1,cv2.DIST_L2,5)
reg, fg = cv2.threshold(dist, 0.7 * dist.max(), 255, 0)

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

#创建连通域
ret, marker = cv2.connectedComponents(fg)

marker = marker + 1
marker[unknow == 255] = 0

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

img[result == -1] = [0, 0, 255]

cv2.imshow('thresh',thresh)
cv2.waitKey(0)

GrabCut法

  • 通过交互的方式获得前景物体
  • 原理:
    • 用户指定前景的大体区域,剩下的为背景区域
    • 用户还可以明确指定某些地方为前景或背景
    • GrabCut采用分段迭代的方法分析前景物体形成模型树
    • 最后根据权重决定某个像素是前景还是背景
  • grabCut(img, mask,rect,bgdModel,fdgModel,iterator,mode)
  • mode:
    • GC_INIT_WITH_RECT
    • GC_INIT_WITH_MASK
  • [实战]
    • 主体结构
    • 鼠标事件的处理
    • 调用GrabCut实现前景与背景的分离
import cv2
import numpy as np

class App:
    
    flag_rect = False
    rect = (0,0,0)
    startX = 0
    stratY = 0
    
    def onmouse(self, event, x, y, flag, param):
        if event = cv2.EVENT_LBUTTONDOWN:
            self.flag_rect = True
            self.stratX = x
            self.stratY = y
        elif event == cv2.EVENT_LBUTTONUP:
            self.flag_rect = Flase
            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))
        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("onmouse")
        
    def run(self):
        cv2.namedWindow('input')
        cv2.setMouseCallback('input', self.onmouse)
        
        self.img = cv2.imread('lena.png')
        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.inshow('input', img)
        	k = cv2.waitKay()
            if k == 27:
                break
            if k == ord('g'):
                bgdModel = np.zeros((1,65), np.float64)
                fdgModel = np.zeros((1,65), np.float64)
                cv2.grabCut(self.img2, self.mask,self.rect,bgdModel,fdgModel,1,cv2.GC_INIT_WITH_RECT)
            mask = 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进行不断的迭代
  • pyrMeanShiftFiltering(img, double sp, double sr, maxLevel = 1, termcrit = TermCriteria…)
    • sp:半径
    • sr:色彩幅值
mean_min = cv2.pyrMeanShiftFiltering(img, 20, 30)
imgCanny = cv2.Canny(mean_img, 150, 300)
contours, _ = cv2.findContours(imgCanny, cv2.RETR_EXTERNANAL, CV2.CHAIN_APPROX_SIMPLE)

视频前后景分离

  • 视频背景扣除原理:
    • 视频是一组连续的帧

    • 帧与帧之间的关系密切(GOP)

    • 在GOP中,背景几乎是不变的

MOG去背景

  • 混合高斯模型为基础的前景/背景分割算法
  • createBackgroundSubstractorMOG(history, nmixtures, backgroundRatio, noiseSigma)
    • history 默认200
    • nmixtures 高斯范围值,默认5
    • backgroundRatio 背景比率,默认0.7
    • noiseSigma 默认0,自动降噪
cap = cv2.VideoCapture('vtest.avi')
mog = cv2.bgsegm.createBackgroundSubstractorMOG()

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()

MOG2去背景

  • 同MOG类似,不过对亮度产生的阴影有更好的识别

  • 优点:可以计算出阴影部分

  • 缺点:会产生很多噪点

  • createBackgroundSubstractorMOG2(history, detectShadows)

    • history 默认500
    • detectShadows 是否检测阴影,默认True

GMG去背景

  • 静态背景图像估计和每个像素的贝叶斯分割抗造型更强

  • createBackgroundSubstractorGMG(initializationFrames)

    • initializationFrames初始参考帧数 默认120
  • 优点:可以计算出阴影部分。同时减少噪点

  • 缺点:如果采用默认值,则在开始一段时间内没有任何信息显示

  • 解决办法:调整初始参考帧数

图像修复

  • inpaint(img, mask, inpaintRadius, flags)
    • mask 是一张与原始图像尺寸一样的黑底白字的残缺位置的图像
    • inpaintRadius 修复半径 每个点的圆形邻域半径
    • flags
      • INPAINT_NS
      • INPAINT_TELEA
det = cv2.inpaint(img, mask, 5, cv2.INPAINT_TELEA)

你可能感兴趣的:(opencv,计算机视觉,人工智能)