sort_region是個很有用的算子,在對多個Region進行排序時,經常用到。
算子含義:根據區域的相對位置對區域進行排序。(Sorting of regions with respect to their relative position.)
算子簽名:sort_region(Regions : SortedRegions : SortMode, Order, RowOrCol : )
例如:
sort_region (Regions, SortedRegions, 'first_point', 'true', 'row')
其中Regions是待排序的多個區域; 'first_point' 是排序模式(SortMode); 'true' 是遞增,如果是'false' 則是遞減;'row' 是按照“行”來排序。
排序模式一共有上面7種,其中最常用的是前三種,而'first_point'、'last_point'是剛好相反的排序方式。因此只需要研究前兩種排序模式就可以了:'character'、 'first_point' 。
一、'first_point'
sort_region (Regions, SortedRegions, 'first_point', 'true', 'row')
含義:根據各個區域的行座標的最小值,按照從小到大的遞增方式,對Regions進行排序。
下圖中,矩形和圓的“行座標的最小值”點如下所示:
寫個程序驗證一下:(圖中細黑線是爲了便於觀察不同Region的相對關係)
1 dev_get_window (WindowHandle)
2 dev_set_color ('red')
3 set_display_font (WindowHandle, 13, 'Courier', 'true', 'false')
4
5 read_image (Image, '黑框.jpg')
6 threshold (Image, Region, 0, 120)
7 fill_up (Region, Region)
8 opening_circle (Region, Region, 3.5)
9 connection (Region, Regions)
10
11 sort_region (Regions, SortedRegions, 'first_point', 'true', 'row')
12
13 dev_display (Image)
14
15 count_obj (SortedRegions, Number)
16 for Index := 1 to Number by 1
17 select_obj (SortedRegions, CurrentRect, Index)
18 dev_display (CurrentRect)
19 area_center (CurrentRect, Area, Row, Column)
20 disp_message (WindowHandle, ' ' + Index, 'image', Row - 8, Column - 20, 'black', 'true')
21 endfor
觀察4號區域,雖然4號區域的中心點座標的Row值都大於5號、6號、7號區域,但是4號區域反而排在前面。
這說明不是按照“中心點”的行座標排序的,而可能是按照“最高點”的行座標來排序的(多次設計程序驗證,發現確實如此)。
二、'character'
sort_region (Regions, SortedRegions, 'character', 'true', 'row')
這種排序方式的探究,是本文的重點。網上搜到的資料,多把它的作用描述爲:先根據行從小到大排序,再根據列從小到大排序。
這種描述當然沒有問題,但是語焉不詳,它迴避了一個問題:哪些區域該被先劃爲同一行?如果垂直方向上區域有重疊怎麼辦?
看一下幫助文檔中怎麼說的:
翻譯:這些區域將被視爲一行中的字符,並將根據它們在行中的順序進行排序:如果兩個區域水平重疊,則將根據其列值對其進行排序,否則將根據其行值對其進行排序。爲了能夠正確地對“行”進行排序,行中的所有區域必須在垂直方向上相互重疊(?)。 此外,相鄰行中的區域不得重疊。
有這麼幾個要點:('character', 'true', 'row')
① 同一行中有1個或多個區域,這些區域合起來叫做“同一行”。
② “同一行”的若干個區域可以重疊,因爲可以通過“列”區分開。
③ 相鄰的“同一行”區域(的最小外接正矩形)不能有任何重疊,如果有重疊,則排序結果不可控。
④ 確定哪些區域屬於“同一行”是核心。
注意:這裏帶雙引號的“同一行”都有特殊的相同意義,後文同。
下面用程序驗證:
1 dev_get_window (WindowHandle)
2 dev_set_color ('blue')
3 set_display_font (WindowHandle, 18, 'Courier', 'true', 'false')
4
5 read_image (Image, '紅線圖.jpg')
6
7 * 反覆改變下面的部分矩形的中心點座標、長寬,觀察
8 gen_rectangle2 (Region1, 80, 120, 0, 40, 30)
9 gen_rectangle2 (Region2, 83, 350, 0, 40, 30)
10 gen_rectangle2 (Region3, 77, 580, 0, 40, 30)
11
12 gen_rectangle2 (Region4, 245, 300, 0, 40, 121)
13
14 gen_rectangle2 (Region5, 400, 235, 0, 40, 30)
15 gen_rectangle2 (Region6, 396, 450, 0, 40, 30)
16
17 concat_obj (Region1, Region2, RectHubs)
18 concat_obj (RectHubs, Region3, RectHubs)
19 concat_obj (RectHubs, Region4, RectHubs)
20 concat_obj (RectHubs, Region5, RectHubs)
21 concat_obj (RectHubs, Region6, RectHubs)
22
23 * 將RectHubs按'character'規則排序
24 sort_region (RectHubs, SortedRegions, 'character', 'true', 'row')
25
26 dev_display (Image)
27
28 count_obj (SortedRegions, Number)
29 for Index := 1 to Number by 1
30 select_obj (SortedRegions, CurrentRect, Index)
31 dev_display (CurrentRect)
32 area_center (CurrentRect, Area, Row, Column)
33 disp_message (WindowHandle, ' ' + Index, 'image', Row - 12, Column - 26, 'black', 'true')
34 endfor
分析:
“第一行”:矩形1、2、3
“第二行”:矩形4
“第三行”:矩形5、6
這三“行”,彼此之間都沒有任何重疊。
將上面程序第12行標紅的數字121改成128,運行得到的排序就變了:
上圖中,長矩形5和矩形4在“垂直方向”有重疊。注意:不需要兩個Region有實際的重疊交集區域,只需要Row座標有重疊就算“垂直方向”重疊。
此時行的分組變成了:
“第一行”:矩形1、2、3
“第二行”:矩形4、5、6
沒有“第三行”了。
如果再亂一點,那就沒辦法根據這種規律排序了,如下圖:
再跑一下前面的“黑框.jpg”圖體會一下:
1 dev_get_window (WindowHandle)
2 dev_set_color ('red')
3 set_display_font (WindowHandle, 13, 'Courier', 'true', 'false')
4
5 read_image (Image, '黑框.jpg')
6 threshold (Image, Region, 0, 120)
7 fill_up (Region, Region)
8 opening_circle (Region, Region, 3.5)
9 connection (Region, Regions)
10
11 sort_region (Regions, SortedRegions, 'character', 'true', 'row')
12
13 dev_display (Image)
14
15 count_obj (SortedRegions, Number)
16 for Index := 1 to Number by 1
17 select_obj (SortedRegions, CurrentRect, Index)
18 dev_display (CurrentRect)
19 area_center (CurrentRect, Area, Row, Column)
20 disp_message (WindowHandle, ' ' + Index, 'image', Row - 8, Column - 20, 'black', 'true')
21 endfor
其運行結果和“分行”情況,如下圖所示:
因此,確定哪些區域屬於“同一行”是 'character' 模式排序的核心。
三、'upper_left'
跟'upper_left'相似的一共有4個:
研究發現,'upper_left'排序模式是根據不同區域的“最小外接斜矩形”(rectangle2)的最高點位置來排序的。
這四種排序模式不算常用,而且理解比較繞,就不過多介紹了。