ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

ObjectMarker:自动生成OpenCV正样本标注描述文件

ObjectMarker:自动生成OpenCV正样本标注描述文件 简介这套资源提供 objectmarker 工具的完整源码与可执行程序面向需要自制物体识别数据集的计算机视觉初、中级开发者。它基于 OpenCV 实现交互式正样本标注用户通过鼠标在图像上框选目标区域程序会将多个边界框信息写入 info.txt方便后续训练检测或分类模型。压缩包共 10 个文件包含 cpp 源码、exe 可执行文件、dll 运行库、txt 说明文档及示例位图整体体积仅 1.01MB结构紧凑、便于直接运行或二次修改。已有 291 人学习下载。借助该工具读者可快速理解正样本描述格式图像名加边界框坐标并掌握用 OpenCV 处理鼠标事件、显示图像和保存标注结果的实现思路对于公开数据集难以覆盖的小众类别也能自行批量标注图像构建贴合业务需求的训练集。附带的 readme 与 info 示例文件有助于快速上手适合用于物体识别项目的前期数据准备和算法验证。1. ObjectMarker给 OpenCV 识别批量生成正样本描述的工具提到 OpenCV 识别从零训练级联分类器是最常见的一条路而这条路的第一步就是准备正样本。正样本不是把图片丢进文件夹就完事OpenCV 要求一个记录目标位置的描述文件格式稍有偏差后面训练直接崩。很多项目卡在图片有几百张、目标又小又多手工数坐标能让心态崩掉。ObjectMarker附源码就是用来解决这个问题的打开图片鼠标框出目标自动生成 OpenCV 训练要用的正样本描述文本。适合训练人脸、车牌、缺陷检测这类目标区域明确的识别场景也适合第一次接触 opencv_traincascade 的初学者。2. 正样本描述文件的格式边界先看懂 info.txt 再开始标用级联分类器训练前OpenCV 要求把所有正样本的标注写进一个文本。这个文件的行格式直接决定后续 opencv_createsamples 能否正确裁出正样本。很多人第一次训练失败不是标注得不准而是格式不对。所以先用一节把它掰开揉碎。2.1 每种 OpenCV 训练工具吃的格式一行一个逻辑样本opencv_traincascade 的 -info 参数接受的文件每一行由三部分组成图像路径、目标个数、目标矩形列表。标准写法是relative/path/to/image.jpg 1 x y w h其中 x、y 是矩形左上角坐标w、h 是宽度和高度单位是像素。所有坐标必须以图片左上角为原点向右向下为正。一张图里有多个目标就把数量改成 2后面跟两组 x y w hrelative/path/to/image.jpg 3 10 15 80 90 120 130 60 70 200 40 55 65这里有个新手常踩的误区以为 w、h 是右下角坐标。实际上 opencv_createsamples 在读取时是按宽度和高度来理解你填成右下角坐标它会把样本裁成一个宽高等于右下角减左上角的巨大区域后面训练直接报废。我一般会写一个小脚本先校验 w、h 都大于 0 且不超过图像尺寸。这里还要区分路径的写法。OpenCV 按相对路径读取图片而相对路径是相对于你执行训练命令时的当前目录。如果 info.txt 写在 train_data 目录下图片在 train_data/positive_images 里路径就应该写成positive_images/001.jpg而不是带一串绝对路径。否则换一台机器跑或者从别的目录启动训练全部路径找不到。2.2 为什么手动维护坐标清单容易出低级错误当图片数量上百张每张里有两三个小目标时手动把坐标敲进文本很难保证不出错。我把常见错误按出现频率排了个序框没有完整框住目标目标边缘被切掉一部分。一张图里多个目标眼睛数漏了数量字段和实际矩形个数对不上。复制粘贴路径时大小写不一致Windows 下没问题Linux 下直接找不到文件。坐标重叠或者负数训练中途才弹 assert failed。这些错误不会在训练刚开始就暴露往往在跑了一两个小时后弹出异常或者训练出的模型误检率高得离谱。因此用工具生成描述文件本质上是在把“人肉计算坐标”换成“鼠标拖框 自动换算”从源头减少数字出错。2.3 ObjectMarker 的标注核心鼠标回调与矩形框管理ObjectMarker 的源码核心其实不复杂基于 OpenCV 的窗口鼠标回调来记录矩形。我拆过类似的工具最关键是三块鼠标按下开始记录鼠标移动时更新临时矩形鼠标松开时把合法矩形存进列表。下面这段代码就是核心循环import cv2 boxes [] # 已确认的矩形列表 start None # 按下鼠标时的坐标 temp None # 移动中的临时矩形 def on_mouse(event, x, y, flags, param): global start, temp if event cv2.EVENT_LBUTTONDOWN: start (x, y) temp (x, y, x, y) elif event cv2.EVENT_MOUSEMOVE: if start: temp (start[0], start[1], x, y) elif event cv2.EVENT_LBUTTONUP: if start and x start[0] and y start[1]: boxes.append((start[0], start[1], x, y)) start None cv2.namedWindow(marker) cv2.setMouseCallback(marker, on_mouse)逻辑说明回调函数根据鼠标事件维护三个变量boxes存放已确认的矩形start记录按下瞬间坐标temp用于实时显示。当左键松开时判断x start[0]且y start[1]作用是排除反向拖拽产生的负宽高矩形。存进boxes的是图片显示坐标系下的绝对坐标写入文件前不需要再换算。参数说明cv2.setMouseCallback里的窗口名必须和namedWindow保持一致。回调里的x, y是窗口显示坐标系的像素值。如果图片在窗口中被缩放显示那么原图坐标需要做一次除法原图坐标 显示坐标 / 缩放比例。大多数复刻源码里会保留这个缩放因子否则框出来的位置会偏移。这块也是你拿到源码后最值得改的地方。我建议在显示窗口上方加一个类似状态栏的区域实时显示当前图片路径、已框目标数量、当前矩形宽高。这个小改动在标注大量小目标时非常救命每框一个目标就 1减少漏标率。如果你的目标物体边缘不明显先用图像增强把对比度拉开再标避免框太小或者框偏移。2.4 程序里如何管理图像目录与自动保存ObjectMarker 一般有个简单的文件队列加载目录下所有 jpg/png按文件名排序逐张展示。标注完一张切到下一张前把该图所有矩形写入输出文件再清空boxes。这样即使中途关掉程序已标注的图片也不会丢。你如果拿到源码想二次开发主要改这几处文件后缀过滤目前只认.jpg和.png如果你的数据集是.bmp要手动加后缀。输出路径默认生成在运行目录下建议改成绝对路径避免不同终端启动时写入位置不一致。图片缩放显示原图分辨率很大时窗口可能放不下需要按比例缩小显示但坐标要还原回原图尺度。3. 从图片目录到输出文件ObjectMarker 标注实操流程3.1 环境准备与源码运行方式拿到 ObjectMarker 源码后先确认 OpenCV 环境。如果源码是 Python 版本安装 opencv-python 就够了如果源码是 C 版本需要编译 OpenCV 并配置 CMake。一个比较省心的做法是先建一个干净的虚拟环境跑通脚本再逐步加依赖。python -m venv venv source venv/bin/activate pip install opencv-python numpy参数说明虚拟环境避免把全局 Python 环境搞乱。opencv-python 自带常用图像处理模块numpy 用于图像数组操作。如果你的源码还用到了 tqdm 做进度条也一并装上。逻辑说明先激活环境再装依赖避免装到系统目录里。后面的运行指令都在这个虚拟环境下执行退出后不影响其他项目。如果源码是 C 版本核心依赖是 opencv 库和 CMake。编译过程相比 Python 会多一步但运行效率更高适合大批量图片。不过大多数场景下Python 版本已经够用毕竟标注操作是交互式的瓶颈在人的手速不在程序速度。3.2 命令行参数与操作流程很多复刻的 ObjectMarker 工具会提供三个参数图片目录、输出文件路径、显示窗口尺寸。常见调用如下python objectmarker.py --img-dir ./positive_images --output info.txt --win-width 800 --win-height 600这里--img-dir指定存放正样本图片的目录--output指定生成的描述文件名--win-width和--win-height是显示窗口的尺寸不是训练尺寸。这两个参数只影响画框时的窗口缩放比例不影响最终坐标精度。如果你把显示窗口设得比原图小内部会按比例缩放坐标换算到原图时依然是准确像素。然后按下面的步骤操作运行命令后窗口出现第一张图。按住鼠标左键拖出矩形框住目标松开左键确认一个框。同一张图有多个目标就继续框直到框完所有目标。按空格键保存本图所有矩形到输出文件并跳到下一张。全部完成后按 q 退出。需要特别提醒的是这里的“保存”是增量写入也就是说跳下一张之前把当前图片的矩形写进文件而不是等全部标注完统一写。这样程序意外崩溃时已标注的图片不会白标。3.3 目录组织建议与输出文件检查建议把正样本图片放在一个独立目录生成文件放在上一级。比如train_data/ positive_images/ 001.jpg 002.jpg info.txt这样在 info.txt 里写positive_images/001.jpg训练时只要在 train_data 目录下启动命令就能找到所有图片。避免写绝对路径否则换一台机器路径全变。保存后打开 info.txt 检查前三行。如果看到类似这样的内容positive_images/001.jpg 2 10 15 80 90 120 130 60 70 positive_images/002.jpg 1 30 40 110 95说明每行格式基本对。再检查矩形是否超出图像边界以及数量字段和实际坐标组数是否一致。我见过最阴间的错误是某一行数量写成 2但后面跟了 3 组坐标OpenCV 读取时按数量截取第三组被当成下一行的开头后面全部错位。所以这个检查不能省。3.4 批量预处理把图片裁好再标省得训练时踩坑标注之前建议对图片做一次统一预处理。常见做法是用脚本把图片统一命名成 6 位数字比如000001.jpg再按需缩放。这样 info.txt 里的文件名是整齐的后续写数据增强脚本也方便。下面是一个简单的前置处理脚本把一张大图按滑动窗口切成小图并跳过面积小于阈值的子图import cv2 import os def preprocess(image_path, output_dir, patch_size256, overlap64): img cv2.imread(image_path) if img is None: print(ffail to read: {image_path}) return h, w img.shape[:2] idx 0 for y in range(0, h - patch_size 1, patch_size - overlap): for x in range(0, w - patch_size 1, patch_size - overlap): patch img[y:y patch_size, x:x patch_size] out_path os.path.join(output_dir, f{idx:06d}.jpg) cv2.imwrite(out_path, patch) idx 1 preprocess(raw.jpg, positive_images)参数说明patch_size是滑窗尺寸overlap是相邻窗口重叠区域这两个值决定你从一张大图能得到多少张子图。如果你的目标物体不会正好跨边界可以不用重叠减少重复样本。逻辑说明脚本按patch_size - overlap作为步长滑动切割避免目标刚好被切碎。所有子图统一命名生成的正样本描述文件里路径也会整齐很多。这里有个取舍滑窗切出来的子图可能大量不包含目标你需要后续用 ObjectMarker 把包含目标的子图挑出来其余删掉否则负样本混进正样本里模型会学得很困惑。4. 标注与训练衔接的常见问题排查五个最容易翻车的坑4.1 训练时提示找不到图片文件现象opencv_traincascade 启动后报错Can not open file或者Failed to read image。原因info.txt 里的路径是相对路径但命令运行的当前目录不在 train_data 下或者路径里的子目录名写错。解决先确认工作目录cd到 train_data 再执行训练命令。在 info.txt 中统一使用斜杠/不要混用 Windows 的反斜杠。如果你用 Windows建议在标注工具里直接把路径替换成标准斜杠避免跨平台时出问题。4.2 生成的样本全是全黑或全白现象训练出的 .vec 里样本无法看标记的物体没有出现在裁片中。原因坐标 w、h 被误填成右下角坐标导致目标偏移或裁到背景或者图像通道处理错误BGR 和 RGB 混用。解决在源码输出前强制检查 w、h 为正数并且x w、y h不超过图像宽高。可加代码把坐标限制在合法范围内def clamp_rect(x, y, w, h, img_w, img_h): x max(0, min(x, img_w - 1)) y max(0, min(y, img_h - 1)) w min(w, img_w - x) h min(h, img_h - y) return x, y, w, h参数说明img_w和img_h是原图宽高传入前从cv2.imread读取。clamp_rect的作用是把越界坐标拉回图像范围内避免生成无效裁剪区域。逻辑说明先 clamp 左上角坐标再根据剩余空间收缩宽高。这里不直接修改原图只是保证写入 info.txt 的坐标合法。建议在保存前对每一条矩形都调用一次。4.3 多目标图只检测出来一部分现象训练完成后检测率很低特别是那些包含多个目标的图片。原因标注的时候漏框某些目标被当成背景模型学到的特征不完整。解决保存前显示当前图片上已经画好的所有框确认数量一致再跳下一张。如果图片数量大可以每 20 张停一次把本轮标注结果打印到终端。批量标注最容易出现“标着标着忘了这张图有几个目标”的情况所以工具里显示已框数量不是小事。4.4 坐标正常但训练一直报错现象提示Invalid rectangle或者训练中途崩溃。原因某些图片尺寸不一致而框坐标是从上一张图片继承下来没有清空。解决每次切换图片时强制清空boxes数组。如果图片尺寸相差大最好在标注前统一缩放或填充保证所有图片的宽高范围一致。否则即使坐标合法不同尺寸的样本混在一起训练也会导致归一化时出现问题。4.5 负样本数量足够但正样本描述文件行首数字是 0现象info.txt 里某行是path.jpg 0opencv_createsamples 直接跳过这行。原因按下空格时boxes列表为空说明没有框任何目标。解决工具里加判断如果boxes为空就不写入该行同时提示当前图片没有标记让你决定是重新标还是跳过。不要写个 0 混过去这一行不会报错但会浪费一次样本机会并且让你以为这批数据没问题。5. 接进 opencv_createsamples用一次可视化校验收尾描述文件生成后最终要喂给 opencv_createsamples 生成 .vec 文件这一步是训练前最后一道关卡。命令格式如下opencv_createsamples -info info.txt -num 2000 -w 24 -h 24 -vec positives.vec参数说明-info指定 ObjectMarker 生成的正样本描述文件-num是抽取的样本数不要超过描述文件中的目标总数否则会报错-w和-h是统一缩放尺寸建议保持 24 或 20不要设太大否则训练时间剧增-vec是输出的样本向量文件。逻辑说明-num的值代表最终参与训练的正样本数量。如果你的描述文件里一共有 1500 个目标就填 1500。填多了会报错填少了浪费已有数据。生成 vec 后我习惯做一次可视化校验不急着开训。最直接的方式是用 opencv_createsamples 自带的展示功能opencv_createsamples -vec positives.vec -show 10这个命令会弹出窗口一屏展示前 10 个正样本。你可以按空格翻页按 ESC 退出。只需要花两分钟就能确认每个样本里目标是否完整、有无被裁掉一半的情况。我以前跳过这步直接开训结果训练了两小时模型识别不到目标回头查才发现框选时所有框都偏了半个身位。从那以后我每次标注完都强制走一遍-show检查确认框内是完整目标再启动训练。希望帮到你。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表