grab-cut 算法(附代码可复现)

GrabCut 该项目的主程序,代码实现了一个交互式的图像分割程序,它通过用户交互来标记前景和背景区域,并使用GMM(高斯混合模型)对图像进行建模和分割。2.迭代优化:通过迭代的方式,不断更新GMM模型的参数,同时构建GCGraph(图形割)并计算最大流,以获得更准确的前景和背景分割结果。可以观察到,掩膜后的图像存在一些小问题,如猫左侧的耳朵缺少了一部分,猫的右爪这一部分还存在一些背景区域的部分。GrabCut的掩膜过程是指根据用户提供的前景和背景区域,创建一个二值化掩膜,用于标记图像中的前景和背景像素。 阅读详情

GrabCut是由Rother等人在2004年提出的交互式前景/背景分割算法,是对Graph Cut算法的重要改进。它的核心思想是通过最少的用户交互(通常只需要画一个矩形框)来实现精确的目标分割。

核心原理

1. 基本思想

  • 将图像分割问题转化为图论中的最小割问题
  • 使用高斯混合模型(GMM)来建模前景和背景的颜色分布
  • 通过迭代优化不断改善分割结果

2. 算法流程

1. 用户输入矩形框标注目标区域
2. 初始化:矩形外=背景,矩形内=可能前景
3. 建立前景和背景的高斯混合模型
4. 构建图结构,计算最小割
5. 更新GMM参数
6. 重复步骤4-5直到收敛

技术细节

图结构构建

  • 节点: 每个像素作为一个节点
  • 边权重:
    • N-links: 相邻像素间的平滑项
    • T-links: 像素到源点/汇点的数据项

能量函数

E = E_data + λ × E_smooth
  • E_data: 数据项(基于GMM的似然)
  • E_smooth: 平滑项(相邻像素一致性)

高斯混合模型

  • 前景和背景各用K个高斯分量建模(通常K=5)
  • 通过EM算法迭代更新GMM参数

python 代码

import cv2
import numpy as np
import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import maximum_flow
import networkx as nx
from PIL import Image
import argparse
import os

