HotPDF ทำ OCR ภาษาจีนและหลายภาษาใน Delphi ผ่าน adapter ฝั่ง RapidOCR DLL native: THPDFRapidOCRDLLOptions.ForLanguage แมป tag ภาษาอย่าง 'zh-CN', 'zh-TW', 'ru' หรือ 'ar' ไปยัง model ฝั่ง recognition กับ character dictionary ที่จับคู่กัน และ THotPDF.ApplyLoadedOCRTextLayer เปลี่ยนบรรทัดที่จดจำได้ให้เป็น text layer Unicode มองไม่เห็นที่ค้นหาได้บนหน้า PDF ที่สแกน
ทำดีโมอักษรลาตินให้รันได้เป็นส่วนง่าย ความพังที่น่าสนใจเริ่มเมื่อคุณสลับไปจีนตัวเต็มหรือรัสเซียแล้ว output กลายเป็นตัวอักษรมั่วที่มั่นใจสุดขีดและมีรูปร่างดูดี หรือเมื่อทุกบรรทัดเงียบ ๆ เสียอักขระตัวสุดท้ายไป หรือเมื่อหน้าอาหรับกลับมาพร้อม text box เรียงผิดลำดับ ทั้งหมดนี้ไม่ raise exception เองสักอย่าง preset ภาษาที่เพิ่มใน HotPDF v2.775.0 มีอยู่เพื่อปิดช่องว่างพวกนี้เป็นหลัก และกับดักสี่ตัวด้านล่างควรค่าแก่การเข้าใจแม้คุณจะไม่แตะโค้ด native เลย เพราะแต่ละตัวอธิบายอาการที่ไม่งั้นคุณต้องไล่กันเป็นวัน
ForLanguage เลือก model กับ dictionary อย่างไร
THPDFRapidOCRDLLOptions.ForLanguage resolve tag ไปยังหนึ่งในเก้าโปรไฟล์ แล้วคืน options ที่ชี้ไปที่ <profile>/recognition.onnx กับ <profile>/dictionary.txt ใต้ไดเรกทอรี model ของคุณ ขณะที่คง detector ที่ใช้ร่วมกัน, angle classifier แบบเลือกได้ และค่าเริ่มต้นของ thread, pixel กับ timeout จาก THPDFRapidOCRDLLOptions.Default เมธอดจะแปลง tag เป็นตัวพิมพ์เล็ก เปลี่ยน underscore เป็น hyphen และตัดช่องว่างรอบ ๆ 'zh_TW', 'ZH-tw' กับ ' zh-tw ' จึงตกลงที่โปรไฟล์เดียวกัน alias เป็นรายการชัดเจน ไม่ใช่การ match ด้วย prefix 'zh-Hant-TW' ถูกยอมรับเพราะอยู่ในรายการ ขณะที่เวอร์ชันภูมิภาคมั่ว ๆ ที่ไม่อยู่ในรายการ raise EArgumentException ก่อน model ตัวใดจะถูกโหลด
| โปรไฟล์ | ภาษา | ตัวอย่าง tag | model ที่ตรึงไว้ |
|---|---|---|---|
ch | จีนตัวย่อและอังกฤษ | zh, zh-CN, zh-Hans, chi_sim | PP-OCRv4 |
chinese_cht | จีนตัวเต็ม | zh-TW, zh-HK, zh-Hant, chi_tra | PP-OCRv3 |
en | อังกฤษ | en, en-US, en-GB, eng | PP-OCRv4 |
latin | ฝรั่งเศส เยอรมัน สเปน โปรตุเกส อิตาลี ดัตช์ ตุรกี | fr, de, es-419, pt-BR, tr | PP-OCRv3 |
japan | ญี่ปุ่น | ja, ja-JP, jpn | PP-OCRv4 |
korean | เกาหลี | ko, ko-KR, kor | PP-OCRv4 |
cyrillic | รัสเซีย ยูเครน บัลแกเรีย เบลารุส | ru, ru-RU, uk, bg | PP-OCRv3 |
arabic | อาหรับ เปอร์เซีย อูรดู | ar, ar-SA, fa, ur | PP-OCRv4 |
devanagari | ฮินดี มราฐี เนปาล | hi, mr, ne | PP-OCRv4 |
ตัว adapter เองไม่เคยดาวน์โหลดอะไรเลย คุณจัดหาไฟล์ครั้งเดียวด้วย helper ที่แถมมา อย่าง tools/Install-RapidOCRModels.ps1 -Destination C:/OCR/models -Language ch,chinese_cht,cyrillic (หรือ -Language All สำหรับทั้งเก้าโปรไฟล์) และ helper จะวาง detector กับ classifier ที่ใช้ร่วมกันไว้ที่ชื่อไฟล์รากที่ Default คาดหวัง หลังจากนั้นสแกนจีนตัวย่อกลายเป็นของที่ค้นหาได้ในไม่กี่บรรทัด ท่อประปาของ engine เป็น seam IHPDFOCREngine ชุดเดิมที่เล่าไว้ในบทความเรื่อง RapidOCR DLL แบบ in-process กับขอบเขต ABI ของมัน บทความนี้จึงโฟกัสที่ภาษาเฉย ๆ
uses
SysUtils, HPDFDoc, HPDFRapidOCRRecognition;
procedure MakeChineseScanSearchable(const SourceFile, TargetFile: string);
var
Doc: THotPDF;
Engine: IHPDFOCREngine;
Models: THPDFRapidOCRDLLOptions;
Layer: THPDFOCRTextLayerOptions;
Info: THPDFOCRTextLayerInfo;
begin
// ch/recognition.onnx + ch/dictionary.txt detector กับ classifier ใช้ร่วมกัน
Models := THPDFRapidOCRDLLOptions.ForLanguage('zh-CN');
Engine := HPDFCreateRapidOCRDLLOCREngine(
'C:\OCR\Win64\HotPDFRapidOCR.dll', 'C:\OCR\models', Models);
Doc := THotPDF.Create(nil);
try
Doc.AutoLaunch := False;
if Doc.LoadFromFile(SourceFile) < 1 then
raise Exception.Create('Cannot load ' + SourceFile);
Layer := THPDFOCRTextLayerOptions.Default; // 300 DPI, MinimumConfidence 0.5
// รายการหน้าว่างหมายถึงทุกหน้า หน้าที่มี text อยู่แล้วถูกข้าม
if not Doc.ApplyLoadedOCRTextLayer([], Engine, Layer, Info) then
raise Exception.Create(string(Info.Diagnostic));
Writeln(string(Info.EngineName), ': ', Info.AcceptedWordCount,
' lines, ', Info.UniqueScalarCount, ' distinct characters');
Doc.SaveLoadedDocument(TargetFile);
finally
Doc.Free;
end;
end;
รายละเอียดสองจุดใน output นั้นควรได้รับบันทึก pipeline ฝั่ง native คืนผลหนึ่งรายการต่อบรรทัดข้อความที่ detect เจอ ไม่ใช่ต่อคำ AcceptedWordCount จึงนับบรรทัดตรงนี้ และ MinimumConfidence ถูกเทียบกับความเชื่อมั่นเฉลี่ยของอักขระทั้งบรรทัด บรรทัดที่เฉลี่ย 0.45 จะถูกทิ้งเป็นชุดเดียว UniqueScalarCount รายงานว่า text layer ต้องแมปอักขระ Unicode ที่ต่างกันกี่ตัวเข้า font กับตาราง ToUnicode ของมัน ซึ่งเป็นเช็คสุขภาพจิตที่ดีว่า CJK จริง ๆ มาถึง ไม่ใช่ fallback ลาตินกองเล็ก ๆ คง interface ของ engine ไว้ข้ามเอกสาร เพราะการ initialize model เกิดใน factory และเป็นขั้นที่แพงที่สุด
ทำไมสลับแค่ model ฝั่ง recognition แล้วได้ตัวอักษรมั่ว
model แบบ CTC ฝั่ง recognition ไม่เคย output อักขระตรง ๆ มัน output แต่ index ของคลาส และ dictionary คือสิ่งเดียวที่เปลี่ยน index 1,204 ให้กลายเป็น glyph สลับ ch/recognition.onnx เป็น cyrillic/recognition.onnx แต่ยังใช้ dictionary จีนต่อ model จะยิง index ซีริลลิกที่ถูกต้องออกมาอย่างสบายใจ แล้ว dictionary ตัวเก่าแปลงมันเป็นอักษรฮันจื้อมั่ว ผลลัพธ์ดูเหมือนข้อความ ผ่านการตรวจ UTF-8 และค้นหาได้เป๊ะกับความว่างเปล่า นั่นเหตุผลที่ ForLanguage เซ็ต RecognitionModel กับ CharacterDictionary พร้อมกันเสมอ และ options ที่ปั้นเองไม่ควรเปลี่ยนข้างเดียวเด็ดขาด
เช็คความปลอดภัยที่คิดขึ้นมาง่ายที่สุดคือเทียบขนาดของ dictionary กับความกว้างของ output ของ model จำเป็นแต่ไม่พอ dictionary สองชุดมีจำนวน entry เท่ากันแต่เรียงคนละลำดับได้ และ off-by-one ในลำดับขยับทุกอักขระหลุดไปหนึ่ง code point HotPDF จึงตรวจสองชั้นตอน factory initialize model ขั้นแรก จำนวนคลาสของ output ต้องเท่ากับจำนวน entry ของ dictionary บวกสอง ขั้นที่สอง เมื่อไฟล์ ONNX ฝังรายการ metadata ชื่อ character มา ทุก entry ของ dictionary จะถูกเทียบกับมันทีละลำดับ และความไม่ตรงจะทำให้ initialize fail ด้วย EInvalidOperation พร้อม diagnostic ฝั่ง native แทนที่จะผลิตขยะที่ดูน่าเชื่อไว้ทีหลัง
"บวกสอง" มาจาก layout ของคลาส คลาส 0 คือ CTC blank คลาส 1 ถึง N คือบรรทัดของ dictionary ตามลำดับไฟล์ และคลาสสุดท้ายคือช่องว่าง dictionary บางชุดยังพา entry ของช่องว่างของตัวเองมาด้วย และบรรทัดนั้นต้องถูกเก็บไว้ตรงตามที่เป็น จุดนี้แหละที่ Trim ที่มีเจตนาดีทำร้ายงานจริง มันเปลี่ยน entry ที่เป็นช่องว่างตัวเดียวให้เป็น string ว่าง แล้วขยับหรือทำตารางพัง การ normalize ที่ปลอดภัยมีอย่างเดียวคือถอด carriage return ต่อท้ายออก dictionary ที่ save ด้วยการจบบรรทัดแบบ CRLF จึงโหลดได้ถูกต้อง ขณะที่ BOM ของ UTF-8, บรรทัดว่าง หรือ entry ที่มี tab จะถูกปฏิเสธ sketch ด้านล่างโชว์ layout นี้ใน Pascal มันเป็นโค้ดเพื่ออธิบาย ไม่ใช่ API ของ HotPDF
// เพื่อประกอบคำอธิบาย: ตารางคลาสที่ CTC recognizer คาดหวัง
uses
SysUtils, IOUtils;
function BuildCTCClassTable(const FileName: string): TArray<string>;
var
Text, Entry: string;
Lines: TArray<string>;
I, Last: Integer;
begin
Text := TEncoding.UTF8.GetString(TFile.ReadAllBytes(FileName));
if (Text <> '') and (Text[1] = #$FEFF) then
raise EArgumentException.Create('Dictionary must be UTF-8 without a BOM');
Lines := Text.Split([#10]);
Last := High(Lines);
if (Last >= 0) and (Lines[Last] = '') then
Dec(Last); // newline ตอนท้ายไฟล์
SetLength(Result, Last + 3);
Result[0] := ''; // class 0: CTC blank
for I := 0 to Last do
begin
Entry := Lines[I];
if (Entry <> '') and (Entry[Length(Entry)] = #13) then
SetLength(Entry, Length(Entry) - 1); // CRLF: ตัดแค่ CR ทิ้ง
if (Entry = '') or (Pos(#9, Entry) > 0) then
raise EArgumentException.Create('Invalid dictionary entry');
Result[I + 1] := Entry; // ห้าม Trim: ' ' เป็นคลาสหนึ่ง
end;
Result[Last + 2] := ' '; // คลาสสุดท้าย: space
// Length(Result) ต้องเท่ากับจำนวนคลาสของ output ของ model
end;
greedy CTC decoding ทำอะไรกันแน่
greedy CTC decoding หยิบคลาสที่ได้คะแนนสูงสุดที่ทุก time step ยุบการซ้ำติดกันให้เหลืออักขระเดียว แล้วทิ้งคลาส blank ไป ตัว blank แหละที่ทำให้อักษรที่ซ้ำจริง ๆ รอดชีวิต model ฝั่ง recognition มองบรรทัดข้อความเป็นลำดับของแถบแนวตั้งแคบ ๆ และสำหรับแต่ละแถบ หรือ time step มัน output ความน่าจะเป็นให้ทุกคลาส บรรทัดที่มี AA中 อาจผลิตลำดับ argmax เป็น A A blank A 中 space การยุบ time step ของ A สองตัวแรกให้เหลือ A เดียว blank คั่นมันออกจาก A ตัวถัดไป ผลลัพธ์คือ AA中 พร้อมช่องว่างท้ายบรรทัดที่ยังคงอยู่ ถ้าไม่มีกฎ blank book กับ bok จะแยกกันไม่ได้เลย
decoder มีแค่สิบกว่าบรรทัด การได้ขอบผิดจึงง่าย และความพังก็เงียบ ถ้า loop argmax ด้านในหยุดก่อนคลาสสุดท้ายหนึ่งอัน คลาส space จะไม่มีวันชนะ และทุกบรรทัดจะกลับมาโดยไม่มีช่องว่างระหว่างคำ ซึ่งทำลายการค้นวลีบนหน้าอังกฤษกับลาติน ถ้า loop นอกหยุดก่อน time step สุดท้ายหนึ่งอัน อักขระสุดท้ายของทุกบรรทัดหายไป กับบรรทัดสั้น ๆ นั่นคือครึ่งหนึ่งถึงสามหน่วยของข้อความทั้งชุด และถ้า repeat guard ไม่ถูกรีเซ็ตด้วย blank อักษรซ้ำอย่าง ll หรือการซ้ำพยางค์จีนอย่าง 谢谢 จะยุบเหลือตัวเดียว decoder ของ HotPDF ใส่คลาสสุดท้ายกับ time step สุดท้ายครบ คงการซ้ำที่ถูกคั่นด้วย blank และเพิ่มการปฏิเสธคะแนนที่ไม่ใช่ค่าจำกัดหรือตกนอก 0 ถึง 1 กับจำนวนคลาสใด ๆ ที่ไม่ตรงกับ dictionary นี่คือตรรกะเดียวกันในรูปตัวอย่าง Pascal
// เพื่อประกอบคำอธิบาย: greedy CTC decoding ที่ขอบถูกต้อง
// Scores เก็บความน่าจะเป็น Steps * Classes ค่า แถวละหนึ่ง time step
function GreedyCTCDecode(const Scores: array of Single;
Steps, Classes: Integer; const Characters: array of string): string;
var
Step, C, Best, Previous: Integer;
BestScore: Single;
begin
if (Classes < 3) or (Length(Characters) <> Classes) or
(Length(Scores) <> Steps * Classes) then
raise EArgumentException.Create('Model output does not match the dictionary');
Result := '';
Previous := 0; // class 0 คือ CTC blank
for Step := 0 to Steps - 1 do // รวม time step สุดท้ายด้วย
begin
Best := 0;
BestScore := Scores[Step * Classes];
for C := 1 to Classes - 1 do // รวมคลาสสุดท้ายด้วย (space)
if Scores[Step * Classes + C] > BestScore then
begin
Best := C;
BestScore := Scores[Step * Classes + C];
end;
if (Best <> 0) and (Best <> Previous) then
Result := Result + Characters[Best];
Previous := Best; // blank รีเซ็ต guard กันซ้ำ
end;
end;
greedy decoding ไม่ใช่กลยุทธ์ CTC ที่แม่นที่สุดที่มี beam search คู่กับ language model แก้ slice ที่กำกวมบางตัวได้ กับเอกสารพิมพ์ที่ 300 DPI ผลแบบ greedy มักคือทุกอย่างที่ model มีให้ และ decoder ไม่ใช่ที่ที่ควรชดเชยความอ่อนแอของ model model ลาตินของ PP-OCRv3 อ่าน ñ เป็น n ได้แม้บน input ที่สะอาด HotPDF ไม่ปิดตาข้ามเรื่องนี้ด้วยการแทนที่อักขระตอน post-processing เพราะตารางแทนที่ที่แก้ภาษาสเปนได้จะทำอย่างอื่นพัง และอักขระผิดใน searchable layer แย่กว่าการพลาดอย่างซื่อสัตย์
HotPDF เรียงบรรทัดข้อความอย่างไร รวมถึงอาหรับขวาไปซ้าย
HotPDF เรียง text box ที่ detect ได้จากบนลงล่าง จับกลุ่ม box เป็นแถวเมื่อมันทับแนวตั้งกันอย่างน้อยครึ่งหนึ่งของความสูง box ที่เตี้ยกว่า แล้วเรียงแต่ละแถวซ้ายไปขวา หรือขวาไปซ้ายเมื่อเปิด RightToLeft อักขระข้างในแต่ละบรรทัดที่จดจำได้ไม่เคยถูกกลับด้าน การจับกลุ่มสำคัญเพราะ detector มักผลิตแถวที่มองเห็นแนวเดียวออกมาหลายกล่อง เช่น ป้ายกำกับกับค่าที่ถูกคั่นด้วยช่องว่างกว้าง การเรียงด้วยพิกัดบนแบบโง่ ๆ จะสอดพวกมันแทรกกับแถวเพื่อนบ้านเมื่อพิกัดบนต่างกันเพียงหนึ่งสอง pixel
preset ของอาหรับเซ็ต RightToLeft := True ซึ่งบอก DLL ให้เรียง box ในแต่ละแถวตามขอบขวา จากระยะขอบขวาเข้าหาใน นั่นคือผลทั้งหมด ข้อความที่ model คืนให้บรรทัดหนึ่งอยู่ในลำดับ Unicode แบบ logical แล้ว คือลำดับที่คนอ่านอาหรับอ่านและพิมพ์ ซึ่งก็คือลำดับที่การ extract text และการค้นหาของ PDF คาดหวัง การกลับ string ด้วยเครื่องจักรเพื่อให้ "ดูถูก" ใน debugger จะทำ search, copy กับ paste และ screen reader พัง การแสดงแบบ bidirectional กับการจัดรูป glyph เป็นหน้าที่ของ viewer
engine หนึ่งตัวเสิร์ฟโปรไฟล์ภาษาหนึ่งโปรไฟล์ ไม่มีการ detect script อัตโนมัติ เอกสารที่ผสม script จึงต้องใช้ engine หนึ่งตัวต่อโปรไฟล์ โดยใช้กับหน้าที่ใช้มัน เพราะ ApplyLoadedOCRTextLayer รับรายการหน้าแบบแจ้งชัดและ commit แต่ละ call เป็น transaction all-or-nothing ของตัวเอง เรื่องนี้จึงตรงไปตรงมา
uses
SysUtils, HPDFDoc, HPDFRapidOCRRecognition;
function CreateRapidEngine(const Tag: string): IHPDFOCREngine;
var
Models: THPDFRapidOCRDLLOptions;
begin
// raise EArgumentException กับ tag ที่ไม่รู้จัก ก่อน model ตัวใดโหลด
Models := THPDFRapidOCRDLLOptions.ForLanguage(Tag);
Models.MaxPixels := 33554432; // กำลังพอสำหรับหน้า A3 ที่ 300 DPI
Result := HPDFCreateRapidOCRDLLOCREngine(
'C:\OCR\Win64\HotPDFRapidOCR.dll', 'C:\OCR\models', Models);
end;
procedure OCRMixedArchive(Doc: THotPDF);
var
Chinese, Arabic: IHPDFOCREngine;
Layer: THPDFOCRTextLayerOptions;
Info: THPDFOCRTextLayerInfo;
begin
Chinese := CreateRapidEngine('zh-TW'); // โปรไฟล์ chinese_cht
Arabic := CreateRapidEngine('ar-SA'); // โปรไฟล์ arabic, RightToLeft = True
Layer := THPDFOCRTextLayerOptions.Default;
if not Doc.ApplyLoadedOCRTextLayer([0, 1, 2], Chinese, Layer, Info) then
raise Exception.Create(string(Info.Diagnostic));
if not Doc.ApplyLoadedOCRTextLayer([3], Arabic, Layer, Info) then
raise Exception.Create(string(Info.Diagnostic));
end;
บรรทัด MaxPixels อยู่ตรงนั้นด้วยเหตุผล options ของ DLL เริ่มต้นที่ 16,777,216 pixel ต่อ request ซึ่งรองรับ A4 กับ US Letter ที่ 300 DPI สบาย ๆ แต่หน้า A3 ที่ 300 DPI คือราว 3508 คูณ 4961 pixel หรือราว 17.4 ล้าน และ request จะถูกปฏิเสธในฐานะเกินงบ ให้เพิ่ม MaxPixels (เพดานคือ 67,108,864) หรือลด THPDFOCRTextLayerOptions.DPI สำหรับขนาดกระดาษใหญ่ การเรียงขวาไปซ้ายใช้ export HPDFRapidOCRSetReadingDirection แบบเสริมของ ABI version 1 adapter ต้องการมันเฉพาะเมื่อเซ็ต RightToLeft DLL รุ่นเก่าจึงยังเสิร์ฟภาษาซ้ายไปขวาได้ และล้มตอนสร้าง engine ด้วย EArgumentException ที่ชี้ชื่อ export ที่หายไปสำหรับอาหรับ
ทำไม model OCR รุ่นใหม่ถึงโหลดไม่ขึ้น
HotPDF RapidOCR DLL ลิงก์ ONNX Runtime 1.14 แบบ static ซึ่งอ่าน model ที่ save ด้วย ONNX IR version 10 ไม่ได้ และ model export ใหม่อย่าง PP-OCRv5 อาจต้องการ runtime ใหม่กว่านั้น model แบบนี้ fail ตอนสร้าง engine พร้อม diagnostic ฝั่ง native ข้อจำกัดนี้เองเป็นเหตุผลที่ language pack ถูกตรึงไว้กับคู่ recognizer กับ dictionary ของ PP-OCRv3 กับ PP-OCRv4 ตัวใดตัวหนึ่ง ไม่ใช่ "ล่าสุด" และเป็นเหตุผลที่ตารางข้างบนผสมสองรุ่นของมัน คู่ที่ถูกตรึงทุกคู่คือคู่ที่โหลดและตรวจผ่านภายใต้ runtime ตัวนั้น
ตัวติดตั้งบังคับคู่พวกนี้ ไฟล์ทุกตัวใน manifest พา hash SHA256 มาด้วย ไฟล์ที่มีอยู่แล้วซึ่ง hash ไม่ตรงจะหยุดการติดตั้งแทนการถูกเขียนทับ และแต่ละดาวน์โหลดลงถิ่นด้วยชื่อชั่วคราว จะย้ายเข้าที่เมื่อ hash ตรงเท่านั้น สิ่งนี้ป้องกันเวอร์ชันเงียบ ๆ ของปัญหา dictionary ใครสักคนเท่าโยน recognition.onnx ใหม่กว่าลงโฟลเดอร์โปรไฟล์ด้วยมือ จำนวนคลาสบังเอิญตรง และไม่มีอะไร fail จนกว่าลูกค้าจะรายงานว่า search หาคำที่ตาเปล่าเห็นชัด ๆ ไม่เจอ ตอน runtime adapter อยู่แบบ offline และไม่เคยไปหยิบ model ที่หาย ฝั่ง recognizer ยังตรวจ shape ของ model ตอนโหลดด้วย ยอมรับ input NCHW ที่ความสูงตายตัว 32 หรือ 48 pixel หรือความสูงแบบ dynamic ซึ่งมันจะรันที่ 48
ถ้าคุณต้องการ script ที่ทั้งเก้าโปรไฟล์ไม่ครอบคลุม คุณยังชี้ RecognitionModel กับ CharacterDictionary ไปที่ไฟล์ของคุณเองได้ เช็คชุดเดิมมีผลเหมือนกัน ซึ่งก็คือจุดประสงค์ คู่ที่ไม่ตรงกันต้อง fail ตอน initialize ไม่ใช่ตอนอยู่ในคลังเอกสารของลูกค้า สำหรับหน้าที่โปรไฟล์ไหนของ RapidOCR ก็ไม่เข้า adapter ของ Tesseract สำหรับ searchable PDFเสียบเข้า call ApplyLoadedOCRTextLayer ตัวเดิมได้ และกับฟอร์ม ASCII พิมพ์เครื่อง engine OCR จับคู่เทมเพลตในตัวไม่ต้องพึ่ง model ใด ๆ เลย
สรุปด่วน: เช็คลิสต์ RapidOCR หลายภาษา
- สร้าง options ด้วย
THPDFRapidOCRDLLOptions.ForLanguageแล้วถือEArgumentExceptionเป็น tag ที่ไม่รองรับ ไม่ใช่ความผิดพลาดระดับ runtime - เปลี่ยน
RecognitionModelกับCharacterDictionaryพร้อมกัน ห้ามทีละอย่างเด็ดขาด จำนวนคลาสเท่ากันไม่พิสูจน์ว่าลำดับอักขระเท่ากัน - เก็บ dictionary เป็น UTF-8 ไม่มี BOM ห้าม trim entry และคาดหวังว่า model จะมี N + 2 คลาส: blank, entry N ตัว, space
- decoder CTC แบบ custom ต้องครอบคลุมคลาสสุดท้ายกับ time step สุดท้าย และคงการซ้ำที่ถูกคั่นด้วย blank
- ใช้ engine หนึ่งตัวต่อโปรไฟล์ภาษา แล้วส่งรายการหน้าแบบแจ้งชัดสำหรับเอกสารที่ผสม script
RightToLeftเปลี่ยนแค่ลำดับ box text ที่จดจำได้ยังอยู่ในลำดับ Unicode แบบ logical- ติดตั้ง model ด้วย
Install-RapidOCRModels.ps1เพื่อให้ pin SHA256 คุมคู่ model กับ dictionary ไว้ และเซ็ตUseAngleClassifier := Falseถ้าคุณติดตั้งแบบมี-SkipClassifier - เพิ่ม
MaxPixelsเกินค่าเริ่มต้น 16,777,216 ก่อนรันหน้า A3 หรือใหญ่กว่าที่ 300 DPI
preset ภาษาของ RapidOCR, adapter ฝั่ง DLL native และ pipeline ของ OCR text layer เป็นส่วนหนึ่งของHotPDF Delphi PDF Component สำหรับ Delphi, C++Builder และ FPC/Lazarus บน Windows เริ่มจาก v2.775.0 สำหรับโปรไฟล์หลายภาษา