图像分割与修复

news2024/11/24 17:42:03

图像分割的方法

(1)传统的图像分割方法

(2)基于深度学习的图像分割方法

传统的图像分割方法

(1)分水岭法

(2)GrabCut法

(3)MeanShift法

(4)背景扣除

分水岭法

 分水岭法原理 

简单来说,如上图所示。图中有很多的沟壑,当用不同颜色的水灌到沟壑中时,在快灌满时会出现一个边界将两边分开。(每张图片有各种各样的像素,那不同的像素之间就形成沟壑)

分水岭法处理步骤

(1)标记背景

(2)标记前景

(3)标记未知域

(4)进行分割

分水岭法实战

分水岭法API

(1)watershed(img,masker)

(2)masker:前景,背景设置不同的值用于区分他们(如何获取前景,背景,和未知区域这个需要腐蚀膨胀的相关知识)

(3)前景可以通过腐蚀或距离变换得到,背景可以通过膨胀得到,未知区域可以使用背景减去前景

(4)距离变换API:distanceTransform(img,distanceType,maskSize)其中

distanceType:是测从非0值到0的距离  DIST_L1 DIST_L2  L1求绝对值 L2求勾股定理 ; maskSize:就是扫描时kernel的大小 L1用3,L2用5

(7)连通域API:connectedComponents(img,connectivity,……)其中

connectivity:4,8(默认)4代表上下左右四个像素如果是一样的就代表是一个连通域,8在4的基础上加上了4个斜对角

 分水岭代码

import cv2
import numpy as np

# 获取背景
# 1,通过二值法得到黑白图片
# 2,通过心态学获取背景

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

# THRESH_BINARY二进制阈值。把亮的处理成白色,暗的处理成黑色,超过100的就变成255,反之变为0。我们使用了_INV那就反过来
ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY_INV)


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

 可以得到图片,发现银币中间还是会出现黑色,但是我们不希望有黑色。

#改进前
ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY_INV)

#改进后
# cv2.THRESH_OTSU可以自适应阈值,将100写为0
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

  可以得到图片,发现银币中间没有黑色了,达到我们的目的。

 全部的代码

import cv2
import numpy as np

# 获取背景
# 1,通过二值法得到黑白图片
# 2,通过心态学获取背景(膨胀)
# 3.获取前景物体

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

# THRESH_BINARY二进制阈值。把亮的处理成白色,暗的处理成黑色,超过100的就变成255,反之变为0。我们使用了_INV那就反过来
# ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY_INV)
# cv2.THRESH_OTSU可以自适应阈值,将100写为0
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 开运算(去噪)(真的有用!!!)
kernel = np.ones((3, 3), np.int8)
open = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

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

# 获取前景
dist = cv2.distanceTransform(open, cv2.DIST_L2, 5)
ret, fg = cv2.threshold(dist, 0.7 * dist.max(), 255, cv2.THRESH_BINARY)

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

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

marker = marker + 1  # 将所有背景都设为1 前景不变
marker[unknow == 255] = 0

# 进行图像分割
result = cv2.watershed(img, marker)  # 结果中边沿都是-1表示
img[result == -1] = [0, 0, 255]

cv2.imshow('img', img)
cv2.imshow('bg', bg)
cv2.imshow('fg', fg)
cv2.imshow('unknow', unknow)
cv2.waitKey(0)

 GrabCut法

 GrabCut 原理

(1)用户指定前景区域,剩下的是背景区域

(2)用户可以明确指出某些地方为前景或背景

(3)GrabCut采用分段迭代的方法分析前景物体形成模型树

(4)最后根据权重决定某个像素是前景还是背景

GrabCut 实战

(1)主体结构(定义接口,成员变量)

(2)鼠标事件的处理

(3)调用GrabCut实现前景和背景的分离

GrabCut API

grabCut(img,mask,rect,bgdModel,fgdModel,iterator,mode)

mask:生成的掩码   BGD背景0  FGD前景1  PD_BGD可能是背景2   PR_FGD可能是前景3

rect: 检测区域

bgdModel: np.float64 type zero arrays of size (1,65) 

fgdModel: np.float64 type zero arrays of size (1,65)

