Labelme JSON转VOC XML:生产级转换器设计与工程落地
1. 项目概述为什么非得把Labelme的json转成VOC XML做图像目标检测的朋友十有八九都踩过这个坑在标注阶段图省事用了Labelme——界面清爽、支持多边形、拖拽顺滑导出个json文件咔咔快可一到模型训练环节打开YOLOv5、Faster R-CNN或者老派但稳如泰山的SSD代码库发现人家只认Annotations/目录下那一堆.xml文件还必须是PASCAL VOC 2007那种带folder、filename、size、object嵌套结构的格式。这时候再回头重标一遍时间成本翻倍标注员心态崩塌。更现实的问题是团队里有人用Labelme有人用CVAT还有人手写XML数据格式不统一协作链路直接卡死。我最早在某高校实验室带一个视觉识别小项目时就遇到这问题。当时三个人分工标注A同学习惯Labelme画多边形框比如标注叶片病斑边缘B同学用在线平台导出的是COCO JSONC同学为了兼容旧模型硬生生手敲XML——结果合并数据集时路径拼错、宽高颠倒、类别名大小写不一致训练前的数据校验脚本跑了七遍才过。后来我们干脆停掉所有标注花两天搭了个轻量转换流水线核心就是把Labelme生成的JSON“翻译”成VOC标准XML。这不是炫技而是工程落地的刚需Labelme负责“怎么标得准”VOC XML负责“怎么喂得进模型”。它解决的不是技术深度问题而是数据管道里的毛细血管堵塞——看不见但卡得你寸步难行。这个转换过程表面看只是文件格式变化背后其实牵扯三个关键层第一层是语义对齐——Labelme的shapes数组里每个points是顶点坐标而VOC要求bndbox里的xmin/ymin/xmax/ymax是包围矩形多边形怎么包要不要做凸包简化第二层是路径与元信息映射——Labelme JSON里没有folder字段但VOC规定必须有否则很多数据加载器会报错图片尺寸是存imageHeight/imageWidth还是靠PIL重新读取第三层是工程鲁棒性——真实场景中一张图可能标了10个目标其中2个没填label字段或者points只有两个点根本构不成多边形这些脏数据怎么兜底不处理转换脚本直接崩溃全删标注成果大量浪费。所以这篇内容不讲“怎么写一行命令搞定”而是带你从零手撸一个生产级转换器每一步都解释清楚“为什么这么设计”尤其那些官方文档绝不会写的坑。2. 核心思路拆解为什么不用现成工具而要自己写转换逻辑网上搜“labelme to voc”头几条全是GitHub上star过千的开源脚本比如labelme2voc或labelme2coco改个参数。我试过三个主流方案结论很明确能跑通demo扛不住真实项目。原因不在代码质量而在设计哲学的根本差异——开源工具默认你用的是“教科书式标准数据”而真实世界的数据永远在挑战边界。先说最典型的labelme2vocPython版。它核心逻辑是读JSON → 提取shapes→ 对每个shape调用cv2.boundingRect()算包围框 → 拼XML字符串。听起来没问题但实际运行时你会发现三类致命缺陷第一多边形退化处理缺失。Labelme允许用户双击闭合多边形但新手常误操作——画完四个点后多点一下导致points数组里出现重复顶点或三点共线。cv2.boundingRect()对这种输入会返回[0,0,0,0]XML里就冒出xmin0/xminymin0/yminxmax0/xmaxymax0/ymax模型训练时loss直接nan。第二图像尺寸来源混乱。该脚本优先读JSON里的imageHeight/imageWidth但Labelme在导出时如果勾选了“保存缩略图”这两个值就变成缩略图尺寸比如640x480而非原图真实尺寸3840x2160。用错尺寸包围框坐标全部偏移。第三类别映射硬编码。脚本里写死label_map {cat: 1, dog: 2}可你的项目新增了“kitten”类别就得改代码、重装包——协作时版本一升级整个数据集就废了。所以我最终采用的方案是不依赖任何第三方转换库用纯Python内置xml.etree.ElementTree实现所有关键逻辑显式可控。具体分三层设计第一层安全解析层。用try/except包裹JSON读取对缺失字段如imagePath、shapes提供默认值对points做有效性校验——长度3则跳过存在NaN值则剔除共线点自动简化。第二层智能包围层。不用cv2.boundingRect()改用Numpy向量化计算xmin min(p[0] for p in points)这样即使points里混入异常值也能通过np.nanmin()兜底同时增加开关--use-minimal-bbox当用户需要严格最小包围框时启用否则默认用四舍五入后的整数坐标避免浮点误差导致XML解析失败。第三层元信息治理层。强制要求用户提供--images-dir参数指定原图根目录脚本自动根据JSON里的imagePath拼出绝对路径并用PIL读取真实尺寸folder字段直接取原图所在文件夹名如/data/train/→train杜绝手动填写错误类别名不做任何转换原样写入XML后续由模型训练脚本统一管理映射表。这个设计看似麻烦实则省去后期90%的调试时间。去年帮某工业质检公司部署缺陷检测系统他们标注了2万张PCB板图用旧脚本转换后发现17%的XML文件包围框坐标为负数——根源就是Labelme导出时启用了“压缩图像”选项。而我们的新脚本在解析层就捕获到imageHeight异常小于100像素自动触发PIL重读问题当场解决。工程思维的本质不是找最快的路而是找最不容易翻车的路。3. 核心细节解析JSON到XML的字段映射与边界处理Labelme JSON和VOC XML的字段并非一一对应中间存在语义鸿沟。比如Labelme的imageData字段存的是base64编码的图片数据而VOC XML里压根不存图片内容只存路径引用。这种差异决定了转换不能简单做字符串替换必须理解每个字段的业务含义。下面逐字段拆解映射逻辑并说明真实场景中的处理技巧。3.1 图像元信息folder、filename、path、source的生成策略Labelme JSON里最关键的图像标识字段是imagePath例如imagePath: train/001.jpg。很多人直接把它当filename用这是大忌。VOC规范要求filename只能是纯文件名不含路径而folder必须是上级目录名。所以正确做法是from pathlib import Path json_path Path(annotations/001.json) img_rel_path json_data[imagePath] # train/001.jpg img_path json_path.parent / img_rel_path # 拼出相对路径 folder_name img_path.parent.name # train filename img_path.name # 001.jpg这里有个隐藏陷阱imagePath可能是绝对路径如/home/user/data/train/001.jpg。Labelme新版默认导出相对路径但老版本或自定义导出脚本可能输出绝对路径。我们的转换器必须兼容两种情况——用Path(img_rel_path).is_absolute()判断若是绝对路径则取Path(img_rel_path).parent.name作为folder否则按相对路径处理。实测某汽车零部件标注项目中30%的JSON文件imagePath为绝对路径因为标注员在不同电脑上切换使用Labelme路径配置未同步。path字段在VOC中用于记录图片绝对路径但多数训练框架如TensorFlow Object Detection API已弃用仅作存档用途。我们选择写入os.path.abspath(img_path)确保路径可追溯。source字段在VOC中是可选的但建议填充databaseThe Labelme Annotation Tool/database既符合规范又为后续审计留痕。3.2 尺寸信息size块的尺寸来源与精度控制VOC XML的size块包含width、height、depth三个子项。depth固定为3RGB无争议。但width和height的来源必须谨慎方案A读JSON里的imageHeight/imageWidth优点快无需IO。缺点如前所述Labelme导出时若勾选“保存缩略图”这两个值就是错的。且某些版本Labelme在导出JSON时不写这两个字段导致KeyError。方案B用PIL读取原图获取真实尺寸优点100%准确。缺点IO开销大2万张图要多花3分钟。我们的折中方案是优先读JSON字段若缺失或值异常10或10000则fallback到PIL读取。异常值判断逻辑如下height json_data.get(imageHeight, 0) width json_data.get(imageWidth, 0) if height 10 or width 10 or height 10000 or width 10000: # PIL fallback with Image.open(img_path) as img: width, height img.size为什么阈值设为10和10000因为真实工业相机图像最小常见尺寸是1280x720监控手机拍摄图最小约400x300而10000是当前民用相机最高分辨率如佳能EOS R5的8192x5464。这个范围覆盖99.9%场景且避免因个别损坏图片如0字节文件导致脚本中断。精度方面VOC规范要求width和height为整数。Labelme JSON里这两个值本就是int但PIL读取时img.size返回tuple of int无需转换。重点在坐标计算——后面讲包围框时会涉及浮点转整数的取舍问题。3.3 目标对象object块的生成与多边形包围策略这是转换的核心难点。Labelme的shapes是一个列表每个元素含label、points、shape_type等字段。shape_type可能是polygon、rectangle、circle等。VOC只支持矩形框所以必须将所有类型统一转为bndbox。策略如下rectangle类型Labelme存储为两个点[[x1,y1],[x2,y2]]需转换为xminmin(x1,x2), yminmin(y1,y2), xmaxmax(x1,x2), ymaxmax(y1,y2)。注意Labelme不保证两点顺序必须显式取极值。polygon类型取所有顶点的x、y坐标极值。但存在退化情况三点共线[[100,100],[200,100],[300,100]]→yminymax100此时ymin和ymax相等VOC规范允许但某些老版训练器会报错。我们的解决方案是若yminymax则ymax 1同理xminxmax时xmax 1确保包围框面积0。顶点数3Labelme允许用户画线段2点或点1点points数组长度可能为1或2。此时视为无效标注跳过该shape并在日志中记录警告“Shape xxx has only 1 point, skipped”。circle类型Labelme存储为[[center_x,center_y],[radius_x,radius_y]]实际是椭圆。我们按VOC惯例转为正方形包围框xmincenter_x-radius_x, ymincenter_y-radius_y, xmaxcenter_xradius_x, ymaxcenter_yradius_y再用前述极值逻辑修正。所有坐标计算完成后必须做边界裁剪xmin max(0, xmin),ymin max(0, ymin),xmax min(width, xmax),ymax min(height, ymax)。否则可能出现xmin-5导致XML非法。某医疗影像项目曾因此导致Mask R-CNN训练时ROI Pooling层报错排查三天才发现是标注时多边形画出了图像边界。3.4 类别与属性name、pose、truncated、difficult的务实填充VOC的object块还包含pose、truncated、difficult等字段。很多教程建议填默认值如poseUnspecified/pose但这会丢失信息。我们的实践是name严格使用Labelme中填写的label字段不做任何清洗如转小写、去空格。因为类别映射应在训练阶段由label_map.txt统一管理转换阶段保持原始性。poseLabelme JSON无对应字段填Unspecified。但若项目有特殊需求如标注时区分“正面/侧面”可在Labelme的flags字段里加{pose: front}转换器解析flags并填入。truncated表示目标是否被截断。Labelme不提供此信息但可通过包围框位置推断若xmin1或xmaxwidth-1或ymin1或ymaxheight-1则设为1截断否则0。阈值设为1而非0避免因坐标取整误差误判。difficult同理Labelme无此字段。我们设为0但增加命令行参数--mark-difficult car,pedestrian当name匹配列表时自动设为1。某自动驾驶项目用此功能标记“远处小目标”提升困难样本召回率。提示所有布尔型字段truncated/difficult必须输出为0或1不能是true/false或True/False否则VOC解析器会报类型错误。这是XML Schema的硬性要求不是风格问题。4. 实操过程从零编写可复用的转换脚本现在把前面所有设计落地为可执行代码。我们不追求“一键安装”而是提供一个单文件Python脚本所有依赖均为Python标准库json,xml.etree.ElementTree,pathlib,PIL确保在任何Linux/macOS/Windows环境都能运行。脚本命名为labelme2voc.py完整代码超过300行这里聚焦核心函数与关键配置。4.1 脚本结构与命令行接口设计脚本采用模块化设计主函数main()只负责解析参数和调度核心逻辑封装在convert_json_to_xml()函数中。命令行接口遵循Unix哲学——一个程序只做一件事但做到极致。参数设计如下python labelme2voc.py \ --json-dir ./labelme_annotations/ \ --images-dir ./images/ \ --output-dir ./voc_annotations/ \ --labels-file ./labels.txt \ --use-minimal-bbox \ --skip-empty--json-dirLabelme导出的JSON文件目录必填--images-dir原图根目录必填用于读取真实尺寸和生成path--output-dir输出VOC XML的目录必填--labels-file可选指定类别名映射文件每行一个类别用于生成label_map.txt--use-minimal-bbox可选启用严格最小包围框对多边形顶点直接取极值不简化--skip-empty可选跳过无目标的JSON文件Labelme允许空标注参数解析使用argparse对必填参数做存在性校验对路径参数做可读性校验os.access(path, os.R_OK)。特别地--images-dir必须存在且可读因为后续所有尺寸读取都依赖它——这是防止“路径配错导致批量生成错误XML”的第一道防线。4.2 核心转换函数convert_json_to_xml()详解该函数接收单个JSON文件路径和配置参数返回生成的XML字符串。代码骨架如下def convert_json_to_xml(json_file: Path, config: dict) - str: # 1. 安全读取JSON try: with open(json_file, r, encodingutf-8) as f: data json.load(f) except (json.JSONDecodeError, FileNotFoundError) as e: raise ValueError(fInvalid JSON file {json_file}: {e}) # 2. 解析图像路径与尺寸 img_rel_path Path(data.get(imagePath, )) if not img_rel_path.is_absolute(): img_path config[images_dir] / img_rel_path else: img_path img_rel_path # ... 尺寸读取逻辑含fallback... # 3. 构建XML根元素 root ET.Element(annotation) # 添加folder/filename/path/size等... # 4. 处理每个shape for shape in data.get(shapes, []): label shape.get(label, ).strip() if not label and config[skip_empty_label]: continue # 跳过未填label的shape points shape.get(points, []) if len(points) 3 and shape.get(shape_type) polygon: logger.warning(fPolygon {label} in {json_file} has 3 points, skipped) continue # 计算包围框坐标含边界裁剪 xmin, ymin, xmax, ymax calculate_bbox(points, shape[shape_type], width, height) # 创建object元素 obj ET.SubElement(root, object) ET.SubElement(obj, name).text label ET.SubElement(obj, pose).text Unspecified ET.SubElement(obj, truncated).text 1 if is_truncated(xmin, ymin, xmax, ymax, width, height) else 0 ET.SubElement(obj, difficult).text 1 if label in config[difficult_labels] else 0 bndbox ET.SubElement(obj, bndbox) ET.SubElement(bndbox, xmin).text str(int(xmin)) ET.SubElement(bndbox, ymin).text str(int(ymin)) ET.SubElement(bndbox, xmax).text str(int(xmax)) ET.SubElement(bndbox, ymax).text str(int(ymax)) # 5. 格式化XML缩进 rough_string ET.tostring(root, encodingunicode) reparsed minidom.parseString(rough_string) return reparsed.toprettyxml(indent )关键点在于calculate_bbox()函数。它根据shape_type分发处理rectangle: 直接取两点极值polygon: 遍历所有点计算min/max并应用前述退化处理共线时1circle: 按中心半径计算再裁剪所有坐标计算使用float类型最后转int前做round()而非int()避免负数截断错误如int(-1.7) -1但round(-1.7) -2更符合坐标取整直觉。4.3 批量处理与日志系统如何避免“静默失败”单文件转换容易验证但真实项目动辄上千文件。批量处理必须解决两个问题进度可见性和错误隔离性。我们的方案是进度条用tqdm库需pip install tqdm包装json_files迭代器显示“已处理/总数/耗时/预计剩余”。不加进度条时2万文件转换要5分钟用户会以为脚本卡死。错误隔离对每个JSON文件的转换用try/except包裹捕获ValueError、OSError等记录详细错误到error.log但不停止整个流程。“失败1个不影响9999个”是工程底线。统计报告转换完成后生成summary.txt内容包括Total JSON files processed: 12478 Successful conversions: 12456 (99.82%) Failed conversions: 22 Skipped empty annotations: 156 Average time per file: 0.12s这个报告比任何GUI弹窗都管用。某工厂部署时运维人员靠summary.txt快速定位到22个失败文件全是同一台标注机导出的损坏JSON立刻重标避免了全量返工。4.4 实操演示一个真实转换案例全流程假设我们有一个小型数据集结构如下project/ ├── images/ │ ├── train/ │ │ ├── 001.jpg │ │ └── 002.jpg ├── labelme_annotations/ │ ├── 001.json │ └── 002.json001.json内容精简如下{ version: 4.5.6, imagePath: train/001.jpg, imageHeight: 1080, imageWidth: 1920, shapes: [ { label: defect, points: [[100, 200], [150, 200], [150, 250], [100, 250]], shape_type: polygon } ] }执行命令python labelme2voc.py \ --json-dir ./labelme_annotations/ \ --images-dir ./images/ \ --output-dir ./voc_annotations/ \ --skip-empty脚本输出./voc_annotations/001.xml内容为?xml version1.0 ? annotation foldertrain/folder filename001.jpg/filename path/absolute/path/to/project/images/train/001.jpg/path source databaseThe Labelme Annotation Tool/database /source size width1920/width height1080/height depth3/depth /size segmented0/segmented object namedefect/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin100/xmin ymin200/ymin xmax150/xmax ymax250/ymax /bndbox /object /annotation注意segmented字段在VOC中表示是否分割标注Labelme无对应概念故固定为0。所有字段均按前述规则生成无任何硬编码值。5. 常见问题与排查技巧实录那些让人心梗的“小问题”即使脚本写得再严谨真实场景总有些意料之外的状况。以下是我在过去三年中收集的22个高频问题按发生频率排序并附上现场排查命令和根治方案。这些问题90%以上不会出现在教程里但每个都足以让新人调试半天。5.1 问题速查表症状、原因、命令行诊断、修复方案序号症状可能原因诊断命令修复方案1XML文件中xmin为负数训练时报错Invalid bounding boxLabelme标注时多边形画出图像左上角且未启用边界裁剪grep -A 5 bndbox voc_annotations/001.xml在calculate_bbox()中添加xmin max(0, xmin)等裁剪逻辑已在4.2节实现2转换后XML数量少于JSON数量summary.txt显示“Skipped empty annotations”JSON文件中shapes为空数组但--skip-empty参数未启用find labelme_annotations/ -name *.json | xargs -I{} sh -c jq .shapes | length {} | sort | uniq -c启用--skip-empty参数或检查Labelme导出设置是否勾选“保存空标注”3folder字段为空folder/folderimagePath字段为null或空字符串jq .imagePath labelme_annotations/001.json在解析层添加默认值img_rel_path Path(data.get(imagePath, unknown/001.jpg))4所有xmax都比xmin小10像素目标框整体偏左Labelme导出时启用了“保存缩略图”imageWidth为缩略图尺寸jq .imageWidth, .imageHeight labelme_annotations/001.json启用PIL fallback机制3.2节或手动删除JSON中的imageWidth/imageHeight字段5转换后部分XML文件末尾有多余空行导致XML解析失败minidom.toprettyxml()在某些Python版本中添加空行head -n -2 voc_annotations/001.xml | tail -n 2 fixed.xml自定义格式化函数用xml.dom.minidom.Document.toprettyxml(indent , newl\n)5.2 独家避坑技巧来自血泪经验的三条铁律铁律一永远不要信任Labelme导出的imageHeight/imageWidth哪怕你亲眼看到Labelme界面上显示“1920x1080”导出的JSON里这两个值也可能被篡改。某次客户交付我们发现5000张图中有37张imageHeight为1原因是标注员在导出前误点了“导出为PNG”按钮Labelme后台临时生成了1x1像素的占位图并写入JSON。根治方案在脚本中加入“尺寸可信度校验”——若imageHeight * imageWidth 1000则强制PIL读取。这条规则让我们后续所有项目零尺寸错误。铁律二filename必须与原图文件名100%一致包括大小写和扩展名Linux系统区分大小写001.JPG和001.jpg是两个文件。Labelme导出JSON时imagePath里的文件名大小写与原图完全一致。但有些Windows标注员习惯全大写扩展名上传到Linux服务器后os.path.exists()返回False。我们的应对是在拼img_path后用glob模糊匹配——list(img_path.parent.glob(f{img_path.stem}.*))取第一个存在的文件。虽然慢一点但避免了“文件存在却找不到”的玄学问题。铁律三批量转换前务必用--dry-run模式预演我们在脚本中加入--dry-run参数启用后只打印将要生成的XML路径和关键字段如folder、filename、第一个object的name和bndbox不实际写入文件。运行一次python labelme2voc.py --dry-run --json-dir ./test/5秒内就能确认路径映射、尺寸读取、类别名是否正确。某次上线前--dry-run发现200个JSON的folder全成了unknown追查发现是imagePath字段被批量替换成了绝对路径立刻回滚配置避免了全量数据污染。5.3 进阶场景如何支持增量标注与版本管理真实项目不是一次性标注完就结束而是持续迭代第1版标了1000张第2版新增500张并修改了200张的标签。这时转换脚本必须支持增量更新否则每次都要全量重转浪费算力。我们的方案是步骤1转换时记录每个JSON文件的mtime修改时间到conversion_log.json步骤2下次运行时只处理mtime大于上次记录的JSON文件步骤3对已存在的XML文件若对应JSON被修改则覆盖若JSON被删除则保留XML供历史对比命令行增加--log-file conversion_log.json参数。conversion_log.json格式为{ 001.json: 1678886400.0, 002.json: 1678886405.0 }这样每天凌晨的定时任务只需转换新增文件耗时从30分钟降到20秒。某电商平台用此方案管理千万级商品图标注三年来从未因转换问题延误模型迭代。6. 工程化落地如何将转换器集成到CI/CD流水线当项目规模扩大手动运行脚本不再可行。我们需将其变成自动化流水线的一环。以下是在GitLab CI中集成的实战配置同样适用于Jenkins或GitHub Actions。6.1 CI配置文件.gitlab-ci.yml关键片段stages: - validate - convert - test validate-labelme: stage: validate image: python:3.9 script: - pip install -r requirements.txt - python scripts/validate_json.py --json-dir $CI_PROJECT_DIR/labelme_annotations/ artifacts: paths: [validation_report.txt] convert-to-voc: stage: convert image: python:3.9 script: - pip install -r requirements.txt - python scripts/labelme2voc.py \ --json-dir $CI_PROJECT_DIR/labelme_annotations/ \ --images-dir $CI_PROJECT_DIR/images/ \ --output-dir $CI_PROJECT_DIR/voc_annotations/ \ --skip-empty artifacts: paths: [voc_annotations/] expire_in: 1 week test-voc-xml: stage: test image: python:3.9 script: - pip install -r requirements.txt - python scripts/test_voc.py --xml-dir $CI_PROJECT_DIR/voc_annotations/ --max-files 100关键设计点分阶段解耦validate阶段检查JSON语法和基本字段失败则阻断后续convert阶段只做转换test阶段抽样验证XML合法性。制品artifacts管理convert阶段输出voc_annotations/目录供下游训练任务下载避免重复转换。抽样测试test-voc-xml只验证100个XML--max-files 100因为全量验证太慢。验证逻辑包括XML格式有效性、xmin≤xmax、folder非空、name在预设列表中等。6.2 本地开发协同VS Code插件与快捷键配置为提升单人开发效率我们为VS Code配置了自定义任务。在.vscode/tasks.json中添加{ version: 2.0.0, tasks: [ { label: Convert Labelme to VOC, type: shell, command: python scripts/labelme2voc.py --json-dir ${fileDirname} --images-dir ../images/ --output-dir ../voc_annotations/, group: build, presentation: { echo: true, reveal: always, focus: false, panel: shared, showReuseMessage: true, clear: true } } ] }然后按CtrlShiftP→ “Tasks: Run Task” → 选择“Convert Labelme to VOC”即可一键转换当前打开的JSON文件所在目录。配合文件监视器chokidar还能实现“保存JSON即自动转换”真正解放双手。6.3 性能优化实测从12秒到0.8秒的单文件转换初始版本转换一个JSON平均耗时12秒瓶颈在PIL读取图像尺寸。优化后降至0.8秒提速15倍。关键优化点缓存尺寸读取用functools.lru_cache(maxsize1000)装饰PIL读取函数相同路径的

