基于圖像處理(HOG)與數據分布特征的水位識別

Update

代碼已經上傳到github上了,可以點這里


Cutting

一直說這要整理一下Computer Vision課程的大作業,拖了好久。這兩天忙著寫一個訂單處理的第三方庫,陷入了僵局,所以換個口味,把大作業整理一下。

Requirement

Water depth measurement.
實現目標:通過使用計算機視覺及圖像處理技術,通過正確檢測插入水體的標尺和水體水平面的刻度值來確定水位高度。圖像數據見附件。
可允許用戶輸入標尺最上端的高度值、照相機鏡頭距離標尺最上端的和水平面形成的夾角、刻度尺正面和照相機之間夾角值,以及標尺每個刻度的高度值。

評分標準:

  1. 能否解決存在的多種問題,其中包括:
    a. 標尺刻度靠近水面的部分可能由于長期浸泡在污水中出現污漬而無法識別。
    b. 水面可能出現的霧氣,造成識別困難。
    c. 標尺可能有一定的弧度,造成精確度量存在問題。
  2. 計算效率:使用任意目前流行的Intel i3處理器及更快的處理器,每個4096*4096像素分辨率以內的圖像測量時間不超過20秒(包含圖像讀取及數據值輸出)。
    3.系統完整性。

使用語言:Visual C++(可使用OpenCV)
部分附件

樣例圖

Train of Thought

整個過程大致分為四個階段:圖像預處理、識別、過濾、數據處理

1. 預處理

首先會進行一個直方圖均衡化的操作。再由于輸入的圖像差別較大,有如上圖這種十分清晰的,也存在模糊到人工識別也比較吃力的。所以顯然不同的清晰度應該有不同的處理方式。這里簡單的將清晰度分為清晰模糊兩類。

對于清晰的圖片,進行適度腐蝕膨脹操作,以進一步提高圖片中標尺的對比度。

            //腐蝕、膨脹
            int erosion_size = 3;
            Mat element = getStructuringElement( MORPH_RECT,
                                                Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                                Point( erosion_size, erosion_size ) );
            /// 腐蝕操作
            erode( origin, origin, element );
            dilate(origin, origin, element);

對于模糊的圖片數據,先進行濾波,再提高對比度

            //創建并初始化濾波模板
            cv::Mat kernel(3,3,CV_32F,cv::Scalar(0));
            kernel.at<float>(1,1) = 5.0;
            kernel.at<float>(0,1) = -1.0;
            kernel.at<float>(1,0) = -1.0;
            kernel.at<float>(1,2) = -1.0;
            kernel.at<float>(2,1) = -1.0;

            cv::filter2D(origin,origin,origin.depth(),kernel);
            
            int alpha = 1.5;
            int beta = 50;
            for( int y = 0; y < origin.rows; y++ )
            {
                for( int x = 0; x < origin.cols; x++ )
                {
                    for( int c = 0; c < 3; c++ )
                    {
                        origin.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( origin.at<Vec3b>(y,x)[c] ) + beta );
                    }
                }
            }

對比效果:


腐蝕膨脹

2. 識別

考查了Haar LikeSIFTLBPHOG等算法。Haar Like多用于人臉識別,LBP多用于基于紋理特征的監測,所以不是很適合。SIFT做了簡單測試,識別效果如下:

SIFT識別效果

不是很理想,所以最后選定了HOG算法。

  • 訓練素材準備
    由于檢測的目標多位于水邊,環境多為山、天空、水、泥土等,所以額外加入了這些素材作為負樣本。由于負樣本創建有一定規格要求,所以使用Python腳本,批量裁剪,最后共得到負樣本42360個。
  • 訓練識別過程
    這一過程網上有不少代碼可供參考,主要是對于參數等選擇比較重要。這里我們定義部分參數如下:
//識別與檢測的參數
#define WIN_SIZE Size(64,64)
#define BLOCK_SIZE Size(8,8)
#define BLOCK_STRIDE Size(4,4)
#define CELL_SIZE Size(4,4)
#define BIN 12

2. 過濾

對于識別結果需要進行過濾。這里我們定義了一個Mask算法,用以合并多個過濾算法多結果。
對于每一種過濾算法,都會有各自的保留區域,將它們疊加,通過某個大小的矩形掃描,如果該矩形區域內,每一層的保留區域面積占比大于一個可調參數Threshold,則認為該矩形區域應該保留。

示意圖

這里我們使用了兩種過濾算法:

  • ColorFilter
    基于顏色特征的過濾。由于標尺上的顏色固定,故可以丟棄與之無關的顏色區域


    顏色過濾
  • Canny邊緣檢測過濾

    Canny算子多用于檢測物體的邊緣,我們通過保留邊緣區域后,并將邊緣鋪展開來,以得到保留區域。
    邊緣檢測過濾

    最后運用上面提到的多層Mask合并算法,得到最終的過濾保留區域。
    Mask疊加

可以看到將過濾結果應用于識別結果時,大量的誤識別被過濾掉了。原圖非常大,綠色的框框即為識別結果。


  • 單峰過濾
    由于一張圖中僅有一個標尺,所以通過前面的過濾后,我們認為,矩形在圖片上的分布應該如圖所示。將除最高峰以外的矩形丟棄。


  • Rectangle修正
    標尺中的"E"標示實際分布是均勻的,所以即使無法完全識別,也可以通過算法進行一個修正,自動補全出未被識別的"E"
    效果如下:


    修正效果

4. 數據處理

最后的處理是針對識別結果進行純數值分析的優化。我們認為識別系統穩定后,會存在一定的固有誤差,可以通過線性擬合的方式進行一個修正。將識別數據與真實數據進行擬合(這一點老師不是很贊成,認為沒有必要)。


數據擬合

Closing

這個大作業感覺還是很有難度的,部分的結果識別還是比較滿意的,但是也有一些圖片是偏差蠻大的。而且由于是直接調用的OpenCV的庫,實際上對圖像處理的一些算法還是沒有很深入,有機會再回來搞搞視覺吧。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 不同圖像灰度不同,邊界處一般會有明顯的邊緣,利用此特征可以分割圖像。需要說明的是:邊緣和物體間的邊界并不等同,邊緣...
    大川無敵閱讀 13,948評論 0 29
  • 知乎上看到一個話題——目前火熱的 Deep Learning 會滅絕傳統的 SIFT / SURF 特征提取方法嗎...
    牛奶芝麻閱讀 101,008評論 4 81
  • 計算機應用 2016,Vol. 36 Issue (11): 2979-2984,2992DOI:10.11772...
    wotacid閱讀 7,347評論 0 2
  • 我走遍世上每個角落 只為尋找最美的樹葉 然后 虔誠的 寫上你的名字 再夾進我最愛的書籍 仿佛這樣 才是永恒
    ivy_y閱讀 149評論 0 0
  • 常聽人說,十個胖子九個虛,這里的虛,就是脾虛。還有人說喝水都長胖,這個胖,也是脾虛不能運化水濕形成的痰濕。今天,和...
    郁茹閱讀 2,322評論 0 1