mode: GC_INIT_WITH_RECT      GC_INIT_WITH_MASK(第一次使用前一个,第二次使用后面的)

GrabCut实战代码 

(1)主体结构的搭建

import cv2
import numpy as np


class App:
    def onmouse(self, event, x, y, flags, param):  # 对于鼠标事件的监听
        print("onmouse")

    def run(self):  # 主体函数
        print("run……")

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

        img = cv2.imread('lena.png')
        cv2.imshow('input', img)
        cv2.waitKey(0)


App().run()

(2)添加鼠标事件

    def onmouse(self, event, x, y, flags, param):  # 对于鼠标事件的监听

        # 主要要实现的三个功能(左键的按下,移动和抬起)
        if (event == cv2.EVENT_LBUTTONDOWN):
            self.flag_ract = True
            self.startX = x
            self.startY = y
            print("LBUTTONDOWN")

        elif (event == cv2.EVENT_LBUTTONUP):
            self.flag_ract = False
            cv2.rectangle(self.img,
                          (self.startX, self.startY),
                          (x, y),
                          (0, 0, 255),
                          3)
            print("LBUTTONUP")

        elif (event == cv2.EVENT_MOUSEMOVE):
            if self.flag_ract == True:
                self.img = self.img2.copy()
                cv2.rectangle(self.img,
                              (self.startX, self.startY),
                              (x, y),
                              (255, 0, 0),
                              3)
                print("MOUSEMOVE")
self.img = cv2.imread('lena.png')
        self.img2 = self.img.copy()

        while (1):
            cv2.imshow('input', self.img)
            k = cv2.waitKey(100)
            if (k == 27):
                break

(3) 调用GrabCut实现前景和背景的分离(总)

import cv2
import numpy as np


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

    def onmouse(self, event, x, y, flags, param):  # 对于鼠标事件的监听

        # 主要要实现的三个功能(左键的按下,移动和抬起)
        if (event == cv2.EVENT_LBUTTONDOWN):
            self.flag_ract = True
            self.startX = x
            self.startY = y
            print("LBUTTONDOWN")

        elif (event == cv2.EVENT_LBUTTONUP):
            self.flag_ract = 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("LBUTTONUP")

        elif (event == cv2.EVENT_MOUSEMOVE):
            if self.flag_ract == 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)

            # 分离后需要把截取的全景取出来
            # 原始图像与上一个掩码  掩码需要的是最大值ff
            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法

 MeanShift 图像分割原理

(1)该方法并不是用于图像分割的,而是在彩色层面的平滑滤波

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

(3)以图像上让任意一点p为圆心,半径为sp,色彩幅值为sr进行不断的迭代

MeanShift 图像分割实战

MeanShift 的API

pyrMeanShiftFiltering(img,sp,sr,maxlevel=1,termcrit=TermCriteria……)

sp:半径

sr:色彩幅值

MeanShift 的实战

import cv2
import numpy as np

img = cv2.imread('flower.png')
mean_img = cv2.pyrMeanShiftFiltering(img, sp=20, sr=30)

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

contours, hierarchy = cv2.findContours(canny_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (255, 0, 0), 2)

cv2.imshow('img', img)
cv2.imshow('mean_img', mean_img)
cv2.imshow('canny_img', canny_img)
cv2.waitKey(0)

视频前后背景分离

 视频背景扣除原理

(1)视频是有一组连续的帧组成的

(2)帧与帧之间关系密切(GOP)

(3)在GOP中,背景几乎是不变的

MOG去背景

MOG去背景的API

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

MOG去背景的实战代码

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(30)
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()

MOG2去背景 

MOG2去背景优缺点

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

缺点:前后景分离时会产生很多噪点

MOG2去背景API

createBacgroundSubtractorMOG2( history(默认值500),……detecShadow(是否检测阴影,True))

MOG2去背景实战代码

import cv2
import numpy as np

cap = cv2.VideoCapture('vtest.avi')
# 好处,可以计算出阴影部分
# 缺点,会产生很多噪点
mog = cv2.createBackgroundSubtractorMOG2()

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

    cv2.imshow('img', fgmask)

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

