项目初始化

This commit is contained in:
2025-09-28 13:37:21 +08:00
commit 7795de3550
21 changed files with 364 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/easyocr-api.iml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,41 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<Languages>
<language minSize="130" name="Python" />
</Languages>
</inspection_tool>
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="8">
<item index="0" class="java.lang.String" itemvalue="protobuf" />
<item index="1" class="java.lang.String" itemvalue="mkl-random" />
<item index="2" class="java.lang.String" itemvalue="numpy" />
<item index="3" class="java.lang.String" itemvalue="starlette" />
<item index="4" class="java.lang.String" itemvalue="charset-normalizer" />
<item index="5" class="java.lang.String" itemvalue="h11" />
<item index="6" class="java.lang.String" itemvalue="obs" />
<item index="7" class="java.lang.String" itemvalue="torch" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="W292" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N803" />
</list>
</option>
</inspection_tool>
</profile>
</component>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (easyocr)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/easyocr-api.iml" filepath="$PROJECT_DIR$/.idea/easyocr-api.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

1
README.md Normal file
View File

@@ -0,0 +1 @@
ocr demo,里面有两个模型 一个是easyocr一个是百度的paddleocr

0
api/__init__.py Normal file
View File

61
api/easy_orc_api.py Normal file
View File

@@ -0,0 +1,61 @@
import os
import cv2
import easyocr
import numpy as np
from core.response import SuccessResponse
from fastapi import APIRouter, UploadFile, Form
from schemas.orc_result import ResultInfo, ResultMain
app = APIRouter()
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
model_dir = os.path.join(BASE_DIR, 'model')
reader = easyocr.Reader(
['ch_sim', 'en'],
model_storage_directory=model_dir,
download_enabled=False,
gpu=True)
def preprocess_img(image):
# 转为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 二值化
_, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 去噪声
denoised = cv2.medianBlur(binary, 3)
return denoised
@app.post("/upload")
async def orc(files: list[UploadFile] = Form(...)):
result = []
for file in files:
main = ResultMain()
main.file_name = file.filename
# 读取上传的文件内容
image_data = await file.read()
# 2. 将字节数据转换为 numpy 数组
np_array = np.frombuffer(image_data, np.uint8)
# 3. 使用 cv2.imdecode 解码为 OpenCV 图像
image = cv2.imdecode(np_array, cv2.IMREAD_COLOR)
new_image = preprocess_img(image)
datas = reader.readtext(np.array(new_image))
infos = []
for data in datas:
info = ResultInfo()
bounding_boxs = data[0]
left_up = bounding_boxs[0]
right_down = bounding_boxs[2]
info.bounding_box_left_up = [int(left_up[0]), int(left_up[1])]
info.bounding_box_right_down = [int(right_down[0]), int(right_down[1])]
info.text = data[1]
info.confidence = round(data[2], 4)
infos.append(info)
main.infos = infos
result.append(main.model_dump())
return SuccessResponse(data=result)

55
api/paddle_ocr_api.py Normal file
View File

@@ -0,0 +1,55 @@
from core.response import SuccessResponse
from fastapi import APIRouter, UploadFile, Form
from schemas.orc_result import ResultInfo, ResultMain
from paddleocr import PaddleOCR
import numpy as np
import cv2
app = APIRouter()
paddle_ocr = PaddleOCR(lang='ch')
def enhance_image(img):
"""增强亮部和暗部,提升数字清晰度"""
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
cl = clahe.apply(l)
enhanced = cv2.merge((cl, a, b))
return cv2.cvtColor(enhanced, cv2.COLOR_LAB2BGR)
@app.post("/upload")
async def orc(files: list[UploadFile] = Form(...)):
result = []
for file in files:
main = ResultMain()
main.file_name = file.filename
# 读取上传的文件内容
image_data = await file.read()
# 从字节数据读取图像
np_array = np.frombuffer(image_data, np.uint8)
img = cv2.imdecode(np_array, cv2.IMREAD_COLOR)
# 图像增强
img = enhance_image(img)
# 4. 调用 OCR 模型进行识别
datas = paddle_ocr.ocr(img, cls=False)
infos = []
if datas:
for data in datas[0]:
info = ResultInfo()
bounding_boxs = data[0]
left_up = bounding_boxs[0]
right_down = bounding_boxs[2]
info.bounding_box_left_up = [int(left_up[0]), int(left_up[1])]
info.bounding_box_right_down = [int(right_down[0]), int(right_down[1])]
info.text = data[1][0]
info.confidence = round(data[1][1], 4)
infos.append(info)
main.infos = infos
result.append(main.model_dump())
return SuccessResponse(data=result)

