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

文章目录

  • 前言
  • 一、图像分割
    • 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图像分割和修复技术的基本理解,并能够开始在自己的项目中应用这些技术。图像处理是一个不断发展的领域,随着技术的进步,将有更多的方法和技术被开发出来。因此,持续学习和实践对于保持在该领域的领先地位至关重要。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【分布式】小白看Ring算法 - 03

相关系列 【分布式】NCCL部署与测试 - 01 【分布式】入门级NCCL多机并行实践 - 02 【分布式】小白看Ring算法 - 03 【分布式】大模型分布式训练入门与实践 - 04 概述 NCCL&#xff08;NVIDIA Collective Communications Library&#xff09;是由NVIDIA开发的一种用于多GPU间…

Navicat 技术指引 | 适用于 GaussDB 的数据迁移工具

Navicat Premium&#xff08;16.2.8 Windows版或以上&#xff09; 已支持对 GaussDB 主备版的管理和开发功能。它不仅具备轻松、便捷的可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结构同步、协同合作、数据迁移等&#xff09;&#xff0c;这…

基于element-ui后台模板,日常唠嗑

后面会补充github地址 文章目录 目录 文章目录 案例说明 1.引入库 2.创建布局组件 3.创建布局组件 4.菜单效果展示 5.创建顶部组件 5.创建顶部面包屑组件 6.创建内容区域组件 7.效果总览 7.布丁&#xff08;实现一些小细节&#xff09; 前言一、pandas是什么&#xff1f;二、使…

Android Studio记录一个错误:Execution failed for task ‘:app:lintVitalRelease‘.

Android出现Execution failed for task :app:lintVitalRelease.> Lint found fatal errors while assembling a release target. Execution failed for task :app:lintVitalRelease解决方法 Execution failed for task ‘:app:lintVitalRelease’ build project 可以正常执…

计算机网络之网络层

一、概述 主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输 1.1网络引入的目的 从7层结构上看&#xff0c;网络层下是数据链路层 从4层结构上看&#xff0c;网络层下面是网络接口层 至少我们看到的网络层下面是以太网 以太网解决了什么问题&#xff1f; 答…

python中一个文件(A.py)怎么调用另一个文件(B.py)中定义的类AA详解和示例

本文主要讲解python文件中怎么调用另外一个py文件中定义的类&#xff0c;将通过代码和示例解读&#xff0c;帮助大家理解和使用。 目录 代码B.pyA.py 调用过程 代码 B.py 如在文件B.py,定义了类别Bottleneck&#xff0c;其包含卷积层、正则化和激活函数层&#xff0c;主要对…

微信小程序实现【点击 滑动 评分 评星(5星)】功能

wxml文件&#xff1a; <view class"wxpl_xing"><view class"manyidu">{{scoreContent}}</view><view><block wx:for{{scoreArray}} wx:for-item"item"><view classstarLen bindtapchangeScore data-sy"{{…

什么是LLC电路?

LLC电路是由2个电感和1个电容构成的谐振电路&#xff0c;故称之为LLC&#xff1b; LLC电路主要由三个元件组成&#xff1a;两个电感分别为变压器一次侧漏感(Lr)和励磁电感(Lm)&#xff0c;电容为变压器一次侧谐振电容(Cr)。这些元件构成了一个谐振回路&#xff0c;其中输入电感…

程序员进阶高管指南,看懂工资最少加5k

从象牙塔毕业跨入社会大染缸&#xff0c;很多人都跟我谈过他们的职业困惑&#xff0c;其中有一些刚刚毕业&#xff0c;有些人已经工作超过10年。基本上是围绕着怎样持续提升&#xff0c;怎样晋升为高级管理者。那么这篇文章&#xff0c;我就来谈一谈程序员到高管的跃升之路。 …

程序环境和预处理(详解版)

我们已经学到这里&#xff0c;这就是关于C语言的最后一个集中的知识点了&#xff0c;虽然它比较抽象&#xff0c;但是了解这部分知识&#xff0c;可以让我们对C代码有更深层次的理解&#xff0c;知道代码在每一个阶段发生什么样的变化。让我们开始学习吧! 目录 1.程序的翻译环…