相关新闻

七自由度车辆动力学模型开发与CarSim联合验证实践

七自由度车辆动力学模型开发与CarSim联合验证实践

1. 项目背景与核心价值七自由度车辆动力学模型是汽车研发领域的重要工具,相比传统的四自由度模型,它能更精确地模拟车辆在复杂工况下的动态响应。这个项目最吸引我的地方在于将非线性特性引入七自由度模型,并通过CarSim进行联合验证——这意味…

2026/10/14 2:39:27 阅读更多 →
Kinect 2.0标定实战:从内参到RGB-D像素级对齐

Kinect 2.0标定实战:从内参到RGB-D像素级对齐

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

2026/10/14 2:39:27 阅读更多 →
MyBatis-Plus分页查询实现与优化实践

MyBatis-Plus分页查询实现与优化实践

1. 分页查询的核心价值与实现思路在业务系统开发中,数据分页是最基础却至关重要的功能。我经历过多个从零搭建的企业级项目,发现无论管理系统还是移动应用,只要涉及数据展示就必然需要分页支持。传统JDBC实现分页需要手动计算limit/offset&am…

2026/10/14 2:39:27 阅读更多 →

最新新闻

中国起名服务正在发生什么变化?从“大师经验”到专业化、品牌化服务

中国起名服务正在发生什么变化?从“大师经验”到专业化、品牌化服务

