日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

基于HALCON的喷码字符自训练与识别

發(fā)布時(shí)間:2023/12/31 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于HALCON的喷码字符自训练与识别 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

最近視覺項(xiàng)目需求,建立10個(gè)及以上的字符模板庫(kù),然后進(jìn)行生產(chǎn)時(shí),提取出噴碼區(qū)域與模板進(jìn)行比對(duì)得到對(duì)應(yīng)的分?jǐn)?shù),以分?jǐn)?shù)的高低來判斷噴碼的好壞。
如圖:噴碼樣品

根據(jù)需求,可以借鑒Halcon中訓(xùn)練字符的思路來解決此問題。
主要流程:摳圖–>訓(xùn)練–>識(shí)別

第一步——訓(xùn)練文件建立

首先用戶輸入檢測(cè)噴碼的字符,在對(duì)應(yīng)位置會(huì)自動(dòng)生成以噴碼為名字的文件夾,然后會(huì)對(duì)應(yīng)生成單個(gè)字符的子文件夾(主要用于存放單個(gè)字符圖片)。
算法邏輯:


這里我們來看看具體的Halcon源碼(僅供參考)

Code:=['6','2'] //輸入需要識(shí)別的字符 filenum:=|Code| //計(jì)算字符個(gè)數(shù) string:=[''] //初始化字符串用于將客戶輸入字符連接起來作為文件名 Color:=1 //0表示藍(lán)色1表示紅色gen_rectangle1 (Rectangle, 2817.87,562.239,7395.57, 4431.49) //繪制的噴碼區(qū)域ROI,可自己繪制修改 *開始摳圖 FilePath:='E:/OCR-test/10模板噴碼測(cè)試/9815B' //圖像路徑 list_files (FilePath, ['files','follow_links'], ImageFiles) tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles) parse_filename (ImageFiles, BaseName, Extension, Directory) *根據(jù)客戶輸入字符自動(dòng)生成文件夾名字 for x := 0 to filenum-1 by 1string[0]:=string[0]+Code[x] //將客戶輸入字符連接起來作為文件名字 endfor Path:='E:/OCR-test/'+string+'/' //需要?jiǎng)?chuàng)建的字符文件夾路徑*判斷是否有主文件夾,沒有則創(chuàng)建主文件夾 file_exists ('E:/OCR-test/'+string, FileExists) //判斷是否存在文件夾,存在FileExists返回1否則返回0 if(FileExists) elsemake_dir ('E:/OCR-test/'+string) //在自定路徑創(chuàng)建文件夾 endif*判斷是否有字符子文件夾沒有就創(chuàng)建子文件夾 for j := 0 to filenum-1 by 1file_exists (Path+Code[j], FileNum)if (FileNum)elsemake_dir (Path+Code[j])endif endfor stop ()

這里是HALCON內(nèi)部的實(shí)現(xiàn),可以在手動(dòng)輸入字符自動(dòng)生成文件夾。

第二步——產(chǎn)品轉(zhuǎn)正

產(chǎn)品的圖片的校正,利用仿射變化來將圖像進(jìn)行平移旋轉(zhuǎn):
通常我們Halcon中計(jì)算出的是弧度,這里我們需要了解符號(hào)代表的意義**(順時(shí)針方向旋轉(zhuǎn)的是負(fù)號(hào),逆時(shí)針方向旋轉(zhuǎn)的是正號(hào))**
效果如下:
轉(zhuǎn)正前:

轉(zhuǎn)正后:

具體的代碼實(shí)現(xiàn):

read_image (Image, ImageFiles[Index])rgb1_to_gray (Image, GrayImage)threshold (GrayImage, Region, 10, 170)connection (Region, RegionTemp)select_shape_std (RegionTemp, RegionTemp, 'max_area', 70)orientation_region (RegionTemp, Phi) //計(jì)算區(qū)域角度area_center (RegionTemp, Area, Row, Column) //計(jì)算區(qū)域中心坐標(biāo)與面積/*保證產(chǎn)品僅有豎直與橫直兩種情況*/if(Phi<0)AimPhi:=rad(-90)elseAimPhi:=rad(90)endifvector_angle_to_rigid (Row, Column, Phi, Row, Column, AimPhi, HomMat2D) //創(chuàng)建變化矩陣affine_trans_image (Image, ImageAffineTrans, HomMat2D, 'constant', 'false') //進(jìn)行仿射變化

