
简介这套实战资源面向计算机视觉入门者与智能交通应用开发者以 Python 结合 OpenCV 把图像预处理、车牌定位、字符分割与模板匹配识别四个环节串联起来可用于课程设计、毕业项目或自学时对照复现完整流程也能为车辆追踪、停车场管理等场景提供技术参考。压缩包共 2000 个文件、约 12.37MB其中 1999 个 jpg 覆盖车辆原图、车牌样本和切分出的单字符素材1 个 py 脚本承载识别主流程字符匹配模板随包提供省去自行采集与标注的成本。目前已有 3109 人学习下载。读者可拿到可直接运行的源码骨架、多车牌的实测图片以及灰度化、二值化、滤波去噪、边缘检测、轮廓查找、形态学处理、垂直投影分割、模板比对等关键步骤的实现参考便于读者调整参数、替换模板或扩展到视频流识别。1. 车牌识别真正难点在预处理一套 Python OpenCV 的可交付方案有位同学用手机拍了二十张停车场入口照片跑完识别只对了六张问题不在模型而是二值化那一步把蓝底白字糊成了一团。车牌识别看着像“检测 识别”两件事实际上一张抓拍图从进来到输出字符串中间要经过定位、矫正、切分、匹配四道关卡任何一道出问题后面的步骤都会白费。这套 Python OpenCV 车牌自动识别方案正是按这四道关卡搭建的附源码、样本数据和字符匹配模板适合做课程设计、毕业设计也适合要给小型停车场或门禁 Demo 补上识别能力的人。2. 需求拆解与技术选型四个处理阶段与工具的职责边界2.1 从一张抓拍图到一条字符串处理链的四个阶段把整个系统看成一条流水线比看成“一个识别函数”更容易做对。输入是一张 BGR 的抓拍图输出是一个字符串加一个置信度中间经过四段第一段是预处理负责把原图变成“车牌区域明显、噪声被压住”的图。第二段是定位输出若干候选矩形框并且要按可信度排序因为很多图里不止一块车牌还可能有广告牌上的蓝色矩形来干扰。第三段是矫正把倾斜、透视变形的车牌拉成固定尺寸的正面图通常归一化到 136×36 或 144×40 这类宽高比接近 3.14 的尺寸。第四段是切分加识别把整块车牌切成七个字符图再逐个与模板比对打分拼成最终结果。每段的输入输出必须是显式的。比如定位模块只接受 BGR 图和一组阈值参数返回(x, y, w, h)列表矫正模块只接受 BGR 图加一个框返回固定大小的 BGR 图。这种约束看起来啰嗦但它是后面能单独调试、单独替换某一环的前提。我见过太多课程设计把四段写成一个八百行的函数定位错了根本不知道是二值化阈值的问题还是轮廓筛选的问题只能靠猜这就是翻车的开始。2.2 为什么用 OpenCV 模板匹配而不是直接上深度学习这个选型不是“退而求其次”而是场景决定的。车牌识别的目标场景通常是固定的一个入口、一个角度范围、一种或两种车牌底色。在这种约束下传统视觉方案的性价比远高于训练模型。具体对比可以看这张表判断标准是交付周期和可解释性而不是绝对精度方案依赖需要的数据量CPU 单图耗时可解释性适合场景颜色/边缘 形态学定位 模板匹配仅 OpenCV、NumPy几十张样本 一套字符模板30120 ms高每步可可视化固定机位、单一底色、课设/毕设轻量检测模型 CNN 字符分类需深度学习框架数千张标注100400 ms中需看热力图多角度、多底色、样本可采集端到端 OCR需预训练模型与大算力迁移学习即可数百 ms 起低通用场景、非固定机位模板匹配的优势在于每一步都能画出来掩膜图、轮廓图、切分后的七个字符图、每个字符的匹配分数。答辩时把这些中间图往 PPT 上一放逻辑链条一目了然这比“我训了个模型准确率 92%”有说服力得多。它的边界也要说清楚模板匹配对字符形变和笔画断裂很敏感对中文省份简称的识别率明显低于数字和字母光照剧烈变化时会掉点。所以方案里通常会加两道保险一是匹配分数低于阈值就输出“待人工确认”二是对易混字符0/O、1/I、8/B、5/S做位置约束比如第二位只可能是字母最后一位只可能是数字或字母用先验知识纠错。提示如果你的数据里同时存在蓝牌和黄牌别指望一套 HSV 阈值能覆盖老老实实写两组范围各跑一遍定位。2.3 源码、样本数据与字符模板的组织方式工程能不能被别人接手八成取决于目录结构。字符模板的命名方式尤其关键文件名就是标签不要另建一份映射表否则改一个字符要动两个文件。plate_recognition/ ├── config.py # 所有阈值、路径、尺寸参数集中在这里 ├── locate.py # 预处理 车牌定位 ├── warp.py # 透视矫正 ├── segment.py # 垂直投影字符切分 ├── recognize.py # 模板匹配识别 ├── run_batch.py # 批量跑图入口 ├── data/ │ ├── samples/ # 原始抓拍图文件名即图片编号 │ └── result.csv # 批量结果含失败原因 └── templates/ ├── province/ # 省份简称每字 1 张尺寸 40x20 │ ├── 京.png │ └── 沪.png └── alnum/ # 数字与字母每字 1 张尺寸 20x40 ├── 0.png ├── A.png └── ...模板尺寸必须固定数字字母统一 20×40省份简称因为字形宽扁用 40×20 更合适硬拉到同一尺寸反而会让匹配分数失真。样本数据按“机位 光照”分组存放比按时间堆放有用得多比如samples/gate1_day/、samples/gate1_night/验收时按组统计准确率你就知道这套参数到底在哪一组成效差。字符模板不需要很多常用字符集大约 65 类31 个省份简称 10 个数字 24 个字母去掉 I 和 O 避免与 1、0 混淆。每类一张干净模板就够起步关键是模板本身要来自同一批数据、经过同样的二值化和尺寸归一化处理否则模板和待测图的分布不一致匹配分数会系统性地偏低。3. 总体架构设计定位、矫正、切分、识别四层怎么划分3.1 图像预处理颜色通道与灰度通道各管一段预处理不是一个函数而是两条并行的支路。颜色支路负责回答“哪里可能是车牌”灰度支路负责回答“车牌的边缘在哪、字符在哪”。两条支路的结果在定位阶段汇合。颜色支路把 BGR 转 HSV。选 HSV 而不是 RGB是因为 HSV 把色调和亮度解耦白天和傍晚的蓝牌在 H 通道上位置接近只是 V 通道整体下降调 V 的下限就能补偿不用重调 H 的范围。蓝色车牌的 H 大致落在 100124 区间饱和度 S 和明度 V 给到 90 以上可以滤掉大部分灰白色干扰。灰度支路做三件事转灰度、高斯滤波、Sobel 求水平梯度。车牌区域的字符是竖向排列的水平方向的梯度变化非常密集用cv2.Sobel(gray, cv2.CV_16S, 1, 0, ksize3)取绝对值后再二值化字符区域会连成一片亮块。这一步在逆光和阴影下比纯颜色法更稳但它对车身文字也很敏感所以只作为颜色掩膜的补充不单独使用。形态学是这两条支路的收尾动作。车牌是一整块连通区域字符之间的小空隙需要被填上用一个扁长的矩形核做闭运算比如(17, 5)横向核大于纵向核是因为车牌横向长、字符间隙主要在横向上。核再大一点相邻的两辆车牌会被粘成一个轮廓再小一点字符之间填不满轮廓会碎成七块。3.2 车牌定位候选框的粗筛、精排与打分定位阶段的目标不是“找到唯一正确的框”而是“给出一个排好序的候选列表”。这个设计上的转变很关键因为单一阈值必然会在某些图上失手留一个候选列表后面可以用识别置信度反选。粗筛靠cv2.findContours拿到所有外轮廓然后用三个几何条件过滤宽高比在 2.24.2 之间标准车牌 440×140比值 3.14留出透视余量、面积大于某个下限太小的一定是噪声、矩形度轮廓面积与外接矩形面积之比大于 0.5。这三条能砍掉九成以上的干扰。精排用打分。给每个候选框算一个分数分数由三部分加权面积占比、宽高比与 3.14 的偏离程度、以及该框内颜色掩膜的白色像素占比。分数高的排前面。实际项目里我一般把权重设成 0.3、0.4、0.3然后在样本集上手动调两轮比拍脑袋定阈值靠谱。import cv2 import numpy as np def score_box(box, mask, img_area): 给候选框打分面积、宽高比、掩膜占比三项加权 x, y, w, h box ratio w / float(h) area_score min(w * h / (img_area * 0.25), 1.0) # 面积越大越好封顶 1 ratio_score max(0.0, 1 - abs(ratio - 3.14) / 3.14) # 越接近 3.14 越高 roi_mask mask[y:y h, x:x w] fill_score roi_mask.mean() / 255.0 # 掩膜白色占比 return 0.3 * area_score 0.4 * ratio_score 0.3 * fill_score这段代码里img_area * 0.25是个经验分母意思是面积达到整图四分之一就认为足够大不再加分避免大广告牌把分数拉爆。ratio_score用线性衰减而不是硬阈值是为了让接近标准的框之间还能分出高下。fill_score依赖前面形态学闭运算的质量如果掩膜坑坑洼洼这一项会普遍偏低此时应该回头调核大小而不是调权重。3.3 几何矫正把斜拍的车牌拉回水平不矫正直接切分是最常见的错误来源。斜拍的车牌在垂直投影上字符列的投影峰会互相重叠切出来的字符要么粘连要么缺笔画。矫正这一步花的代码不多收益极大。标准做法是取候选框的四个角点做透视变换。如果轮廓本身比较规整可以直接用cv2.minAreaRect求出最小外接旋转矩形再cv2.boxPoints拿到四个顶点如果轮廓有明显的缺角就用外接矩形的四个角点近似虽然会引入一点误差但对后续切分足够。变换的目标尺寸要按车牌真实宽高比定136×36 是我常用的原因是字符模板按这个尺度设计切出来的单字符正好落在 20×40 附近不用反复缩放。插值方式选cv2.INTER_CUBIC虽然慢一点但字符边缘更清晰比INTER_LINEAR的匹配分数平均高 23 个百分点。def warp_plate(bgr, box, target(136, 36)): 把候选框内的车牌区域矫正到固定尺寸 x, y, w, h box roi bgr[y:y h, x:x w] src np.float32([[0, 0], [w, 0], [w, h], [0, h]]) dst np.float32([[0, 0], [target[0], 0], [target[0], target[1]], [0, target[1]]]) M cv2.getPerspectiveTransform(src, dst) return cv2.warpPerspective(roi, M, target, flagscv2.INTER_CUBIC)参数target不要随意改。改了之后字符模板的尺寸必须同步改否则cv2.matchTemplate会因为尺寸不匹配直接报错或者更糟尺寸凑巧兼容但分布错位匹配分数普遍虚高却识别全错这种问题极难排查。3.4 模块接口约定用数据结构固定上下游契约四层之间传什么最好用数据结构写死而不是传一堆散装变量。一个简单的结果类就能让调试效率翻倍from dataclasses import dataclass, field from typing import List, Tuple import numpy as np dataclass class PlateResult: box: Tuple[int, int, int, int] # 原图坐标 plate_bgr: np.ndarray # 矫正后的车牌图 chars: List[np.ndarray] field(default_factorylist) # 切分出的字符图 text: str # 最终字符串 scores: List[float] field(default_factorylist) # 每个字符的匹配分 property def avg_score(self) - float: return sum(self.scores) / len(self.scores) if self.scores else 0.0avg_score这个属性是给上层用的批量跑图时按平均分排序最低的那批就是最该人工看的图。box保留原图坐标是为了能把识别结果画回原图做可视化答辩演示时这张叠加图比任何数字都直观。接口定好之后单独替换识别模块就变得很轻想从模板匹配换成 CNN 分类器只要新模块能填满chars、text、scores三个字段其他代码一行不用动。这是分层设计在实际项目里最实在的好处。4. 代码实现把四段流水线拼成可运行工程4.1 工程目录与配置项把可调参数集中到一处前面定过目录这里说配置怎么放。所有阈值、尺寸、路径都收进config.py用普通字典或类属性都行关键是不要散落在各模块里。散落之后你在locate.py里把 S 的下限从 90 调到 70忘了warp.py里还有一份结果两边行为不一致排查半天。# config.py CONFIG { hsv_blue: {lower: (100, 90, 90), upper: (124, 255, 255)}, hsv_yellow: {lower: (15, 90, 90), upper: (35, 255, 255)}, morph_kernel: (17, 5), min_area: 1200, ratio_range: (2.2, 4.2), rect_fill_min: 0.5, plate_size: (136, 36), alnum_size: (20, 40), province_size: (40, 20), match_threshold: 0.45, template_dir: templates, sample_dir: data/samples, result_csv: data/result.csv, }match_threshold定在 0.45 是经验值用TM_CCOEFF_NORMED时正确匹配一般落在 0.550.85错误匹配多在 0.20.40.45 是个保守的分界。阈值定太高正常图会被判成失败定太低错字会被当成对的输出。这个值一定要在自己的样本集上验证别照抄。4.2 定位与矫正颜色掩膜到透视变换的实现把 3.1 到 3.3 的思路落到一个函数里注意两件事蓝色和黄色车牌分别处理候选框按分数排序返回全部。def locate_plates(bgr, cfgCONFIG): 返回按分数降序排列的候选框列表 img_area bgr.shape[0] * bgr.shape[1] hsv cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV) boxes, scores [], [] for key in (hsv_blue, hsv_yellow): lower np.array(cfg[key][lower]) upper np.array(cfg[key][upper]) mask cv2.inRange(hsv, lower, upper) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_RECT, cfg[morph_kernel])) contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: x, y, w, h cv2.boundingRect(c) if w * h cfg[min_area]: continue ratio w / float(h) lo, hi cfg[ratio_range] if not (lo ratio hi): continue if cv2.contourArea(c) / float(w * h) cfg[rect_fill_min]: continue boxes.append((x, y, w, h)) scores.append(score_box((x, y, w, h), mask, img_area)) order np.argsort(scores)[::-1] # 分数从高到低 return [boxes[i] for i in order]cv2.RETR_EXTERNAL只取外轮廓是因为车牌区域内部还有字符孔洞用RETR_TREE会把每个字符也当轮廓送进来白白增加过滤负担。morph_kernel用扁长核是前面讲过的横向闭运算把字符间隙填上让整块车牌成为一个连通域。拿到候选框后对前三个框各跑一次矫正和识别取平均分最高的那个作为最终结果。这个“多候选 置信度反选”的策略比只取面积最大的框稳得多尤其是在有蓝色广告牌的画面里。4.3 切分与匹配垂直投影加模板打分切分用垂直投影逻辑简单但参数敏感。核心思路是统计每一列的白像素数量连续有白像素的列构成一个字符块列间空白的宽度超过阈值就断开。def segment_chars(gray_plate, min_w8, max_w45, gap_th2): 垂直投影切分返回字符图列表 _, bin_img cv2.threshold(gray_plate, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) bin_img cv2.morphologyEx(bin_img, cv2.MORPH_OPEN, np.ones((2, 2), np.uint8)) # 去掉细小噪点 col_sum (bin_img 0).sum(axis0) chars, start [], None for i, v in enumerate(col_sum): if v gap_th and start is None: start i elif v gap_th and start is not None: if min_w i - start max_w: chars.append(bin_img[:, start:i]) start None if start is not None and min_w len(col_sum) - start max_w: chars.append(bin_img[:, start:]) return charsgap_th2的意思是某列白像素数不超过 2 就当空白这个值太小会把笔画稀疏的字符比如 1切断太大则粘连。min_w和max_w卡的是字符宽度范围超出范围的块多半是车牌边框或铆钉直接丢弃。正常切出来应该是 7 个字符块如果不是 7说明这一张大概率要失败可以直接标记为“切分异常”而不是硬着头皮识别。识别部分用cv2.matchTemplate加TM_CCOEFF_NORMED逐个模板比对取最高分。第一位是省份简称走province模板目录后六位走alnum目录。class TemplateMatcher: def __init__(self, cfgCONFIG): self.size_alnum cfg[alnum_size] self.size_prov cfg[province_size] self.alnum self._load(f{cfg[template_dir]}/alnum, self.size_alnum) self.province self._load(f{cfg[template_dir]}/province, self.size_prov) def _load(self, folder, size): table {} for name in os.listdir(folder): char os.path.splitext(name)[0] img cv2.imread(os.path.join(folder, name), cv2.IMREAD_GRAYSCALE) if img is None: # 路径含中文时 imread 会返回 None continue img cv2.resize(img, size) _, img cv2.threshold(img, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) table[char] img return table def match(self, char_img, is_provinceFalse): table self.province if is_province else self.alnum size self.size_prov if is_province else self.size_alnum query cv2.resize(char_img, size) best, best_score , -1.0 for char, tpl in table.items(): s cv2.matchTemplate(query, tpl, cv2.TM_CCOEFF_NORMED)[0][0] if s best_score: best, best_score char, s return best, best_scoreTM_CCOEFF_NORMED输出在 -1 到 1 之间对整体亮度变化不敏感比TM_SQDIFF更适合模板和待测图来自不同光照的情况。注意待测字符图也要先 resize 到同一尺寸再比对缺了这一步matchTemplate会直接抛尺寸不匹配异常或者更隐蔽地返回一个无意义的高分。省份简称的识别率天然偏低因为中文字形复杂、笔画细二值化后容易断。实际做法是给省份单独放宽阈值或者在结果里标一个低置信度标记让人工复核时优先看这一位。4.4 批量跑图与结果落盘让失败样本自己浮出来单张跑通只完成了一半工作量另一半是批量跑图、统计失败原因。结果表里除了识别文本还要记录失败阶段这样你才能知道问题集中在定位还是切分。def run_batch(sample_dir, cfgCONFIG): matcher TemplateMatcher(cfg) rows [] for name in sorted(os.listdir(sample_dir)): path os.path.join(sample_dir, name) img cv2.imread(path) # 路径含中文请改用 imdecode if img is None: rows.append((name, , read_error, 0.0)) continue boxes locate_plates(img, cfg) if not boxes: rows.append((name, , locate_fail, 0.0)) continue best_text, best_score, stage , -1.0, segment_fail for box in boxes[:3]: plate warp_plate(img, box, cfg[plate_size]) gray cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY) chars segment_chars(gray) if len(chars) ! 7: continue text, scores , [] for i, ch in enumerate(chars): c, s matcher.match(ch, is_province(i 0)) text c scores.append(s) if sum(scores) / len(scores) best_score: best_text, best_score, stage text, sum(scores) / len(scores), ok rows.append((name, best_text, stage, round(best_score, 3))) pd.DataFrame(rows, columns[file, text, stage, score]) \ .to_csv(cfg[result_csv], indexFalse, encodingutf-8-sig)locate_plates返回多个候选时只试前三个是性能和收益的折中再多试几个收益递减但耗时线性增长。stage字段是最有价值的一列跑完一批图先看stage的分布如果locate_fail占四成说明定位参数有问题根本不用去看识别准确率。score排序后取最低的十张就是你的重点复查清单。注意cv2.imread在 Windows 下遇到中文路径会静默返回 None不会报错。批量跑图时如果发现大量read_error先检查文件名。5. 常见问题排查这套链路最容易出问题的五个点5.1 换一组图片就大面积定位失败现象自己拍的样本上定位很准换一批别人给的图locate_fail比例突然涨到一半以上。原因HSV 阈值是在单一光照下调出来的换了机位、时段、天气之后蓝色车牌的 S 和 V 分布整体偏移固定阈值直接失效。另外白牌、绿牌根本没写对应的范围自然定位不到。解决把阈值改成可搜索的参数用一批混合样本做小范围网格搜索S 和 V 各取三档选命中率最高的一组。同时给每种底色单独配置一条颜色分支分支数量由你的实际数据决定不要假设只有蓝牌。做完这一步再补一条兜底规则颜色分支全部失败时退回到 Sobel 边缘 形态学的纯灰度定位。5.2 定位框落在车身上而不是车牌上现象可视化图里红框圈住的是车身侧面或者蓝色车标车牌在框外。原因候选框按面积排序而车身、广告牌的面积远大于车牌。粗筛条件里的面积下限只设了下界没设上界大块区域全部通过。解决在打分里压低面积的权重提高宽高比和掩膜填充率的权重同时给面积加一个上限比如超过整图 15% 的框直接排除。另外取前三个候选分别识别、用置信度反选也能在不完美的候选里挑出正确结果。5.3 切出来的字符数量不是七个现象segment_chars返回 5 个、6 个或 9 个字符块后面识别直接跳过或者输出乱码。原因有三类二值化后字符笔画断成两截被当成两个字符相邻字符粘连被当成一个车牌边框、铆钉、螺丝被当成字符。垂直投影对断裂和粘连都没有免疫力。解决先做开运算去小噪点核 2×2 就够再大笔画就没了再对切分结果做后处理按宽度排序宽度明显偏小的块尝试与相邻块合并宽度明显偏大的块用投影谷值二次切分。最后加一条长度校验切不出 7 个就直接标记为异常样本不要硬识别。5.4 匹配分数很高但结果全是错字现象每个字符的匹配分都在 0.8 以上拼出来的字符串却明显不对。原因模板和待测图的尺度和极性不一致。常见情况是模板是白字黑底、待测图二值化后是黑字白底TM_CCOEFF_NORMED对反相并不总是敏感会给出虚高的分数。另一种情况是 resize 时用了默认的双线性插值模板线条被抹平反而和任何输入都“有点像”。解决在_load和match里统一做一次极性检查统计白像素占比超过 0.5 就bitwise_not反相保证两边都是白字黑底。resize 统一用INTER_NEAREST或INTER_CUBIC不要混用。改完之后重新验证一批已知答案的样本分数分布应该明显拉开。5.5 省份简称几乎没对过现象后六位数字字母基本正确第一位汉字错得离谱。原因中文字形笔画多、结构复杂二值化后细节丢失严重模板只有一张无法覆盖不同字体、不同模糊程度加上省份简称的候选集有三十多类干扰项太多。解决给省份单独放大匹配尺寸比如 40×20 而不是硬压到 20×40容忍更多细节每个省份准备 23 张不同来源的模板取最高分把识别结果和车牌第二位字母做联合校验某些组合在实际中不存在可以直接排除一部分候选。如果条件允许第一位单独换成一个小的分类器比模板匹配稳得多。6. 验收与答辩用四组指标证明这条链路可靠验收不能只看“我跑通了”。评审最常问的是“准确率多少、怎么算的、在什么数据上算的”。准备好下面四组指标问题基本都能接住。指标计算方式建议判定线说明定位命中率IoU0.5 的图数 / 总图数≥ 90%定位不准后面全是白费先看这个整牌准确率七位全对 / 总图数≥ 75%最核心指标别用单字准确率糊弄单字准确率正确字符数 / 总字符数≥ 90%用来定位问题在切分还是匹配单图耗时平均 msCPU≤ 150 ms超过这个数实时场景就不用谈了统计一定要分组。按光照分成白天、傍晚、强逆光三组按机位分成正拍和斜拍两组每组单独算整牌准确率。整体 80% 但逆光组只有 40%这个结论比一个笼统的数字有价值得多也是答辩时最能体现你做过实验的地方。样本量别太少少于 50 张的统计没有说服力凑不出就说明数据采集还没做完。演示环节建议脚本化把流程固定成五步先展示一张原图再展示颜色掩膜然后展示候选框排序把前三个框用不同颜色画出来接着展示矫正后的车牌和切分出的七个字符图最后展示匹配分数表和最终字符串。中间任何一步出问题你都能立刻指出卡在哪一层而不是只能说“它有时候不太准”。现场容易翻车的两个细节提前处理掉。一是换一台电脑演示路径变了、OpenCV 版本变了cv2.imread可能读不到图演示前在目标机器上完整跑一遍批量脚本。二是准备一组“已知会失败”的样本主动讲清楚失败原因和后续改进方向这比被评委问出来强得多。评委不怕方案有边界怕的是你说不清边界在哪。我从做完第一个车牌项目之后养成一个习惯每次交付前一定把result.csv里score最低的十张图逐张打开看一遍不管整体准确率多好看。那十张图里藏着的往往是同一类问题比如某个机位的反光、某种字体的粘连改一处参数就能把整体拉上去三五个点。这个习惯比任何调参技巧都管用。希望帮到你。本文还有配套的精品资源点击获取