cap.release()
cv2.destroyAllWindows()

GMG去背景

GMG去背景优缺点

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

缺点:默认值帧数很大,需要等待较长时间

MOG2去背景API

createBacgroundSubtractorGMG(initializaFranmes(初始帧数 120))

MOG2去背景实战代码

import cv2
import numpy as np

cap = cv2.VideoCapture('vtest.avi')
# 好处,可以算出阴影部分,同时减少噪点
# 缺点,如果采用默认值,开始很长时间没有任何显示
# 解决方法,调整初始参考帧数量
mog = cv2.bgsegm.createBackgroundSubtractorGMG(10)  # 这个就是参考帧数量

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

    cv2.imshow('img', fgmask)

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

cap.release()
cv2.destroyAllWindows()

图像修复实战

 

图像修复相关原理

图像修复API

inpaint(img,mask,inpaintRadius,flags)

img:原始图像

mask:与原始图像大小相同的黑底白色的残缺位置的图片(可以自己制作出来)

inpaintRadius:每个破损的点会画一个半径,根据半径内的值计算出破损区域的值并填入

flags:INPAINT_NS , INPAINT_TELEA

图像修复实战代码

import cv2
import numpy as np

img = cv2.imread('inpaint.png')
mask = cv2.imread('inpaint_mask.png', 0)  # 0 使其变成8位

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

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

原图处理后的图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1326999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux调试器gdb的用法

Linux调试器gdb的用法 1. debug/release版本之间的比较2. gdb调试器的基本指令3. 使用展示 1. debug/release版本之间的比较 在之前学习C语言的的时候出过一期vs的调试技巧。 而对于现在的Linux下的调试器gdb其实也是换汤不换药的,基本上的调试思路是不会改变的&am…

Electron Vite打包后,部分图标未显示的解决方案

背景 这个问题,弄了一晚上,头都大了,找了一堆博客也没解决。主要参考这个:https://blog.csdn.net/m0_73845616/article/details/129741099。 下面讲一下我的解决方案。 解决方案 上面链接里的方法,我采用第二、三个都…

鸿蒙-arkTs:访问控制授权申请

module.json5文件中 requestPermissions 进行配置(值为数组,可配置多个) ohos.permission.INTERNET {"name": "ohos.permission.INTERNET" }

鸿蒙-HarmonyOS之初见

鸿蒙初识,此事能成!! 自己安装工具、配置环境并运行成功,流程记录。 一、首先官网下载开发工具 官网地址:https://developer.huawei.com/consumer/cn/ 当前最新的版本3.1 ,windows和Mac,Mac又…

GD32移植STM32工程(因为懒,所以移植)

文章目录 一、前言二、差异性三、软件移植部分1.前期准备1.1 安装GD32固件库1.2 选择所用芯片 2.修改程序2.1 启动时间(内部时钟可不改)2.2 主频2.2.1 系统时钟配置2.2.2 108MHz宏定义第一处第二处第三处第四处第五处 2.2.3 串口2.2.4 FLASH 四、总结 一…

c语言错误总结

函数 A:void类型函数可以 B:不需要,如果return 不返回任何值,函数会在return语句执行后终止执行,后面的语句不会执行 C:对的 D:不可能,return只能返回一个数据 A:函数不一定有返回值 B:可以…

php伪协议 [NISACTF 2022]easyssrf

打开题目 我们直接用 file:/// 协议读取看看flag文件 file:///flag 点击curl得到回响 得到提示告诉我们应该看看提示文件 file:///fl4g 跟着去访问了一下 再跟着去访问 从代码中我们可以看出 get传参file,我们用stristr检测file参数里面是否含有file&#xff…

企业需要哪些数字化管理系统?

企业需要哪些数字化管理系统? ✅企业引进管理系统肯定是为了帮助整合和管理大量的数据,从而优化业务流程,提高工作效率和生产力。 ❌但是,如果各个系统之间不互通、无法互相关联数据的话,反而会增加工作量和时间成本…

Qt之QWidget 自定义倒计时器

