C# 结合PaddleOCRSharp搭建Http网络服务

Windows打开端口:
控制面板 > 系统和安全 > 防火墙> 高级设置 → 入站规则 → 右侧选择 → 新建规则 → 端口 → 协议类型 TCP→ 端口

using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Linq;
using PaddleOCRSharp;
using HttpMultipartParser;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Drawing.Imaging;
using OpenCvSharp;
using System.Net.Http;class Program
{static void Main(string[] args){//string remoteUrl = "http://10.50.7.210:9011/profile/upload/2025/05/21/image_20250521093746A004.jpg";// curl "http://localhost:8082/image-ocr?templateCode=abc123&path=E://3.png"// 打开端口:控制面板 > 系统和安全 >  防火墙> 高级设置 → 入站规则 → 右侧选择 → 新建规则 → 端口  → 协议类型 TCP→ 端口string baseUrl = "http://127.0.0.1:8082/image-ocr/";//string baseUrl = "http://*:8082/image-ocr/";var server = new OCRHttpServer(baseUrl);Console.CancelKeyPress += (sender, e) =>{e.Cancel = true;server.Stop();};server.Start();Console.WriteLine("Press CTRL+C to stop the server...");Console.WriteLine("curl \"http://localhost:8082/image-ocr?templateCode=n&path=imagePath\"");while (true){Thread.Sleep(100);}}}class OCRHttpServer
{private readonly HttpListener _listener;private readonly string _baseUrl;private PaddleOCREngine engine;private PaddleStructureEngine structengine;public OCRHttpServer(string baseUrl){_baseUrl = baseUrl;_listener = new HttpListener();_listener.Prefixes.Add(baseUrl);}public void OCRModel_Load(){string outpath = Path.Combine(Environment.CurrentDirectory, "out");if (!Directory.Exists(outpath)){ Directory.CreateDirectory(outpath); }自带轻量版中英文模型V3模型//OCRModelConfig config = null;//服务器中英文模型//OCRModelConfig config = new OCRModelConfig();//string root = System.IO.Path.GetDirectoryName(typeof(OCRModelConfig).Assembly.Location);//string modelPathroot = root + @"\inferenceserver";//config.det_infer = modelPathroot + @"\ch_ppocr_server_v2.0_det_infer";//config.cls_infer = modelPathroot + @"\ch_ppocr_mobile_v2.0_cls_infer";//config.rec_infer = modelPathroot + @"\ch_ppocr_server_v2.0_rec_infer";//config.keys = modelPathroot + @"\ppocr_keys.txt";//英文和数字模型V3OCRModelConfig config = new OCRModelConfig();string root = System.IO.Path.GetDirectoryName(typeof(OCRModelConfig).Assembly.Location);string modelPathroot = root + @"\en_v3";config.det_infer = modelPathroot + @"\en_PP-OCRv3_det_infer";config.cls_infer = modelPathroot + @"\ch_ppocr_mobile_v2.0_cls_infer";config.rec_infer = modelPathroot + @"\en_PP-OCRv3_rec_infer";config.keys = modelPathroot + @"\en_dict.txt";//OCR参数OCRParameter oCRParameter = new OCRParameter();oCRParameter.cpu_math_library_num_threads = 10;//预测并发线程数oCRParameter.enable_mkldnn = true;//web部署该值建议设置为0,否则出错,内存如果使用很大,建议该值也设置为0.oCRParameter.cls = false; //是否执行文字方向分类;默认falseoCRParameter.det = true;//是否开启方向检测,用于检测识别180旋转oCRParameter.use_angle_cls = false;//是否开启方向检测,用于检测识别180旋转oCRParameter.det_db_score_mode = true;//是否使用多段线,即文字区域是用多段线还是用矩形,//初始化OCR引擎engine = new PaddleOCREngine(config, oCRParameter);Console.Clear();//模型配置,使用默认值StructureModelConfig structureModelConfig = null;//表格识别参数配置,使用默认值StructureParameter structureParameter = new StructureParameter();structengine = new PaddleStructureEngine(structureModelConfig, structureParameter);Console.Clear();}public void Start(){_listener.Start();Console.WriteLine($"Server started at {_baseUrl}");OCRModel_Load();ThreadPool.QueueUserWorkItem((o) =>{try{while (_listener.IsListening){ThreadPool.QueueUserWorkItem((contextState) =>{var context = (HttpListenerContext)contextState;try{HandleRequest(context);}catch (Exception ex){Console.WriteLine($"Error handling request: {ex.Message}");SendErrorResponse(context, 500, "Internal Server Error");}finally{context.Response.Close();}}, _listener.GetContext());}}catch (Exception ex){Console.WriteLine($"Server error: {ex.Message}");}});}public void Stop(){_listener.Stop();_listener.Close();Console.WriteLine("Server stopped");}private void HandleRequest(HttpListenerContext context){HttpListenerRequest request = context.Request;HttpListenerResponse response = context.Response;if (request.HttpMethod == "POST"){HandlePostRequest(request, response);}else if (request.HttpMethod == "GET"){HandleGetRequest(request, response);}else{SendError(response, "Unsupported HTTP method");}response.OutputStream.Close();}private string HandleImageOCRRequest(string imagePath){string jsonResponse = string.Empty;try{if (string.IsNullOrEmpty(imagePath)){// 返回成功响应var response = new{Status = "Error",Message = "",ReceivedAt = DateTime.Now};jsonResponse = JsonSerializer.Serialize(response);return jsonResponse;}jsonResponse = ProgressImage(imagePath);return jsonResponse;}catch (Exception ex){Console.WriteLine($"Error processing string: {ex}");var response = new{Status = "Error",Message = "",ReceivedAt = DateTime.Now};jsonResponse = JsonSerializer.Serialize(response);return jsonResponse;}}//用OpenCV实现分块检测private string ProgressImage(string imagePath){string jsonResponse = string.Empty;string message = string.Empty;using (Mat src = Cv2.ImRead(imagePath, ImreadModes.Color)){if (src.Empty())throw new Exception("无法加载图像");Mat gray = new Mat();Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);//图片边缘裁掉多少像素的边缘int gap = 5;int height = src.Rows;int width = src.Cols;// 创建掩膜(矩形区域)Mat mask = new Mat(height, width, MatType.CV_8UC1, Scalar.All(0));Rect rectROI = new Rect(gap, gap, width - gap * 2, height - gap * 2);Mat roiMask = new Mat(mask, rectROI);roiMask.SetTo(Scalar.All(255));// 阈值分割Mat thresh = new Mat();Cv2.Threshold(gray, thresh, 254, 255, ThresholdTypes.Binary);// 与掩膜进行 AND 操作Mat maskedThresh = new Mat();Cv2.BitwiseAnd(thresh, mask, maskedThresh);// 填充孔洞Mat filled = new Mat();maskedThresh.CopyTo(filled);// 创建FloodFill所需的mask(比原图大2像素)Mat floodFillMask = new Mat(filled.Rows + 2, filled.Cols + 2, MatType.CV_8UC1, Scalar.All(0));// 执行floodfill从边界开始填充背景Cv2.FloodFill(filled, floodFillMask, new OpenCvSharp.Point(0, 0), new Scalar(255),out Rect rect,new Scalar(), new Scalar(),FloodFillFlags.Link8);// 反转图像以获取填充后的对象Cv2.BitwiseNot(filled, filled);// 查找轮廓(相当于连接区域)OpenCvSharp.Point[][] contours;HierarchyIndex[] hierarchy;Cv2.FindContours(filled, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);Console.WriteLine(imagePath);// 遍历每个轮廓for (int i = 0; i < contours.Length; i++){Rect boundingRect = Cv2.BoundingRect(contours[i]);// 裁剪图像Mat cropped = new Mat(src, boundingRect);// 保存裁剪图像到临时路径string tempImagePath = Path.Combine("E:/File/", $"{i + 1}.png");Cv2.ImWrite(tempImagePath, cropped);// 转换为 byte[]byte[] imageBytes = cropped.ToBytes();// OCR 识别OCRResult ocrResult = engine.DetectText(imageBytes); // 假设 engine 是已初始化的 OCR 引擎string outMessage = "";string printMessage = "";foreach (var item in ocrResult.TextBlocks){string input = item.ToString(); // 根据实际结构调整var idMatch = Regex.Match(input, @"^([^,]+)");string text = idMatch.Success ? idMatch.Groups[1].Value.Trim() : "";var coordinatesMatch = Regex.Match(input, @"\[(\([^)]*\)(?:,\([^)]*\))*)\]");string coordsStr = coordinatesMatch.Success ? coordinatesMatch.Groups[1].Value.Trim() : "";outMessage += text + ":" + coordsStr + ";";printMessage += text + "    ";}message += $"Rectangle{i + 1}:{{{outMessage}}}";Console.WriteLine($"Rectangle {i+1}");Console.WriteLine($"OCR Result: {printMessage}");}}// 14. 返回 JSON 结果var response = new{Status = "Success",Message = message,ReceivedAt = DateTime.Now};jsonResponse = JsonSerializer.Serialize(response);return jsonResponse;}// 处理 GET 请求,解析 query string 中的 templateCode 和 pathprivate void HandleGetRequest(HttpListenerRequest request, HttpListenerResponse response){// 使用 HttpUtility.ParseQueryString 来解析查询字符串Uri url = request.Url;if (url == null){SendError(response, "Invalid request URL");return;}NameValueCollection queryParams = System.Web.HttpUtility.ParseQueryString(url.Query);string templateCode = queryParams["templateCode"];string path = queryParams["path"];if (string.IsNullOrEmpty(templateCode) || string.IsNullOrEmpty(path)){SendError(response, "Missing required parameters: templateCode and path");return;}string responseBody = "";responseBody = HandleImageOCRRequest(path);byte[] buffer = Encoding.UTF8.GetBytes(responseBody);response.ContentType = "text/plain";response.ContentLength64 = buffer.Length;response.OutputStream.Write(buffer, 0, buffer.Length);}// 处理 POST multipart/form-data 文件上传private void HandlePostRequest(HttpListenerRequest request, HttpListenerResponse response){string boundary = request.ContentType?.Split('=')[1];if (string.IsNullOrEmpty(boundary)){SendError(response, "Invalid Content-Type");return;}using (Stream input = request.InputStream){Encoding encoding = Encoding.UTF8;string formData = ReadMultipartFormData(input, encoding, boundary);string responseBody = $"Received POST:\nFile Content:\n{formData}";byte[] buffer = encoding.GetBytes(responseBody);response.ContentType = "text/plain";response.ContentLength64 = buffer.Length;response.OutputStream.Write(buffer, 0, buffer.Length);}}// 发送错误信息private void SendError(HttpListenerResponse response, string message){byte[] buffer = Encoding.UTF8.GetBytes(message);response.StatusCode = (int)HttpStatusCode.BadRequest;response.ContentType = "text/plain";response.ContentLength64 = buffer.Length;response.OutputStream.Write(buffer, 0, buffer.Length);}// 读取 multipart/form-data 内容private string ReadMultipartFormData(Stream inputStream, Encoding encoding, string boundary){StreamReader reader = new StreamReader(inputStream, encoding);string boundaryLine;StringBuilder result = new StringBuilder();while ((boundaryLine = reader.ReadLine()) != null){if (boundaryLine.Contains(boundary)) continue;// 跳过 headersstring line;while (!(string.IsNullOrEmpty(line = reader.ReadLine()))) { }// Read content until next boundarystring content;while ((content = reader.ReadLine()) != null && !content.Contains(boundary)){result.AppendLine(content);}break; // 只处理第一个 part}return result.ToString().Trim();}private void SendResponse(HttpListenerContext context, string responseString){try{byte[] buffer = Encoding.UTF8.GetBytes(responseString);context.Response.ContentLength64 = buffer.Length;context.Response.OutputStream.Write(buffer, 0, buffer.Length);}catch (Exception){}}private void SendErrorResponse(HttpListenerContext context, int statusCode, string message){context.Response.StatusCode = statusCode;SendResponse(context, message);}
}

起服务后:
在这里插入图片描述
测试:

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文精读】2024 ECCV--MGLD-VSR现实世界视频超分辨率(RealWorld VSR)

文章目录 一、摘要二、问题三、Method3.1 Latent Diffusion Model3.2 Motion-guided Diffusion Sampling3.3 Temporal-aware Decoder Fine-tuning 四、实验设置4.1 训练阶段4.2 训练数据 贡献总结 论文全称&#xff1a; Motion-Guided Latent Diffusion for Temporally Consis…

初学c语言21(文件操作)

一.为什么使用文件 之前我们写的程序的数据都是存储到内存里面的&#xff0c;当程序结束时&#xff0c;内存回收&#xff0c;数据丢失&#xff0c; 再次运行程序时&#xff0c;就看不到上次程序的数据&#xff0c;如果要程序的数据一直保存得使用文件 二.文件 文件一般可以…

历年厦门大学计算机保研上机真题

2025厦门大学计算机保研上机真题 2024厦门大学计算机保研上机真题 2023厦门大学计算机保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/school 数字变换过程的最大值与步数 题目描述 输入一个数字 n n n&#xff0c;如果 n n n 是偶数就将该偶数除以 2 2 2&…

MySql--定义表存储引擎、字符集和排序规则

示例&#xff1a; CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,email VARCHAR(100) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;注意事项&#xff1a; 字符集和排序规则可以按列覆盖表…

深耕数字化赛道,联众优车以创新风控体系构筑汽车金融护城河

近年来&#xff0c;在汽车金融市场规模持续扩大的行业背景下&#xff0c;企业风险管理能力已成为决定市场竞争格局的关键要素。面对快速扩张的市场需求&#xff0c;银保监会2024年发布的《汽车金融公司监管评级办法》明确要求行业强化风控能力建设&#xff0c;央行《金融科技发…

第十九章 正则表达式

第十九章 正则表达式 文本型数据在所有的类UNIX系统(如 Linux)中会扮演着重要角色&#xff0c;在完全领会这些工具的全部特征之前&#xff0c;要先了解一下工具最为复杂的用法和相关技术&#xff1a;正则表达式。 什么是正则表达式 简单地说&#xff0c;正则表达式是一种用于…

内存监控方法与要点详解

引言 在软件性能测试领域&#xff0c;内存管理是评估系统稳定性和性能的关键指标之一。作为软件测试工程师&#xff0c;我们经常遇到因内存泄漏、内存溢出等问题导致的系统崩溃或性能下降。本文将深入探讨性能测试中内存监控的方法和要点&#xff0c;帮助测试团队更有效地识别…

56、Ocelot 概述

Ocelot 是一个基于 .NET Core 开发的开源 API 网关&#xff0c;主要用于微服务架构中&#xff0c;为多个后端服务提供统一的访问入口。它通过集中化管理请求路由、认证、限流、负载均衡等功能&#xff0c;简化了客户端与后端服务之间的交互&#xff0c;同时增强了系统的安全性和…

如何将多张图组合到一张图里同时保留高的分辨率(用PPT+AdobeAcrobat)

文章目录 一、用PPT排版得到一页排布了很多图片的PPT二、用AdobeAcrobat打开pdf文件三、最后得到的图片 一、用PPT排版得到一页排布了很多图片的PPT 步骤如下 ①将幻灯片大小的长设置为17.2&#xff0c;宽根据图像多少进行调整&#xff0c;我这里是10 幻灯片大小的长设置步骤&…

【Web应用】若依框架:基础篇12 项目结构

文章目录 ⭐前言⭐一、课程讲解&#x1f31f;1、寻找合适的对象✨1) ⭐二、怎样选择设计模式&#xff1f;&#x1f31f;1、寻找合适的对象✨1) ⭐三、怎样使用设计模式&#xff1f;&#x1f31f;1、寻找合适的对象✨1) ⭐总结 标题详情作者JosieBook头衔CSDN博客专家资格、阿里…

SolidWorks 文件打开时电脑卡顿问题分析与解决

最近遇到一个问题就是我点击solid work的文件的时候会将电脑卡住然后电脑开始飞速的加载内存&#xff0c;鼠标移动很卡顿 解决办法&#xff1a; 1.找到资源管理器 当遇到这种情况时&#xff0c;可以尝试通过资源管理器来解决问题。首先&#xff0c;找到任务管理器&#xff08…

更新密码--二阶注入攻击的原理

1.原理知识&#xff1a; 二阶SQL注入攻击&#xff08;Second-Order SQL Injection&#xff09;原理详解 一、基本概念 二阶注入是一种"存储型"SQL注入&#xff0c;攻击流程分为两个阶段&#xff1a; ​​首次输入​​&#xff1a;攻击者将恶意SQL片段存入数据库​…

在 WSL Ubuntu-24.04 上安装 Nacos 2.5.1 并使用 MySQL 数据库

在微服务架构中&#xff0c;Nacos 是一个非常重要的服务发现和配置管理工具。本文将详细介绍如何在 WSL&#xff08;Windows Subsystem for Linux&#xff09;中的 Ubuntu-24.04 系统上安装 Nacos 2.5.1&#xff0c;并将其配置为使用 MySQL 数据库进行数据存储。我们将使用 roo…

2.qml使用c++

目录 1.概述2.注册方式3. 分类①枚举类②工具类③数据类④资源类②视图类 1.概述 qml是用来干嘛的&#xff1f; 当然是提高UI开发效率的 为什么要混合C&#xff1f; 因为qml无法处理密集型数据逻辑 而加入c则兼顾了性能 达到11>2 总结就是 qml 开发UI, C 实现逻辑 而js的用…

位置规划模式和周期同步位置模式区别

专业方向&#xff1a; 伺服电机位置控制模式&#xff08;电气自动化&#xff09; 标题解释 位置规划模式&#xff08;Profile Position Mode&#xff0c;PP&#xff09;和周期同步位置模式&#xff08;Cyclic Synchronous Position Mode&#xff0c;CSP&#xff09;区别。 常规…

C# ToString格式说明符

货币 "C"或"c" //C Console.WriteLine(666.ToString("C"));//&#xffe5;666.00//C数字 表示保留几位小数精度 Console.WriteLine(666.ToString("C1"));//&#xffe5;666.0 Console.WriteLine(666.ToString("C3"));//&…

基本数据指针的解读-C++

1、引言 笔者认为对于学习指针要弄清楚如下问题基本可以应付大部分的场景&#xff1a; ① 指针是什么&#xff1f; ② 指针的类型是什么&#xff1f; ③ 指针指向的类型是什么&#xff1f; ④ 指针指向了哪里&#xff1f; 2、如何使用指针 使用时的步骤如下&#xff1a; ① …

【Elasticsearch】suggest_mode

suggest_mode 是 Elasticsearch 中 term suggester 和 phrase suggester 的一个参数&#xff0c;用于控制建议的生成方式。它有以下三种模式&#xff1a; 1. missing&#xff1a;默认值。仅对索引中不存在的词项提供建议。如果输入的词已经在索引中存在&#xff0c;则不会生成建…

九、【前后端联调篇】Vue3 + Axios 异步通信实战

九、【前后端联调篇】Vue3 Axios 异步通信实战 前言准备工作第一步&#xff1a;安装 Axios第二步&#xff1a;封装 Axios 实例第三步&#xff1a;创建 API 服务模块第四步&#xff1a;在组件中调用 API第五步&#xff1a;测试前后端联调 总结 前言 在 Web 开发中&#xff0c;…

【计算机网络】传输层TCP协议——协议段格式、三次握手四次挥手、超时重传、滑动窗口、流量控制、

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;计算机网络 &#x1f339;往期回顾&#x1f339;&#xff1a; 【计算机网络】传输层UDP协议 &#x1f516;流水不争&#xff0c;争的是滔滔不息 一、TCP协议 UDP&…