遥感图像分割与国土分类:PSPNet/DeepLabV3+课程设计源码全解析

发布时间:2026/9/23 2:13:52
遥感图像分割与国土分类:PSPNet/DeepLabV3+课程设计源码全解析
简介一份基于图像分割的卫星遥感国土分类项目源码面向计算机相关专业正在做课程设计、期末大作业的学生以及需要项目实战练习的开发者。项目以遥感影像为输入利用图像分割模型完成国土利用类别划分代码中覆盖数据预处理、数据加载、PSPNet与DeepLabV3系列网络构建、训练及日志记录等关键环节形成一套结构完整、可直接复用的技术方案。压缩包共12个文件以8个Python脚本为主分别负责预处理、加载、模型定义与训练等流程另含日志文件记录训练过程、文本说明用于补充数据与运行注意事项以及一张展示效果示意图总体积2.49MB。该源码经过严格调试能够直接运行便于学习者按模块拆解学习也可快速改造适配自己的课题。目前已有158人学习参考适合作为遥感图像分类、图像分割方向的课程设计或入门实战素材。1. 基于图像分割的卫星遥感国土分类这份课程设计源码包到底值不值得跑做遥感图像分类的课程设计最怕的不是模型不懂而是拿到一份源码发现跑不起来数据路径写死、依赖版本对不上、训练到一半显存爆掉最后只能拿别人的结果图硬着头皮答辩。这份基于图像分割对卫星遥感图像进行国土分类的项目源码最大的价值在于它把预处理、数据加载、模型训练到结果展示的完整链路都补齐了而且同时给了 PSPNet、DeepLabV3、DeepLabV3 三套分割网络训练日志和 poster 展示图也都在适合用来做课程设计或期末大作业的底子。用一句话说它是能让你在两周内交出一份有完整实验对比的遥感分割作业的现成骨架而不是一个跑不通的玩具。适合计算机视觉方向正在做课程设计的学生也适合想快速上手遥感语义分割的开发者。2. 先看懂压缩包里有什么五个核心文件的职责划分与整体数据流2.1 从文件名反推代码结构这份压缩包的文件命名非常有课程设计的风格——每个文件承担一个明确职责没有多余的抽象层。先看 preprocess.py 和 preprocess_water.py 这对文件前者是通用预处理后者专门处理水体相关的地物类别。从命名能推断作者在实验过程中发现水体在遥感影像上容易和阴影、深色植被混淆所以单独拆了一个预处理脚本来做针对性增强。这种拆分方式在遥感分割任务里很常见对重点类别单独处理而不是所有类别一套参数走天下。data_load.py 负责数据加载和增强pspnet.py 和 deeplabv3.py、deeplabv3_plus.py 是三个独立的模型定义文件。最后 deecamp_train.py 是训练主脚本deeplab_v3.log 和 pspnet.log 分别是两次训练的日志记录26组poster展示.png 是答辩用的结果对比图。整个链路是原始影像加标签图然后归一化、切块、数据增强进模型训练最后输出分割结果做可视化对比。这份资源里data目录下有一个「高精卫星保密数据无法开源.txt」的说明文件这个要提前记住源码包里没有数据集你需要自己准备遥感影像和对应的标签图。如果学校没有提供数据用公开的遥感分割数据集也能跑通。2.2 数据流梳理从原始影像到分割结果根据文件职责可以还原出作者的完整实验流程。第一步是 preprocess.py 将原始 TIF 影像和矢量标签统一处理成模型能吃的尺寸和格式这里通常包含辐射定标、大气校正后的反射率数据转 uint8、归一化到 0-1 区间以及将矢量标签栅格化。第二步是数据切块遥感影像动辄上万乘上万像素不可能整张喂进显存一般切成 256x256 或 512x512 的 patch步长设计为有重叠的 sliding window 来增广样本量。第三步由 data_load.py 完成在线增强随机翻转、旋转、色彩抖动这类操作可以在训练时做遥感影像的增强有个关键约束——必须对图像和标签做完全相同的空间变换否则标签就对不上了。第四步进入 deecamp_train.py这个脚本把数据集、模型、损失函数、优化器串起来用交叉熵作为主损失某些实现里会叠加 dice loss 来处理类别不平衡。最后从训练日志里读取 mIoU 曲线用 26 组对比图呈现不同模型在同一区域的分割差异。2.3 这份源码的数据组织方式遥感分割的数据目录组织一般长这样images 放原始影像labels 放单通道的标签掩码图类别索引从 0 开始计数背景通常是 0。如果作者在 preprocess.py 里写了类别合并的逻辑那标签里就可能是合并后的类别 ID比如把林地、草地、灌木合并成「植被」一个大类水体单独保留建筑和道路合并成「不透水面」。这种类别合并的操作在国土分类任务里非常常见因为很多细分地物在卫星影像上根本无法区分强行分反而拉低准确率。对做课程设计来说最好的策略是保持作者的类别体系不变先跑通全流程再替换成自己的数据。数据量不用大每类 50-100 张切块图就能完成一次像样的训练实验。3. 模型选型拆解PSPNet、DeepLabV3、DeepLabV3 三套分割网络怎么选3.1 为什么要在一份代码里同时放三套模型课程设计需要对比实验这是答辩时老师最常问的部分「你为什么要用这个方法不用别的方法」如果只跑了一个模型这个问题很难答充分。作者把 PSPNet、DeepLabV3、DeepLabV3 三个网络放在一起本质上就是给你准备了一套完整的对比实验素材——三个模型用同样的训练数据、同样的预处理流程、同样的评估指标结果差异全部归因于网络结构本身。从遥感分割的角度看这三套模型的选择也很有讲究。遥感影像里的地物尺度变化极大一条河流可能是几十像素宽一片农田却占据上千像素。PSPNet 用金字塔池化模块PPM在四个不同尺度上做池化把全局上下文信息聚合起来对中等尺度的地物分割效果扎实。DeepLabV3 用空洞卷积Atrous Convolution在保持分辨率的同时扩大感受野对细长地物比如道路、河流更友好。DeepLabV3 在 V3 基础上加了解码器模块把浅层特征和深层特征融合边缘细节恢复得更好。3.2 三套网络的核心结构差异与实现要点PSPNet 的主干网络通常是 ResNet50 或 ResNet101在主干最后接金字塔池化模块四个池化分支的输出尺寸分别是 1x1、2x2、3x3、6x6每个分支经过 1x1 卷积降维后上采样回原始特征图尺寸再和主干特征做 concat最后通过分类卷积输出分割结果。PyTorch 里的实现骨架是这样的import torch import torch.nn as nn import torch.nn.functional as F class PyramidPoolingModule(nn.Module): def __init__(self, in_channels, pool_sizes[1, 2, 3, 6]): super().__init__() self.stages nn.ModuleList() for size in pool_sizes: self.stages.append(nn.Sequential( nn.AdaptiveAvgPool2d(output_sizesize), nn.Conv2d(in_channels, in_channels // 4, kernel_size1, biasFalse), nn.BatchNorm2d(in_channels // 4), nn.ReLU(inplaceTrue) )) self.bottleneck nn.Sequential( nn.Conv2d(in_channels * 2, in_channels, kernel_size1, biasFalse), nn.BatchNorm2d(in_channels), nn.ReLU(inplaceTrue) ) def forward(self, x): h, w x.size(2), x.size(3) pyramid_features [x] for stage in self.stages: pooled stage(x) pooled F.interpolate(pooled, size(h, w), modebilinear, align_cornersTrue) pyramid_features.append(pooled) out torch.cat(pyramid_features, dim1) return self.bottleneck(out)这段代码里pool_sizes控制金字塔的尺度数量in_channels // 4是降维比例遥感影像的通道数经过主干网络后会变成 2048降维到 512 再拼接避免后续计算量过大。align_cornersTrue这个参数在上采样时一定要保持统一否则训练时和推理时的特征对齐方式不一致分割结果会出现几像素的偏移。DeepLabV3 的核心是 ASPP 模块它用 1x1 卷积加三个不同空洞率的 3x3 空洞卷积通常是 6、12、18再加一个全局平均池化分支来捕捉图像级上下文。空洞率的选择直接决定感受野大小在 512x512 输入下空洞率 18 的卷积核实际感受野能覆盖整张图的一半以上。需要注意的坑是空洞卷积在 BN 层存在训练和推理统计量不一致的问题所以实际训练时通常把主干网络锁定为 BN 冻结状态只训练 ASPP 和解码器部分。DeepLabV3 则是在 DeepLabV3 的 ASPP 输出后面接了解码器把主干网络浅层的低层特征通常是 stride 为 4 的特征图和 ASPP 输出上采样 4 倍后的特征 concat再经过 3x3 卷积细化。这个设计的直接收益是边界分割精度提升对遥感影像里建筑物轮廓、道路边界的恢复效果明显好于前两个模型。3.3 课程设计场景下的选型策略如果让我给一个明确的建议优先跑 DeepLabV3因为它的分割边界质量最好答辩展示时的视觉效果最直观26 组 poster 对比图里通常也是它表现最稳定。如果训练资源紧张显存不够 8G就退回 DeepLabV3——它没有解码器参数量和计算量都更小训练速度能快 30% 左右。PSPNet 适合做中间对比项证明你做了多个模型的横向对比。这三个模型在代码里共用同一套数据加载和训练逻辑切换模型只需要改 deecamp_train.py 里的实例化那一行。常见做法是加一个--model命令行参数比如python deecamp_train.py --model deeplabv3_plus这样跑对比实验时不需要改代码只改参数就行。4. 预处理与训练实操从数据准备到 deecamp_train.py 的完整流程4.1 数据准备没有开源数据集怎么跑起来压缩包里明确写了数据是保密的所以第一步是解决数据问题。如果是课程设计通常学校会提供研究区域的影像和土地利用分类数据这些数据一般以 TIF 或多边形 shapefile 形式存在。你需要做的预处理是把影像和标签统一成相同的地理范围影像转成 uint8 三通道或四通道格式标签栅格化成单通道的类别 ID 矩阵。具体可以参考 preprocess.py 的常见实现思路用 GDAL 库读取地理空间数据pip install gdal rasterio numpy pillow opencv-python读入影像后做归一化时遥感影像的像素值范围不是固定的 0-255。有的影像可能是 16 位深DN 值范围在 0-10000 以上。如果直接除以 255所有像素都会变成接近 1 的值模型根本学不到特征。正确的做法是先做 2% 线性拉伸将 2% 和 98% 分位数之间的像素值映射到 0-255 区间然后把 0-255 再除以 255 归一化到 0-1。这一步直接影响分割精度是预处理里最容易翻车的地方。rasterio 做归一化的参考代码import rasterio import numpy as np def normalize_percentile(src_path, dst_path, low2, high98): with rasterio.open(src_path) as src: img src.read().astype(np.float32) bands [] for b in range(img.shape[0]): band img[b] p_low, p_high np.percentile(band, [low, high]) band np.clip((band - p_low) / (p_high - p_low 1e-6), 0, 1) * 255 bands.append(band.astype(np.uint8)) out_img np.stack(bands, axis0) profile src.profile profile.update(dtypenp.uint8, countout_img.shape[0]) with rasterio.open(dst_path, w, **profile) as dst: dst.write(out_img) normalize_percentile(raw_image.tif, norm_image.tif)这里low和high参数控制拉伸范围改成 [1, 99] 会更激进适合对比度偏低的影像改成 [5, 95] 会更保守保留更多原始信息。遥感影像的水体、阴影区域通常分布在低分位数区如果拉伸过猛这些区域会完全变黑水体类别就废了。实际做的时候可以先把拉伸后的影像用 matplotlib 画出来看一眼确认地物纹理还能分辨再进训练流程。标签生成部分如果你拿到的数据是 shapefile 矢量多边形需要用 rasterio.features.rasterize 栅格化。步骤是先把多边形的类别属性映射成整数 ID再写入到和影像同样尺寸的数组里import fiona import rasterio from rasterio.features import rasterize import numpy as np # class_mapping: 地物名称到整数ID的映射 class_mapping { water: 1, forest: 2, cropland: 3, building: 4, bareland: 5 } with fiona.open(land_use.shp, r) as shapes: geoms [(feature[geometry], class_mapping[feature[properties][class]]) for feature in shapes] with rasterio.open(norm_image.tif) as src: out_shape (src.height, src.width) transform src.transform mask rasterize( geoms, out_shapeout_shape, transformtransform, fill0, dtypenp.int64 ) np.save(label.npy, mask)fill0表示背景类别 ID 是 0这在交叉熵损失里对应ignore_index0训练时背景像素不参与 loss 计算。栅格化之后一定也要用 matplotlib 画出来看一眼最常出的问题是矢量数据的坐标系和影像不一致导致标签整体偏移——这两者的投影坐标系必须完全一样否则切块后图里标签全错位测量误差只有几十米但切块后可能就跨了整张图。4.2 数据切块和 data_load.py 的加载策略遥感影像切块时我一般会写一个通用的切块脚本把大图切成 stride 小于 patch size 的重叠块import numpy as np def crop_patches(img, label, patch_size512, stride256): h, w img.shape[:2] patches_img, patches_label [], [] for y in range(0, h - patch_size 1, stride): for x in range(0, w - patch_size 1, stride): patches_img.append(img[y:ypatch_size, x:xpatch_size]) patches_label.append(label[y:ypatch_size, x:xpatch_size]) # 覆盖右下角边缘 if h % stride ! 0: y h - patch_size for x in range(0, w - patch_size 1, stride): patches_img.append(img[y:ypatch_size, x:xpatch_size]) patches_label.append(label[y:ypatch_size, x:xpatch_size]) return np.stack(patches_img), np.stack(patches_label)patch_size选 512 是因为大多数分割网络下采样 8 倍或 16 倍输出尺寸需要被 8 整除512 正好满足。stride设成 256 意味着相邻 patch 有 50% 重叠样本量翻倍对数据不多的情况很有用。推理阶段不需要重叠切块stride 直接等于 patch size 就行重叠部分会重复预测浪费算力。data_load.py 里的加载逻辑通常用 PyTorch 的 Dataset 类封装这里有一个关键细节遥感数据增强必须考虑标签对齐。PyTorch 官方的 transforms 不会同时处理图片和标签所以需要自己写一个同步变换函数import random import torch from torch.utils.data import Dataset from torchvision import transforms class RemoteSensingDataset(Dataset): def __init__(self, img_paths, label_paths, augmentTrue): self.img_paths img_paths self.label_paths label_paths self.augment augment self.to_tensor transforms.ToTensor() def __len__(self): return len(self.img_paths) def __getitem__(self, idx): img np.load(self.img_paths[idx]) # (H, W, C) uint8 label np.load(self.label_paths[idx]) # (H, W) int64 if self.augment: if random.random() 0.5: img img[:, ::-1, :] label label[:, ::-1] if random.random() 0.5: angle random.choice([90, 180, 270]) img np.rot90(img, kangle // 90, axes(0, 1)) label np.rot90(label, kangle // 90, axes(0, 1)) img self.to_tensor(img.copy()) label torch.from_numpy(label.copy()).long() return img, label这里的翻转和旋转操作必须对图像和标签使用相同的随机种子分支绝不能在图像上随机翻转了、标签保持原样。np.rot90的axes(0, 1)是沿 H 和 W 方向旋转如果写成axes(0, 2)就会把通道维当空间维旋转所有颜色通道错乱训练出来的结果会惨不忍睹。4.3 deecamp_train.py 的训练配置与损失函数设计训练脚本里需要关注的几个核心参数batch size、学习率、epoch 数、损失函数、评估指标。遥感分割的常见配置是 batch size 4-8取决于显存、初始学习率 0.01用 SGD momentum 0.9或 0.0001用 Adam、训练 60-100 epoch、用 poly 学习率衰减策略。遥感图像类别分布极度不均匀水体可能只占 5% 的像素农田可能占 40%直接用普通交叉熵会导致模型把所有像素都预测成农田——因为这样 loss 也很低。所以训练脚本里通常会做类别加权import torch import torch.nn as nn class WeightedSegLoss(nn.Module): def __init__(self, num_classes, ignore_index0): super().__init__() # 每个类别的权重按像素占比的倒数归一化 # 遥感分割中水体占比小但重要权重应调高 self.weights torch.tensor([ 0.0, # 背景 ignore 5.0, # 水体样本少权重高 0.8, # 植被样本多权重低 1.5, 2.0, 2.5 ], dtypetorch.float32) self.ignore_index ignore_index self.criterion nn.CrossEntropyLoss( weightself.weights, ignore_indexignore_index ) def forward(self, pred, target): return self.criterion(pred, target)这里self.weights数组的顺序必须和类别 ID 一一对应如果你的数据和作者的类别体系不同这里的权重一定要重新统计自己数据的每类像素占比再调整。最简单的做法是把所有类别的权重初始化为 1.0第一次训练跑 20 个 epoch看验证集每类 IoU把低 IoU 类别的权重调高 1.5-2 倍再重新训练。训练命令的参考python deecamp_train.py \ --model deeplabv3_plus \ --backbone resnet50 \ --dataset ./data \ --batch_size 8 \ --epochs 100 \ --lr 0.01 \ --gpu 0 \ --output_dir ./checkpoints这段命令里有几个参数值得解释--lr 0.01配合poly衰减策略学习率会在训练后期降到接近 0让模型收敛更稳定如果换成 Adam 优化器学习率要改成 0.0001这个差距是两个数量级的不能随便沿用。--backbone resnet50是最稳妥的选择ResNet101 精度高一些但显存占用几乎翻倍没有 12G 以上显存不建议尝试。训练过程中盯两个指标训练 loss 的下降趋势和验证集 mIoU 的上升曲线。如果 loss 震荡不降大概率是学习率太大如果 mIoU 一直在 30% 以下徘徊先去看损失权重和类别映射对不对。训练结束后模型权重会保存成.pth文件之后用验证集可视化推理结果输出对比图用于 poster 展示。5. 避坑与排错训练日志暴露出的六个高频问题5.1 数据路径不一致导致读取失败现象运行 deecamp_train.py 后立刻报 FileNotFoundError但路径明明存在。原因代码里写的是相对路径而你的工作目录和项目根目录不一致比如在 IDE 里运行时默认工作目录是项目根目录但在命令行运行时可能是 home 目录。解决在 deecamp_train.py 开头强制切换工作目录或者在读取路径前os.chdir(os.path.dirname(os.path.abspath(__file__)))。这是最省钱也最有效的修复办法我跑所有课程设计代码第一件事就是把这个加上。5.2 显存溢出 OOM现象训练到第一个 epoch 就报CUDA out of memory。解决先把 batch size 减半如果还不行就把输入尺寸从 512 改成 384 或者 256。注意输入尺寸变化后网络里的上采样目标也要同步变化DeepLabV3 的 decoder 部分一般不受影响因为它是相对尺寸上采样。另一个有效手段是开启梯度累积每 2 个 batch 累积一次梯度再更新参数效果等效于 batch size 翻倍但显存占用不变。5.3 分割结果出现棋盘格效应现象模型训练完成后推理的分割图边缘出现整齐的小方块像马赛克一样。原因上采样方式不统一。训练时用F.interpolate(..., modebilinear, align_cornersTrue)推理时如果用了别的上采样方式或者 align_corners 参数不一致特征图的坐标对齐就有几个像素的偏差。解决把代码里所有F.interpolate和nn.Upsample的参数统一改成modebilinear, align_cornersTrue。5.4 类别没有归一化导致 loss 跳动剧烈现象训练 loss 曲线在 1.0 左右剧烈震荡完全不下降。原因标签数组里的类别 ID 不是从 0 开始的连续整数而是直接用的地物编码比如 10、20、30加载模型时会因为类别索引超出 num_classes 范围报错而这个报错有时被 PyTorch 吞掉了只表现为 loss 异常。解决在 preprocess.py 里做一次类别重映射把稀疏的类别编码映射成 0, 1, 2... 的连续序列。映射关系用 dict 维护保存一份映射表方便反查。5.5 水体目标完全预测不出来现象验证阶段其他类别都正常但水体 IoU 为 0所有水体像素都预测成了森林或阴影。原因遥感影像里云层阴影和水体的光谱特征很接近尤其是近红外波段两者都表现为低反射率。训练时水体像素占比本来就低加权不够又被阴影区域干扰模型直接放弃了水体这个类别。解决参考压缩包里 preprocess_water.py 的思路单独对水体做预处理。通常做法是计算归一化差值水体指数 NDWI (Green - NIR) / (Green NIR)把这个指数作为一个额外的输入通道拼到影像上让模型能利用光谱指数特征而不是全靠 RGB。def add_ndwi_channel(img): # img: (C, H, W)假设第2个通道是Green第3个是NIR green img[1].astype(np.float32) nir img[2].astype(np.float32) ndwi (green - nir) / (green nir 1e-6) ndwi np.clip(ndwi, 0, 1) * 255 return np.concatenate([img, ndwi[None, ...]], axis0).astype(np.uint8)加了 NDWI 通道后输入通道数从 3 变成 4对应地要把第一层卷积的in_channels参数改成 4。这个改动很便宜但对水体分割的提升是肉眼可见的。5.6 训练日志和结果对不上现象deeplab_v3.log 里的 mIoU 显示 85%但自己拿验证集评估只有 60%。原因训练日志记录的是训练集或验证集的分数而且可能用了与最终评估不同的数据划分。遥感数据有强空间自相关性相邻像素几乎一样如果切块时没有对 patch 做随机打乱并按影像分组划分数据集相邻 patch 会同时出现在训练集和验证集里验证分数虚高。解决按 patch 所属的原始影像划分数据集同一张影像切出的所有 patch 要么全在训练集要么全在验证集。文件组织上可以给每个 patch 文件名加上所属影像的编号作为前缀划分时按前缀分组。6. 从跑通到能答辩在验证集上做对每一类别的可视化与定量评估6.1 逐类 IoU 才是课程设计的灵魂课程设计答辩时最忌讳只贴一张「整体准确率 95%」的图——老师会立刻追问是哪一类 95%水体是多少建筑物是多少。所以训练完成后要写一个逐类评估脚本打印每个类别的 IoU 和像素准确率并且把每个类别的错误分割可视化到地图上。这一步比模型调参更能体现工作量。参考评估代码import numpy as np import torch def compute_iou_per_class(pred, target, num_classes): ious [] for cls in range(1, num_classes): # 0 通常是背景 pred_mask (pred cls) target_mask (target cls) intersection (pred_mask target_mask).sum() union (pred_mask | target_mask).sum() iou intersection / (union 1e-6) ious.append(iou) return ious pred torch.load(val_pred.pt).numpy() target torch.load(val_target.pt).numpy() ious compute_iou_per_class(pred, target, num_classes6) print(Per-class IoU:, {i1: round(v, 4) for i, v in enumerate(ious)})逐类 IoU 出来后用类别错误矩阵confusion matrix看具体错到哪比如建筑和裸地互相混淆水体和阴影互相混淆。这组数据在答辩时可以直接支撑「我的模型未来可以针对哪些方向改进」的提问。6.2 可视化对比图的正确做法同一区域多模型并行展示压缩包里的 26 组 poster 展示图核心展示逻辑是同一块区域原始影像放最左边人工标签放第二列PSPNet 预测、DeepLabV3 预测、DeepLabV3 预测依次排开最后加一列差异高亮图。这种并排对比的视觉冲击力远比单张效果图强老师一眼就能看出哪个模型边界更干净、哪个模型漏掉了小水体。画对比图时常用做法是给每个类别分配固定颜色比如水体用蓝色、植被用绿色、建筑用灰色、裸地用黄色。这种类别配色规则和土地利用专题图的通用配色一致不用自己发挥。用 matplotlib 把多张子图画在一个画布上时注意所有子图的 colorbar 必须用同一套类别颜色映射否则不同图之间颜色对应的类别不一致答辩时会被当成硬伤。6.3 三个加分配置技巧第一个技巧是用torch.utils.tensorboard记录训练曲线把学习率、loss、mIoU 画在 timeline 里答辩时能展示训练过程的动态变化不是只有最终结果。第二个技巧是保存每个 epoch 结束时的验证集预测图挑一个中间的 epoch 和一个最终的 epoch 做对比展示「随着训练推进水体边缘逐渐变整齐」的过程这种渐进式效果图比最终效果更有说服力。第三个技巧是写一个简单的 Grad-CAM 可视化脚本给老师直观展示模型是依据影像的哪些区域做出分类决策的虽然遥感分割里 Grad-CAM 不一定精确但能证明你对模型机理有理解。这三步做完你的课程设计就不仅仅是一份能跑的代码而是一套完整的实验体系和可视化证据链。回想我自己做遥感分割课程设计那会第一版只跑了一个模型一张效果图被老师问「你的边界误差分析在哪」直接卡住。后来所有实验都强制走一遍逐类评估加多模型对比的流程从那以后每次做实验都把可视化脚本和模型代码一起保存防止答辩前翻车。这份源码包能帮你少走很多弯路希望帮到你。本文还有配套的精品资源点击获取