全卷积网络FCN语义分割实战:PyTorch实现行人分割

简介:全卷积网络(FCN)是图像分割领域的里程碑式模型,Penn-Fudan Database由宾夕法尼亚大学与复旦大学联合构建,专门用于行人检测与分割研究。面向深度学习与计算机视觉学习者,这份资源将两者结合,提供了一整套基于PyTorch的FCN训练与评估代码,以及街景图像、分割掩模和对应的标注文件,便于从数据加载到模型训练完整复现实验。资源共533个文件,以340张PNG图像、172个TXT说明或日志、6个Python训练脚本为主,另有NPY格式的评估指标文件和XML配置等,压缩包约184.68MB,目录按数据、代码和结果分类,便于快速定位。目前已有504人学习使用,适合希望深入理解FCN上采样、跳跃连接等原理并动手训练分割模型的读者,可直接基于脚本调整批量大小、学习率等超参数,并根据输出的平均交并比(meanIU)评估效果。

1. 全卷积网络:一张街头照片如何被逐像素抠出行人

语义分割最直观的落地场景,是拿一张街头照片,让程序像PS一样把行人轮廓逐像素抠出来。全卷积网络(Fully Convolutional Network)正是这类任务的经典基线——把VGG这种分类网络里的全连接层全部丢掉,改成卷积层,让网络能接受任意尺寸输入并输出同分辨率的分割图。这份源码基于Penn-Fudan行人分割数据集,实现了一条从数据加载、模型训练到预测可视化的完整pipeline,而且FCN-8s的跳跃连接部分写得相当精简、易读。它适合两类人:刚接触分割任务、想找一个最小可运行工程跑通全流程的入门者,以及需要快速把单类别分割改成多类别、或者把骨干换成轻量网络做部署的开发者。接下来按模型、数据、代码、避坑的顺序拆开,每一步都落到可执行的位置。

2. 网络结构与设计:从VGG16到FCN-8s的语义分割改造

2.1 为什么要“全卷积”:去掉全连接层的真正原因

经典VGG16接收224×224的固定输入,经过五个卷积块和三层全连接,最终输出1000类概率。全连接层吃掉了绝大部分参数量,同时带来两个问题:输入尺寸必须固定,特征一旦展平就丢掉了像素间的空间位置关系。分割任务恰恰是逐像素做预测,空间位置就是命根子。FCN的做法非常直接——把全连接层换成卷积层,让网络用滑窗的方式保留位置信息,输入尺寸也不再受限。

用conv6和conv7去替代VGG原来的全连接头是社区里的标准做法:原第一个全连接层接收7×7×512的特征,等价于一个7×7卷积;第二个等价于1×1卷积。因此FCN里常见的是kernel=7、padding=3的conv6加kernel=1的conv7,把分类头转成密集预测头。这样改造后,网络最终输出特征图的空间分辨率由最后一次池化决定,语义分割的第一块地基就稳了。

2.2 FCN-32s/16s/8s:跳跃连接的三种配方与取舍

池化层让特征图逐级缩水,VGG16到pool5时已经缩到原图的1/32。如果直接把pool5的输出上采样32倍,得到的是FCN-32s——最平滑也最粗糙的版本。高层特征语义强但几何细节丢得厉害,直接放大到原图就像把一张缩略图强行拉伸,轮廓糊成一团。FCN的改进点在“跳跃连接”:把深层语义和浅层细节相加,逐步找回边界。

三条路径的差异用一个表就能看明白:

变体融合路径最终上采样倍率边界质量
FCN-32s无融合32x轮廓模糊
FCN-16spool5特征2x + pool416x中等
FCN-8s上一步2x + pool38x最锐利

FCN-16s把pool5特征上采样2倍,与1×1卷积投影后的pool4特征逐元素相加,再整体上采样16倍。FCN-8s在此基础上继续:把融合后的1/16特征再上采样2倍,与pool3特征相加,最后上采样8倍回原图。这份源码默认实现FCN-8s,但forward里每条路径都独立成层,改成FCN-32s或16s只需要裁剪两行加法,这为后续做消融实验留了很大余地。

2.3 二值分割的损失设计与输出头选择

Penn-Fudan的标注是像素级掩码,背景为0、行人为1,天然是二分类。输出头用1×1卷积把融合特征投影成单通道预测图,配合Sigmoid和BCEWithLogitsLoss完成训练。这里有个非常常见的理解误区:BCEWithLogitsLoss内部已经内置了Sigmoid计算,输出层只需要给原始logits。如果自己在输出层又接一个Sigmoid,训练初期loss会卡在log2附近不降,预测值始终围绕0.5打转。换到多类别场景才需要不同设计:输出通道数改成类别数,损失换成CrossEntropyLoss,训练目标从“每个像素是否前景”变成“每个像素属于哪个类”。

