OCR識(shí)別系統(tǒng)實(shí)戰(zhàn):藥品包裝與輪胎DOT碼)
簡(jiǎn)介一份面向C#與HALCON開發(fā)者的工業(yè)級(jí)OCR字符識(shí)別實(shí)戰(zhàn)資料聚焦藥品包裝生產(chǎn)日期和輪胎DOT碼兩大典型場(chǎng)景適合具備一定編程基礎(chǔ)、從事工業(yè)自動(dòng)化與機(jī)器視覺的工程師。PDF文檔共1個(gè)文件、599KB內(nèi)容完整涵蓋從OCR原理、HALCON核心算子解析到VS2022.NET Core環(huán)境配置再到圖像預(yù)處理、文本定位、字符識(shí)別、結(jié)果驗(yàn)證及數(shù)據(jù)上報(bào)的全流程。示例代碼可直接復(fù)用并深入講解多線程、GPU加速、ROI局部處理等性能優(yōu)化技巧以及容錯(cuò)重試機(jī)制保障生產(chǎn)環(huán)境穩(wěn)定性。擴(kuò)展部分還涉及深度學(xué)習(xí)OCR如PP-OCRv4、3D OCR與動(dòng)態(tài)訓(xùn)練系統(tǒng)為后續(xù)技術(shù)升級(jí)提供方向。目前已有282人學(xué)習(xí)適合用于快速搭建高精度識(shí)別系統(tǒng)并落地部署。 在工業(yè)視覺這個(gè)行當(dāng)里摸爬滾打這些年OCR字符識(shí)別算是遇到頻率最高的需求之一但也是“看似簡(jiǎn)單、落地踩坑無數(shù)”的典型方向。尤其這幾年藥品包裝追溯和輪胎DOT碼這兩個(gè)場(chǎng)景幾乎成了標(biāo)簽打印質(zhì)量檢測(cè)、產(chǎn)品溯源管理繞不開的硬需求。我之前用C#配合HALCON 24.11做了一套工業(yè)級(jí)OCR識(shí)別系統(tǒng)從相機(jī)采圖、圖像預(yù)處理、字符分割識(shí)別到上位機(jī)交互完整跑通了藥品包裝生產(chǎn)日期、批號(hào)和輪胎DOT碼兩條產(chǎn)線。這篇就把整個(gè)過程中真正有用的設(shè)計(jì)思路、代碼實(shí)現(xiàn)和排坑經(jīng)驗(yàn)整理出來給正在做類似項(xiàng)目的朋友一個(gè)可以“抄作業(yè)”的參考。這套方案適合誰(shuí)如果你正在用C#做上位機(jī)開發(fā)接到工業(yè)視覺相關(guān)的需求或者已經(jīng)在用HALCON但主要停留在模板匹配、測(cè)量層面想往字符識(shí)別方向深挖一步這篇內(nèi)容應(yīng)該能幫你省不少試錯(cuò)時(shí)間。你不光能看到具體怎么調(diào)包、怎么封裝還能看到我在兩種完全不同材質(zhì)、不同光照條件下的產(chǎn)線上分別選了什么樣的圖像預(yù)處理方案以及C#和HALCON之間到底怎么通信才算穩(wěn)定高效。這些細(xì)節(jié)如果沒人告訴你自己一點(diǎn)點(diǎn)摸索至少要一兩周。1. 系統(tǒng)整體設(shè)計(jì)與硬件選型1.1 項(xiàng)目背景與需求分析先說兩個(gè)場(chǎng)景的差異。藥品包裝的OCR目標(biāo)通常是紙盒側(cè)面或鋁塑泡罩背面的生產(chǎn)日期、有效期、批號(hào)字符是噴墨打印的字體相對(duì)規(guī)整但存在油墨不均勻、噴頭堵塞導(dǎo)致的斷線、淺印這類問題。輪胎DOT碼則完全不同它是在硫化過程中直接成型在胎側(cè)橡膠上的凸起字符光照角度稍不對(duì)就會(huì)出現(xiàn)陰影干擾而且輪胎表面有紋理、胎毛、雜質(zhì)字符本身還有一定的曲率變形。這兩種需求放一起做就意味著不能“一套流程打天下”。我最初也試過直接用默認(rèn)參數(shù)去跑DOT碼結(jié)果識(shí)別率不到七成后來拆開分析才知道問題主要出在前處理階段——對(duì)比度拉伸和濾波參數(shù)完全不適合橡膠材質(zhì)。這算是第一個(gè)需要重視的經(jīng)驗(yàn)OCR工程的性能瓶頸往往不在識(shí)別算法本身而在前面的圖像預(yù)處理和質(zhì)量判定邏輯是否貼合實(shí)際產(chǎn)線。1.2 相機(jī)、鏡頭與光源怎么選硬件選型這件事直接影響后面所有軟件算法的效果建議第一步就定清楚。藥品包裝線我用的是一臺(tái)??低?00萬(wàn)像素黑白工業(yè)相機(jī)配8mm定焦工業(yè)鏡頭工作距離大約300mm視野大概能覆蓋一個(gè)藥盒的整個(gè)側(cè)面。輪胎DOT碼那邊用的是一臺(tái)200萬(wàn)像素的相機(jī)加12mm鏡頭視野聚焦在單個(gè)DOT碼區(qū)域這樣能獲得較大的字符像素高度——我要求DOT碼字符至少占30個(gè)像素以上這是HALCON OCR模型訓(xùn)練時(shí)比較穩(wěn)妥的經(jīng)驗(yàn)值。光源這邊藥品包裝用白色條形LED低角度照明就能打出均勻的漫反射噴碼字符和紙盒背景之間灰度差足夠。輪胎橡膠是黑色吸光材質(zhì)低角度白光會(huì)直接產(chǎn)生大范圍陰影換成了高角度環(huán)形光源后凸起字符的頂部會(huì)被照亮而凹槽保持暗色字符和背景之間就形成了穩(wěn)定的對(duì)比。這一點(diǎn)非常關(guān)鍵同樣是OCR不同材質(zhì)的光源方案可能完全相反。1.3 一個(gè)被問爛的問題海康相機(jī)版本要和視覺軟件版本對(duì)得上嗎群里經(jīng)常被問到“??低暪I(yè)相機(jī)和VisionMaster版本號(hào)要不要對(duì)應(yīng)”這里額外說明一下。如果你走的是海康的MVS SDK做二次開發(fā)相機(jī)固件跟SDK之間確實(shí)有版本匹配要求官方手冊(cè)里寫得很清楚不匹配會(huì)出現(xiàn)掉線、取流異常的問題。所以建議先裝最新版MVS再用其自帶的“設(shè)備管理”檢查固件版本不一致就升級(jí)固件。但我這套系統(tǒng)里相機(jī)采集其實(shí)沒有直接用MVS的上位機(jī)界面而是在C#里通過MVS的SDK調(diào)取圖像然后把圖像數(shù)據(jù)轉(zhuǎn)成HALCON的HObject對(duì)象去做處理。這里真正的銜接點(diǎn)不是MVS和HALCON而是MVS采集回調(diào)拿到的像素格式和HALCON的圖像類型能不能對(duì)上。我用的是黑白相機(jī)Mono8格式這一步轉(zhuǎn)換非常簡(jiǎn)單基本是直接構(gòu)造HImage對(duì)象。如果你用的是彩色相機(jī)還需要額外做一次灰度轉(zhuǎn)換別忽略。2. HALCON 24.11 環(huán)境準(zhǔn)備與C#工程集成2.1 HALCON 24.11的新特性與實(shí)際安裝注意點(diǎn)HALCON 24.11這個(gè)版本在OCR方面最大的變化是深度學(xué)習(xí)OCR算子集的完善內(nèi)置了更緊湊的工業(yè)字符識(shí)別模型對(duì)低對(duì)比度、低分辨率字符的魯棒性比舊版有明顯提升。安裝過程倒沒什么特別但有兩個(gè)細(xì)節(jié)建議留意一是安裝路徑不要帶中文和空格否則C#引用DLL時(shí)可能出現(xiàn)奇怪的加載失敗二是HALCON安裝完后要確認(rèn)系統(tǒng)環(huán)境變量HALCONROOT是否正確配置這關(guān)系到后續(xù)C#工程里DLL搜索路徑能不能自動(dòng)找全。另外HALCON 24.11提供了License助手工具開發(fā)階段我使用的是官方評(píng)估許可正式上線時(shí)請(qǐng)購(gòu)買正版許可并完成授權(quán)配置。具體的激活細(xì)節(jié)不做展開這里只想提醒不要在許可服務(wù)的穩(wěn)定性上省事產(chǎn)線上掉授權(quán)比掉相機(jī)嚴(yán)重十倍。2.2 C#調(diào)用HALCON的兩種主流方式第一種是直接用HALCON的.NET接口也就是在C#項(xiàng)目里添加halcondotnet.dll和hdevengine.dll的引用把HDevelop里寫好的算法導(dǎo)出成C#類然后在工程里實(shí)例化調(diào)用。第二種是用HALCON的HDevEngine在C#里直接加載.hdev腳本執(zhí)行。我實(shí)際項(xiàng)目中用的是第一種原因是導(dǎo)出后的C#代碼完全可見中間變量可以方便地插入日志和調(diào)試斷點(diǎn)對(duì)于工業(yè)設(shè)備這種需要后期維護(hù)的項(xiàng)目友好得多。HALCON導(dǎo)出的C#類一般長(zhǎng)這樣public class OCR_Process : HTool { public void ProcessImage(HObject ho_Image, out HTuple hv_ResultText, out HTuple hv_Score) { // 這里是從HDevelop導(dǎo)出的算法邏輯 HOperatorSet.ReadOcrClassCnn(...); HOperatorSet.DoOcrMulti(...); } }這里有個(gè)使用心得導(dǎo)出的類默認(rèn)繼承HTool如果只是簡(jiǎn)單調(diào)用直接在窗體里new出來就能用。但如果產(chǎn)線對(duì)節(jié)拍有要求建議把識(shí)別邏輯放在獨(dú)立線程里同時(shí)給HALCON的執(zhí)行引擎設(shè)置線程數(shù)。HALCON的HOperatorSet內(nèi)部本身是支持并行處理的但C#里的UI線程如果跟圖像處理線程混在一起很容易出現(xiàn)界面卡死一次采圖加識(shí)別大約80msUI如果按同步方式處理操作點(diǎn)位一多就明顯感覺不跟手。2.3 C#工程里配置HALCON DLL的正確路徑很多新手在這步會(huì)卡很久。正常配置是在Visual Studio里右鍵項(xiàng)目選擇“添加引用”瀏覽到HALCON安裝目錄下的bin\dotnet35或者bin\dotnetstandard2.0根據(jù)你的.NET版本選擇對(duì)應(yīng)的DLL。比如我用的.NET Framework 4.7.2選dotnet35編譯出來的halcondotnet.dll就沒問題。另外要把HALCON的bin目錄加入系統(tǒng)PATH或者直接把需要的DLL復(fù)制到exe同級(jí)目錄不然運(yùn)行時(shí)會(huì)報(bào)“找不到hcanvas.dll”之類的錯(cuò)誤。這里還有一個(gè)容易忽略的點(diǎn)HALCON 24.11默認(rèn)優(yōu)先支持.NET 6.0/8.0如果你還在用.NET Framework建議確認(rèn)一下安裝包是否帶全了對(duì)應(yīng)的.Net Framework Assembly。我一開始直接用.NET 6.0寫了個(gè)測(cè)試程序編譯沒問題但在客戶老工控機(jī)Win7 .NET Framework 4.5.2上直接跑不起來最后改成.NET Framework 4.7.2才解決。做工業(yè)項(xiàng)目之前一定先確認(rèn)現(xiàn)場(chǎng)工控機(jī)的系統(tǒng)環(huán)境和.NET運(yùn)行庫(kù)版本。3. OCR識(shí)別主流程從圖像采集到結(jié)果輸出3.1 一張清晰合格的圖像是識(shí)別的起點(diǎn)這個(gè)環(huán)節(jié)我單獨(dú)拿出來強(qiáng)調(diào)因?yàn)樗菀妆坏凸?。很多人拿到圖像直接就去調(diào)OCR識(shí)別參數(shù)結(jié)果識(shí)別率不穩(wěn)定就認(rèn)為是HALCON的OCR引擎不行其實(shí)往往是前面采圖環(huán)節(jié)就埋了雷。工業(yè)場(chǎng)景下我定義“合格圖像”有三個(gè)標(biāo)準(zhǔn)字符區(qū)域灰度和背景灰度差至少大于30字符邊緣不存在明顯的運(yùn)動(dòng)模糊字符像素高度不低于15像素藥品包裝或30像素輪胎DOT碼。生產(chǎn)線節(jié)拍快相機(jī)曝光和頻閃光源要配合好。藥品包裝線用的頻閃模式相機(jī)外觸發(fā)拍照曝光時(shí)間控制在500微秒左右配合光源的頻閃瞬間亮度能有效凍結(jié)藥盒在傳送帶上的輕微運(yùn)動(dòng)。輪胎線因?yàn)橛袡C(jī)械定位停穩(wěn)后才拍照曝光時(shí)間可以稍微長(zhǎng)一點(diǎn)達(dá)到更好的信噪比。這里我強(qiáng)烈建議在項(xiàng)目調(diào)試初期做一次“曝光階梯測(cè)試”固定光源亮度從100微秒到5毫秒按步進(jìn)采集一組圖像選灰度直方圖和對(duì)比度最好的那一檔。3.2 圖像預(yù)處理流程灰度、閾值、區(qū)域提取與掩膜預(yù)處理是我認(rèn)為整個(gè)流程里最體現(xiàn)經(jīng)驗(yàn)的部分。藥品包裝字符是深色油墨印在淺色紙盒上閾值分割非常簡(jiǎn)單全局閾值就能拿到很干凈的字符區(qū)域。但輪胎DOT碼是淺色凸起字符印在黑色橡膠上雖然理論上也很容易分割但實(shí)際情況是橡膠表面有大量紋理全局閾值會(huì)帶進(jìn)來非常多的小噪聲區(qū)域。我的處理鏈路是彩色圖轉(zhuǎn)灰度然后根據(jù)直方圖做一次灰度映射拉伸對(duì)比度接著用中值濾波去除橡膠紋理顆粒再通過動(dòng)態(tài)閾值或局部閾值分割出候選字符區(qū)域。這個(gè)流程里有兩個(gè)關(guān)鍵點(diǎn)一是中值濾波的掩膜尺寸不宜過大我用的是5x5太大會(huì)直接把字符邊緣抹平二是分割之后一定要用形態(tài)學(xué)開運(yùn)算去掉細(xì)小的孤立噪聲我用的是3x3圓形結(jié)構(gòu)元素開運(yùn)算一次即可別多次迭代。處理后還需要通過掩膜排除不需要的區(qū)域。比如藥品包裝盒上除了生產(chǎn)日期還有條形碼、藥品名稱、公司logo這些區(qū)域如果不做排除OCR引擎會(huì)把它們也當(dāng)作字符去識(shí)別產(chǎn)生大量錯(cuò)誤輸出。排除方式是在HALCON里用reduce_domain操作把ROI縮小到只包含噴碼區(qū)域或者用串行連接的幾個(gè)矩形區(qū)域做union形成一塊“復(fù)合掩膜”。輪胎DOT碼那邊也需要排除胎側(cè)花紋和胎毛區(qū)域否則識(shí)別結(jié)果會(huì)出現(xiàn)不少亂碼。3.3 HALCON OCR引擎的調(diào)用邏輯與模型選型HALCON里的OCR識(shí)別主要有傳統(tǒng)OCR分類器和深度學(xué)習(xí)CNN兩大類。傳統(tǒng)方式用read_ocr_class_mlp讀取訓(xùn)練好的OCR模型針對(duì)特定字體做訓(xùn)練后在字體規(guī)整的場(chǎng)景下精度很高。深度學(xué)習(xí)方式用read_ocr_class_cnn讀取預(yù)訓(xùn)練模型對(duì)打印質(zhì)量差、變形、低對(duì)比度的字符有更好的泛化能力。我在藥品包裝線上用的是傳統(tǒng)MLP模型因?yàn)樗幒袊姶a字體固定只要在調(diào)試階段用現(xiàn)場(chǎng)采集的幾百?gòu)垐D做過一次字體訓(xùn)練識(shí)別率就能到99.5%以上。輪胎DOT碼則用了CNN模型因?yàn)榱蚧址旧泶嬖谝欢ㄗ冃味蚁鹉z熱脹冷縮會(huì)輕微改變字符比例CNN模型對(duì)這些情況容忍度更高。兩種模型在HALCON里的調(diào)用方式幾乎一致核心算子都是do_ocr_multi只是前面讀取的模型文件不同HOperatorSet.ReadOcrClassCnn(Industrial_0-9A-Z_NoRej, out ho_OCRHandle); HOperatorSet.DoOcrMulti(ho_CharRegions, ho_Image, ho_OCRHandle, out hv_Char, out hv_Confidences);如果你要訓(xùn)練的字符集不止數(shù)字和大寫字母比如包含“-”、“/”、“.”這樣的特殊符號(hào)HALCON允許在模型訓(xùn)練工具里單獨(dú)添加這些類別的訓(xùn)練樣本。我自己就把藥品批號(hào)里的“/”和批號(hào)尾號(hào)的特殊分隔符單獨(dú)加進(jìn)訓(xùn)練集識(shí)別穩(wěn)定性提升很明顯。3.4 字符分割策略從Connected Components到OCR分類OCR流程中一塊硬骨頭是“分割”也就是把一個(gè)字符串圖像切成單個(gè)字符區(qū)域。藥品包裝的噴碼字符間距固定、互不粘連用連通域分析就能切得比較干凈。具體做法是先threshold得到候選區(qū)域再用connection算子找出每個(gè)獨(dú)立連通域接著用select_shape根據(jù)寬度、高度、面積過濾掉非字符區(qū)域最后按x坐標(biāo)對(duì)字符區(qū)域做排序。輪胎DOT碼的分割要麻煩一點(diǎn)。DOT碼是連續(xù)壓印的有些字符之間的距離非常近連通域分析偶爾會(huì)把兩個(gè)字符切成一個(gè)區(qū)域這時(shí)HALCON的segment_characters算子就派上用場(chǎng)了它可以基于字符寬度先驗(yàn)把粘連區(qū)域進(jìn)一步拆分。不過這里要小心segment_characters在字符本身筆畫斷裂時(shí)也會(huì)誤切割我遇到過一次“D”識(shí)別成“O”的情況就是因?yàn)樨Q向筆畫斷裂后被切成了兩個(gè)區(qū)域。后來我在分割前加了一步閉運(yùn)算把筆畫斷裂處補(bǔ)上誤切問題基本消失。4. C#上位機(jī)與掃碼槍觸發(fā)、產(chǎn)線通信4.1 C#里掃碼槍觸發(fā)事件的解析與封裝掃碼槍在工業(yè)視覺系統(tǒng)里通常作為“觸發(fā)源”存在掃碼成功意味著視覺系統(tǒng)開始采圖識(shí)別。市面上的掃碼槍大多數(shù)模擬鍵盤輸出直接向聚焦窗口發(fā)送字符在C#里最穩(wěn)的做法是用串口或者網(wǎng)口SDK去接管。我用的掃碼槍支持串口輸出C#里通過SerialPort控件接收數(shù)據(jù)當(dāng)收到完整條碼后觸發(fā)拍照。有一個(gè)很重要的經(jīng)驗(yàn)掃碼槍串口數(shù)據(jù)是分包到達(dá)的可能一次讀完條碼要收兩三個(gè)包所以不能收到一個(gè)字符就觸發(fā)拍照。我的做法是把串口數(shù)據(jù)累積到字符串緩沖區(qū)里檢測(cè)到結(jié)束符通常是換行符\r\n才認(rèn)為完整解析。同時(shí)加了一個(gè)超時(shí)保護(hù)如果掃碼槍在線、產(chǎn)線觸發(fā)信號(hào)正常但3秒內(nèi)沒收到完整條碼就拋出“掃碼超時(shí)”報(bào)警防止產(chǎn)線靜默停線這個(gè)機(jī)制上線后幫我擋了好幾次掃碼槍松動(dòng)導(dǎo)致的事故。private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { string data serialPort.ReadExisting(); buffer data; if (buffer.Contains(\r\n)) { string fullCode buffer.Replace(\r\n, ).Trim(); buffer ; // 觸發(fā)采圖或傳給PLC this.Invoke(new Action(() TriggerVisualInspection(fullCode))); } }4.2 相機(jī)觸發(fā)方式硬觸發(fā)與軟觸發(fā)怎么選工業(yè)相機(jī)一般支持硬觸發(fā)和軟觸發(fā)兩種方式。硬觸發(fā)是PLC給相機(jī)一個(gè)IO脈沖相機(jī)立刻曝光采集實(shí)時(shí)性好、不受上位機(jī)系統(tǒng)調(diào)度影響適合高速產(chǎn)線。軟觸發(fā)是上位機(jī)通過SDK發(fā)指令讓相機(jī)采圖靈活性高但實(shí)時(shí)性受系統(tǒng)負(fù)載影響。我在視覺系統(tǒng)里走了軟觸發(fā)原因是我需要把掃碼槍數(shù)據(jù)、PLC信號(hào)、OCR結(jié)果三者做邏輯聯(lián)動(dòng)硬觸發(fā)不好處理這種多信號(hào)時(shí)序問題。不過軟觸發(fā)有一個(gè)明顯短板如果上位機(jī)CPU占用率突然飆高采圖延遲會(huì)變大可能導(dǎo)致產(chǎn)品已經(jīng)離開視野才拍照。我的緩解方案是給視覺線程設(shè)置更高的線程優(yōu)先級(jí)同時(shí)把相機(jī)緩沖區(qū)設(shè)置到最大這樣即使采圖命令延遲幾十毫秒也能拿到存入相機(jī)內(nèi)存的上一幀圖像相當(dāng)于加了軟性的“延遲保護(hù)”。如果你對(duì)實(shí)時(shí)性要求非常嚴(yán)格還是建議用硬觸發(fā)C#這邊只做結(jié)果讀取和判定。4.3 識(shí)別結(jié)果傳給PLC和數(shù)據(jù)庫(kù)的幾種方式識(shí)別完成后結(jié)果需要回傳給產(chǎn)線PLC做分流控制同時(shí)存入本地?cái)?shù)據(jù)庫(kù)做追溯。PLC通信我用的是TCP Socket直連Modbus TCP協(xié)議。這里直接說C#的開銷問題如果每個(gè)產(chǎn)品都建立一個(gè)新的TCP連接產(chǎn)線一小時(shí)幾千個(gè)產(chǎn)品會(huì)讓PLC頻繁處理連接建立和銷毀整體負(fù)荷偏高。更合理的做法是程序啟動(dòng)時(shí)建立長(zhǎng)連接之后一直復(fù)用心跳包按秒級(jí)發(fā)送做?;?。C#里實(shí)現(xiàn)長(zhǎng)連接其實(shí)很直接用TcpClient實(shí)例化后在主線程保持住識(shí)別結(jié)果通過MemoryStream封裝成Modbus寫寄存器報(bào)文發(fā)送。對(duì)于“TCP連接數(shù)量多少合適”這類問題工業(yè)場(chǎng)景下我的經(jīng)驗(yàn)是一臺(tái)工控機(jī)對(duì)PLC只需要1個(gè)長(zhǎng)連接如果有多臺(tái)設(shè)備組網(wǎng)每個(gè)PLC單獨(dú)建立連接池但總數(shù)控制在10個(gè)以內(nèi)再多就要考慮轉(zhuǎn)發(fā)服務(wù)了。數(shù)據(jù)庫(kù)寫入我用的是SQLite。為什么不直接上SQL Server因?yàn)楫a(chǎn)線工控機(jī)環(huán)境可能很惡劣數(shù)據(jù)庫(kù)服務(wù)越簡(jiǎn)單越不容易出問題SQLite單文件部署、掉電不損壞、C#里用System.Data.SQLite接入非常方便。數(shù)據(jù)表按日期分表每天一個(gè)Table字段包括條碼、OCR識(shí)別結(jié)果、判定結(jié)果、圖像保存路徑、時(shí)間戳。圖像文件按日期和條碼命名存到本地硬盤過一段時(shí)間可以壓縮歸檔這樣追溯的時(shí)候既能查文字記錄也能直接調(diào)出當(dāng)時(shí)的圖像。5. 常見問題與排查技巧實(shí)錄5.1 OCR識(shí)別率波動(dòng)的四大典型原因我在項(xiàng)目維護(hù)階段遇到過識(shí)別率從99%突然掉到90%的情況排查了好久才定位到原因。整理成表格方便你對(duì)照排查。造成原因光照亮度漂移處理辦法定期用標(biāo)準(zhǔn)色卡做灰度校準(zhǔn)檢查光源控制器輸出電流。 造成原因相機(jī)鏡頭積灰或起霧處理辦法加裝壓縮空氣吹掃裝置每周人工清潔一次。 造成原因字符區(qū)域定位偏移處理辦法增加模板匹配定位步驟不要固定ROI坐標(biāo)。 造成原因模型未覆蓋新字體處理辦法收集新樣本增量訓(xùn)練更新OCR模型文件。這個(gè)表格里的前三條都是“硬件環(huán)境變化導(dǎo)致圖像變化”最后一條是“軟件模型不適應(yīng)新數(shù)據(jù)”。我個(gè)人的習(xí)慣是每天開機(jī)后跑一次標(biāo)準(zhǔn)片自檢如果識(shí)別置信度低于閾值就觸發(fā)提示在產(chǎn)線上基本能做到“異常早發(fā)現(xiàn)、不停線”。5.2 HALCON與C#集成時(shí)最容易踩的三個(gè)坑第一個(gè)坑是DLL版本不一致。HALCON不同版本生成的halcondotnet.dll有差異比如24.11和24.05之間可能存在接口不一致。解決方案很簡(jiǎn)單開發(fā)機(jī)和產(chǎn)線工控機(jī)必須裝同一版本HALCON編譯發(fā)布時(shí)把對(duì)應(yīng)版本DLL一起帶上不要混用。第二個(gè)坑是32位與64位不匹配。C#工程編譯目標(biāo)x86或者x64必須和HALCON安裝版本一致。如果C#是x86但裝了64位的HALCON運(yùn)行庫(kù)程序啟動(dòng)時(shí)直接拋BadImageFormatException。產(chǎn)線工控機(jī)經(jīng)常有老舊的32位驅(qū)動(dòng)一旦混用就很難排查建議新建項(xiàng)目時(shí)直接鎖定x64統(tǒng)一架構(gòu)。第三個(gè)坑是圖像內(nèi)存釋放。HALCON的HObject對(duì)象如果頻繁創(chuàng)建不釋放內(nèi)存會(huì)持續(xù)增長(zhǎng)跑上幾天后工控機(jī)會(huì)越來越卡。C#里雖然HALCON提供了Dispose方法但建議在每幀處理完后的finally塊里統(tǒng)一調(diào)用或者在處理循環(huán)外部使用using語(yǔ)句包圍HObject作用域這個(gè)習(xí)慣一定要養(yǎng)成。5.3 識(shí)別結(jié)果后處理置信度閾值與二次復(fù)核OCR識(shí)別完成后不能直接把字符串當(dāng)成最終結(jié)果。HALCON的do_ocr_multi會(huì)返回每個(gè)字符的置信度我通常設(shè)置一個(gè)0.9的置信度閾值如果任何一個(gè)字符低于這個(gè)值就判定為“待復(fù)核”。這里分享一個(gè)不算技巧的技巧工業(yè)場(chǎng)景里“拒識(shí)”比“誤識(shí)”安全得多。如果字符識(shí)別錯(cuò)了還當(dāng)作正確結(jié)果傳給PLC到了包裝環(huán)節(jié)才發(fā)現(xiàn)批次號(hào)對(duì)不上那就是批量質(zhì)量事故。如果識(shí)別不了直接判定為NG讓PLC把產(chǎn)品推到復(fù)檢位讓人工再確認(rèn)一眼成本低得多。還有一個(gè)實(shí)用做法對(duì)識(shí)別出來的字符串做格式校驗(yàn)。比如藥品批號(hào)一般是“字母數(shù)字字母數(shù)字”這樣的結(jié)構(gòu)DOT碼有固定的前兩位字母加四位數(shù)字的產(chǎn)線編號(hào)段。在C#里用正則表達(dá)式做一道格式過濾不符合格式的即便是高置信度識(shí)別結(jié)果也判為異常。這個(gè)后處理邏輯能把“識(shí)別對(duì)了但內(nèi)容本身不規(guī)范”的問題一并攔截。5.4 產(chǎn)線光照干擾與反射噪聲的實(shí)戰(zhàn)處理最后聊一個(gè)非常讓人頭疼的問題產(chǎn)線不是實(shí)驗(yàn)室環(huán)境光干擾無處不在。藥品包裝線的頂燈、人走過帶來的散射光、輪胎線旁邊的弧焊光弧都會(huì)瞬間改變圖像亮度分布。我用的處理方案是給相機(jī)加裝偏振片同時(shí)給光源也加偏振片一橫一豎互相抵消。對(duì)于藥品包裝這種光滑紙面偏振片效果非常明顯直接消除反光高光輪胎橡膠是漫反射為主偏振片作用有限就靠提高光源亮度和縮短曝光時(shí)間來壓制環(huán)境光。如果你在現(xiàn)場(chǎng)發(fā)現(xiàn)識(shí)別率時(shí)好時(shí)壞先別急著改算法。把異常的圖像存下來回放看一遍90%的問題都出在“光”上。這也是為什么我在系統(tǒng)里特地保留了“每幀圖像保存”功能平時(shí)不啟用排查問題時(shí)打開發(fā)現(xiàn)問題之后再關(guān)掉避免硬盤被塞滿。這套“圖像可回溯”機(jī)制幫我在遠(yuǎn)程支持客戶時(shí)省了很多電話溝通成本。6. 一點(diǎn)收尾心得這套系統(tǒng)從開發(fā)到穩(wěn)定運(yùn)行前后差不多用了三周時(shí)間其中硬件調(diào)試和圖像預(yù)處理占了差不多一半的時(shí)間。我個(gè)人最大的體會(huì)是工業(yè)視覺OCR項(xiàng)目真正拉開差距的不是你會(huì)不會(huì)調(diào)HALCON算子而是你有沒有一套系統(tǒng)化的工程思維——從硬件選型到圖像質(zhì)量把控從字符分割到結(jié)果后處理每一個(gè)環(huán)節(jié)都要有明確的判定標(biāo)準(zhǔn)和容錯(cuò)機(jī)制。另一個(gè)很深的感觸是現(xiàn)場(chǎng)需求永遠(yuǎn)比你想象的復(fù)雜留好日志、留好圖像、留好遠(yuǎn)程排查通道比模型本身更能救命。如果你正在做類似的項(xiàng)目建議先從藥品包裝或者標(biāo)簽打印這類字符規(guī)整的場(chǎng)景入手跑通全流程再往輪胎DOT碼這種高難度場(chǎng)景推進(jìn)。把基礎(chǔ)鏈路走扎實(shí)了再難的項(xiàng)目也就是在這條主線上加加減減而已。本文還有配套的精品資源點(diǎn)擊獲取