OpenCV快速入门:图像分析——图像分割和图像修复

news2024/11/13 11:57:03

文章目录

  • 前言
  • 一、图像分割
    • 1.1 漫水填充法
      • 1.1.1 漫水填充法原理
      • 1.1.2 漫水填充法实现步骤
      • 1.1.3 代码实现
    • 1.2 分水岭法
      • 1.2.1 分水岭法原理
      • 1.2.2 分水岭法实现步骤
      • 1.2.3 代码实现
    • 1.3 GrabCut法
      • 1.3.1 GrabCut法原理
      • 1.3.2 GrabCut法实现步骤
      • 1.3.3 代码实现
    • 1.4 Mean-Shift法
      • 1.4.1 Mean-Shift法原理
      • 1.4.2 Mean-Shift法实现步骤
      • 1.4.3 代码实现
  • 二、图像修复
    • 2.1 图像修复原理
      • 2.1.1 Telea方法
      • 2.1.2 Navier-Stokes方法
      • 2.1.3 代码实现
    • 2.2 修补算法
      • 2.2.1 修补算法原理
      • 2.2.2 修补算法实现步骤
      • 2.2.3 OpenCV代码实现
        • 2.2.3.1 方形补丁修补
        • 2.2.3.2 圆形补丁修补
  • 总结

前言

OpenCV(Open Source Computer Vision Library)作为一个开源的计算机视觉和机器学习软件库,提供了丰富的图像处理功能,使得图像分析变得更加高效和易于实现。本篇博客旨在提供一个关于OpenCV中图像分割和图像修复技术的入门指南,从基本原理到代码实现,简要覆盖这些技术的关键方面。
opencv logo

一、图像分割

图像分割是图像处理中的一项重要技术,它涉及将图像划分为多个部分或区域,以便更容易地分析和处理。

1.1 漫水填充法

1.1.1 漫水填充法原理

漫水填充 (Flood Fill)算法基于区域生长的概念。它从图像中的一个点(种子点)开始,然后向所有与该点相连的、颜色/强度相似的区域扩展。

1.1.2 漫水填充法实现步骤

  1. 选择一个种子点。
  2. 检查相邻像素是否属于同一区域(基于颜色/强度相似度)。
  3. 如果相邻像素符合条件,则包括它,并继续向外扩展。
  4. 重复此过程直到无法扩展。

1.1.3 代码实现

import cv2
import numpy as np

# 读取图像
image = cv2.imread('tulips.jpg')
# 创建一个与图像大小相同的掩码(mask),并初始化为全0
mask = np.zeros((image.shape[0] + 2, image.shape[1] + 2), dtype=np.uint8)

# 定义填充的起始点
start_point1 = (100, 100)  # 开始填充的坐标
start_point2 = (420, 200)  # 开始填充的坐标
# 定义填充颜色
fill_color = (0, 0, 0)  # 黑色
# 定义颜色容差范围
tolerance = (160, 160, 160, 160)  # 上下左右的容差

# floodFill函数的参数
flood_fill_flags = 4
flood_fill_flags |= 255 << 8
flood_fill_flags |= cv2.FLOODFILL_FIXED_RANGE

# 调用floodFill函数
image_fill = image.copy()
cv2.floodFill(image_fill, mask, start_point1, fill_color, tolerance, tolerance, flood_fill_flags)
cv2.floodFill(image_fill, mask, start_point2, fill_color, tolerance, tolerance, flood_fill_flags)

# 显示结果
mask_img = cv2.merge([mask,mask,mask])
# 获取图像的高度和宽度
height, width ,channel= image.shape
# 创建一个新的图像,高度和宽度各增加一
new_height = height + 2
new_width = width + 2
image_origin = np.zeros((new_height, new_width, channel), dtype=np.uint8)
# 将原始图像复制到新图像中
image_origin[:height, :width] = image

image_flood = np.zeros((new_height, new_width, channel), dtype=np.uint8)
# 将原始图像复制到新图像中
image_flood[:height, :width] = image_fill