24
application.py Normal file
View File

@@ -0,0 +1,24 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from api.easy_orc_api import app as easy_orc_api
from api.paddle_ocr_api import app as paddle_ocr_api
app = FastAPI()
'''
添加cros中间件允许跨域请求
'''
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(paddle_ocr_api, prefix="/ocr", tags=["ocr识别"])

32
core/response.py Normal file
View File

@@ -0,0 +1,32 @@
# 依赖安装pip install orjson
from fastapi.responses import ORJSONResponse as Response
from fastapi import status as http_status
from core import status as http
class SuccessResponse(Response):
"""
成功响应
"""
def __init__(self, data=None, msg="success", code=http.HTTP_SUCCESS, status=http_status.HTTP_200_OK, **kwargs):
self.data = {
"code": code,
"message": msg,
"data": data
}
self.data.update(kwargs)
super().__init__(content=self.data, status_code=status)
class ErrorResponse(Response):
"""
失败响应
"""
def __init__(self, msg=None, code=http.HTTP_ERROR, status=http_status.HTTP_200_OK, **kwargs):
self.data = {
"code": code,
"message": msg,
"data": []
}
self.data.update(kwargs)
super().__init__(content=self.data, status_code=status)

14
core/status.py Normal file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2022/8/10 22:20
# @File : status.py
# @IDE : PyCharm
# @desc : 简要说明
HTTP_SUCCESS = 200
HTTP_ERROR = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404

5
main.py Normal file
View File

@@ -0,0 +1,5 @@
import uvicorn
from application import app
if __name__ == '__main__':
uvicorn.run("main:app", port=9800, reload=False, host='0.0.0.0')

BIN
model/zh_sim_g2.pth Normal file

Binary file not shown.

6
requirement.txt Normal file
View File

@@ -0,0 +1,6 @@
fastapi==0.112.2
uvicorn==0.32.1
easyocr==1.7.2
orjson==3.10.16
python-multipart==0.0.20
paddleocr==2.10.0

18
schemas/orc_result.py Normal file
View File

@@ -0,0 +1,18 @@
from pydantic import BaseModel, ConfigDict, field_validator
class ResultInfo(BaseModel):
bounding_box_left_up: list[int] | None = []
bounding_box_right_down: list[int] | None = []
text: str | None = None
confidence: float | None = None
model_config = ConfigDict(from_attributes=True)
class ResultMain(BaseModel):
file_name: str | None = None
infos: list[ResultInfo] | None = []
model_config = ConfigDict(from_attributes=True)

17
utils/opencv_util.py Normal file
View File

@@ -0,0 +1,17 @@
# 增强对比度 + 灰度转换 + 自适应阈值
import cv2
img = cv2.imread("fb1df265-5085-4bc2-881b-7674b620c4ac.jpg")
# 转灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 提升对比度
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
enhanced = clahe.apply(gray)
# 二值化处理
binary = cv2.adaptiveThreshold(enhanced, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 2)
cv2.imwrite("processed.png", binary)

39
utils/os_utils.py Normal file
View File

@@ -0,0 +1,39 @@
import os
from fastapi import UploadFile
def file_path(*path):
"""
拼接返回文件路径
:param path:
:return:
"""
return_path = os.path.join(*path)
return return_path
def create_folder(*path):
"""根据路径创建文件夹"""
folder_path = os.path.join(*path)
try:
os.makedirs(folder_path, exist_ok=True)
except Exception as e:
print(f"创建文件夹时错误: {e}")
return folder_path
def save_images(*path, file: UploadFile):
"""
保存上传的图片
:param path: 路径
:param file: 文件
:return:
"""
save_path = os.path.join(*path, file.filename)
os.makedirs(os.path.dirname(save_path), exist_ok=True)
with open(save_path, "wb") as f:
for line in file.file:
f.write(line)
return save_path

11
utils/pillow_util.py Normal file
View File

@@ -0,0 +1,11 @@
from PIL import Image, ImageEnhance
# 加载图片
img = Image.open("fb1df265-5085-4bc2-881b-7674b620c4ac.jpg")
# 增强对比度1.5 倍为示例,你可以调节参数)
enhancer = ImageEnhance.Contrast(img)
img_enhanced = enhancer.enhance(4.0)
# 保存增强后的图像
img_enhanced.save("enhanced_image_pillow.png")