前言
模闆比對和仿射變換,經常一起使用,他們之前的位置變換一般有兩種情況!
情況一
模闆是一個很正的圖,利用模闆的位置,将歪的圖像擺正。
情況二
模闆和圖檔正不正都無所謂,隻需想模闆的位置,比對到目前圖檔的位置。
先從比較簡單的第二種情況說起:
我們首先從标準的原圖中擷取模闆(後面會講到,從圖中得到模闆,和從模闆檔案中得到模闆的細微差別。)比如從原圖裡扣出一部分作為模闆如:
reduce_domain (Image, RegionErosion, ImageReduced)
建立模闆
然後,就可以通過 create_shape_model 建立模闆了。
*建立模闆
create_shape_model (ImageReduced, 3, 0, rad(360), 'auto', 'auto', 'use_polarity', 'auto', 'auto', ModelID)
觀察模闆
接下來可以看看,模闆大概的樣子,幫助後面模闆比對時,确認相關參數(該函數也可忽略):
* 觀察模闆
inspect_shape_model (ImageReduced, ShapeModelImage, ShapeModelRegion, 4, 65)
模闆比對
接下來就是 抓取新的一張圖 做模闆比對。兩張圖在同一鏡頭參數,是以共用一坐标系,這是前提,注意這點,友善接下來的了解。
* 模闆比對
find_shape_model (SearchImage, ModelID, 0, rad(360), 0.3, 1, 0.5,
'least_squares', 0, 1,
RowMatch, ColumnMatch, AngleMatch, Score)
這裡的 SearchImage就是新的一張圖,ModelID就是建立模闆時的輸出參數,和模闆對應。
這裡和 仿射變換 密切相關的參數是: RowMatch, ColumnMatch, AngleMatch。也就是 XY和角度。
find_shape_model 通過 ModelID,擷取到模闆的相關資訊.(比如,模闆的形狀)
拿到了資訊之後,就開始在新圖中找比對,輸出比對的内容的坐标以及旋轉角度,這個旋轉的角度是相對應模闆圖像的偏移角度,坐标就是比對内容區域中心在圖中的坐标。
仿射變換
*擷取标準圖的摳圖中心
area_center(ImageReduced, Area, Row1, Column1)
*根據兩個中心和角度,算出旋轉矩陣
vector_angle_to_rigid (Row1, Column1, 0, RowMatch, ColumnMatch, AngleMatch, MovementOfModel)
*根據旋轉中心做仿射變換
affine_trans_region(RegionOpening1, RegionAffineTrans, MovementOfModel,
'nearest_neighbor')
模闆比對隻是告訴了我,新的圖像中被比對到的位置(XY)以及對應模闆圖像的偏移角度。
那,如何将 模闆本身 移動到 新圖像中比對到的内容,與之重合?
vector_angle_to_rigid
我們需要算子:vector_angle_to_rigid
可以認為,這個算子需要兩個輸入,需要移動的圖形的位姿(xy和角度),以及目标點的位姿(xy和角度)。最後會輸出一個矩陣,這個矩陣,這個矩陣可以完成圖形仿射變換。
那模闆本身在原圖中的坐标,我們可以通過 area_center 這個算子計算得到。(需要知道角度嗎?答案是不需要,因為模闆比對給出的角度是比對到的内容和模闆的角度偏移量。是以模闆的角度預設為0)
是以,就有:
*根據兩個中心和角度,算出旋轉矩陣
vector_angle_to_rigid (Row1, Column1, 0, RowMatch,
ColumnMatch, AngleMatch, MovementOfModel)
Row1, Column1, 0: 就是 模闆的位姿資訊。注意這裡角度就是0
RowMatch, ColumnMatch, AngleMatch:這個就是模闆比對找到的目标資訊。
注意:如果找打的是多個目标,那麼這些變量代表的都是數組。
最後一個參數,MovementOfModel,就是輸出的 變換矩陣。
affine_trans_region
最後,移動這個操作可以通過,affine_trans_region,完成:
*根據旋轉中心做仿射變換
affine_trans_region(RegionOpening1, RegionAffineTrans, MovementOfModel,
'nearest_neighbor')
如果是移動圖檔可以使用,affine_trans_image。
圖像擺正
擺正的思路就是,先去一個擷取一個正的模闆。讀取的圖檔可能是偏的。是以這次不動的是模闆,移動的是圖檔。
* 圖像擺正
area_center(SearchImage, Area, Row2, Column2)
vector_angle_to_rigid (RowMatch, ColumnMatch, AngleMatch, Row2, Column2, 0, MovementOfModel)
affine_trans_image (SearchImage, ImageAffineTrans, MovementOfModel,
'constant', 'false')
是以這次,在算子vector_angle_to_rigid 中,模闆比對得到的坐标放在前面(誰動,誰放在前面),而圖檔坐标放在後面。如果隻考慮擺正,這裡其實有用的隻是角度。
從圖中得到模闆,和從模闆檔案中得到模闆的細微差別
如果是從圖像裡得到模闆,那麼模闆的位置,以及其他資訊可以直接拿到。
還有更常見的一種用法,就是先将模闆儲存成檔案。也就是先制作一個模闆。
create_shape_model (ImageReduced, 2, 0, rad(360), 'auto', 'auto',
'use_polarity', 'auto', 'auto', ModelID)
write_shape_model (ModelID, name +'.mb')
write_shape_model
建立模闆之後,通過 write_shape_model 将建立的模闆進行儲存。
read_shape_model
需要使用模闆比對時,在将其讀出:
* 讀取模闆
read_shape_model ('數字05.mb', ModelID)
* 産生的輪廓在原點
get_shape_model_contours (ModelContours, ModelID, 1)
get_shape_model_contours
讀出模闆,得到 ModleID, 然後 get_shape_model_contours 可以根據 ModleID 得到模闆的輪廓。
但是此時,輪廓的位置時在圖檔原點上。(是以,儲存的模闆檔案是不包含位置資訊的)
是以要通過 vector_angle_to_rigid 計算矩陣時,位置參數XY可以填0,角度當然也是0.
這個就是通過模闆生成的輪廓,可以看到有點小瑕疵,我們要處理一下:
select_contours_xld (UnionContours, SelectedContours,
'contour_length', 20, 20000, -0.5, 0.5)
上面這句話的意思就是較短的輪廓線不要:
還有些輪廓線雖然連在一起,但是不是一個整體,這樣不利于我們進行填充(有時,我們需要對輪廓線進行填充)。
union_adjacent_contours_xld
union_adjacent_contours_xld,可以将連着的輪廓線變成一個對象:
gen_region_contour_xld
gen_region_contour_xld ,對輪廓線進行填充
* 填充
gen_region_contour_xld (SelectedContours, RegionXLD, 'filled')
但是,如果此時填充,會遇到一個問題,前面說到,get_shape_model_contours 擷取的輪廓中心坐标在圖檔原點,那麼,就會有部分的輪廓在圖檔的外面,在外面的部分無法填充。是以,一般我們需要将輪廓移到圖檔内在填充。不過這裡需要注意的是,再進行仿射變換的話,起始坐标,必須是這個移到後的點,而不是(0,0)。
小結
這篇文章,主要介紹了模闆比對和仿射變換的相關内容,模闆比對的很多相關參數,沒有一一講解。我覺得 模闆比對和仿射變換 的關系 這個更為重要,也更難了解。後續有時間,我也會将模闆比對的關參數記錄一下。歡迎評論區讨論。