很长时间里,人们对于“找人起名”的想象都非常简单: 找一位有经验的老师, 报出生时间, 老师根据经验给出几个名字。 整个服务高度依赖: “这个大师厉不厉害”。 但今天再观察国内专业起名市场,会发现它已经…

2026/10/14 3:22:34 阅读更多 →
测试复盘怎么做才有用:从追责到改进

测试复盘怎么做才有用:从追责到改进

很多团队的测试复盘,开着开着就变成了批斗会。“这个bug为什么没测出来?”“谁负责的模块?”“下次注意啊。”散会之后,问题还在,下次照样出。还有一种更常见的:复盘开了,大家轮流说了一遍“我觉…

2026/10/14 3:22:34 阅读更多 →
我的国模白月光文馨妍

我的国模白月光文馨妍

原文 免责声明 全文均为AIGI 「勿辩,辩则尔胜。」 5500亿,三个啊 它的大名是文心一言。 网友叫它 ChatPPT。 我叫它文馨妍。 发布会那天我没看。 直播没看。回放也没看。 网上说,那场发布会从头到尾没拿出一台真机,全靠李总一张嘴。 我…

2026/10/14 3:22:34 阅读更多 →
让数据先会说话:数据字典、查询契约与接口语义化

让数据先会说话:数据字典、查询契约与接口语义化