5个免费在线工具推荐

NSDT 三维场景建模工具GLTF/GLB在线编辑器Three.js AI自动纹理化开发包YOLO 虚幻合成数据生成器3D模型在线转换 1、NSDT 三维场景建模 访问地址&#xff1a;NSDT 编辑器 2、GLTF/GLB在线编辑器 访问地址&#xff1a;GLTF 编辑器 3、Three.js AI自动纹理化开发包 图一为原始模…

C++类与对象(4)—日期类的实现

目录 一、类的创建和方法声明 二 、输出&运算符重载 三、检查合法性 1、获取对应年月的天数 2、初始化 四、实现加等和加操作 1、先写再写 2、先写再写 3、两种方式对比 五、实现自增和--自减 1、自增 2、自减 六、 实现减等和减操作 1、减等天数 2、加负数…

【数据结构/C++】线性表_双链表基本操作

#include <iostream> using namespace std; typedef int ElemType; // 3. 双链表 typedef struct DNode {ElemType data;struct DNode *prior, *next; } DNode, *DLinkList; // 初始化带头结点 bool InitDNodeList(DLinkList &L) {L (DNode *)malloc(sizeof(DNode))…

motionlayout的简单使用

MotionLayout 什么是motionLayout&#xff1f; MotionLayout 是 Android 中的一个强大工具&#xff0c;用于创建复杂的布局动画和过渡效果。它是 ConstraintLayout 的一个子类&#xff0c;继承了 ConstraintLayout 的布局功能&#xff0c;同时添加了动画和过渡的支持。Motion…

深度解析 Docker Registry:构建安全高效的私有镜像仓库

文章目录 什么是Docker Registry&#xff1f;Docker Hub vs. 私有RegistryDocker Hub&#xff1a;私有Registry&#xff1a; 如何构建私有Docker Registry&#xff1f;步骤一&#xff1a;安装Docker Registry步骤二&#xff1a;配置TLS&#xff08;可选&#xff09;步骤三&…

Adobe xd有免费版可以使用吗?

Adobexd现在收费了吗&#xff1f;Adobexd是收费的。Adobexd在中国提供个人版和团队版两项收费政策。个人版每月订阅60元&#xff0c;每年订阅688元&#xff1b;团队版每月订阅112元/用户&#xff0c;每年订阅1288元/用户。 虽然AdobeXD的免费计划已经下线&#xff0c;但Adobe仍…

穿山甲SDK 集成·android接入广告·app流量变现

接入穿山甲SDK的app 数独训练APP 广告接入示例: Android 个人开发者如何接入广告SDK&#xff0c;实现app流量变现 接入穿山甲SDK app示例&#xff1a; android 数独小游戏 经典数独休闲益智 随着移动互联网的快速发展&#xff0c;广告成为了许多应用开发者获取收益的主要方…

【2023.11.23】JDBC基本连接语法学习➹

1.导入jar包依赖&#xff1a;mysql-connector-java-8.0.27.jar 2.连接数据库&#xff01; 3.无法解析类->导入java.sql.*&#xff0c;&#xff08;将项目方言改为Mysql&#xff09; JDBC&#xff0c;启动&#xff01;&#xff01; public class Main {public static voi…

原生js实现form表单保存按钮触发后表单只读以及编辑按钮灰化,编辑按钮触发后表单是编辑状态以及保存按钮灰化

一、问题场景&#xff1f; 原生js实现form表单保存按钮触发后表单只读以及编辑按钮灰化&#xff0c;编辑按钮触发后表单是编辑状态以及保存按钮灰化 场景1&#xff1a;初始化进去的时候&#xff0c;编辑灰化&#xff0c;保存高亮&#xff0c;表单为编辑状态 场景2&#xff1a…

增量有余、后劲不足,星途汽车10月份销量环比下降3.9%

撰稿|行星 来源|贝多财经 近日&#xff0c;奇瑞集团发布了10月销量月报。报告显示&#xff0c;奇瑞集团于2023年10月销售汽车20.03万辆&#xff0c;同比增长50.8%&#xff0c;单月销量首次突破20万辆&#xff1b;2023年前10个月的累计销量为145.36辆&#xff0c;同比增长41.6…