cv2.imshow('Flood Filled Image', cv2.hconcat([image_origin,image_flood, mask_img]))
cv2.waitKey(0)
cv2.destroyAllWindows()

Flood Filled Image
cv2.floodFill 函数用于实现漫水填充算法,即填充一个连通区域的颜色或图案。这个函数非常适合于图像分割、对象检测和图像编辑等任务。下面是对 cv2.floodFill 函数参数和功能的简要介绍:

def floodFill(image, mask, seedPoint, newVal, loDiff=None, upDiff=None, flags=None)

  1. image: 输入/输出图像。这是一个单通道或三通道的8位或浮点图像。除非设置了 FLOODFILL_MASK_ONLY 标志,否则此函数会修改输入图像。

  2. mask: 操作掩码,应该是一个单通道8位图像,比输入图像宽2个像素,高2个像素。这是一个输入和输出参数,因此在使用前需要初始化。漫水填充不能穿过掩码中非零的像素。例如,边缘检测器的输出可以作为掩码,以阻止填充穿过边缘。

  3. seedPoint: 开始点。这是漫水填充开始的像素位置。

  4. newVal: 重新绘制域像素的新值。

  5. loDiffupDiff: 分别代表最大下限和上限的亮度/颜色差异。这些参数决定了填充颜色与周围像素颜色的最大允许差异。

  6. rect: 可选的输出参数,函数设置为重新绘制域的最小边界矩形。

  7. flags: 操作标志。前8位包含连接值,4代表只考虑四个最近邻像素(那些共享边的像素),8代表将考虑八个最近邻像素(那些共享角的像素)。接下来的8位(8-16位)包含用来填充掩码的值(默认值为1)。例如,4 | (255 << 8) 将考虑4个最近邻居,并用255的值填充掩码。

这个函数通过比较像素与其邻居或种子点的颜色/亮度差异来确定哪些像素属于同一连接组件,并将这些像素填充为新的颜色或值。在实际应用中,需要根据具体的图像和需求调整参数,以达到最佳的填充效果。

1.2 分水岭法

1.2.1 分水岭法原理

分水岭(Watershed)算法模拟地理学中的水流原理。在图像中,任何灰度值可以看作高度,算法模拟雨水流入低洼地区,形成不同的“湖泊”,每个湖泊代表图像的一个分割区域。

1.2.2 分水岭法实现步骤

  1. 对图像应用边缘检测,例如使用Canny算法。
  2. 应用距离变换。
  3. 应用分水岭算法分割图像。

1.2.3 代码实现

import cv2
import numpy as np