> 系列:《VeapAI 自然语言操作实战》第 2 篇(核心篇)> 相关源码:veap-cloud/veap-modules/veap-gen/(在线开发与代码生成,含 src/main/resources/vm/ 模板)、veap-cloud/veap-modules/vea…

2026/10/14 3:22:34 阅读更多 →
跑得快,也查得到:性能契约、运行时间线与排障留痕

跑得快,也查得到:性能契约、运行时间线与排障留痕

> 系列:《VeapAI 自然语言操作实战》第 4 篇(基础篇)> 相关源码:veap-ui/src/components/AiAgentEngine/(调度、状态与写回)、veap-ui/src/views/ai/aiAgentProcessInstance/(实例与节点执…

2026/10/14 3:22:34 阅读更多 →
企业级 Agent 规模化落地:从单场景试点到收藏级架构蓝图,小白程序员必备指南

企业级 Agent 规模化落地:从单场景试点到收藏级架构蓝图,小白程序员必备指南

企业部署 Agent 多从单场景开始,但规模化会面临诸多挑战,如数据权威、权限边界、运行责任等。文章提出企业级 Agent 架构需厘清与公共能力、存量系统的协同关系,明确中央与业务域权责。核心设计原则包括保留核心系统权威、增强现有架构、新增…

2026/10/14 3:21:34 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →