OpenCV 图像分割与修复

一 图像分割的基本概念

1 什么是图像分割

将前景物体从背景中分离出来。

2 图像分割的方法

①传统的图像分割方法
在这里插入图片描述
在这里插入图片描述
分水玲法的处理步骤
第一步:标记背景;
第二步:标记前景;
第三步:标记未知域;
第四步:进行分割;

② 基于深度学习的图像分割方法
③分水玲法
分水岭API

watershed(img,masker)
masker,前景、背景设置不同的值用以区分它们
import cv2
import numpy as np

#获取图片
#通过二值发得到黑白图片
#通过形态学获取背景

img=cv2.imread('water_coins.jpeg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

ret,thresh=cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

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

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


cv2.imshow("thresh",thresh)
cv2.imshow("bg",bg)
cv2.waitKey(0)
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
from matplotlib import pyplot as plt

#获取图片
#通过二值发得到黑白图片
#通过形态学获取背景

img=cv2.imread('water_coins.jpeg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

ret,thresh=cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

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

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

#获取前景物体
dist=cv2.distanceTransform(open1,cv2.DIST_L2,5)

ret,fg=cv2.threshold(dist,0.7*dist.max(),255,cv2.THRESH_BINARY)

#plt.imshow(dist,cmap='gray')
#plt.show()
#exit()

#获取未知区域
fg=np.uint8(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.imshow("bg",bg)
cv2.imshow("dist",dist)
cv2.imshow("unknow",unknow)
cv2.imshow("img",img)
cv2.waitKey(0)

在这里插入图片描述

④GrabCut法
通过交互的方式获得前景物体;
GrabCut原理
用户指定前景的大体区域,剩下的为背景区域。
用户还可以明确指定某些地方为前景或背景
GrabCut采用分段迭代的方法分析前景物体形成模型树
实战GrabCut
主体结构
鼠标事件的处理
GrabCut API

grabCut(img,
mask,
rect,
bgdModel,fgdModel,
5,//iterator
mode)
mask生产的掩码
BGD:背景,0
FGD:前景,1
PR_BGD:可能是背景,2
PR_FGD:可能是前景,3
Model
bgdMode,np.float64 type zero arrays of size(1,65).
fgdModel,同上。
GC_INIT_WITH_RECT
GC_INIT_WITH_MASK
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('./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.imshow('input', self.img)
            cv2.imshow('output', self.output)
            k = cv2.waitKey(100)
            if k == 27:
                break

            if k == ord('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()

调用GrabCut实现前景和背景的分离
⑤MeanShift法
⑥背景扣除
视频是一组连续的帧(一副幅图组成);
帧与帧之间关系密切(GOP);
在GOP中,背景几乎是不变的;

1 MOG去背景

混合高斯模型为基础的前景/背景分割算法
createBackgroundSubtractorMOG(…)

createBackgroundSubtractorMOG(
history,//默认200
nmixtures,//高斯范围值,默认5
backgroundRatio,//背景比率,默认0.7
noiseSigma//默认0 自动降噪

2 其它背景扣除方法

1)MOG2去背景

同MOG类似,不过对亮度产生的阴影有更好的识别;
createBackgroundSubtractorMOG2(…)

createBackgroundSubtractorMOG2(
history,//500毫秒
....
detectShadows//是否检测阴影,True)
静态背景图像估计和每个像素的贝叶斯分割抗噪性更强
createBackgroundSubtractorGMG(...) 
createBackgroundSubtractorGMG(
initializationFrams,//初始帧数,120
...)
import cv2
import numpy as np

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

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

    cv2.imshow('img',fgmask)

    k=cv2.waitKey(0)

    if k==27:
        break

cap.release()
cv2.destroyAllWindows()

二 MeanShift原理

严格来说该方法并不是用来对图像分割的,而是在色彩层面的平滑滤波。

它会中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域。

它以图像上任一点P为圆心,半径为sp,色彩幅值为sr进行不断地迭代。
效果
在这里插入图片描述
API

pyrMeanShiftFiltering(img,
double sp,
double sr,
maxLevel=1,
termcrit=Termcriteria.
sp:半径
sr:色彩幅值
import cv2
import numpy as np

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

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

imgcanny=cv2.Canny(mean_img,150,300)

contours,_=cv2.findContours(imgcanny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

cv2.drawContours(img,contours,-1,(0,0,255))

cv2.imshow('flower',img)

cv2.imshow('mean_img',mean_img)

cv2.imshow('canny',imgcanny)

cv2.waitKey(0)

三 图像修复

1 inpaint API

inpaint(img,
mask,
inpaintRadius,//每个点的圆形领域半径
flags//INPAINT_NS,INPAINT_TELEA)

```csharp
import cv2
import numpy as np

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

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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值