2.4 预训练初始化与分层学习率

VGG主干直接加载ImageNet预训练权重是分割项目拉开训练速度的关键。torchvision里一行vgg16(pretrained=True)就能拿到权重,而FCN自己新增的conv6、conv7以及跳跃连接里的1×1投影层没有预训练权重,必须随机初始化。如果共用同一个学习率,随机初始化层会拖慢主干的微调节奏。我习惯给新增层配2倍学习率,主干用基础学习率;在Penn-Fudan这种百张量级的小数据集上,甚至可以冻结pool3之前的全部参数,只微调后面几层。等换到更大数据集,再放开全量微调也不迟。

3. 数据集处理:Penn-Fudan行人分割标注的加载与增强

3.1 标注格式与可视化检查

Penn-Fudan的数据目录很干净:PNGImages放原图,Masks放同名掩码图。掩码是灰度PNG,行人区域为白色255、背景为黑色0,每个行人在掩码里直接以亮色区域呈现。初学者最容易忽略的一点是:灰度掩码不会自动变成二值标签,直接除以255也只是得到0到1之间的浮点标签,阈值判断时会出问题。加载时应该用(mask > 0).to(torch.long)把像素值规整到0和1,这一步决定了后续损失函数能否正确收敛,属于血泪经验级别的关键细节。

拿到一份新分割数据集,我强烈建议先随机抽三到五个样本,把原图和掩码叠加显示出来,确认标注轮廓与图片内容对齐而不是错位或者反相。经典数据集的掩码质量通常有保障,但自己收集的数据经常出现掩码灰度值不统一、前景标签被误标成背景这类问题。视觉检查花不了五分钟,却能避免训练两小时后才发现标签根本不配对的时间浪费。

3.2 Dataset实现与增强策略

PyTorch的Dataset类要保证__getitem__返回固定的元组:原图、掩码、图像路径。原始图片用PIL读取,掩码统一转成灰度模式,再做尺寸预处理。关键决策在插值方式:原图用双线性插值,掩码必须使用最近邻插值。原因是掩码是离散类别标签,双线性插值会在背景和前景之间生成0.5这种不存在的类别值,最近邻插值才能保持标签纯净。这个取舍在工程里经常被忽视,等到可视化预测结果时才发现“样本里多了一堆灰色边缘”。

数据增强我采用随机水平翻转加小幅随机缩放,再用RandomCrop固定到统一尺寸。分割任务的增强要特别留意几何变换的一致性:原图水平翻转时,掩码必须以相同概率同步翻转;缩放时掩码插值方式仍然固定为最近邻。常见做法是把整套变换封装成一个类,对image和mask共用同一组随机参数,这样才能避免“原图翻了、掩码没翻”的错位问题。

3.3 训练脚本的文件结构与DataLoader组装

项目的文件划分很克制,五个文件就能撑起完整流程:

文件职责
model.pyFCN8s模型定义与上采样层初始化
dataset.pyPennFudanDataset类与数据增强逻辑
train.py训练循环、优化器、学习率调度
predict.py加载权重、单图推理与可视化叠加
utils.py像素准确率与IoU计算

DataLoader组装时有个隐蔽问题:Penn-Fudan原始图像尺寸并不是完全一致的,直接按batch堆叠会在维度上翻车。常见解法有两种,一是在Dataset里统一resize到固定尺寸,模型输入和掩码尺寸都好控制;二是保留原始尺寸,在collate_fn里对同batch内的图片做padding补到最大宽高。前者简单稳定,适合快速跑通;后者能避免缩放带来的标注偏移,适合追求精度的实验。这份代码里用的是统一resize方案,想改第二种只需替换collate_fn一个函数。

4. 核心代码拆解:模型定义、训练循环与评估指标

4.1 FCN8s模型定义:VGG骨干与三层跳跃融合