class GrabCut:
    """
    GrabCut算法的完整实现
    基于论文: "GrabCut" Interactive Foreground Extraction using Iterated Graph Cuts
    """
    
    def __init__(self, n_components=5, gamma=50, lambda_val=9*50, n_iter=5):
        """
        初始化GrabCut算法参数
        
        Args:
            n_components: GMM组件数量
            gamma: 边缘权重参数
            lambda_val: 平滑项权重
            n_iter: 迭代次数
        """
        self.n_components = n_components
        self.gamma = gamma
        self.lambda_val = lambda_val
        self.n_iter = n_iter
        
        # 标签定义
        self.GC_BGD = 0      # 背景
        self.GC_FGD = 1      # 前景
        self.GC_PR_BGD = 2   # 可能背景
        self.GC_PR_FGD = 3   # 可能前景
        
    def init_mask_with_rect(self, img_shape, rect):
        """
        用矩形框初始化mask
        
        Args:
            img_shape: 图像形状 (height, width)
            rect: 矩形框 (x, y, width, height)
        
        Returns:
            mask: 初始化的mask
        """
        mask = np.zeros(img_shape[:2], dtype=np.uint8)
        mask.fill(self.GC_BGD)  # 全部设为背景
        
        x, y, w, h = rect
        # 矩形内部设为可能前景
        mask[y:y+h, x:x+w] = self.GC_PR_FGD
        
        return mask
    
    def init_gmm(self, img, mask):
        """
        初始化前景和背景的高斯混合模型
        
        Args:
            img: 输入图像
            mask: 分割mask
            
        Returns:
            bgd_gmm, fgd_gmm: 背景和前景的GMM模型
        """
        # 提取背景和前景像素
        bgd_pixels = img[(mask == self.GC_BGD) | (mask == self.GC_PR_BGD)]
        fgd_pixels = img[(mask == self.GC_FGD) | (mask == self.GC_PR_FGD)]
        
        # 创建GMM模型
        bgd_gmm = GaussianMixture(n_components=self.n_components, random_state=42)
        fgd_gmm = GaussianMixture(n_components=self.n_components, random_state=42)
        
        # 训练GMM
        if len(bgd_pixels) > 0:
            bgd_gmm.fit(bgd_pixels.reshape(-1, 3))
        if len(fgd_pixels) > 0:
            fgd_gmm.fit(fgd_pixels.reshape(-1, 3))
            
        return bgd_gmm, fgd_gmm
    
    def calculate_beta(self, img):
        """
        计算beta参数用于边缘权重
        """
        h, w = img.shape[:2]
        beta = 0
        count = 0
        
        # 水平相邻像素
        for i in range(h):
            for j in range(w-1):
                diff = img[i, j] - img[i, j+1]
                beta += np.sum(diff**2)
                count += 1
        
        # 垂直相邻像素
        for i in range(h-1):
            for j in range(w):
                diff = img[i, j] - img[i+1, j]
                beta += np.sum(diff**2)
                count += 1
        
        # 对角相邻像素
        for i in range(h-1):
            for j in range(w-1):
                diff = img[i, j] - img[i+1, j+1]
                beta += np.sum(diff**2)
                count += 1
                
                diff = img[i, j+1] - img[i+1, j]
                beta += np.sum(diff**2)
                count += 1
        
        beta = 1.0 / (2 * beta / count) if beta > 0 else 0
        return beta
    
    def construct_graph(self, img, mask, bgd_gmm, fgd_gmm):
        """
        构建图结构用于最小割
        """
        h, w = img.shape[:2]
        n_pixels = h * w
        
        # 计算beta参数
        beta = self.calculate_beta(img)
        
        # 创建图的容量矩阵
        # 节点编号: 0 - source, 1 to n_pixels - 像素节点, n_pixels+1 - sink
        n_nodes = n_pixels + 2
        source = 0
        sink = n_pixels + 1
        
        # 初始化容量矩阵
        capacity = np.zeros((n_nodes, n_nodes))
        
        # 计算数据项(T-links)
        for i in range(h):
            for j in range(w):
                pixel_idx = i * w + j + 1  # 像素节点编号(从1开始)
                pixel_color = img[i, j].reshape(1, -1)
                
                # 计算前景和背景的似然
                if len(bgd_gmm.means_) > 0:
                    bgd_prob = -bgd_gmm.score(pixel_color)
                else:
                    bgd_prob = 0
                    
                if len(fgd_gmm.means_) > 0:
                    fgd_prob = -fgd_gmm.score(pixel_color)  
                else:
                    fgd_prob = 0
                
                # 根据mask状态设置T-links
                if mask[i, j] == self.GC_BGD:
                    # 确定背景
                    capacity[source, pixel_idx] = 0
                    capacity[pixel_idx, sink] = self.lambda_val
                elif mask[i, j] == self.GC_FGD:
                    # 确定前景
                    capacity[source, pixel_idx] = self.lambda_val
                    capacity[pixel_idx, sink] = 0
                else:
                    # 可能前景/背景
                    capacity[source, pixel_idx] = bgd_prob
                    capacity[pixel_idx, sink] = fgd_prob
        
        # 计算平滑项(N-links)
        for i in range(h):
            for j in range(w):
                pixel_idx = i * w + j + 1
                
                # 右邻居
                if j < w - 1:
                    neighbor_idx = i * w + (j + 1) + 1
                    diff = img[i, j] - img[i, j+1]
                    weight = self.gamma * np.exp(-beta * np.sum(diff**2))
                    capacity[pixel_idx, neighbor_idx] = weight
                    capacity[neighbor_idx, pixel_idx] = weight
                
                # 下邻居
                if i < h - 1:
                    neighbor_idx = (i + 1) * w + j + 1
                    diff = img[i, j] - img[i+1, j]
                    weight = self.gamma * np.exp(-beta * np.sum(diff**2))
                    capacity[pixel_idx, neighbor_idx] = weight
                    capacity[neighbor_idx, pixel_idx] = weight
                
                # 对角邻居
                if i < h - 1 and j < w - 1:
                    neighbor_idx = (i + 1) * w + (j + 1) + 1
                    diff = img[i, j] - img[i+1, j+1]
                    weight = self.gamma * np.exp(-beta * np.sum(diff**2)) / np.sqrt(2)
                    capacity[pixel_idx, neighbor_idx] = weight
                    capacity[neighbor_idx, pixel_idx] = weight
                
                if i < h - 1 and j > 0:
                    neighbor_idx = (i + 1) * w + (j - 1) + 1
                    diff = img[i, j] - img[i+1, j-1]
                    weight = self.gamma * np.exp(-beta * np.sum(diff**2)) / np.sqrt(2)
                    capacity[pixel_idx, neighbor_idx] = weight
                    capacity[neighbor_idx, pixel_idx] = weight
        
        return capacity, source, sink
    
    def solve_min_cut(self, capacity, source, sink):
        """
        求解最小割问题
        """
        # 转换为稀疏矩阵
        capacity_sparse = csr_matrix(capacity)
        
        # 计算最大流(最小割)
        flow_value, flow_dict = maximum_flow(capacity_sparse, source, sink)
        
        return flow_dict
    
    def update_mask(self, flow_dict, img_shape, source, sink):
        """
        根据最小割结果更新mask
        """
        h, w = img_shape[:2]
        mask = np.zeros((h, w), dtype=np.uint8)
        
        for i in range(h):
            for j in range(w):
                pixel_idx = i * w + j + 1
                
                # 检查是否与source连通(前景)
                if flow_dict.residual[source, pixel_idx] > 0:
                    mask[i, j] = self.GC_PR_FGD
                else:
                    mask[i, j] = self.GC_PR_BGD
        
        return mask
    
    def grabcut(self, img, rect, n_iter=None):
        """
        主要的GrabCut算法流程
        
        Args:
            img: 输入图像
            rect: 初始矩形框 (x, y, width, height)
            n_iter: 迭代次数
            
        Returns:
            mask: 分割结果mask
        """
        if n_iter is None:
            n_iter = self.n_iter
            
        # 初始化mask
        mask = self.init_mask_with_rect(img.shape, rect)
        
        # 迭代优化
        for iteration in range(n_iter):
            print(f"GrabCut迭代 {iteration + 1}/{n_iter}")
            
            # 学习GMM模型
            bgd_gmm, fgd_gmm = self.init_gmm(img, mask)
            
            # 构建图
            capacity, source, sink = self.construct_graph(img, mask, bgd_gmm, fgd_gmm)
            
            # 求解最小割
            flow_dict = self.solve_min_cut(capacity, source, sink)
            
            # 更新mask
            new_mask = self.update_mask(flow_dict, img.shape, source, sink)
            
            # 检查收敛
            if np.array_equal(mask, new_mask):
                print(f"收敛于第 {iteration + 1} 次迭代")
                break
                
            mask = new_mask
            
        return mask