# 读取图像
image = cv2.imread('tulips.jpg')
# 转换为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 应用阈值化来标记前景区域
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 去除噪声
kernel = np.ones((7, 7), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

# 确定背景区域
sure_bg = cv2.dilate(opening, kernel, iterations=6)
# 确定前景区域
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
_, sure_fg = cv2.threshold(dist_transform, 0.8 * dist_transform.max(), 255, 0)

# 找到未知区域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)

# 标记标签
_, markers = cv2.connectedComponents(sure_fg)

# 增加1以确保背景不是0,而是1
markers = markers + 1

# 标记未知区域为0
markers[unknown == 255] = 0

# 应用分水岭
cv2.watershed(image, markers)
image[markers == -1] = [255, 255, 255]

# 遍历所有的标记
for marker in np.unique(markers):
    if marker == 0 or marker == -1:
        # 忽略背景和边界
        continue

    # 创建一个掩码,使得当前标记区域为白色,其他区域为黑色
    mask = np.zeros(gray.shape, dtype=np.uint8)
    mask[markers == marker] = 255

    # 应用掩码到原始图像
    segmented_image = cv2.bitwise_and(image, image, mask=mask)

    # 显示提取的区域
    cv2.imshow(f'Segmented area {marker}', segmented_image)

# 显示结果
cv2.imshow('Segmented Image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Segmented Image
cv2.watershed 用于基于标记的图像分割的函数,实现了一种变体的分水岭算法。这个函数的关键功能是将图像分割成多个区域,这些区域基于提供的标记来确定。

def watershed(image, markers)

  1. image: 输入参数。这是一个8位的3通道图像,即一般的彩色图像。这个图像是要应用分水岭算法进行分割的图像。

  2. markers: 输入/输出参数。这是一个32位单通道图像,代表标记。它的大小应该与 image 相同。在输入时,markers 图像中应该有正值(>0)标记出预期分割区域的大致轮廓。每个区域由一个或多个连接组件表示,像素值为1、2、3等。函数处理后,markers 中的每个像素将被设置为其所属“种子”组件的值,或在区域边界处被设置为-1。

    • 正值(>0): 表示不同的对象或区域。
    • 零值(0): 表示这些像素的归属尚未确定,需要算法来定义。
    • 负值(-1): 在函数输出中,这表示不同区域之间的边界。

cv2.watershed 函数的目的是根据提供的标记,将图像分割成不同的区域。这对于图像分割、对象识别和计算机视觉应用特别有用。在实际应用中,通常需要先对图像进行预处理(如边缘检测、阈值化等),然后生成合适的标记图像,最后应用这个函数进行分割。

1.3 GrabCut法

1.3.1 GrabCut法原理

GrabCut是一种基于图论的图像分割方法,使用用户定义的前景和背景区域来初始化分割。算法通过迭代方式优化每个像素属于前景或背景的概率。

1.3.2 GrabCut法实现步骤

  1. 用户定义前景和背景区域。
  2. 算法初始化并迭代更新每个像素的标签(前景或背景)。
  3. 使用GMM(高斯混合模型)对颜色分布建模。
  4. 利用图割算法优化像素标签。

1.3.3 代码实现

import cv2
import numpy as np

# 读取图像
image = cv2.imread('tulips.jpg')

# 定义前景和背景模型
mask = np.zeros(image.shape[:2], np.uint8)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)

# 定义矩形(用户定义的前景区域)
rect = (100, 50, 200, 300)

# 应用GrabCut
cv2.grabCut(image, mask, rect, bgdModel, fgdModel, 1, cv2.GC_INIT_WITH_RECT)

# 提取前景和可能的前景区域
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
image = image * mask2[:, :, np.newaxis]

# 显示结果
cv2.imshow('GrabCut Image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

GrabCut
cv2.grabCut 实现了 GrabCut 算法,这是一种用于图像分割的迭代算法。GrabCut 算法可以有效地从图像中分离前景(目标对象)和背景。

def grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)

  1. img: 输入参数。这是一个8位的3通道图像,即一般的彩色图像。这个图像是要应用 GrabCut 算法的对象。

  2. mask: 输入/输出参数。这是一个8位单通道的掩码图像。掩码的元素可以是 GrabCutClasses 中的一个,表示像素的不同分类(如明确的背景、可能的背景、明确的前景、可能的前景)。当 mode 设置为 GC_INIT_WITH_RECT 时,函数会初始化这个掩码。

  3. rect: 输入参数,表示包含分割对象的感兴趣区域(ROI)。当 mode == GC_INIT_WITH_RECT 时使用此参数。ROI 外的像素被标记为“明确的背景”。

  4. bgdModel: 输入/输出参数。这是用于背景模型的临时数组。处理同一图像时不应修改它。

  5. fgdModel: 输入/输出参数。这是用于前景模型的临时数组。处理同一图像时不应修改它。

  6. iterCount: 输入参数,表示算法应该执行的迭代次数。

  7. mode: 输入参数,操作模式,可以是 GrabCutModes 中的一个。常见模式包括 GC_INIT_WITH_RECT(使用矩形初始化)和 GC_INIT_WITH_MASK(使用掩码初始化)。

cv2.grabCut 函数的主要用途是通过迭代方式将图像中的目标对象与背景分离。这在图像编辑、计算机视觉和对象识别等领域非常有用。函数的实现方式是先用一个矩形粗略地标记出感兴趣的对象,然后算法迭代地改进前景和背景的分割。

1.4 Mean-Shift法

1.4.1 Mean-Shift法原理

Mean-Shift算法是一种基于特征空间分析的非参数密度估计技术。在图像分割的上下文中,它通常用于基于颜色的聚类。

1.4.2 Mean-Shift法实现步骤

  1. 在特征空间(例如颜色空间)中选择一个窗口。
  2. 计算窗口内所有点的均值。
  3. 移动窗口到均值位置。
  4. 重复步骤2和3,直到收敛。

1.4.3 代码实现

import cv2

# 读取图像
image = cv2.imread('tulips.jpg')

# 转换为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 应用Canny边缘检测
edges = cv2.Canny(gray, 50, 150)

# Mean-Shift 参数
spatial_radius = 20  # 空间窗口大小
color_radius = 40    # 颜色窗口大小
max_pyramid_level = 2 # 金字塔层数

# 应用Mean-Shift算法
result = cv2.pyrMeanShiftFiltering(image, spatial_radius, color_radius, max_pyramid_level)
# 转换为灰度图
gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
# 应用Canny边缘检测
result_edges = cv2.Canny(gray, 50, 150)

# 显示结果
img_edges = cv2.merge([edges,edges,edges])
img_result_edges = cv2.merge([result_edges,result_edges,result_edges])
cv2.imshow('Mean-Shift Segmentation', cv2.vconcat([
    cv2.hconcat([image, img_edges]),
    cv2.hconcat([result,img_result_edges])
]))
cv2.waitKey(0)
cv2.destroyAllWindows()

Mean-Shift Segmentation
cv2.pyrMeanShiftFiltering 用于执行图像分割的 Mean-Shift 算法的函数。这个函数主要用于平滑图像的颜色梯度,同时保留边缘信息,从而对图像进行“平面化”处理。以下是对 cv2.pyrMeanShiftFiltering 函数的参数和功能的简要介绍:

def pyrMeanShiftFiltering(src, sp, sr, dst=None, maxLevel=None, termcrit=None)

  1. src: 输入参数,源图像。这是一个8位的3通道图像,即一般的彩色图像。

  2. sp: 输入参数,空间窗口半径。这个参数决定了像素邻域的大小。在此邻域内进行Mean-Shift迭代。

  3. sr: 输入参数,颜色窗口半径。这个参数决定了颜色空间中像素邻域的大小,用于在颜色空间内聚类。

  4. dst: 输出参数,目标图像。这是处理后的图像,格式和大小与源图像相同。

  5. maxLevel: 可选输入参数,金字塔的最大层级。当这个值大于0时,算法首先在金字塔的最小层上执行,然后结果被传播到更大的层上。

  6. termcrit: 可选输入参数,终止条件。它决定了Mean-Shift迭代何时停止。

cv2.pyrMeanShiftFiltering 函数的主要功能是对图像进行分割和平滑处理,同时保留边缘。在空间和颜色空间中,函数对每个像素进行迭代,直到满足终止条件。这个过程可以帮助去除图像的细节和噪声,同时保留主要的结构信息。这种方法在图像分割和对象识别等应用中非常有用。在实际使用时,spsr 参数需要根据具体的应用场景和图像内容进行调整。

二、图像修复

在图像处理领域,图像修复是一项至关重要的技术,它涉及修复图像中的损坏部分或去除不需要的对象。

2.1 图像修复原理

图像修复 (Inpainting)是一种用于修复图像中损坏区域的技术。它通过分析周围的像素来重建缺失或损坏的部分。OpenCV提供了两种主要的Inpainting技术:Telea方法和Navier-Stokes方法。

2.1.1 Telea方法

Telea方法是一种基于快速行进算法的图像修复技术。这种方法的核心思想是从损坏区域的边缘开始,逐步向内部填充,直到整个区域被修复完毕。

原理
Telea方法的关键在于它如何选择用于填充缺失区域的像素值。它考虑到了边缘周围像素的信息,并基于这些信息来估计缺失像素的最佳值。具体而言,该方法依赖于周围像素的几何距离和光强差异来计算修复值。

应用
Telea方法非常适合于修复小到中等大小的损坏区域。由于其基于边缘信息进行填充,因此在修复裂缝或小孔等缺陷时表现尤为出色。

2.1.2 Navier-Stokes方法

Navier-Stokes方法是另一种流行的图像修复技术。它基于流体动力学中的Navier-Stokes方程,适用于重建更大区域的图像。

原理
这种方法将图像修复问题视为一个流体动力学问题,其中图像的每个像素都被视为流体粒子。它利用Navier-Stokes方程来模拟流体粒子的运动,从而估算缺失区域的像素值。

应用
Navier-Stokes方法特别适用于大面积损坏的修复,例如修复破损的古老照片或艺术作品中的大片缺失部分。该方法能够有效地重建图像的结构和纹理信息,使修复后的区域与周围环境融合得更自然。

2.1.3 代码实现

import cv2
import numpy as np


def inpaint_image(image, mask, inpaint_radius=3):
    restored_telea = cv2.inpaint(image, mask, inpaint_radius, cv2.INPAINT_TELEA)
    restored_ns = cv2.inpaint(image, mask, inpaint_radius, cv2.INPAINT_NS)
    return restored_telea, restored_ns


# 加载图像
image = cv2.imread('tulips.jpg')

# 创建第一个掩模,用于模拟损坏的区域
mask1 = np.zeros(image.shape[:2], np.uint8)
mask1[40:60, 50:550] = 255  # 水平损坏区域
mask1[60:260, 300:320] = 255  # 垂直损坏区域
mask1[200:220, 100:300] = 255  # 水平损坏区域

# 创建第二个掩模,用于模拟损坏的区域
mask2 = np.zeros(image.shape[:2], np.uint8)
cv2.circle(mask2, (395, 215), 80, 255, -1)  # 圆形损坏区域

# 应用掩模,模拟损坏
damaged_image1 = image.copy()
damaged_image1[mask1 == 255] = [0, 0, 0]
damaged_image2 = image.copy()
damaged_image2[mask2 == 255] = [0, 0, 0]

# 使用封装的函数进行修复
restored_telea1, restored_ns1 = inpaint_image(damaged_image1, mask1)
restored_telea2, restored_ns2 = inpaint_image(damaged_image2, mask2)

# 显示结果
horizontal_stack1 = np.hstack((damaged_image1, restored_telea1, restored_ns1))
horizontal_stack2 = np.hstack((damaged_image2, restored_telea2, restored_ns2))
vertical_stack = np.vstack((horizontal_stack1, horizontal_stack2))
cv2.imshow('Restored Image Telea and Navier-Stokes', vertical_stack)
cv2.waitKey(0)
cv2.destroyAllWindows()

Restored Image Telea and Navier-Stokes
cv2.inpaint 用于修复图像中的选定区域的函数。它基于图像的邻域信息来重建图像的损坏或不希望的部分。这个函数特别适合用于去除扫描照片中的灰尘和划痕,或从静态图像或视频中去除不需要的对象。

def inpaint(src, inpaintMask, inpaintRadius, flags, dst=None)

  1. src: 输入参数,源图像。这应该是一个8位、16位无符号或32位浮点的单通道或三通道图像。

  2. inpaintMask: 输入参数,修复掩模。这是一个8位单通道图像,非零像素指示需要修复的区域。

  3. inpaintRadius: 输入参数,圆形邻域的半径。每个待修复点考虑的邻域大小由此半径决定。

  4. flags: 输入参数,修复方法。可以是以下两种之一:

    • INPAINT_NS: 基于 Navier-Stokes 的方法。
    • INPAINT_TELEA: Alexandru Telea 提出的方法。
  5. dst: 输出参数,与源图像大小和类型相同的输出图像。

cv2.inpaint 函数通过考虑待修复区域边界附近的像素来重建选定的图像区域。该方法可用于修复小的图像区域,例如去除图像中的小斑点或遮挡物。它通过估算损坏区域周围的颜色和强度分布,以合理的方式填充这些区域,从而达到修复的效果。

在实际应用中,需要根据具体问题选择合适的修复半径和方法。例如,较小的半径适用于小面积的修复,而较大的半径可能更适合广泛区域的修复。同样,两种不同的方法(INPAINT_NS 和 INPAINT_TELEA)在不同类型的图像和损坏情况下可能会有不同的效果。

2.2 修补算法

2.2.1 修补算法原理

修补(Patching)算法通过选取图像中未损坏的区域并用其覆盖损坏部分来进行修复。这种方法对于去除图像中的小对象或缺陷特别有效。

2.2.2 修补算法实现步骤

  1. 选择一个图像的未损坏区域作为补丁。
  2. 选择需要修复的区域。
  3. 将补丁应用到损坏的区域。

2.2.3 OpenCV代码实现

2.2.3.1 方形补丁修补
import cv2
import numpy as np

# 加载图像
image = cv2.imread('tulips.jpg')

# 创建掩模,用于模拟损坏的区域
mask2 = np.zeros(image.shape[:2], np.uint8)
cv2.circle(mask2, (395, 215), 80, 255, -1)  # 圆形损坏区域

# 应用掩模,模拟损坏
damaged_image = image.copy()
damaged_image[mask2 == 255] = [0, 0, 0]

# 选择一个补丁区域
# 注意:这里的坐标(x1, y1, x2, y2)需要根据您的图像进行调整
x1, y1, x2, y2 = 20, 20, 140, 150  # 补丁区域的坐标
patch = image[y1:y2, x1:x2]

# 确定损坏区域的坐标
# 这里我们使用与圆形损坏区域相同的坐标
dx1, dy1, dx2, dy2 = 395 - 80, 215 - 80, 395 + 80, 215 + 80

# 确保补丁和损坏区域的大小相同
patch_resized = cv2.resize(patch, (dx2 - dx1, dy2 - dy1))

# 应用补丁
restored_image = damaged_image.copy()
restored_image[dy1:dy2, dx1:dx2] = patch_resized

# 显示修复后的图像
cv2.imshow('Restored Image', cv2.hconcat([image, damaged_image,restored_image]))
cv2.waitKey(0)
cv2.destroyAllWindows()

Restored Image

2.2.3.2 圆形补丁修补
import cv2
import numpy as np

# 加载图像
image = cv2.imread('tulips.jpg')

# 创建掩模,用于模拟损坏的区域
mask2 = np.zeros(image.shape[:2], np.uint8)
cv2.circle(mask2, (395, 215), 80, 255, -1)  # 圆形损坏区域

# 应用掩模,模拟损坏
damaged_image = image.copy()
damaged_image[mask2 == 255] = [0, 0, 0]

# 选择一个圆形补丁区域
px, py, radius = 78, 80, 70  # 原始补丁的半径
patch_mask = np.zeros(image.shape[:2], np.uint8)
cv2.circle(patch_mask, (px, py), radius, 255, -1)

# 创建原始补丁图像
original_patch = np.zeros_like(image)
original_patch[patch_mask == 255] = image[patch_mask == 255]

# 放大补丁到新半径
new_radius = 80
scale_factor = new_radius / radius
resized_patch = cv2.resize(original_patch, (0, 0), fx=scale_factor, fy=scale_factor)

# 重新创建圆形掩模以裁剪放大的补丁
resized_mask = np.zeros(resized_patch.shape[:2], np.uint8)
cv2.circle(resized_mask, (int(px*scale_factor), int(py*scale_factor)), new_radius, 255, -1)
final_patch = np.zeros_like(resized_patch)
final_patch[resized_mask == 255] = resized_patch[resized_mask == 255]

restored_image = damaged_image.copy()
# 应用放大的圆形补丁
for i in range(-new_radius, new_radius):
    for j in range(-new_radius, new_radius):
        if i**2 + j**2 <= new_radius**2:
            restored_image[215 + i, 395 + j] = final_patch[int(py * scale_factor) + i, int(px * scale_factor) + j]

# 显示修复后的图像
cv2.imshow('Restored Image', cv2.hconcat([image, damaged_image,restored_image]))
cv2.waitKey(0)
cv2.destroyAllWindows()

Restored Image


总结

在本篇博客中,我们探讨了OpenCV中几种常用的图像分割方法:漫水填充法、分水岭法、GrabCut法和Mean-Shift法,以及图像修复技术:Telea方法和Navier-Stokes方法,还有修补算法。每种方法都有其独特的原理和适用场景。漫水填充法和分水岭法适用于基于区域的分割,GrabCut法适合交互式前景提取,而Mean-Shift法适用于基于密度的聚类分割。在图像修复方面,Telea方法和Navier-Stokes方法提供了强大的工具,用于修复图像中的损坏区域。

通过本篇博客,我们能够获得对OpenCV图像分割和修复技术的基本理解,并能够开始在自己的项目中应用这些技术。图像处理是一个不断发展的领域,随着技术的进步,将有更多的方法和技术被开发出来。因此,持续学习和实践对于保持在该领域的领先地位至关重要。

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

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

相关文章

面试题:为什么生产环境中,建议禁用 Redis 的 keys 命令?

keys命令的用法&#xff1a; keys pattern查找符合正则匹配的key的列表。扫描对象是Redis服务中所有的key&#xff0c;想想都很慢对不对&#xff1f; 同时执行keys命令的同时&#xff0c;Redis进程将被阻塞&#xff0c;无法执行其他命令&#xff0c;假如超过了哨兵的down-aft…

Android系统预装带so的apk

文章目录 前言配置新建Android.mk核心命令首次编译Apk已生成 但是无arm文件system.img 也已经更新 第一次刷入打开APP后闪退加入so文件如下为修改后的mk 第二次刷入mm报错查看手机系统abi路径下分别生成两个环境的so官方LOCAL_MULTILIB描述so打包错误验证so位数注释v7部分 第三…

界面组件DevExpress Reporting v23.1 - Web报表设计器功能升级

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表 界面组件DevExpress Reporting v23.1已经发布一段…

图解分库分表

中大型项目中&#xff0c;一旦遇到数据量比较大&#xff0c;小伙伴应该都知道就应该对数据进行拆分了。有垂直和水平两种。 垂直拆分比较简单&#xff0c;也就是本来一个数据库&#xff0c;数据量大之后&#xff0c;从业务角度进行拆分多个库。如下图&#xff0c;独立的拆分出…

【PyQt】(自定义类)阴影遮罩

写了一个感觉有些用的小玩具。 用于给控件添加阴影遮罩(强调主控件的同时屏蔽其余控件的点击) 自定义阴影遮罩Mask&#xff1a; from PyQt5.QtCore import QPoint,QRect,Qt,QPoint,QSize from PyQt5.QtWidgets import QWidget,QLabel,QPushButton,QVBoxLayout from PyQt5.QtGu…

Javaweb之前后台分离开发介绍的详细解析

2.1 前后台分离开发介绍 在之前的课程中&#xff0c;我们介绍过&#xff0c;前端开发有2种方式&#xff1a;前后台混合开发和前后台分离开发。 前后台混合开发&#xff0c;顾名思义就是前台后台代码混在一起开发&#xff0c;如下图所示&#xff1a; 这种开发模式有如下缺点&a…

视频剪辑技巧:如何高效批量转码MP4视频为MOV格式

在视频剪辑的过程中&#xff0c;经常会遇到将MP4视频转码为MOV格式的情况。这不仅可以更好地编辑视频&#xff0c;还可以提升视频的播放质量和兼容性。对于大量视频文件的转码操作&#xff0c;如何高效地完成批量转码呢&#xff1f;现在一起来看看云炫AI智剪如何智能转码&#…

基于STC12C5A60S2系列1T 8051单片读写掉电保存数据IIC总线器件24C02一字节并显示在液晶显示器LCD1602上应用

基于STC12C5A60S2系列1T 8051单片读写掉电保存数据IIC总线器件24C02一字节并显示在液晶显示器LCD1602上应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍IIC通信简单…

【Java从入门到大牛】网络编程

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;Java从入门到大牛 &#x1f320; 首发时间&#xff1a;2023年11月23日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f4…

【LeetCode:2304. 网格中的最小路径代价 | dijkstra(迪杰斯特拉)】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

YOLOv8改进 | CARAFE既减少参数又提高精度的上采样方法

论文地址&#xff1a;官方论文地址点击即可跳转 代码地址&#xff1a;官方代码地址点击即可跳转 一、本文介绍 本文给大家带来的CARAFE&#xff08;Content-Aware ReAssembly of FEatures&#xff09;是一种用于增强卷积神经网络特征图的上采样方法。其主要旨在改进传统的上采…

手写数字可视化_Python数据分析与可视化

手写数字可视化 手写数字流形学习 手写数字 手写数字无论是在数据可视化还是深度学习都是一个比较实用的案例。 数据在sklearn中&#xff0c;包含近2000份8 x 8的手写数字缩略图。 首先需要先下载数据&#xff0c;然后使用plt.imshow()对一些图形进行可视化&#xff1a; 打开c…

Springmvc原理解析

1. DispatcherServlet springmvc的核心控制器&#xff0c;负责截获所有的请求&#xff0c;当截获请求后委托给HandlerMapping进行请求映射的解析工作&#xff0c;目的是找到哪一个Controller的方法可以处理该请求&#xff0c;找到后再交由给HandlerAdaptor去负责调用并返回Mod…

利用人工智能打破应试教育惯性促进学生思维活化与创新能力培养的研究

全文均为人工智能独立研究完成 应试教育导致学生迷信标准答案惯性导致思维僵化-移动机器人-CSDN博客 用AI魔法打败AI魔法-CSDN博客 课题名称建议&#xff1a;“利用人工智能打破应试教育惯性&#xff0c;促进学生思维活化与创新能力培养研究”。 这个课题名称明确指出了研究的…

ConcurrentHashMap的数据结构+以及各个版本之间的区别

ConcurrentHashMap 1.7与1.8的区别 1、锁结构不同 2、put的流程不同 3、size的计算方式不同(1.8使用的使用basecell[]计算&#xff0c;有点类似于LongAdder&#xff0c;1.7使用三级通缉判断是否一样&#xff0c;不一样通过分段式加锁再求和) 4、数据结构不同&#xff0c;1.6 Re…

[BJDCTF2020]The mystery of ip1

提示 ssti模板注入head头x-forwarded-for 每一次做题的最开始流程都大致因该是 信息收集找可以操控的地方 查看hint页面的源代码又发现它提示说 ####你知道为什么会知道你的ip吗 查看flag页面 从刚才给我的提示以及他这里显示的我的ip&#xff0c;大概找到了我可操作的可控点 …

Flutter 小技巧之 3.16 升级最坑 M3 默认适配技巧

如果要说 Flutter 3.16 升级里是最坑的是什么&#xff1f;那我肯定要说是 Material 3 default &#xff08;M3&#xff09;。 倒不是说 M3 bug 多&#xff0c;也不是 M3 在 3.16 上使用起来多麻烦&#xff0c;因为虽然从 3.16 开始&#xff0c;MaterialApp 里的 useMaterial3 …

海报设计必备:揭秘5款炙手可热的设计工具

1.即时设计&#xff1a;能实现在线协作的海报设计软件 即时设计作为 2020 年上线的国产设计工具&#xff0c;目前已经有了超百万的注册用户&#xff0c;获得了广大设计师的一致好评。与其他传统海报设计软件相比&#xff0c;即时设计具有这几个优点&#xff1a;一是所有功能都…

自定义字符-摄氏度汉字一

本文为博主 日月同辉&#xff0c;与我共生&#xff0c;csdn原创首发。希望看完后能对你有所帮助&#xff0c;不足之处请指正&#xff01;一起交流学习&#xff0c;共同进步&#xff01; > 发布人&#xff1a;日月同辉,与我共生_单片机-CSDN博客 > 欢迎你为独创博主日月同…