import torch import torch.nn as nn import torch.nn.functional as F from torchvision import models class FCN8s(nn.Module): def __init__(self, num_classes=1, pretrained=True): super().__init__() vgg = models.vgg16(pretrained=pretrained) features = list(vgg.features.children()) # 按VGG的池化位置切出五个特征段 self.pool1 = nn.Sequential(*features[:4]) # conv1_x + pool1 self.pool2 = nn.Sequential(*features[4:9]) # conv2_x + pool2 self.pool3 = nn.Sequential(*features[9:16]) # conv3_x + pool3 self.pool4 = nn.Sequential(*features[16:23]) # conv4_x + pool4 self.pool5 = nn.Sequential(*features[23:30]) # conv5_x + pool5 # 用卷积层模拟VGG原来的全连接层 self.conv6 = nn.Conv2d(512, 4096, kernel_size=7, padding=3) self.relu6 = nn.ReLU(inplace=True) self.drop6 = nn.Dropout2d(0.5) self.conv7 = nn.Conv2d(4096, 4096, kernel_size=1) self.relu7 = nn.ReLU(inplace=True) self.drop7 = nn.Dropout2d(0.5) # 三类预测头:主输出 + 两路跳跃特征 self.score_final = nn.Conv2d(4096, num_classes, kernel_size=1) self.score_pool4 = nn.Conv2d(512, num_classes, kernel_size=1) self.score_pool3 = nn.Conv2d(256, num_classes, kernel_size=1) # 反卷积上采样,倍率由kernel、stride、padding共同决定 self.upsample2x_1 = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=4, stride=2, padding=1) self.upsample2x_2 = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=4, stride=2, padding=1) self.upsample8x = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=16, stride=8, padding=4) def forward(self, x): pool1 = self.pool1(x) pool2 = self.pool2(pool1) pool3 = self.pool3(pool2) pool4 = self.pool4(pool3) pool5 = self.pool5(pool4) conv6 = self.drop6(self.relu6(self.conv6(pool5))) conv7 = self.drop7(self.relu7(self.conv7(conv6))) score_final = self.score_final(conv7) score_pool4 = self.score_pool4(pool4) score_pool3 = self.score_pool3(pool3) # 第一路融合:主分支上采样2倍后与pool4相加 out = self.upsample2x_1(score_final) + score_pool4 # 第二路融合:上一步再上采样2倍后与pool3相加 out = self.upsample2x_2(out) + score_pool3 # 最终上采样8倍,回到输入分辨率 out = self.upsample8x(out) return out

逻辑说明:forward里的两个加法操作就是FCN-8s的跳跃连接核心。score_pool4和score_pool3先用1×1卷积把通道压到与主输出相同的num_classes,这样逐元素相加时通道数天然对齐。转置卷积的kernel、stride、padding组合决定了上采样倍率:2倍上采样用kernel=4、stride=2、padding=1,8倍上采样用kernel=16、stride=8、padding=4,这组参数是PyTorch里转置卷积输出尺寸计算的标准配方。参数说明:num_classes=1对应二分类前景/背景;改成多类别时这里是类别总数,同时需要把损失函数从BCE换成CrossEntropyLoss,前面2.3节已经提过。

4.2 训练循环:BCE损失、AdamW与学习率调度

def train_one_epoch(model, loader, optimizer, criterion, device): model.train() total_loss = 0.0 for images, masks in loader: images = images.to(device) masks = masks.to(device).float().unsqueeze(1) # [B, 1, H, W] optimizer.zero_grad() logits = model(images) # [B, 1, H, W] loss = criterion(logits, masks) # BCEWithLogitsLoss loss.backward() optimizer.step() total_loss += loss.item() * images.size(0) return total_loss / len(loader.dataset)

逻辑说明:掩码原始形状是[B, H, W],而logits是[B, 1, H, W],必须用unsqueeze(1)在通道维上补一个维度,否则BCEWithLogitsLoss在计算时维度广播会对不上。训练时标签转成float是BCE损失的要求,CrossEntropyLoss则要求标签保持long类型。优化器使用AdamW,初始学习率1e-4,每20个epoch乘以0.9做阶梯式衰减。对这种百张量级的小数据集,40到60个epoch足够让前景IoU稳定下来。为什么不用SGD加momentum?Adam在调参不充分时更稳,SGD对学习率和momentum的组合更敏感,项目默认AdamW是在降低跑通门槛,追求更高精度时再切SGD不迟。

4.3 预测流程与概率图可视化

def predict(model, image_path, device): model.eval() img = Image.open(image_path).convert("RGB") w, h = img.size img_t = transform(img).unsqueeze(0).to(device) # [1, 3, H, W] with torch.no_grad(): logits = model(img_t) probs = torch.sigmoid(logits) mask = (probs > 0.5).squeeze(0).squeeze(0).cpu().numpy() # [H, W] # 原图上叠加半透明红色蒙层 overlay = np.zeros((h, w, 4), dtype=np.uint8) overlay[mask] = (255, 0, 0, 160) return Image.alpha_composite(img.convert("RGBA"), Image.fromarray(overlay))