class GrabCutOpenCV:
    """
    使用OpenCV实现的GrabCut算法封装
    """
    
    def __init__(self):
        pass
    
    def grabcut(self, img, rect, n_iter=5):
        """
        使用OpenCV的GrabCut实现
        
        Args:
            img: 输入图像
            rect: 初始矩形框 (x, y, width, height)  
            n_iter: 迭代次数
            
        Returns:
            mask: 分割结果
        """
        # 初始化mask和模型
        mask = np.zeros(img.shape[:2], np.uint8)
        bgd_model = np.zeros((1, 65), np.float64)
        fgd_model = np.zeros((1, 65), np.float64)
        
        # 执行GrabCut
        cv2.grabCut(img, mask, rect, bgd_model, fgd_model, n_iter, cv2.GC_INIT_WITH_RECT)
        
        # 创建输出mask
        mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
        
        return mask2


def demo_grabcut():
    """
    GrabCut算法演示
    """
    # 创建测试图像
    img = create_test_image()
    
    # 定义矩形框 (x, y, width, height)
    rect = (50, 50, 200, 150)
    
    # 方法1: 自定义实现
    print("使用自定义GrabCut实现...")
    grabcut_custom = GrabCut(n_iter=3)
    mask_custom = grabcut_custom.grabcut(img, rect)
    
    # 方法2: OpenCV实现
    print("使用OpenCV GrabCut实现...")
    grabcut_opencv = GrabCutOpenCV()
    mask_opencv = grabcut_opencv.grabcut(img, rect)
    
    # 可视化结果
    visualize_results(img, rect, mask_custom, mask_opencv)


def create_test_image():
    """
    创建测试图像
    """
    # 创建一个简单的测试图像
    img = np.zeros((300, 400, 3), dtype=np.uint8)
    
    # 背景
    img[:, :] = [100, 150, 200]  # 蓝色背景
    
    # 前景对象(红色圆形)
    center = (200, 150)
    radius = 80
    cv2.circle(img, center, radius, (50, 50, 200), -1)  # 红色圆
    
    # 添加一些噪声
    noise = np.random.randint(-20, 20, img.shape, dtype=np.int16)
    img = np.clip(img.astype(np.int16) + noise, 0, 255).astype(np.uint8)
    
    return img


def visualize_results(img, rect, mask_custom, mask_opencv):
    """
    可视化GrabCut结果
    """
    plt.figure(figsize=(15, 10))
    
    # 原始图像
    plt.subplot(2, 3, 1)
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    plt.title('原始图像')
    plt.axis('off')
    
    # 矩形框
    plt.subplot(2, 3, 2)
    img_with_rect = img.copy()
    x, y, w, h = rect
    cv2.rectangle(img_with_rect, (x, y), (x+w, y+h), (0, 255, 0), 2)
    plt.imshow(cv2.cvtColor(img_with_rect, cv2.COLOR_BGR2RGB))
    plt.title('初始矩形框')
    plt.axis('off')
    
    # 自定义实现结果
    plt.subplot(2, 3, 3)
    result_custom = img.copy()
    result_custom[mask_custom == 0] = [0, 0, 0]  # 背景变黑
    plt.imshow(cv2.cvtColor(result_custom, cv2.COLOR_BGR2RGB))
    plt.title('自定义GrabCut结果')
    plt.axis('off')
    
    # OpenCV实现结果
    plt.subplot(2, 3, 4)
    result_opencv = img.copy()
    result_opencv[mask_opencv == 0] = [0, 0, 0]  # 背景变黑
    plt.imshow(cv2.cvtColor(result_opencv, cv2.COLOR_BGR2RGB))
    plt.title('OpenCV GrabCut结果')
    plt.axis('off')
    
    # 自定义mask
    plt.subplot(2, 3, 5)
    plt.imshow(mask_custom, cmap='gray')
    plt.title('自定义实现Mask')
    plt.axis('off')
    
    # OpenCV mask
    plt.subplot(2, 3, 6) 
    plt.imshow(mask_opencv, cmap='gray')
    plt.title('OpenCV实现Mask')
    plt.axis('off')
    
    plt.tight_layout()
    plt.show()


def batch_grabcut(image_dir, output_dir, rects_file):
    """
    批量处理图像的GrabCut分割
    
    Args:
        image_dir: 图像目录
        output_dir: 输出目录
        rects_file: 矩形框文件(每行格式: filename x y w h)
    """
    grabcut = GrabCutOpenCV()
    
    # 读取矩形框信息
    rects = {}
    with open(rects_file, 'r') as f:
        for line in f:
            parts = line.strip().split()
            filename = parts[0]
            rect = tuple(map(int, parts[1:5]))
            rects[filename] = rect
    
    # 处理每张图像
    for filename, rect in rects.items():
        img_path = os.path.join(image_dir, filename)
        if not os.path.exists(img_path):
            continue
            
        # 读取图像
        img = cv2.imread(img_path)
        if img is None:
            continue
            
        print(f"处理图像: {filename}")
        
        # 执行GrabCut
        mask = grabcut.grabcut(img, rect)
        
        # 保存结果
        result = img.copy()
        result[mask == 0] = [0, 0, 0]  # 背景变黑
        
        output_path = os.path.join(output_dir, f"grabcut_{filename}")
        cv2.imwrite(output_path, result)
        
        # 保存mask
        mask_path = os.path.join(output_dir, f"mask_{filename}")
        cv2.imwrite(mask_path, mask * 255)


