關於Halcon中variation_model模型的快速解讀。

  十一期間在家用期間研讀了下Halcon的variation_model模型,基本上全系復現了他的所有技術要求和細節,這裏做個記錄。

  其實這個模型的所有原理都不是很複雜的,而且Halcon中的幫助文檔也講的很是清楚,所以通過猜測、測試、編碼基本能搞清楚是怎麼回事。

  關於這個模型,Halcon裏有如下十來個函數:

  create_variation_model、prepare_variation_model, train_variation_model、compare_variation_model、prepare_direct_variation_model、clear_variation_model, clear_train_data_variation_model, compare_ext_variation_model, get_thresh_images_variation_model, get_variation_model、 clear_train_data_variation_model, write_variation_model 。

  看起來涉及到了蠻多的東西的。

  那麼一般的工作流程是:create_variation_model  ---> train_variation_model ---> prepare_variation_model  --->   compare_variation_model  ---> clear_variation_mode。

  即: 創建模型,然後訓練模型,接着就是準備模型,這個時候就可以使用了,那麼可以開始做輸入比較了,比較完事了,清楚模型。 

  所謂的variation_model的模型呢,其實是從一系列已經確認是OK的樣圖中,訓練出2幅結果圖,即上限圖和下限圖,也可以認爲是訓練出圖像公差帶,當要進行比較的時候,就看輸入的圖像的每個像素是否位於這個公差帶之類,如果是,則這個點是合格的,不是,則這個像素點就是不合格的區域。 

  那麼在Halcon中,把這個工作就分解爲了上面這一大堆函數。我們稍微來對每個函數做個解析。

  一、create_variation_model  創建模型。

  這個算子有如下幾個參數:

      create_variation_model( : : Width, Height, Type, Mode : ModelID)

  這裏主要是注意Type和Mode兩個參數。  

  其中Type可以取'byte', 'int2', 'uint2' 這三種類型,我這裏的解讀是這個算子支持我們常用的8位灰度圖像 和 16位的Raw圖像, 16位因爲有signed short和unsigned short,所有這裏也有int2 和uint2兩種類型。

  Mode參數有3個選擇,: 'standard', 'robust', 'direct',這也是這個算子的靈魂所在,具體的做法後續再說,在創建時只是保存了他們的值,並沒有做什麼。

  那麼創建的工作要做的一個事情就是分配內存,Halcon裏的幫助文章是這樣描述的:

  A variation model created with create_variation_model requires 12*Width*Height bytes of memory for Mode = 'standard' and Mode = 'robust' for Type = 'byte'. For Type = 'uint2' and Type = 'int2', 14*Width*Height are required. For Mode = 'direct' and after the training data has been cleared with clear_train_data_variation_model, 2*Width*Height bytes are required for Type = 'byte' and 4*Width*Height for the other image types.

  爲什麼是這樣的內存,我們後續再說,接着看下一個函數。

  二、train_variation_model 訓練模型

  這個算子是這個功能的最有特色的地方,他用於計算出variation_model 模型中的 ideal image和 variation image,即理想圖像和方差圖像。

  當Mode選擇 'standard', 'robust'時,此算子有效,當Mode爲'direct'無效。

  Mode爲 'standard'時,訓練採用求多幅平均值的方式獲取理想圖像以及對應的方差圖像,Mode爲 'robust'時,採用,求多幅圖像的中間值的方式獲取理想圖像以及對應的方差圖像。

  注意,這裏的求均值和方差是針對同一座標位置,不同圖像而言的,而不是針對單一圖像領域而言,這個概念一定不能能錯了,比如訓練5副圖像,他們某一行的對應位置數據分別爲:

       

  當選擇模式爲 'standard',訓練結果的 ideal image 值應該是(實際還需要四捨五入求整):     

         

   當選擇模式爲 'robust',訓練結果的 ideal image 值應該是:  

         

   當選擇'standard'模式,我們可以在找到一副OK圖像的時候,單獨把這幅圖像的數據訓練到variation_model模型,而如果使用'robust'方式,則必須一次性把所有的OK圖像添加到訓練模型中,無法動態的添加對象,但是,由於'robust'模式採用的是中值的方式,因此,其抗噪音效果要好很多。

  爲什麼'standard'模式可以隨時添加,而'robust'只能一次性添加,其實這個也很簡單,前一次求平均值的信息如果臨時保存了,那麼在新的OK圖需要添加時,可以直接利用前一次的有關信息進行溝通,而如果是採用求中值的方式,前面的排序信息一是難以保存(數據量大),二是即使保存了,對本次排序的作用也不大。 

  這個時候我們停來下分析下前面Halcon文檔裏的提出的variation_model模型的內存佔用大小,假如我們的Type是byte類型,使用'standard'模式,那麼Ideal Image佔用一份Width*Height字節內存,variation image必須是浮點類型的,佔用 4 * Width*Height字節內存,另外,我們能隨時添加新的OK的圖像,應該還需要一個臨時的int 類型的數據保存累加值(雖然Ideal Image保存了平均值,但是他是已經進行了取捨了, 精度不夠),這需要額外的4 * Width*Height字節內存,後面我們提到variation_model還需要有2個width * height自己大小的內存用來保存上限和下限的圖像數據,因此這裏就有大概 1 + 4 + 4 + 2 = 11 * width * height的內存了,還差一個,呵呵,不知道幹啥的了。 

  選擇'robust'模式時, ideal image好說,就是取中間值,但是對於variation image,並不是普通的方差圖像,在halcon中時這樣描述的:The corresponding variation image is computed as a suitably scaled median absolute deviation of the training images and the median image at the respective image positions,實際上,他這裏是計算的絕對中位差,即計算下面這個數的中間值了。       

         MAD=median(Xmedian(X))

  這個還需要舉例說明嗎????

  對於使用‘standard’模式的計算優化,也是有很多技巧的,不過這個應該很多人能掌握吧。但是如果是'robust'模式,直接寫求中值的方法大家應該都會,但是因爲這是個小規模大批量的排序和求中值的過程,其實是非常耗時的,比如W = 1000, H=1000,如果訓練20副圖像,那麼就是1000*1000 = 100萬個20個數字的排序,而且還涉及到到一個非常嚴重的cache miss問題。 即這20個數字的讀取每次都是跨越很大的內存地址差異的。

  如何提高這個排序的過程,我覺得在這裏指令集是有最大的優勢的,他有兩個好處,一是一次性處理多個字節,比如SSE處理16個字節,這樣我也就可以一次性加載16個字節,整體而言就少了很多次cache miss,第二,如果我需要利用指令集,則我需要儘量的避免條件判斷,因此,很多稍微顯得高級一點的排序都不太合適,我需要找到那種固定循環次數的最爲有效,比如冒泡排序,他就是固定的循環次數。

  對於N個圖像的逐像素排序求中值,一個簡單的C代碼如下所示:

  

  純C代碼的話,這個的效率絕對不是最高的,有很多優秀的排序算法都可以比這個快很多。但是他是最簡單,也是最簡潔的,最適合進行SIMD優化的。 看到中間的X循環了嗎,那就是他主要的計算量所在,這個循環用指令集優化是不是很簡單。

  有人說這個循環就是個典型的判斷分支語句啊,你剛剛說要避免分支,這明顯不就是個矛盾嗎,那麼我如果把這個循環這樣寫呢:

        

 

  他們結果是不是一樣,還有分支嗎,好了,到這一步,後面的SIMD指令應該不需要我說怎麼寫了吧,_mm_min_epu8 + _mm_max_epu8。

  至於median absolute deviation的中值的計算,除了需要計算MAD值之外,其他有任何區別嗎? MAD不恰好也可以用byte類型來記錄嗎,應該懂了吧。 

  三、prepare_variation_model 準備模型

     這個算子的有如下幾個參數:

      prepare_variation_model( : : ModelID, AbsThreshold, VarThreshold : )

  這個算子實際上是根據前面的訓練結果結合輸入的 AbsThreshold和VarThreshold參數確定最終的上限和下限圖像,即確認公差帶。

  Halcon內部的計算公式爲:

          

   i(x,y)是前面得到的Ideal Image, v(x,y)爲variation image,  au/al/bu/bl即爲算子的輸入參數。這個沒有啥好說的,具體可以看Halcon的幫助文檔。

  四、 compare_variation_model 比較模型

   算子原型爲:    compare_variation_model(Image : Region : ModelID : )

  經過前面的一些列操作,我們的準備工作就完成了,現在可以用來進行檢測了,檢測的依據如下式:  

          

   即在公差帶內的圖像爲合格部分,否則爲不合格部分。

  五、其他算子  

    clear_variation_model          --    刪除模型數據,這個沒啥好說的

    prepare_direct_variation_model    --    直接準備模型數據,這個在Mode設置爲direct時有效,他無需經過訓練,直接設置上下限數據,一般不使用

    clear_train_data_variation_model            --    清除訓練數據,當我們訓練完成後,那個Ideal Image 、variation image、臨時數據等等都是沒有用的了,都可以釋放掉,只需要保留上下限的數據了。

   還有幾個算子沒有必要說了吧。 

  總的來說,這是個比較簡單的算子,實際應用中可能還需要結合模版匹配等等定位操作,然後在映射圖像等,當然也有特殊場合可以直接使用的。 

  我這裏做了一個DEMO,有興趣的朋友可以試用一下: https://files.cnblogs.com/files/Imageshop/Variation_Model.rar?t=1697790804&download=true

 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章