逻辑说明:推理时把模型切到eval模式,关闭梯度计算。sigmoid把logits转换成0到1的概率值,阈值0.5是二分类的默认选择。如果前景区域比较稀疏、模型输出概率整体偏低,可以把阈值降到0.3再观察效果,这属于玄学调参范畴,最终以肉眼视觉效果为准。注意mask经过两次squeeze之后从[B,1,H,W]变成[H,W]的二维数组,正好对应原图的像素网格。

4.4 评估指标:像素准确率与mIoU的落地实现

def compute_iou(pred_mask, true_mask): pred_mask = pred_mask > 0 true_mask = true_mask > 0 intersection = (pred_mask & true_mask).sum() union = (pred_mask | true_mask).sum() if union == 0: return 1.0 if intersection == 0 else 0.0 return intersection / union def evaluate(model, loader, device): model.eval() iou_list = [] correct, total = 0, 0 with torch.no_grad(): for images, masks in loader: logits = model(images.to(device)) preds = logits > 0 masks = masks.bool() correct += (preds == masks).sum().item() total += masks.numel() for p, t in zip(preds.cpu(), masks.cpu()): iou_list.append(compute_iou(p, t)) pa = correct / total miou = float(np.mean(iou_list)) return pa, miou

逻辑说明:IoU计算里union==0的分支特别重要,一张图完全没有前景时,网络也预测全背景,此时两者完全一致,按定义应当计为1.0而不是除零报错。像素准确率PA在背景占比极高的图片上会虚高——一张图99%是背景,模型全预测背景也能拿99%的准确率。因此分割任务更关注mIoU,它对类别不平衡更敏感。评估时把预测和标签都转成bool再比较,能直接利用PyTorch的张量广播机制,避免写多层for循环。

5. 常见避坑:训练分割模型最容易踩的五个坑

5.1 损失函数不下降:Sigmoid与BCEWithLogitsLoss被重复叠加

现象:训练前几步loss卡在0.693附近,预测输出全是0.5左右的中间值,几个epoch过去纹丝不动。原因:输出层加了nn.Sigmoid(),损失函数又选了BCEWithLogitsLoss,Sigmoid被算了两遍。解决:输出层只保留原始logits,推理时再用torch.sigmoid做概率转换。在代码里检查的方法是打印logits的数值范围,如果最大值不超过1,多半就是叠加了Sigmoid的典型症状。

5.2 掩码标签没归一化,预测结果全黑或全白

现象:训练loss正常下降,但可视化分割结果要么全黑要么全白,跟原图像素没有对应关系。原因:掩码是0到255的灰度图,有人直接除以255得到0到1之间的浮点标签,模型把“0.5”当成了一个独立类别;或者前景被设成255,验证时掩码和预测二值化的阈值对不上。解决:在Dataset加载阶段统一执行(mask > 0).to(torch.long),只做一次规整,后续所有逻辑都基于0/1标签,能少掉一半的调试时间。

5.3 上采样特征图尺寸对不上,forward直接报错

现象:训练跑到第一个step就报shape mismatch,报错集中在torch.add操作上。原因:VGG的maxpool在偶数尺寸下可以整除,但输入宽高一旦是奇数,pool后的特征经过转置卷积无法恢复成整数倍尺寸,pool5和pool4特征差出一个像素。解决:最简单的办法是训练时把输入统一resize到16的倍数,一劳永逸;如果想保留任意输入尺寸,把固定倍率的转置卷积换成F.interpolate(size=pool4.shape[2:])做动态对齐,牺牲一点性能换取鲁棒性。

5.4 显存不足训练中断,Batch Size降到1还是不够

现象:训练到第二步OOM退出,改小Batch Size之后仍然训练很慢,甚至继续OOM。原因:VGG16的conv7有4096个通道,在1/32分辨率上依然占大量显存,转置卷积的梯度回传又额外翻了一倍显存开销。解决:先把Batch Size降到2验证显存是否够用,再把Dropout关掉或者把conv7通道数从4096改成1024,这一步能显著压缩显存占用。对这部分代码,还可以用torch.cuda.amp混合精度训练,在支持自动混合精度的显卡上能省接近一半显存,且精度损失通常可以忽略。

5.5 mIoU指标好看但边缘全是锯齿,可视化效果与数据对不上