def main():
    """
    主函数
    """
    parser = argparse.ArgumentParser(description='GrabCut算法演示')
    parser.add_argument('--mode', choices=['demo', 'batch'], default='demo',
                       help='运行模式')
    parser.add_argument('--image_dir', help='图像目录(批量模式)')
    parser.add_argument('--output_dir', help='输出目录(批量模式)')
    parser.add_argument('--rects_file', help='矩形框文件(批量模式)')
    
    args = parser.parse_args()
    
    if args.mode == 'demo':
        demo_grabcut()
    elif args.mode == 'batch':
        if not all([args.image_dir, args.output_dir, args.rects_file]):
            print("批量模式需要指定 --image_dir, --output_dir, --rects_file")
            return
        batch_grabcut(args.image_dir, args.output_dir, args.rects_file)


if __name__ == "__main__":
    main()

算法缺陷:

核心算法缺陷

1. 颜色假设过强

# 问题示例:前景背景颜色相似时失效
前景:绿色苹果
背景:绿色叶子
结果:无法有效区分,分割边界模糊
  • 根本原因:仅基于RGB颜色建模,忽略纹理、形状等信息
  • 失效场景:迷彩服、绿草中的绿色物体、雪中的白色物体

2. 高斯混合模型局限

  • 假设过简单:认为前景/背景颜色服从高斯分布
  • 组件数固定:通常K=5,无法自适应调整
  • 多模态处理差:复杂纹理和渐变色彩建模不准确

3. 图割方法限制

  • 局部最优:容易陷入局部最优解
  • 边界不准确:在细节边缘(如毛发、半透明区域)表现差
  • 拓扑约束:难处理复杂拓扑结构(如网状物体)
OpenCV——Grabcut算法 Grabcut 算法主要运用于计算机视觉中的前背景分割,立体视觉和抠图等。该算法利用了图像中的纹理(颜色)信息和边界(反差)信息,只要少量的用户交互操作即可得到比较好的分割结果. 1. Grabcut 的目标和背景的模型是RGB三通道的混合高斯模型GMM; 2.Grab Cut为一个不断进行分割估计和模型参数学习的交互迭代过程; 3.Grab Cut只需要提供背景区域的像素集就可以了。也就是说你只需要框选目标,那么在方框外的像素全部当成背景,这时候就可以对GMM进行建模和完成良好... 阅读详情

相关推荐

图像前景分割之GrabCut算法

参考: 参考项目一:https://github.com/NathanZabriskie/GraphCut 参考项目二:https://github.com/cm-jsw/GraphCut 运行环境: 1.python3.x 2.所需库函数:numpy,opencv-python 3.操作步骤: ...

xjtuse123的博客 2420

图像分割—GrabCut算法

Grabcut是基于图割(graph cut)实现的图像分割算法,它需要用户输入一个bounding box作为分割目标位置,实现对目标与背景的分离/分割,这个跟KMeans与MeanShift等图像分割方法有很大的不同,但是Grabcut分割速度快,效果好,支持交互操作,因此在很多APP图像分割/背景虚化的软件中可以看到其身影。 该算法主要基于以下知识: k均值聚类 高斯混合模型建模(GMM)...

红叶谷 wsp_1138886114的博客 2万+

Linux通用系统高危漏洞修复案例

2024年3月28日,监 Linux kernel权限提升漏洞(CVE-2024-1086)的PoC/EXP在互联网上公开,该漏洞的CVSS评分为7.8,目前漏洞细节已经公开披露,美国网络安全与基础设施安全局(CISA)6月1日也更新了其已知漏洞(KEV)目录,要求联邦机构在 2024 年 6 月 20 日之前打上补丁,修复追踪编号为 CVE-2024-1086 的 Linux 内核权限提升漏洞。由于该漏洞的公开性,攻击者可能会利用这个漏洞进行恶意攻击,因此建议尽快采取修复措施。

企业实战系列集 ●●● https://ximenjianxue.blog.youkuaiyun.com 4940

opencv实战项目二十九:GrabCut分割人像

在数字图像处理领域,人像分割是一项极具挑战性的任务,它旨在从复杂背景中准确提取出人物图像。随着技术的不断发展,人像分割技术在许多领域都展现出了广泛的应用前景,如摄影后期处理、视频监控、虚拟现实等。在这其中,GrabCut 算法作为一种高效、精确的图像分割方法,备受关注。本文将带你深入了解 GrabCut 算法,探讨如何利用它来实现人像的精确分割,让你在处理图像时能够轻松应对复杂背景,为创作和科研带来更多可能性。