vector_angle_to_rigid (Row, Column, Phi, Row1, Column1, AimPhi, HomMat2D)
**Row:**變化前原點(diǎn)列坐標(biāo)(這里是產(chǎn)品的中點(diǎn))
**Column:**變化前原點(diǎn)行坐標(biāo)(這里是產(chǎn)品的中點(diǎn))
**Phi:**變化前的原點(diǎn)角度
**Row1:**變化后原點(diǎn)列坐標(biāo)
**Column1:**變化后原點(diǎn)行坐標(biāo)
**AimPhi:**變化的原點(diǎn)角度
**HomMat2D:**生成的旋轉(zhuǎn)+平移矩陣

第三步——字符摳圖

現(xiàn)在需要將我們的噴碼字符利用圖像分割技術(shù)將其提取出來
首先將圖像通道分割下(這里是彩色圖片,黑白圖片可以直接進(jìn)行提取)
此處以藍(lán)色噴碼為例:
使用通道相減突出藍(lán)色區(qū)域,然后做簡(jiǎn)單的閾值分割

sub_image (R, G, ImageTemp, 1, 0) //彩色圖片由于是紅色噴碼進(jìn)行通道相減增加對(duì)比度threshold (ImageTemp, RegionRoi, 14, 255) //初步選出感興趣區(qū)域opening_rectangle1 (RegionRoi, RegionOpen, 5, 5) //降低干擾reduce_domain (ImageTemp, RegionOpen, ImageReduced) //圖像裁剪留下噴碼區(qū)域crop_domain (ImageReduced, ImagePart1) //圖像填充在窗口中顯示

如果有的噴碼噴印傾斜,需要校正。(原因:因?yàn)樾枰眯螒B(tài)學(xué)將噴碼連接為一個(gè)圖像對(duì)象,防止噴碼粘連)

*矯正傾斜噴碼text_line_slant (ImagePart1, ImagePart1,150,-rad(45),rad(45), SlantAngle) //自動(dòng)計(jì)算圖像斜率 hom_mat2d_identity (HomMat2DIdentity) //建立單位矩陣hom_mat2d_slant (HomMat2DIdentity, -SlantAngle, 'x', 0, 0, HomMat2DSlant) //計(jì)算傾斜矯正矩陣affine_trans_image (ImagePart1, AffImagePart1, HomMat2DSlant, 'nearest_neighbor', 'true') //使用傾斜矯正矩陣將傾斜的噴碼變化為豎直

傾斜噴碼:

傾斜校正:

接著,將需要的噴碼提取出來進(jìn)行***歸一化操作***(這步很重要!!!)就是將摳取出的噴碼圖片為一張二值圖像(只有黑和白)。

threshold (AffImagePart1, RegionRoi, 14, 255)opening_rectangle1 (RegionRoi, RegionOpen, 10, 5) dilation_rectangle1 (RegionOpen, RegionTemp, 1, 200) //豎直膨脹dilation_rectangle1 (RegionTemp, RegionTemp, 10, 1) //橫向膨脹connection (RegionTemp, RegionTemp)intersection (RegionTemp, RegionOpen, RegionInter)select_shape (RegionInter, RegionTemp, ['height','area','width'], \'and', [250,3000,90], [500,50000,300])count_obj (RegionTemp, Number)sort_region (RegionTemp, RegionTemp, 'character', 'true', 'row') //字符排序/*以下代碼表示將單個(gè)噴碼單獨(dú)截取保存進(jìn)入對(duì)應(yīng)的子文件夾*/for RedIndex := 1 to Number by 1 select_obj (RegionTemp, ObjectRegionTemp, RedIndex) //將排好順序的噴碼按照序號(hào)單個(gè)處理smallest_rectangle2 (ObjectRegionTemp, Row4, Column4, Phi2, Length11, Length21)gen_rectangle2 (Rectangle3, Row4, Column4, Phi2, Length11, Length21)reduce_domain (AffImagePart1, Rectangle3, ImageReduced1)crop_domain (ImageReduced1, ImagePart)binary_threshold (ImagePart, RegionCode, 'max_separability', 'light', UsedThreshold1) //單個(gè)字符提取opening_rectangle1 (RegionCode, RegionCode, 10, 5)get_image_size (ImagePart, Width, Height) //計(jì)算窗口圖片大小gen_image_const (ImageBk, 'byte', Width, Height) //創(chuàng)建一個(gè)與窗口大小一致的圖片overpaint_region (ImageBk, ImageBk, 255, 'fill') //將創(chuàng)建的圖片背景噴印為白色overpaint_region (ImageBk, RegionCode, 0, 'fill') //將噴碼制定為黑色噴印在背景上tuple_rand (1, Rand) //生成一個(gè)隨機(jī)數(shù)Index_rand:=int(Rand*1000) write_image (ImageBk, 'jpeg', 0, Path+Code[RedIndex-1]+'/'+Code[RedIndex-1]+'_'+Index_rand) //保存歸一化后的字符模板

