FIRST
Browse files- app.py +106 -0
- requirements.txt +7 -0
- stripeRemover.py +121 -0
app.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import cv2
|
| 3 |
+
import numpy as np
|
| 4 |
+
import aiohttp
|
| 5 |
+
import asyncio
|
| 6 |
+
from stripeRemover import StripeRemover
|
| 7 |
+
|
| 8 |
+
class OCRUI:
|
| 9 |
+
def __init__(self):
|
| 10 |
+
self.API_URL = "http://s15.serv00.com:9081/compareAnalyze"
|
| 11 |
+
self.stripe_remover = StripeRemover()
|
| 12 |
+
|
| 13 |
+
def process_image(self, image, method):
|
| 14 |
+
if image is None:
|
| 15 |
+
return None
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
if method == "Original":
|
| 19 |
+
return cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
|
| 20 |
+
elif method == "Fourier":
|
| 21 |
+
return self.stripe_remover.fourier_method(image)
|
| 22 |
+
elif method == "Morphological":
|
| 23 |
+
return self.stripe_remover.morphological_method(image)
|
| 24 |
+
elif method == "Adaptive":
|
| 25 |
+
return self.stripe_remover.adaptive_threshold_method(image)
|
| 26 |
+
elif method == "Enhanced":
|
| 27 |
+
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
|
| 28 |
+
return self.stripe_remover.enhance_image(gray)
|
| 29 |
+
except Exception as e:
|
| 30 |
+
return None
|
| 31 |
+
|
| 32 |
+
async def send_to_api(self, image_bytes):
|
| 33 |
+
async with aiohttp.ClientSession() as session:
|
| 34 |
+
data = aiohttp.FormData()
|
| 35 |
+
data.add_field('image', image_bytes,
|
| 36 |
+
filename='image.jpg',
|
| 37 |
+
content_type='image/jpeg')
|
| 38 |
+
data.add_field('model', 'GEMINI')
|
| 39 |
+
|
| 40 |
+
try:
|
| 41 |
+
async with session.post(self.API_URL, data=data) as response:
|
| 42 |
+
return await response.json()
|
| 43 |
+
except Exception as e:
|
| 44 |
+
return {"error": str(e)}
|
| 45 |
+
|
| 46 |
+
def ocr_process(self, image, task, preprocess_method):
|
| 47 |
+
if image is None:
|
| 48 |
+
return "Please upload an image", "No image provided"
|
| 49 |
+
|
| 50 |
+
# Preprocess image
|
| 51 |
+
processed_img = self.process_image(image, preprocess_method)
|
| 52 |
+
if processed_img is None:
|
| 53 |
+
return "Image processing failed", "Processing error"
|
| 54 |
+
|
| 55 |
+
# Prepare image for API
|
| 56 |
+
encode_params = [cv2.IMWRITE_JPEG_QUALITY, 50]
|
| 57 |
+
_, img_bytes = cv2.imencode('.jpg', processed_img, encode_params)
|
| 58 |
+
|
| 59 |
+
# Call API
|
| 60 |
+
result = asyncio.run(self.send_to_api(img_bytes.tobytes()))
|
| 61 |
+
|
| 62 |
+
if result is None or "error" in result:
|
| 63 |
+
return "API call failed", "Error calling OCR service"
|
| 64 |
+
|
| 65 |
+
# Format results
|
| 66 |
+
text_output = f"Task: {task}\nResults:\n{str(result)}"
|
| 67 |
+
html_output = f"<pre>{text_output}</pre>"
|
| 68 |
+
|
| 69 |
+
return text_output, html_output
|
| 70 |
+
|
| 71 |
+
def create_ui():
|
| 72 |
+
ui = OCRUI()
|
| 73 |
+
|
| 74 |
+
with gr.Blocks() as demo:
|
| 75 |
+
gr.Markdown("# 美宜佳DEMO")
|
| 76 |
+
|
| 77 |
+
with gr.Row():
|
| 78 |
+
with gr.Column():
|
| 79 |
+
image_input = gr.Image(type="numpy", label="Input Image")
|
| 80 |
+
preprocess_dropdown = gr.Dropdown(
|
| 81 |
+
choices=["Original", "Fourier", "Morphological", "Adaptive", "Enhanced"],
|
| 82 |
+
label="Preprocessing Method",
|
| 83 |
+
value="Original"
|
| 84 |
+
)
|
| 85 |
+
task_dropdown = gr.Dropdown(
|
| 86 |
+
choices=["Plain OCR", "Format OCR", "Box OCR"],
|
| 87 |
+
label="OCR Task",
|
| 88 |
+
value="Plain OCR"
|
| 89 |
+
)
|
| 90 |
+
process_btn = gr.Button("Process Image")
|
| 91 |
+
|
| 92 |
+
with gr.Column():
|
| 93 |
+
text_output = gr.Textbox(label="OCR Results")
|
| 94 |
+
html_output = gr.HTML(label="Formatted Results")
|
| 95 |
+
|
| 96 |
+
process_btn.click(
|
| 97 |
+
fn=ui.ocr_process,
|
| 98 |
+
inputs=[image_input, task_dropdown, preprocess_dropdown],
|
| 99 |
+
outputs=[text_output, html_output]
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
return demo
|
| 103 |
+
|
| 104 |
+
if __name__ == "__main__":
|
| 105 |
+
demo = create_ui()
|
| 106 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, share=True)
|
requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit>=1.0.0
|
| 2 |
+
torch>=1.8.0
|
| 3 |
+
opencv-python>=4.5.0
|
| 4 |
+
matplotlib>=3.3.0
|
| 5 |
+
numpy>=1.19.0
|
| 6 |
+
aiohttp>=3.8.0
|
| 7 |
+
typing-extensions>=4.0.0
|
stripeRemover.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import cv2
|
| 2 |
+
import numpy as np
|
| 3 |
+
|
| 4 |
+
class StripeRemover:
|
| 5 |
+
def __init__(self):
|
| 6 |
+
pass
|
| 7 |
+
|
| 8 |
+
def fourier_method(self, image):
|
| 9 |
+
"""傅里叶变换去除条纹"""
|
| 10 |
+
# 转换为灰度图像
|
| 11 |
+
if len(image.shape) > 2:
|
| 12 |
+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
| 13 |
+
else:
|
| 14 |
+
gray = image.copy()
|
| 15 |
+
|
| 16 |
+
# 傅里叶变换
|
| 17 |
+
dft = cv2.dft(np.float32(gray), flags=cv2.DFT_COMPLEX_OUTPUT)
|
| 18 |
+
dft_shift = np.fft.fftshift(dft)
|
| 19 |
+
|
| 20 |
+
# 创建掩模
|
| 21 |
+
rows, cols = gray.shape
|
| 22 |
+
crow, ccol = rows // 2, cols // 2
|
| 23 |
+
mask = np.ones((rows, cols, 2), np.uint8)
|
| 24 |
+
mask[crow-5:crow+5, :] = 0 # 调整带宽以匹配条纹频率
|
| 25 |
+
|
| 26 |
+
# 应用掩模和逆变换
|
| 27 |
+
fshift = dft_shift * mask
|
| 28 |
+
f_ishift = np.fft.ifftshift(fshift)
|
| 29 |
+
img_back = cv2.idft(f_ishift)
|
| 30 |
+
img_back = cv2.magnitude(img_back[:,:,0], img_back[:,:,1])
|
| 31 |
+
|
| 32 |
+
# 归一化处理
|
| 33 |
+
img_back = cv2.normalize(img_back, None, 0, 255, cv2.NORM_MINMAX)
|
| 34 |
+
return np.uint8(img_back)
|
| 35 |
+
|
| 36 |
+
def morphological_method(self, image):
|
| 37 |
+
"""形态学操作去除条纹"""
|
| 38 |
+
# Convert to grayscale if needed
|
| 39 |
+
if len(image.shape) > 2:
|
| 40 |
+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
| 41 |
+
else:
|
| 42 |
+
gray = image.copy()
|
| 43 |
+
|
| 44 |
+
# Create horizontal kernel (adjust size if needed)
|
| 45 |
+
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1))
|
| 46 |
+
|
| 47 |
+
# Detect lines using morphological operations
|
| 48 |
+
detected_lines = cv2.morphologyEx(gray, cv2.MORPH_OPEN, horizontal_kernel)
|
| 49 |
+
|
| 50 |
+
# Remove detected lines and normalize
|
| 51 |
+
result = cv2.subtract(gray, detected_lines)
|
| 52 |
+
|
| 53 |
+
# Normalize and enhance contrast
|
| 54 |
+
result = cv2.normalize(result, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
|
| 55 |
+
|
| 56 |
+
# Convert back to BGR for display
|
| 57 |
+
return cv2.cvtColor(result, cv2.COLOR_GRAY2BGR)
|
| 58 |
+
|
| 59 |
+
def adaptive_threshold_method(self, image):
|
| 60 |
+
"""自适应阈值处理"""
|
| 61 |
+
if len(image.shape) > 2:
|
| 62 |
+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
| 63 |
+
else:
|
| 64 |
+
gray = image.copy()
|
| 65 |
+
|
| 66 |
+
# 自适应阈值处理
|
| 67 |
+
thresh = cv2.adaptiveThreshold(gray, 255,
|
| 68 |
+
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
|
| 69 |
+
cv2.THRESH_BINARY, 11, 2)
|
| 70 |
+
|
| 71 |
+
# 中值滤波去噪
|
| 72 |
+
result = cv2.medianBlur(thresh, 3)
|
| 73 |
+
return result
|
| 74 |
+
|
| 75 |
+
def enhance_image(self, image):
|
| 76 |
+
"""图像增强处理"""
|
| 77 |
+
# CLAHE对比度增强
|
| 78 |
+
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
|
| 79 |
+
enhanced = clahe.apply(image)
|
| 80 |
+
|
| 81 |
+
# 锐化处理
|
| 82 |
+
kernel = np.array([[-1,-1,-1],
|
| 83 |
+
[-1, 9,-1],
|
| 84 |
+
[-1,-1,-1]])
|
| 85 |
+
sharpened = cv2.filter2D(enhanced, -1, kernel)
|
| 86 |
+
|
| 87 |
+
return sharpened
|
| 88 |
+
|
| 89 |
+
def adaptive_enhance(self, image):
|
| 90 |
+
"""自适应阈值 + 图像增强"""
|
| 91 |
+
thresh_result = self.adaptive_threshold_method(image)
|
| 92 |
+
return self.enhance_image(thresh_result)
|
| 93 |
+
|
| 94 |
+
def fourier_enhance(self, image):
|
| 95 |
+
"""傅里叶变换 + 图像增强"""
|
| 96 |
+
fourier_result = self.fourier_method(image)
|
| 97 |
+
return self.enhance_image(fourier_result)
|
| 98 |
+
|
| 99 |
+
def morphological_enhance(self, image):
|
| 100 |
+
"""形态学操作 + 图像增强"""
|
| 101 |
+
morph_result = self.morphological_method(image)
|
| 102 |
+
# Convert BGR to gray for enhance_image
|
| 103 |
+
gray = cv2.cvtColor(morph_result, cv2.COLOR_BGR2GRAY)
|
| 104 |
+
enhanced = self.enhance_image(gray)
|
| 105 |
+
return cv2.cvtColor(enhanced, cv2.COLOR_GRAY2BGR)
|
| 106 |
+
|
| 107 |
+
def adaptive_fourier(self, image):
|
| 108 |
+
"""自适应阈值 + 傅里叶变换"""
|
| 109 |
+
thresh_result = self.adaptive_threshold_method(image)
|
| 110 |
+
return self.fourier_method(thresh_result)
|
| 111 |
+
|
| 112 |
+
def morphological_adaptive(self, image):
|
| 113 |
+
"""形态学操作 + 自适应阈值"""
|
| 114 |
+
morph_result = self.morphological_method(image)
|
| 115 |
+
gray = cv2.cvtColor(morph_result, cv2.COLOR_BGR2GRAY)
|
| 116 |
+
return self.adaptive_threshold_method(gray)
|
| 117 |
+
|
| 118 |
+
def fourier_morphological(self, image):
|
| 119 |
+
"""傅里叶变换 + 形态学操作"""
|
| 120 |
+
fourier_result = self.fourier_method(image)
|
| 121 |
+
return self.morphological_method(fourier_result)
|