HanWenKing的博客 2549

Ubuntu下轻量GIF录制工具Peek原理与实战指南

GIF屏幕录制是Linux桌面教学与协作中的基础技术需求,其本质是将屏幕帧流实时量化压缩为支持动画的索引色图像格式。实现可靠录制需兼顾显示协议适配(如Wayland下的PipeWire捕获)、色彩量化算法(中位切割与感知优先调色板)及运动检测丢帧等关键技术。在Ubuntu生态中,Peek凭借原生GTK3集成、零配置设计和对PipeWire的深度支持,成为GNOME/Xfce环境下最省心的轻量级GIF录制方案。它专为终端操作演示、设置流程记录、GitHub文档嵌入等典型场景优化,兼顾体积控制(<3MB)、加载

既是过河之卒,惟有奋力向前。 399

工业相机CCM色彩校正实战指南:从原理到产线落地

色彩校正是工业视觉系统实现精准检测的基础能力,其核心在于CCM(Color Correction Matrix)——一种基于CIE色度空间的线性映射机制,用于将传感器原始RGB响应准确转换至sRGB等标准色域。不同于白平衡的全局缩放,CCM通过3×3矩阵对各通道进行加权变换,直接影响色差ΔE精度与AOI识别准确率。在PCB焊点识别、锂电池蓝膜检测、汽车零部件表面分析等典型场景中,未校准或配置错误的CCM会导致误报率飙升、缺陷漏检等严重工程问题。本文聚焦Basler、海康、LabVIEW等主流平台下的CCM参

weixin_33895516的博客 414

基于Grab Cut交互性图像分割

引言 Grab Cut是在Graph Cut上进行改进的,相比后者,前者的新颖之处在于: 迭代预测估计(iterative estimation) 不完全标记(incomplete labelling) 用户可以通过较少的交互性标记,就可以完成图像分割。具体的原理参考以下文章: GraphCut入门学习 图像分割之(一~四)GraphCut,GrabCut函数使用和源码解读 图割小结 ...

Titus_1996的博客 877

基于dlib的疲劳驾驶检测系统:人脸关键点与眼睑开度实时告警

计算机视觉技术近年来在主动安全领域应用广泛,其中人脸关键点定位是分析驾驶员状态的基础。dlib作为轻量级视觉库,通过68点人脸关键点模型可提取眼睑、嘴部、头部等关键区域几何特征,进而量化眼睑开合度(EAR)、嘴部开合度(MAR)及头部姿态。这些生理指标构成疲劳驾驶检测的核心判据,结合PERCLOS时间窗统计,能够识别持续闭眼、频繁打哈欠等危险状态。在车队监控、驾驶辅助系统等场景,基于dlib的实时方案以低成本、低算力优势实现毫秒级告警,成为原型验证和工程落地的常用路径。本文详解了该系统的技术路线与避坑要点。

weixin_33841503的博客 281

Open Notebook 发布操作手册:版本镜像构建、清单验证、RC 栈验证与 GitHub 发布的完整命令参考