第四步——字符訓(xùn)練

字符的圖片現(xiàn)在有了,接下來就可以通過簡(jiǎn)單的二值閾值分割得到字符區(qū)域:
字符摳圖結(jié)果:

算法邏輯:

首先我們需要建立一個(gè)“字符集文件”字符集文件的格式為“.trf”
創(chuàng)建一個(gè)Halcon中定義的一個(gè)錯(cuò)誤處理來規(guī)避重復(fù)創(chuàng)建字符集文件,默認(rèn)下一次的創(chuàng)建會(huì)復(fù)寫字符集。

TrainFile1:=string+'-0-9A-Z.trf' dev_set_check ('~give_error') //錯(cuò)誤處理起始 delete_file (TrainFile1) //刪除舊版本字符集 dev_set_check ('give_error')

將字符寫入字符集:
此處兩個(gè)for循壞,是實(shí)現(xiàn)自動(dòng)將字符寫入對(duì)應(yīng)子文件

for FileIndex := 0 to filenum-1 by 1list_files (Path+Code[FileIndex], ['files','follow_links'], ImageFiles)tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)for Index := 0 to |ImageFiles| - 1 by 1read_image (Image, ImageFiles[Index])binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold)opening_rectangle1 (Region, RegionOpen, 5, 5)append_ocr_trainf (RegionOpen, GrayImage,Code[FileIndex], TrainFile1) endfor endfor stop ()

字符集的創(chuàng)建完畢后我們開始自己訓(xùn)練我們的分類器(MLP)文件格式為“.omc”
其中uniq(sort(Code)),表示分類的類別不能有重復(fù)的,這個(gè)是合并重復(fù)的標(biāo)簽。
例如:標(biāo)簽中a[‘0’,‘0’,‘0’,‘2’,‘1’]使用了后會(huì)變?yōu)閍[‘0’,‘1’,‘2’]

read_ocr_trainf_names (TrainFile1, CharacterNames, CharacterCount) create_ocr_class_mlp (8, 10, 'constant', 'default', uniq(sort(Code)), 80, 'none', 10, 42, OCRHandle) trainf_ocr_class_mlp (OCRHandle, TrainFile1, 200, 1, 0.01, Error, ErrorLog) FontFile:='shanjin.omc' write_ocr_class_mlp(OCRHandle,FontFile) clear_ocr_class_mlp (OCRHandle) stop ()

第五步—— 字符檢測(cè)識(shí)別

最后進(jìn)行我們字符的識(shí)別,同樣的將字符提取出來,讀取我們自己的分類器(MLP)進(jìn)行OCR識(shí)別
算法邏輯:

這里我們來看看具體的源碼(僅供參考)

list_files (FilePath, ['files','follow_links'], ImageFiles) tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles) for Index := 0 to |ImageFiles| - 1 by 1read_image (Image, ImageFiles[Index])rgb1_to_gray (Image, GrayImage)Locate (Image, ImageTemp, ProductRegion, []) //圖像定位與轉(zhuǎn)正CodeDiff:=31Params:=[Color,CodeDiff]ExtracteRegionOCV (ImageTemp, Rectangle, ProductRegion, RegionResult, Params, NumberDots, NumberAllDots) //噴碼的提取stop ()fill_up_shape (RegionResult, RegionFillUp, 'area', 1, 100)sort_region (RegionFillUp, SortedRegions, 'character', 'true', 'row')union1 (SortedRegions, RegionUnion)difference (ImageTemp, RegionUnion, RegionDifference)paint_region (RegionDifference, GrayImage, ImageOcrRaw, 255, 'fill')paint_region (RegionUnion, ImageOcrRaw, ImageOcr, 0, 'fill')read_ocr_class_mlp (FontFile, OCRHandle)do_ocr_multi_class_mlp (SortedRegions, ImageOcr, OCRHandle, Class, Confidence)stop () endfor

最終結(jié)果:

寫在最后

在我們訓(xùn)練完畢MLP后我們想要測(cè)試他的能力怎么辦呢?我們可以使用助手的功能:
在調(diào)試自己訓(xùn)練的分類器是否正確的時(shí)候可以打開Halcon自帶的OCR助手來查看自己的分類器能力。

在其中加載自己的字符集和分類器

這里我們還可以點(diǎn)擊編輯菜單中選擇"生成變化"這里可以我們的字符集變得更豐富:

然后用分類器(MLP)測(cè)試下識(shí)別的能力:

總結(jié)

以上是生活随笔為你收集整理的基于HALCON的喷码字符自训练与识别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。