# ocr-cmp **Repository Path**: arch-builder/ocr-cmp ## Basic Information - **Project Name**: ocr-cmp - **Description**: 简单的 ocr demo - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-15 - **Last Updated**: 2026-02-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ocr-cmp 图片、pdf 内容识别检索 - [x] 识别图片、pdf 内容 - [x] 对内容进行关键字切分 - [x] 根据 OCR 结果,计算关键字的坐标 - [] 封装为服务提供接口 - [] OCR 结果中跨行处理(可能需要换 OCR 模型) ## 搭建开发环境 建议使用 python 自带的 venv 创建虚拟环境 ### 安装依赖 **激活虚拟环境后** ```bash $ pip install -r requirements.txt ``` 或者 ```bash $ pip install -r requirements-gpu.txt ``` aarch64 平台与 x86 安装的版本可能不一样,可使用下面的命令手动安装或者下载: ```bash $ pip download paddleocr==3.2.0 --platform manylinux2014_aarch64 --only-binary=:all: $ pip download paddlepaddle==3.3.0 --platform manylinux2014_aarch64 --only-binary=:all: ``` 安装: ```bash $ pip install -v ./paddleocr-xxxx.whl --no-index --find-links=./ ``` ### 使用开发模式将本地项目纳入模块识别路径 ```bash $ pip install -e . --no-build-isolation ``` 使用开发模式时,如果用 pip 安装了新包,导出 requirements 时需要排除当前项目: ``` $ pip freeze | sed '/^-e/d' > requirements.txt # for zsh using zimfw $ pip freeze | sed '/^-e/d' >! requirements.txt ``` ## 版本发行 执行构建命令: ```bash $ python -m build ``` 项目根目录中生成子目录 `dist`: ```bash $ ls dist # ocrcmp-1.0.0-py3-none-any.whl ocrcmp-1.0.0.tar.gz ``` 其中 `whl` 后缀名的包即发行的版本。 **如果要发行新版本,一定要修改版本号:** ```python # src/ocrcmp/__version__.py __version__ = "1.0.0" ``` ## 命令验证 #### 分词样例 ```bash $ python src/ocrcmp/cmd/seg.py -t "这是一个铁路线上的小站,只有慢车才停两三分钟。快车疾驰而过,旅客们甚至连站名还来不及看清楚。 就在这一刹那,你也许看到一间红瓦灰墙的小屋,一排漆成白色的小栅栏,或者还有三五个人影。而这一切又立即消失了,火车两旁依然是逼人而来的山崖和巨石。 这是一个在北方山区常见的小站。小屋左面有一张红榜,上面用大字标明了二百四十一天安全无事故的记录,贴着竞赛优胜者的照片。红榜旁边是一块小黑板,上面用白粉写着早晨广播的新闻和首都报纸摘要。出站口的旁边贴着一张讲卫生的宣传画。月台上,有两三个挑着箩筐的农民。几步以外,站上的两位工作人员正在商量着什么。" ``` #### 识别 demo ```bash $ python src/ocrcmp/main.py -f ~/Documents/OCR/合同.jpg -c conf/dev.yaml ``` ## 创建倒排索引 创建倒排索引需要对文本段进行分词,这里用 jieba3 完成,后续可更换。 ### 计算每个分词在文本中的下标 举例说明如下,文本段为 ```plaintext 这是一个铁路线上的小站,只有慢车才停两三分钟。快车疾驰而过,旅客们甚至连站名还来不及看清楚。 就在这一刹那,你也许看到一间红瓦灰墙的小屋,一排漆成白色的小栅栏,或者还有三五个人影。而这一切又立即消失了,火车两旁依然是逼人而来的山崖和巨石。 这是一个在北方山区常见的小站。小屋左面有一张红榜,上面用大字标明了二百四十一天安全无事故的记录,贴着竞赛优胜者的照片。红榜旁边是一块小黑板,上面用白粉写着早晨广播的新闻和首都报纸摘要。出站口的旁边贴着一张讲卫生的宣传画。月台上,有两三个挑着箩筐的农民。几步以外,站上的两位工作人员正在商量着什么。 ``` 分词后计算各单子在文本段中出现位置的起始下标: ```json { "这是": [0, 120], "一个": [2, 122], "铁路": [4], "路线": [5], "铁路线": [4], "上": [7, 145, 190, 232, 252], "的": [8, 65, 75, 112, 131, 164, 175, 201, 215, 225, 242, 253], "小站": [9, 132], ",": [11, 29, 53, 68, 79, 100, 144, 167, 189, 233, 250], "只有": [12], "慢车": [14], "才": [16], "停": [17], "两三": [18, 235], "三分": [19], "分钟": [20], "两三分": [18], "三分钟": [19], "两三分钟": [18], "。": [22, 45, 89, 118, 134, 178, 211, 229, 245, 267], "快车": [23], "疾驰": [25], "而": [27, 90, 110], "过": [28], "旅客": [30], "们": [32], "甚至": [33], "连": [35], "站名": [36], "还": [38, 82], "不及": [40], "来不及": [39], "看清": [42], "清楚": [43], "看清楚": [42], " ": [46, 119], "就": [47], "在": [48, 124, 261], "这": [0, 49, 91, 120], "一刹": [50], "刹那": [51], "一刹那": [50], "你": [54], "也许": [55], "看到": [57], "一间": [59], "红瓦": [61], "灰墙": [63], "小屋": [66, 135], "一排": [69], "漆成": [71], "白色": [73], "小": [9, 66, 76, 132, 135, 186], "栅栏": [77], "或者": [80], "还有": [82], "三五": [84], "五个": [85], "三五个": [84], "人影": [87], "一切": [92], "又": [94], "立即": [95], "消失": [97], "了": [99, 152], "火车": [101], "两旁": [103], "依然": [105], "是": [1, 107, 121, 183], "逼人": [108], "而来": [110], "山崖": [113], "和": [115, 204], "巨石": [116], "北方": [125], "山区": [127], "常见": [129], "左面": [137], "有": [13, 83, 139, 234], "一张": [140, 220], "红榜": [142, 179], "上面": [145, 190], "用": [147, 192], "大字": [148], "标明": [150], "二百": [153], "四十": [155], "二百四十": [153], "一天": [157], "安全": [159], "无事": [161], "事故": [162], "无事故": [161], "记录": [165], "贴着": [168, 218], "竞赛": [170], "优胜": [172], "胜者": [173], "优胜者": [172], "照片": [176], "旁边": [181, 216], "一块": [184], "小黑": [186], "黑板": [187], "小黑板": [186], "白粉": [193], "写": [195], "着": [169, 196, 219, 239, 264], "早晨": [197], "广播": [199], "新闻": [202], "首都": [205], "报纸": [207], "摘要": [209], "站口": [213], "出站口": [212], "卫生": [223], "讲卫生": [222], "宣传": [226], "宣传画": [226], "月": [230], "台上": [231], "三个": [236], "两三个": [235], "挑着": [238], "箩筐": [240], "农民": [243], "几步": [246], "以外": [248], "站上": [251], "两位": [254], "工作": [256], "作人": [257], "人员": [258], "工作人员": [256], "正在": [260], "商量": [262], "什么": [265] } ``` 有的分词可能在文本段中出现不止一次,因此需要用列表记录分词在文本段中出现过的所有位置的下标。 **这一步需要注意时间复杂度,不建议使用列表自带的 `index` 方法。** ## 分词坐标计算 几个假设前提: 1. 假设 OCR 识别出的图片/pdf 文件中每段文本的大小相同; ``` (x1, y1) (x01, y01) (x02, y02) (x2, y2) +-----------------------------------------------------+ | | word | | # 文本段 +-----------------------------------------------------+ (x4, y4) (x04, y04) (x03, y03) (x3, y3) 0 1 2 3 ... n-1 begin begin+m ``` 2. 假设一行有 n 个字,某个分词的坐标为 `[(x01, y01), (x02, y02), (x03, y03), (x04, y04)]` 长度为 m 个字,起始下标为 begin,计算横坐标: ``` (x01-x1)/begin = (x2-x1)/n (x02-x1)/(begin+m) = (x2-x1)/n (x03-x4)/(begin+m) = (x3-x4)/n (x04-x4)/(begin) = (x3-x4)/n # 注意:文本方向是从左到右时,纵坐标的变化幅度非常小 (y1-y01)/begin = (y1-y2)/n (y1-y02)/(begin+m) = (y1-y2)/n (y4-y04)/begin = (y4-y3)/n (y4-y03)/(begin+m) = (y4-y3)/n ``` 这样就计算出每个分词在图片中的位置坐标(包含 pdf 文件对应的页码)