现象:mIoU做到0.7以上,放大预测图边缘却全是毛刺,明显比标注粗糙。原因:交叉熵损失独立处理每个像素,没有显式惩罚边界处的几何结构,模型在类别主体上得分高、在边界像素上摇摆不定。解决:在损失函数里加一个Dice loss分支,或者对边缘像素手动加权。这是分割任务里最典型的“指标好看、实际效果难看”的案例,以后凡是评估模型效果,我都会把可视化结果和指标一起看,两者缺一不可。

6. 二次开发:从二值分割扩展到多类别与轻量部署

6.1 多类别分割的三处核心改动

把二值分割扩成多类别,只需要改三个地方。模型层把num_classes从1改成类别总数,比如8车道场景就是FCN8s(num_classes=8);损失函数把BCEWithLogitsLoss换成CrossEntropyLoss,默认的ignore_index可以设成255跳过标注中的不确定区域;标签处理不能再走mask > 0,而是保留mask的类别索引,训练时标签保持long类型。评估逻辑也要同步改,IoU从“前景对背景”变成每个类别逐一计算再取平均。

model = FCN8s(num_classes=8) criterion = nn.CrossEntropyLoss(ignore_index=255) # 标签shape从[B,1,H,W]变成[B,H,W],保持long类型

这组改动里最容易翻车的点是通道顺序:logits的通道维输出[B,8,H,W],而CrossEntropyLoss期望的目标是[B,H,W]的索引图,不用刻意做one-hot编码,PyTorch会自动在内部完成比对。

6.2 更换轻量骨干与ONNX部署

显存紧张或推理速度敏感时,把VGG骨干换成MobileNetV3是常见路径。替换时要同步调整跳跃连接的特征通道数:VGG的pool4是512通道、pool3是256通道,MobileNetV3末端通道数完全不同,score_pool4和score_pool3的输入通道必须跟着改。另一个部署技巧是把训练好的模型导出成ONNX格式,导出时把输入尺寸固定成[1,3,512,512],再用ONNX Runtime做推理,可以绕开PyTorch的依赖环境。我一般会在导出前用torch.onnx.export跑一遍单张图片,确认输出shape与原模型一致再交出去。

6.3 改造后的快速验证套路

每次改完结构,我会用同一张小测试图做三件事:打印logits的shape,确认输出分辨率与输入一致;检查预测类别的数值范围,确认没有NaN或者全零输出;叠加可视化原图,观察三类以上目标的边界是否粘连。这三个动作加起来不到两分钟,却能拦住大多数结构改动引入的回归问题。从那以后,我每次调整模型结构都强制走一遍这套验证流程,宁可多跑几秒钟也不把不确定的模型扔进训练循环。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

神经密度估计黑盒优化:从NLL陷阱到模式丢弃的完整治理方案

神经密度估计黑盒优化:从NLL陷阱到模式丢弃的完整治理方案

训练密度估计模型的时候,最容易遇到的尴尬场景是:训练集上的负对数似然(NLL)一路走低,Loss曲线漂亮得可以发朋友圈,但你把模型生成的样本拿出来一看——要么全挤在均值附近,要么干脆生成出分布里…

2026/10/22 10:36:47 阅读更多 →
密度估计神经网络黑盒问题优化:从能量模型到可解释异常检测

密度估计神经网络黑盒问题优化:从能量模型到可解释异常检测

密度估计神经网络黑盒问题优化【附代码】做密度估计的同行应该都遇到过这类场景:模型训练完,样本分数分布很漂亮,ROC曲线也好看,可一到实际业务里就露馅。要么把大量正常样本判成异常,要么面对某个离群数据时给出一个让…

2026/10/20 10:28:09 阅读更多 →
霞鹜文楷 LXGW WenKai 完整指南:三步装好的免费商用开源中文楷体

霞鹜文楷 LXGW WenKai 完整指南:三步装好的免费商用开源中文楷体

霞鹜文楷 LXGW WenKai 完整指南:三步装好的免费商用开源中文楷体 【免费下载链接】LxgwWenKai An open-source Chinese font derived from Fontworks Klee One. 一款开源中文字体,基于 FONTWORKS 出品字体 Klee One 衍生。 项目地址: https://gitcode…

2026/10/22 13:16:34 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/22 10:18:38 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/22 11:01:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/22 9:44:47 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/22 10:42:00 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/22 10:40:08 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/22 10:56:37 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/22 1:47:45 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/21 21:32:28 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/22 5:12:39 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 21:50:56 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 21:51:55 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 16:24:48 阅读更多 →