尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

VIN码识别实战:从Pascal VOC数据集到YOLO训练与校验全攻略

发布时间:2026/9/26 13:04:17

资讯中心
01
ARTICLE

VIN码识别实战:从Pascal VOC数据集到YOLO训练与校验全攻略

VIN码识别实战:从Pascal VOC数据集到YOLO训练与校验全攻略
简介带标注的车辆VIN码车架号识别数据集围绕车辆唯一标识编码的自动检测与识别需求构建面向智能交通、车辆管理及自动化采集领域的算法工程师和研究人员。VIN码相当于车辆的“身份证”在二手车评估、零部件追溯、年检审核等场景中需要准确读取但实际图像常存在角度倾斜、光照不均、金属反光等干扰。数据采用Pascal VOC XML标准标注格式每个XML文件记录对应图像中车架号区域的位置框、类别标签及图像基本信息可直接接入YOLO、Faster R-CNN等主流检测框架开展训练与评估免去手工标注和格式转换成本。压缩包内共2000个XML标注文件整体大小127.39MB文件组织清晰便于按图像索引划分训练集、验证集与测试集。据资源介绍该数据集识别率可达99.5%能够帮助开发者快速验证算法的鲁棒性也可作为真实场景下的补充训练样本。目前已有47人学习浏览适合需要高质量车辆VIN码样本进行模型微调、算法对比或毕业设计的研究者直接使用。1. VIN码识别不是普通OCR这套2795张带标数据集到底解决什么问题二手车估值、保险定损、车辆年检这类系统里最常被要求“上线就得准”的功能就是VIN码识别。车架号是一串17位字符冲压位置在不同车型上五花八门反光、锈蚀、铆钉遮挡经常让OCR模型在实验室里跑得很好、一到现场就翻车业内常把这叫“玄学科目”。这套带标注的车辆VIN码数据集一共2795张图片标注格式是Pascal VOC的XML项目自述识别率能到99.5%。它面向的不是“能不能读出一段文字”而是“把车架号从复杂背景里稳定定位并逐字符读对”。适合两类人一类是刚接手车联网或汽车后市场项目、需要一份能直接落地的训练数据的工程师另一类是想在目标检测框架里复现完整VIN码识别链路的学习者。我按实操顺序往下拆把数据格式、转换脚本、训练参数和验收时容易踩的坑一次说清楚。2. VIN码识别的数据底子Pascal VOC标注里藏着哪些关键信息先别急着训练。我拿到任何VOC格式的标注包第一步永远是绕开模型花几十分钟把XML逐字段吃透。这一步省掉后面大概率会出现“训练时一个类都没学到”或者“验证集漂亮、现场全伤”的翻车现场。2.1 VIN码本身的字符规则为什么模型总在字母和数字上翻车VIN码是17位前3位是WMI世界工厂代码第4到第9位是车辆特征段第10到第17位是生产年份、工厂和序列号。跟普通OCR文本不一样VIN码为防视觉混淆明确禁用了I、O、Q这三个字母所以标准VIN字符集是10个数字加23个大写字母一共33个字符。这给模型带来的直接影响是分类面比全字母表小但“长得像”的字符一点不少。最容易翻车的几对是字母O和数字0、字母I和数字1、字母Z和数字2、字母S和数字5。很多数据包的标注质量差距恰恰就在这些字符上有的标错一个整个17位串就作废。还有一点很多人忽略第9位是校验位。VIN码在前8位确定后按ISO 3779的加权算法算出一个校验字符放在第9位。这意味着识别结果不是“16位对1位错就得返工”而是可以通过校验位直接判断这一串结果是否自洽。我现在做VIN识别项目后端验收一定会跑校验位脚本这在最后一章细说。2.2 标注边界框的两种形态整串框和单字符框Pascal VOC格式本身只记录类别名字、边界框坐标和图片尺寸它并不限定标的是“整段VIN区域”还是“每个字符一个框”。我见过两类VIN数据包第一类是一张图只给一个名为“vin”的框框住整条车架号区域。这种标注适合先训练一个区域检测模型检测出VIN位置再裁剪下来做字符识别。第二类是字符级标注每个字符一个box类别是0-9和A-Z这类可以一口气做“检测识别”按坐标排序直接拼出字符串。在打开这套数据集之后先确认下载包里是哪种形态。怎么确认我一般直接看XML里object的数量和name取值。如果一张图只有一个namevin/name那就是区域级标注如果有十几个name0/name、nameA/name这样的对象那就是字符级。两种形态的训练链路完全不同看错会白干一个星期。2.3 XML逐字段拆解怎么读一个VIN标注文件Pascal VOC的XML结构固定一个典型标注文件长这样annotation folderVIN_images/folder filenameVIN_0281.jpg/filename source databaseVIN Dataset/database /source size width1280/width height720/height depth3/depth /size object namevin/name truncated0/truncated difficult0/difficult bndbox xmin312/xmin ymin268/ymin xmax916/xmax ymax352/ymax /bndbox /object /annotation这里最关键的三个字段是size里的宽高、name类别、bndbox的四个坐标。坐标是像素绝对值训练时都要除以图片宽高做归一化。很多新手直接拿坐标去算目标尺寸忘了先读size结果转换后的txt文件全是大于1的越界框。我拆这类XML的习惯是直接用Python内置的xml解析库不额外装依赖import xml.etree.ElementTree as ET tree ET.parse(VIN_0281.xml) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) for obj in root.findall(object): name obj.find(name).text box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) print(name, xmin, ymin, xmax, ymax, img_w, img_h)先把这段跑通你能立刻知道这张图里的标注框在什么位置、宽高比多少。对于VIN这种横向长条文本正常框的宽高比在3:1到10:1之间如果某个框接近正方形那多半是把车灯、中网一起框进去了这种标注会在训练时把背景当特征。2.4 标注质量自查先统计分布再上模型数据集不是拿来就能训的哪怕标注工具是LabelImg或者CVAT导出的统一格式人工标注依旧会带脏。我拿到标注后的第一件事是全局统计看每个类出现多少次、每张图平均几个框、框面积占比。from collections import Counter xml_files glob.glob(annotations/*.xml) name_counter Counter() box_area_ratio [] for xml_file in xml_files: tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) for obj in root.findall(object): name_counter[obj.find(name).text] 1 box obj.find(bndbox) w float(box.find(xmax).text) - float(box.find(xmin).text) h float(box.find(ymax).text) - float(box.find(ymin).text) box_area_ratio.append((w * h) / (img_w * img_h)) print(类别分布:, name_counter) print(平均框面积占比:, sum(box_area_ratio) / len(box_area_ratio))如果类别分布里出现大量你根本不需要的类名比如“background”“text”说明标注规范没统一。如果平均框面积占比低于2%说明大部分图片里VIN码区域很小训练时特征难学需要上调训练输入分辨率。提示这一步发现的问题不要直接删图先去看标注文件很多XML和图片文件名对不上或者size写错导致XML里坐标和实际图片尺寸不匹配。这类问题直接在转换阶段统一处理方法见下一章。看完这一步你已经知道这份数据能不能用、该怎么用。下一章就是把XML整理成目标检测框架能直接吃的东西。3. 把XML转成YOLO格式清洗、划分与三个必做的预处理Pascal VOC XML是给“人读和标注工具”用的格式YOLO、MMDetection这些框架要的是纯文本txt。所以中间这段转换是整个流程里最机械、也最决定成败的一步。3.1 先做文件名规整XML和图片对不上是常态下载资源解压后最常见的问题是images目录和annotations目录文件名不一致。有的包图片是VIN_0001.jpgXML是VIN_0001.xml这算好的有的包图片带_copy后缀XML却只有原文件名还有中文文件名在Windows下导出后被编码搞乱XML里filename是乱码。我一般会先写一个脚本把文件名对齐规则是以XML文件名为基准图片扩展名补上jpg或png两张表做匹配。import os import glob img_dir images xml_dir annotations out_img_dir images_aligned out_xml_dir annotations_aligned os.makedirs(out_img_dir, exist_okTrue) os.makedirs(out_xml_dir, exist_okTrue) for xml_path in glob.glob(os.path.join(xml_dir, *.xml)): base os.path.splitext(os.path.basename(xml_path))[0] img_candidates glob.glob(os.path.join(img_dir, base .*)) if not img_candidates: print(missing image for, base) continue img_path img_candidates[0] # 统一复制到新目录后续全部以新目录为准 os.system(fcp {img_path} {out_img_dir}/{base}.jpg) os.system(fcp {xml_path} {out_xml_dir}/{base}.xml)这段代码不做花哨操作就是把能找到配对的图片统一改成“同名.jpg”保证后面遍历时文件对一定存在。找不到图片的XML单独输出到日志别静默跳过否则训练集会比标注集少一截自己不察觉。3.2 VOC转YOLO类别映射与坐标归一化转换脚本的核心是读XML坐标、按图片宽高归一化、写出“类别id x_center y_center width height”的txt一行。对区域级标注整个类就一个vin对字符级标注要把33个字符都加进类别表。import os import glob import xml.etree.ElementTree as ET # 如果你的数据集是字符级标注把下面这行换成完整33类列表 class_names [vin] # 字符级版本示例 # class_names [0,1,2,3,4,5,6,7,8,9, # A,B,C,D,E,F,G,H,J,K,L, # M,N,P,R,S,T,U,V,W,X,Y,Z] def voc_to_yolo(xml_path, txt_path): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: print(fskip unknown class: {name}) continue cls_id class_names.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) xml_files glob.glob(annotations_aligned/*.xml) for xml_path in xml_files: txt_path os.path.splitext(xml_path)[0] .txt voc_to_yolo(xml_path, txt_path)几个参数值得注意。class_names.index(name)依赖列表顺序YOLO训练时类别id必须和数据配置里的names顺序一致顺序错一个模型学出来的类别就全部错位。另外归一化坐标用的是XML里自带的size不是你猜的固定分辨率。不同照片尺寸不一样这个数据集里可能混着1920×1080和1280×720归一化时尺寸读错框会整体偏掉。3.3 按“车辆”划分数据防止同一辆车泄漏到验证集这张直接决定你的验证集数字有没有参考意义。VIN码是按车唯一的同一辆车从不同角度拍三四张照片如果这些图被随机分到训练集和验证集验证集里就会出现和训练集高度相似的“记忆样本”验证指标虚高换新车就现原形。我一般会牺牲一点随机性优先保证“一车不跨集”。from collections import defaultdict import random images sorted(glob.glob(images_aligned/*.jpg)) # 这个key函数是关键按文件名里的车辆ID分组 # 文件命名常见为 VIN_车型_序号.jpg这里取第一个下划线前的字段 def vehicle_key(img_path): return os.path.basename(img_path).split(_)[0] groups defaultdict(list) for img in images: groups[vehicle_key(img)].append(img) vehicle_list list(groups.keys()) random.seed(42) random.shuffle(vehicle_list) split_point int(len(vehicle_list) * 0.85) train_vehicles set(vehicle_list[:split_point]) val_vehicles set(vehicle_list[split_point:]) train_files [] val_files [] for v in train_vehicles: train_files.extend(groups[v]) for v in val_vehicles: val_files.extend(groups[v]) print(train images:, len(train_files), val images:, len(val_files))我后面把85%车辆分给训练集、15%分给验证集。如果发现车辆ID区分不出来就退一步用图片感知哈希做去重但优先还是看文件名。很多数据集命名本身就是“车辆ID_角度_序号”直接按这个ID分组最可靠。3.4 清洗脏标注小框、越界框、空文件转换后还要过一遍清洗规则把明显错误的样本剔掉。VIN码在实拍图里即便距离较远高度一般也不会低于20像素那些高度只有5像素的框很大概率是误标或标错位置。def clean_label(txt_path, min_h20, min_area300): with open(txt_path, r) as f: lines f.readlines() keep [] for line in lines: parts line.strip().split() if len(parts) ! 5: continue _, x_center, y_center, w, h parts w float(w) h float(h) # 越界框直接丢 if not (0 x_center 1 and 0 y_center 1): continue if w 0 or h 0: continue # 小框丢 if h min_h / 1280 or w min_w / 1280: continue keep.append(line) if len(keep) ! len(lines): with open(txt_path, w) as f: f.writelines(keep)这里的过滤阈值要按实际图片分辨率换算。上面的min_h/1280是假设图片高度为1280如果数据包主要照片是720p要改成min_h/720。不要用绝对像素因为同一张图在标注XML里的height可能从720到2160不等。注意清洗不是删标注文件本身而是清txt行。原XML保留方便后面回溯检查。转换、划分、清洗三步做完你手里已经有了一份train/val目录分明、边界框全部合法、同类不跨集的数据。下面就是模型训练和参数调整环节。4. 训练与参数调优先检测区域再逐字符识别这一步最容易犯的错是“拿到标注就训一个端到端模型什么中间步骤都不要”。对于VIN码识别我强烈建议拆成两步链路而不是一步到位。原因是车架号区域在整张图里占比往往很小端到端模型对小目标的识别稳定性远不如两阶段。4.1 先选链路区域检测还是字符级检测如果数据包是区域级标注也就是只有一个vin框那训练目标就是让检测器找到车架号位置。推理时把检测框裁出来再做字符识别。字符识别这一步有两条路一是用另一套字符级检测模型在裁剪区域里把33类字符框出来再排序二是直接用PaddleOCR或自训CRNN做整行识别。如果数据包本身就是字符级标注那就更简单一个模型同时输出字符框和类别按x坐标从左到右排成字符串。后面我的命令示例以字符级标注为主因为这样更容易看清训练参数对识别率的影响。如果你的包只有区域级标注把nc改成1跑同一套流程就行。4.2 YOLOv8训练配置数据YAML和一条能跑的命令我拿YOLOv8举例因为它对VOC和txt格式支持最省事配置也直观。先准备数据YAMLpath: /data/vin_dataset train: images/train val: images/val names: 0: vin如果字符级数据集names要从0到32列全33个字符顺序和你转换脚本里的class_names完全一致这是最容易错的地方。训练命令按常规跑yolo detect train datavin.yaml modelyolov8n.pt epochs150 imgsz640 batch16 lr00.005这里解释几个参数含义。imgsz640是最低起步值VIN码字符密集如果显存允许我会直接上imgsz1280小字符的召回率会明显上升。batch16配合常规最好epochs150对2795张图的数据量来说够用再多容易过拟合。lr0保持默认0.01也行但VIN码目标小、类别多我习惯调低到0.005让收敛更稳。训练完先看验证集mAPyolo detect val modelruns/detect/train/weights/best.pt datavin.yamlmAP50如果低于0.9不要先怀疑模型回头查转换脚本是否把坐标弄颠倒了。我之前见过一个项目YOLO输出框整体偏移mAP只有0.6结果发现XML读取时把xmax当成了width换了正确的读法之后直接到0.95。4.3 数据增强把有限的2795张图“变”出多样性VIN码实拍场景里最怕的是反光和透视YOLO内置增强已经默认开了部分翻转和颜色扰动但VIN码字符串翻转90度没有意义还会让模型误学倒置字符。所以我会关闭不必要的增强重点打开噪声和光照扰动。yolo detect train datavin.yaml modelyolov8n.pt epochs150 imgsz1280 batch8 \ flipud0.0 fliplr0.5 hsv_h0.015 hsv_s0.7 hsv_v0.4flipud0.0是关掉上下翻转VIN码倒过来在物理世界基本不存在学了只会让模型对正样本更犹豫。fliplr0.5保留水平翻转但要注意翻转后的文本顺序反过来检测阶段无所谓识别阶段排序时必须做镜像处理。hsv_v0.4调大亮度扰动因为车架号反光是高亮过曝不是简单的对比度变化多模拟这层扰动能提升现场泛化性。4.4 后处理把检测框重排成VIN字符串检测模型输出一堆框每个框带类别和坐标但VIN码是有序字符串必须按从左到右排列。为了抗微小的上下偏移我会先按y坐标聚类再在每一行里按x排序。def detections_to_text(detections, conf_thresh0.5): # detections: list of (cls_id, x_center, y_center, w, h, conf) dets [d for d in detections if d[5] conf_thresh] dets.sort(keylambda d: d[2]) # 先按y中心点排序 rows [] current_row [] last_y None for d in dets: y d[2] if last_y is None or abs(y - last_y) 0.05: current_row.append(d) else: rows.append(current_row) current_row [d] last_y y if current_row: rows.append(current_row) text for row in rows: row.sort(keylambda d: d[1]) # 同行按x中心点排序 for d in row: text class_names[d[0]] return text这段代码里有两个调参点conf_thresh0.5对字符级检测可以放低到0.4因为VIN码字符小模型置信度普遍不高abs(y-last_y) 0.05表示两框垂直中心差距小于图片高度的5%算同一行实拍图片如果车子倾斜VIN文本本身就不是严格水平这个阈值要放宽。到这里模型已经能出结果了。但出结果不等于能用VIN码识别真正的拦路虎在下一章这些坑里。5. VIN码识别常见问题与排查5条踩出来的记录这部分全是我在类似项目里实际翻过车的场景每一条都按“现象、原因、解决”说清楚。有些坑在训练时肉眼可见有些要到现场才暴露。5.1 反光亮斑把字符“吃”掉现象白天户外实拍的车架号中间几个字符被一道亮白色反光覆盖模型检测框还在但分类置信度很低最终结果出现乱码。训练集里也有类似图片但模型没学会“框住但不读错字符”。原因VIN码大多冲压在金属车架或玻璃下方强光下高光区域过曝字符边缘和背景的灰度差值消失字符在像素层面已经“溶”进高光里。解决在清洗和划分之后加一道针对高光的增强用OpenCV把训练图随机提亮并降低对比度让模型见过更多高光变体。现场采集时多一个偏光角度或用手机闪光灯补侧面光。后处理上对置信度低的字符打标记不硬拼让校验位脚本去否决这条结果。5.2 标注框吞进了背景模型学到一堆无关特征现象训练时loss下降正常但验证集mAP一直卡在0.7上不去把误检框画出来看发现有些框锁在VIN附近的铆钉、螺帽上和文本完全无关。原因人工标注时为了让框“好看”把上下留边加得很大甚至把VIN前后两颗铆钉圈进框里。模型学会的是“有铆钉的金属条”就是目标真正的文本反而成了次要特征。解决回看XML统计框的宽高比分布VIN框宽高比低于3的情况基本都存在多余留边。用上一章的清洗脚本统一缩框按中心点朝上下各收缩10%保持宽不变让标注框紧贴字符。龙骨只要一次效果立竿见影。5.3 第9位校验字符频繁出错现象整条VIN识别出来16位都对只有第9位不对而且不止一台车出现是成批出现。原因第9位是校验位字符可能是数字也可能是X样本分布天然不均衡。大多数车型校验结果是数字X在第9位出现频率低模型对X的置信度先天偏低。解决单独统计训练集中第9位字符的类别分布如果X样本极少把X类做小幅过采样或复制增强。更实用的做法是不依赖模型对校验位的高置信度在最终输出时用校验规则修正第9位先算前8位和后8位反推正确校验字符再做一次替换。5.4 行倾斜和透视让字符排序错乱现象后处理排序后字符串变得一团乱字符本身识别对了但顺序乱了整个VIN串被判为无效。原因VIN码有不少贴在倾斜的挡风玻璃下方或弧形车架上实拍图普遍带透视形变。模型输出的字符框中心不是一条水平线简单按x坐标排序会穿插错位。解决排序前先对检测框做一条最小二乘拟合线把所有框中心投影到这条直线上再按投影坐标排序。代码量不大但抗倾斜能力比纯y聚类强很多。更彻底的办法是训练前做随机透视增强让检测器对形变后的边界框更稳定。import numpy as np def boxes_sort_by_line(dets): pts np.array([[d[1], d[2]] for d in dets]) k, b np.polyfit(pts[:, 0], pts[:, 1], 1) proj pts[:, 0] * k - pts[:, 1] b order np.argsort(proj) return [dets[i] for i in order]这段排序的逻辑是拟合一条字符中心直线按每个点到直线投影的位置排序等价于把所有字符按“沿文本方向”排队。注意这里的pts[:,0]是x坐标pts[:,1]是y坐标方向反过来会得到完全逆序的结果。5.5 类别样本不均衡模型把O认成0现象验证集整体准确率还行但把错误样本单独拎出来看一半是把字母O识别成数字0另一半是把1识别成I。原因VIN字符集里数字0和字母O在印刷体上几乎一模一样只有细微的缺口差异。加上训练集中0类样本可能是O类的两倍多模型直接走捷径遇到中间有缺口的字符也按高频类输出。解决最有效的不是调损失函数而是检查标注是否严格执行“O类只标真O0类只标真0”。如果标注本身就混怎么训都白搭。我会单独抽出O和0两类样本手动复核一遍XML里的字符值再训练时对这两个类加一点类别权重。提示不要在推理阶段用“看字形缺口”做规则修正因为冲压字体在不同车型上差异很大规则写死一个车龄的车还行跨车型就废了。模型学不清的靠标注规范解决而不是靠后处理猜。五条坑踩完训练和部署链路基本稳定下面说怎么给这份数据集的“99.5%识别率”把好最后一关。6. 最后一步用校验位算法给识别结果把关VIN码和普通OCR有个根本区别它有自洽的校验规则。识别结果对错不能只看“每个字符看起来像不像”而要用第9位校验位做数学验证。这也是我每次交付VIN识别项目时的最后一道收尾工序比单纯刷准确率指标可靠得多。6.1 VIN第9位校验规则规则对应ISO 3779和中国标准GB 16735。把VIN字符串每个字符按映射表转成数值再乘以固定的位置权重求和后对11取余。余数10的校验位是字母X其他余数直接对应0到9的数字。第9位本身的权重是0也就是说不参与计算只作为被验证对象。字符映射表有个特点字母I和O被禁用J映射到1R映射到9。这和检测模型里的34类规则是一致但不同方向的约束检测模型面向视觉字符校验规则面向数学编号。两个都过这条结果才算真成立。6.2 一个可以直接跑的校验脚本def vin_check_char(vin: str) - str: vin vin.upper() if len(vin) ! 17: raise ValueError(VIN length must be 17) char_map { 0:0, 1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8, 9:9, A:1, B:2, C:3, D:4, E:5, F:6, G:7, H:8, J:1, K:2, L:3, M:4, N:5, P:7, R:9, S:2, T:3, U:4, V:5, W:6, X:7, Y:8, Z:9, } weights [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2] total 0 for i, ch in enumerate(vin): val char_map.get(ch) if val is None: return invalid_char total val * weights[i] remainder total % 11 return X if remainder 10 else str(remainder) def is_valid_vin(vin: str) - bool: try: return vin_check_char(vin) vin[8].upper() except ValueError: return False运行逻辑很简单is_valid_vin拿识别结果字符串算出期望校验字符再和实际第9位对比。weights数组里第9位对应0所以算出来的余数不会受原串第9位影响。常见初学误区是把remainder10判断成“结果无效”实际上余数10对应的有效校验位是X不是错号。调用也方便批量跑识别结果时逐条打标python check_vin.py --input results.csv --col vin6.3 怎么把“识别率99.5%”变成你的验收口径网上挂的99.5%这个数我建议你不要直接拿来当现场验收目标。那大概率是在一定场景、固定角度、标准光照下测出来的结果。你拿到数据集自己训练验收口径要拆成三档字符识别率、单条VIN通过率、校验位通过率。字符识别率是每个字符的独立准确率训练过程可以看单条VIN通过率要求整串17位全部正确这是业务上真正关心的校验位通过率则是间接验证。这三档数字放在一起才能说明模型在你这批数据上的真实水平。如果校验位通过率明显低于字符识别率说明错误集中在某一个或某几个字符位上回到类别分布去查一定是样本不均衡的问题。我从那以后每次交付VIN识别项目都会把校验脚本和模型打包一起发验收时先跑一遍校验位通过率不过直接返工省掉了大量扯皮。如果你也在做车架号识别建议同样把这条规则固化成强制流程希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。