简述 Qt提供的带进度显示的只有一个QProgresBar,这个控件要么是加载进度从0~100%,要么是持续的两边滚动;而我想要是倒计时的效果,所以QProgresBar并不满足要求,而Qt重写控件相对于MFC来说简直是轻而易举,所以就整了两种不同的倒计时控件; 效果 代码 QPushButton的绘制部…

边缘计算有哪些常用场景?TSINGSEE边缘AI视频分析技术行业解决方案

随着ChatGPT生成式人工智能的爆发,AI技术在业界又掀起一波新浪潮。值得关注的是,边缘AI智能也在AI人工智能技术进步的基础上得到了快速发展。IDC跟踪报告数据显示,2021年我国的边缘计算服务器整体市场规模达到33.1亿美元,预计2020…

2023最新版JavaSE教程——第11天:常用类和基础API

目录 一、字符串相关类之不可变字符序列:String1.1 String的特性1.2 String的内存结构1.2.1 概述1.2.2 练习类型1:拼接1.2.3 练习类型2:new1.2.4 练习类型3:intern() 1.3 String的常用API-11.3.1 构造器1.3.2 String与其他结构间的…

Spring统一数据返回格式处理String类型出错解析

Spring 统一数据返回格式是使用 Spring 进行开发时很常用的一个功能,但是当其处理返回类型原先为 String 类型的时候就会出错报错,需要我们额外对 String 类型进行处理。 例如:现在我开发一个项目,项目中我想要统一返回下述的 Res…

作业--day35

练习数据库命令 1> 创建一个工人信息库,包含工号(主键)、姓名、年龄、薪资; 2> 添加三条工人信息(可以完整信息,也可以非完整信息); 3> 修改某一个工人的薪资(…

深度学习14—注意力机制与自注意力机制

注:以下均为个人学习笔记,发布只为方便学习阅读,若觉侵权,请联系删除!! 1.李沐老师课堂学习理解笔记 1.1 随意线索和不随意线索 1.2 注意力机制 通过注意力池化层来有偏向性的选择某些输入。 1.3 注意力…

【QT】C++/Qt使用Qt自带工具windeployqt打包

基本操作 运行项目debug或者release 将运行后的可执行文件单独放到一个文件夹中 根据项目使用的kits来选择Qt的打包工具 打开工具后移动到exe文件夹下执行windeployqt xxx.exe 预览图 问题 打包后再其他电脑上运行出现下图错误 将自己电脑的这个文件拷到可执行文件夹中既…

构建高效持久层:深度解析 MyBatis-Plus(02)

目录 引言1. 逻辑删除1.1 概述1.2 逻辑删除的优势1.3.为什么使用逻辑删除1.4 综合案例 2. 乐观锁和悲观锁2.1.什么是乐观锁和悲观锁2.2.乐观锁和悲观锁的区别2.3.综合案例 3. 分页插件总结 引言 在现代软件开发中,数据库操作是不可或缺的一环。为了提高系统的性能、…

网络通信day5作业

1> 使用select完成TCP客户端程序 客户端: #include<myhead.h>#define FPORT 9999 #define FIP "192.168.125.130"#define KPORT 6666 #define KIP "192.168.125.130"int main(int argc, const char *argv[]) {//创建套接字文件描述符int cfd…

关于EasyExcel 合并单元格方法该如何实现

在做一个业务的导出&#xff0c;目前遇到一个需求&#xff0c;如下图&#xff1a; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metad…

美好蕴育润康真的对孕妇好吗?有效吗?

在孕期&#xff0c;孕妇的营养摄入对于胎儿的健康发育至关重要。因此&#xff0c;选择一款合适的孕期营养补充品成为了许多孕妇关注的焦点。美好蕴育润康作为一款备受推崇的孕期营养补充品&#xff0c;究竟是否真的对孕妇有益&#xff0c;是否有效呢&#xff1f; 首先&#xff…

数据治理与大模型一体化实践

引言: 大模型落地到当前这个阶段&#xff0c;核心关注点还是领域大模型&#xff0c;而领域大模型落地的前提在于两点&#xff1a;需求端&#xff0c;对当前应用的降本增效以及新应用的探索&#xff1b;供给端&#xff0c;训练技术已经有较高的成熟度。 专家介绍&#xff1a; …