本文基于 Open Notebook 仓库中的发布运行手册 [runbook.md](https://link.gitcode.com/i/51338bba74f37a1ff1f885e251f1efe7) 展开,系统讲解稳定版发布流程中"切版 → 推镜像 → 验证 → 发布 → 清理"各阶段(Phase 5–8)的可复制命令。读完本文,你将掌握如何用 CI 构建双架构版本镜像、如何用 `dock

gitblog_01192的博客 471

Klocwork安装

简单介绍一下Klocwork在windows下的安装,操作系统是win7,Klocwork的版本是10.0。 第一步:由于Klocwork的安装程序已十分成熟,所以在安装之前不需要什么准备共走。双击Klocwork的安装包,会出现下图的安装引导界面,点击Next按钮。 第二步:下图是协议界面,点击Next按钮。 第三步:选择Klocwork的安装目录,点击Next按钮 第四步:

旮旯 9931

MOSFET和IGBT栅极驱动器电路的基本原理学习(2)

1.PWM直接驱动 驱动主开关晶体管栅极的最简单方法是利用 PWM 控制器的栅极驱动输出,如图 (1)如 图 8中所示,PWM 控制器和 MOSFET 之间可能有较大距离。由于栅极驱动和接地环路迹线形成的环路,这个距离形成了寄生电感,从而降低了开关速度,并导致栅极驱动波形中形成振铃。为了降低与栅极驱动连接相关的电感,需要更宽的 PCB 迹线。 (2)直接栅极驱动的另一个问题是PWM 控制器的驱动电流能力有限。极少有集成电路能提供高于 1A 的峰值栅极驱动能力。 2.旁路电容的确定 (1)位置 如果是独立的

weixin_43732932的博客 5832

雅思常用习语词汇积累

常见雅思习语词汇总结

工匠精神coding,终生学习 529

基于Apache SeaTunnel构建CDC数据同步管道

Apache SeaTunnel是一个数据集成开发平台,其发展经历了几个重要阶段:ETL时代(90年代):面向结构化数据库的数据同步,用于构建数据仓库。MPP和分布式技术流行:使用技术如Hive进行数据仓库的构建。此阶段主要使用mapreduce程序进行数据搬运和转换。数据湖技术流行:重视数据集成,强调先同步数据至数据湖仓储,再进行业务面向的转换和设计。CDC,即变更数据捕获,是一种捕获数据库变更事件(如插入、更新、删除)的技术。

weixin_54625990的博客 2172

Blender快捷键核心逻辑与高效建模实战指南

在三维建模与数字内容创作领域,软件操作效率是衡量专业能力的重要指标。其核心原理在于通过优化人机交互逻辑,将高频操作转化为肌肉记忆,从而减少认知负荷,维持创作心流。从技术价值看,一套设计精良的快捷键体系能极大提升建模、动画等工作的精确度与速度,是区分业余爱好者和专业创作者的关键。在应用场景上,无论是影视特效、游戏资产制作还是工业设计可视化,熟练运用快捷键都是实现高效生产的基石。本文聚焦于Blender这一主流三维软件,深入解析其以模态驱动和上下文感知为核心的设计哲学,并系统梳理了从视图导航、物体变换到高级编辑

weixin_33937913的博客 372

微信DAT图片恢复全攻略:从文件路径到批量解密(附最新工具下载)

本文详细介绍了微信DAT图片恢复的全过程,从文件路径定位到批量解密操作,帮助用户高效恢复加密存储的图片。文章涵盖新旧版本微信的存储结构差异,推荐使用专业解密工具进行批量转换,并提供了提升恢复成功率的实用技巧和常见问题解决方案。

weixin_29325007的博客 455

避坑指南:Xilinx SelectIO IP核官方例程里那些容易忽略的细节(复位、时钟与数据回环)

本文深入解析Xilinx SelectIO IP核设计中复位策略、时钟域交互和数据回环验证三大关键领域的实战避坑技巧。针对官方例程中易被忽视的细节,如复位同步链深度、时钟相位约束和数据对齐机制,提供经过项目验证的优化方案,帮助工程师节省80%以上的调试时间。特别适用于FPGA开发中高速接口设计场景。

weixin_42561476的博客 449

AI音效新征程:HunyuanVideo-Foley视频配音实战指南

**摘要:**字节跳动推出的HunyuanVideo-Foley模型通过AI技术重构音效制作流程,将传统Foley制作从高成本专业团队协作(800-1500元/分钟)转变为智能化解决方案。该模型采用视觉-语义-声学三模态架构,实现视频内容到音效的精准匹配,支持12个行业场景定制化应用。核心创新包括事件理解技术(区分"玻璃破碎(意外/故意)"等细微差异)、物理模拟引擎及情感映射系统,使音效情感契合度提升27%。

zzywxc787的博客 1140

Android Audio其他——数字音频接口(附)

数字音频接口 DAI,即 Digital Audio Interfaces,顾名思义,DAI 表示在板级或板间传输数字音频信号的方式。相比于模拟接口,数字音频接口抗干扰能力更强,硬件设计简单,DAI 在音频电路设计中得到越来越广泛的应用。

小旭的专栏 1028

【图像分割】GrabCut分割

文章目录GrabCut分割基于Graph Cuts分割改进Graph Cuts分割(GrabCut分割)前景/背景的颜色模型GrabCut算法流程完整代码如下 GrabCut分割 GrabCut是对GraphCuts的改进版,是迭代的Graph Cut。 基于Graph Cuts分割 Graph Cuts是基于图论的分割方法。 第一种普通顶点对应于图像中的每个像素。每两个邻域顶点(对应于图像中每两个邻域像素)的连接就是一条边。 另外两个终端顶点,叫S ( source:代表前景)和T(sink:代表背景)。

零碎@流年絮语 的博客 1887

Linux内核4.14版本——drm框架分析(1)——drm简介

本文介绍了DRM架构的发展历史、驱动框架以及简单示例,旨在帮助读者了解DRM架构的形成、功能流程实现。

phmatthaus的专栏 2558

《UDS协议从入门到精通》系列——图解0x22:通过ID读数据

如何向车辆ECU通过DID写入数据?有哪些注意事项?图解+示例带你快速上手0x22服务!!

车载系统攻城狮 8714

抠图应用程序设计(一)——GrabCut算法的实现

简介 ​ GrabCut是一种基于Graph Cut的图像分割算法,从待分割的对象周围用户指定的边界框开始,使用高斯混合模型估计目标对象和背景的颜色分布。在像素标签上构造马尔可夫随机场,其能量函数优先选择具有相同标签的连接区域,并不断优化迭代求取最优解,GrabCut的用户操作和效果如下: Graph Cut算法 ​ Graph Cut算法是一种能量优化算法,广泛应用于计算机视觉领域中的前背景分割、立体视觉、抠图技术等。该方法把图像分割问题和图的最小化分割问题关联起来,通过计算对无向图的分割完成图像分割操

Rosen的博客 4058

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

白话文讲计算机视觉-第七讲-GrabCut算法

我们在计算完成之后,我们会得到一个新的蒙版,这个蒙版里面包含了0~3的4种数据,而我们按照上述的方法进行计算,算法会判断哪些可能是前景,哪些可能是背景。因此,我们令蒙版中等于2的数据为0,也就是可能是背景的地方为0,然后令3为1,也就是前景的地方为1。在计算完毕后,如果是背景,那么仍然为0,如果是前景,那么为1。在新图层中,我们用白色的刷子,把那些本来应该是前景,但是却没算成前景的地方给标记出来,然后把应该是背景的地方,但是却搞错的用黑色标记,剩下不改变的地方用灰色标记。额,又是小熊,为啥博主总是用它呢?

小木的博客 8062

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

opencv-GrabCut 图像分割算法

opencv-GrabCut 图像分割算法

weixin_42367888的博客 643

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Grabcut

1 导语   想跟偶像合影,但是一直没有机会,怎么办?PS,太复杂,不太会。美图秀秀,只能增白磨皮。最后还是编程靠谱 这里用的技术就是Grabcut。Grabcut主要是一种交互式分割算法,用户需要圈出自己想要分割的东西,grabcut会迭代地将其分割出来,并且迭代过程中用户可以交互。下图实验中只是圈出矩形,并未交互,可以看出算法效果还是非常鲁棒的。        

PeaceInMind的博客 10000

计算机视觉——使用OpenCV GrabCut算法从图像中移除背景

GrabCut算法是一种用于图像前景提取的技术,由Carsten Rother、Vladimir Kolmogorov和Andrew Blake三位来自英国剑桥微软研究院的研究人员共同开发。该技术的核心目标是在用户进行最少交互操作的情况下,自动从图像中分割出前景对象。 在GrabCut算法中,用户只需在图像上用矩形框选出包含前景对象的区域,算法随后会迭代地进行分割,直至得到最佳结果。在这个过程中,若算法错误地将某些前景区域标记为背景或反之,用户可通过在图像上绘制笔触进行修正,指导算法在下一次迭代中进行更准

知来者逆的博客 3320
上一篇: RECORD1:CMAPSS 数据集处理和可视化(附代码)
下一篇: 基于Gurobi 的多仓库多车辆路径优化模型(含代码)
Codinggggg
博客等级 码龄5年 44粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值