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
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83087.shtml
英文地址,請注明出處:http://en.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&…