胡瓊鏵,應霜霜,馬 超
(哈爾濱理工大學 計算機科學與技術學院,黑龍江 哈爾濱 150080)
目前,利用物聯(lián)網(wǎng)、人工智能以及移動互聯(lián)網(wǎng)等新一代信息技術對現(xiàn)有生產(chǎn)、生活等不同場景下的各類基礎設施進行改造、升級,以提高人們的生產(chǎn)、生活的效率以及便捷性已成為主流趨勢。其中,儀表系統(tǒng)即是其中的一類主要基礎設施。隨著信息與通信、電子信息等技術的逐漸成熟,新鋪設的儀表系統(tǒng)普遍具備數(shù)字化、智能化特征,可支持遠程監(jiān)控功能的實現(xiàn)。但是目前的現(xiàn)實場景下,仍存在大量的舊式儀表,它們無法支持遠程監(jiān)控功能的實現(xiàn),這對于現(xiàn)在基礎設施的改造、升級工作造成了較大的障礙。同時,簡單的對舊式儀表系統(tǒng)進行替換,也存在較大的困難,例如,新式儀表系統(tǒng)普遍價格較高,現(xiàn)存的舊式儀表所處的場景不具備安裝新式儀表系統(tǒng)的客觀條件等。
針對這一問題,本文提供一種基于KNN算法的儀表實時監(jiān)控邊緣平臺,其可部署在現(xiàn)有的舊式儀表系統(tǒng)周圍,以實現(xiàn)對舊式儀表系統(tǒng)實時數(shù)據(jù)的智能識別,并將其傳輸至遠程的云服務平臺。本邊緣平臺的硬件部分以樹莓派為基礎,搭載圖像采集模塊以及基于KNN算法的圖像智能識別模塊,遠端云服務平臺采用前后端分離的架構,作為整個系統(tǒng)的控制中心,具有監(jiān)控、統(tǒng)計、報警等多項功能,滿足了對儀表系統(tǒng)這一基礎設施的數(shù)字化、智能化管理需求。其中,在智能算法的選擇方面,我們綜合考慮了多種不同算法在執(zhí)行時間、準確率與召回率、需要消耗的計算資源等多方面的情況,最終決定采用KNN算法,其是一種耗費計算資源較低,且性能較高的經(jīng)典機器學習算法,相對來說,更合適資源受限的邊緣計算平臺。
本邊緣平臺選擇使用樹莓派4(Raspberry Pi 4)作為硬件平臺,搭載圖像采集模塊、圖像傳輸模塊??紤]暗光以及光線條件較差的環(huán)境,在攝像頭搭載2-3個紅外補光燈,補光燈可根據(jù)光照環(huán)境的強弱自動調(diào)節(jié)曝光補償程度,從而使攝像頭獲得不錯的成像效果。
利用攝像頭指定時間間隔收集儀表盤的圖像,成像保存在樹莓派圖像采集模塊中,樹莓派中的圖像分析模塊接收圖片信息后,進行圖像預處理:轉化成灰度圖、降噪、旋轉圖像使數(shù)字在水平線上、識別邊緣和線條取得數(shù)字特征、高斯濾波、銳化、二值化處理,從而獲得效果最佳的儀表盤二值化圖像。然后,采用機器學習訓練KNearestOcr模型,采用OpenCV集成的KNN算法識別字符。輸出結果將其反饋到終端應用(移動端微信小程序,移動端App,網(wǎng)頁等)。處理過的圖像加入到模板庫中,更新訓練集,提高模型識別數(shù)字的精準程度。整體設計架構如圖1所示。
圖1 總體設計架構
OpenCV是一個基于BSD許可(開源)發(fā)行的跨平臺計算機視覺和機器學習軟件庫,可以運行在Linux、Windows、Android和Mac OS等不同的操作系統(tǒng)上。它輕量級而且高效,集成了圖像處理和計算機視覺方面的很多通用算法。
在此處,OpenCV庫的主要任務是對采集儀表盤圖像進行早期的預處理:提供轉化為灰度圖、圖像降噪、圖像旋轉、高斯濾波、銳化、二值化處理等圖像預處理的集成算法,從而獲得效果最佳的二值化圖像。
識別圖像中的文本是一種非常流行的計算機視覺應用,此過程通常稱為光學字符識別(Optical Character Recognition,OCR)。主要有以下步驟:
2.2.1 圖像獲取
利用OpenCV,我們只需要數(shù)行源代碼即可實現(xiàn)通過USB網(wǎng)絡攝像頭獲取電表圖像以及從文件里獲取圖像信息。在這里我們定義一個基類ImageInput(),這個基類負責保留圖像地址以及圖像采集的時間戳。接下來需要派生類DirectoryInput()和CameraInput()各自實現(xiàn)nextImage()方法。前者負責從文件讀取圖像。后者負責通過VideoCapture.open()打開攝像頭輸入通道,獲取圖像。最后通過saveImage()方法存儲圖像。至此,提供了一個簡單的USB視頻類供攝像頭獲取圖像以及進行讀取、存儲。分辨率為640×480像素,這對于本系統(tǒng)而言已經(jīng)足夠了。畢竟較高的分辨率并不能提高字符識別的準確性,并會占用更多的內(nèi)存和CPU時間進行圖像處理,而這在Raspberry Pi上是非常有限的資源。
2.2.2 cv::Mat圖像存儲
現(xiàn)在,我們來簡要了解一下OpenCV是如何存儲圖像的。從文件中讀取圖像的imread()和從相機中捕捉圖像的VideoCapture.read()都會產(chǎn)生類型為cv::Mat的對象。
命名空間前綴cv封裝了OpenCV的大多數(shù)類和函數(shù),以避免與其他庫發(fā)生名稱沖突。Mat是一個n維數(shù)組或矩陣,可以用來存儲不同的東西。
Mat對象_img包含捕獲的圖像在默認情況下,imread()和VideoCapture.read()在BGR(藍-綠-紅)顏色空間中生成圖像。這與已知的RGB顏色模型相同,只是記憶中的顏色通道反向排列。該模型用藍、綠、紅三個獨立的強度值來描述圖像的每個像素。
另一個常用的顏色模型是灰度,用單個灰度值對每個像素進行編碼。在這種情況下,cv::Mat是一個二維矩陣,而它在BGR色彩空間是三維的。使用channels()函數(shù)可以檢測圖像的顏色模型。BGR返回值為3,灰度值為1。
一個常用的函數(shù)是用cvtColor方法將BGR圖像轉換為灰度:
cv::Mat color,gray;
color=cv::imread(filename);
cvtColor(color,gray,CV_BGR2GRAY);
2.2.3 圖像處理
電表獲取的圖像存儲在cv::Mat對象中。在我們能夠對計數(shù)器進行字符識別之前,算法必須識別和提取計數(shù)器的單個數(shù)字。ImageProcessor類封裝了這樣做所需的所有方法。
使用setput()傳遞要處理的圖像。函數(shù)process()執(zhí)行完整的處理。成功時,getOutput()提供結果。它由圖像矢量組成。每個圖像都包含計數(shù)器的一個數(shù)字。函數(shù)process()將各個處理步驟委托給其他私有函數(shù)。每個圖像的過程都是一樣的:轉換成灰度圖像、旋轉,使計數(shù)器的數(shù)字在水平線上、找到并切下每個數(shù)字。
2.2.4 圖像旋轉
將圖像轉換為灰度后,算法應該將圖像旋轉到計數(shù)器的所有數(shù)字在一條水平線上。得到水平排列的,明亮的輪廓。圖像的旋轉通過映射變換執(zhí)行cv::warpAffine()函數(shù)。簡單地說,這些就是圖像的變化,所有的平行線即使經(jīng)過平移、旋轉和縮放變換后仍然是平行的。所有這些變換都可以用變換矩陣來描述。當要對同一幅圖像應用多個映射變換時,出于性能方面的原因,通常有意義的做法是先一步一步地將每個變換矩陣相乘,最后對圖像進行實際的變換。預設角度的圖像旋轉被外包給rotate()函數(shù)。
2.2.5 識別邊緣和線條
其實,OpenCV的很大一部分是用于邊緣和線條的識別。在此我們用的是Canny算法。Canny()接收灰度圖像作為輸入,輸出一幅以檢測到的邊緣為輸出的圖像。
cv::Mat ImageProcessor::cannyEdges(){
cv::Mat edges;
cv::Canny(_imgGray,edges,
_config.getCannyThreshold1(),
_config.getCannyThreshold2());
return edges;
}
不重要的細節(jié)現(xiàn)在基本上從邊緣圖像消失了。然而,多余的圖像信息仍然存在:儀表外殼邊緣、計數(shù)器邊緣和計數(shù)環(huán)邊緣。圖像依舊角度不正確,但是水平線的偏差正好是我們需要對齊圖像的角度。
我們接下來通過cv::HoughLines()進行Hough變換,返回包含所有檢測到的向量行。HoughLines()返回以弧度為單位的角度,而rotate()需要以角度為單位的旋轉角度。
由上一步得到的向量_digits的每個分量都包含一個數(shù)字的邊緣圖像。
計算機通過光學字符識別(OCR)的方法得到由圖像來表示字符的信息。一種常用的技術是機器學習。第一步是用各種測試數(shù)據(jù)訓練系統(tǒng)。這就產(chǎn)生了一個模型,它描述了從數(shù)據(jù)(圖像)到信息(字符編碼)的映射。使用這個模型,訓練后的系統(tǒng)就可以在第二步中將未知數(shù)據(jù)轉換成所需的信息,且每一輪圖像識別后都會將得到的字符存儲到本地并持續(xù)更新訓練模板庫,從而逐漸提高圖像識別的精確度。
KNN(K-Nearest-Neighbor)算法是一種常見的監(jiān)督學習方法。工作原理是提取樣本,根據(jù)某種距離形式來計算與檢測樣本距離最靠近的K個“鄰居”,以此來分類檢測樣本屬于哪一類。
通常將樣本中出現(xiàn)次數(shù)最多的標記作為分類的結果,越靠近平均值,樣本就屬于這一類。在計算樣本距離時我們采用歐式距離公式來實現(xiàn)。
接下來就是最簡單的轉換,將數(shù)字圖片黑色部分(背景)變0,有數(shù)字輪廓的部分變1。轉換后的大小要合適,太小會影響識別準確度,太大會增加計算量。
機器學習的算法有很多種,OpenCV在很大程度上實現(xiàn)了這些算法。為一個特定的問題選擇正確的算法需要大量的經(jīng)驗和知識。下面使用了最簡單的算法之一:K近鄰(KNN)。眾所周知,它非常準確,但另一方面,它消耗了大量的CPU時間和內(nèi)存。這些缺點對我們的應用程序來說并不是那么關鍵——有足夠的條件。雖然內(nèi)存僅限樹莓派,但對于只需要檢測8-15位數(shù)字的小尺寸模型來說,它應該足夠了。
對于訓練和字符識別的實施,班級KNearestOcr負責:
class KNearestOcr{
public:
int learn(const cv::Mat&img);
char recognize(const cv::Mat&img);
voidsaveTrainingData();
boolloadTrainingData();
private:
cv::MatprepareSample(const cv::Mat&img);
voidinitModel();
cv::Mat_samples;
cv::Mat_responses;
CvKNearest*_pModel;
};
機器學習程序可以處理各種輸入數(shù)據(jù),而不僅僅是圖片。輸入數(shù)據(jù)的準備也稱為“特征提取”。相關特征在我們利用OpenCV進行圖像預處理中已經(jīng)完成。它提供了數(shù)字的輪廓,沒有任何背景和顏色信息。首先,它利用cv::resize()將所有的數(shù)字統(tǒng)一為10×10像素大小。由于KNN處理的是浮點數(shù)的一維向量,因此使用函數(shù)reshape()和convertTo()將圖像矩陣轉換為如下格式:
cv::MatKNearestOcr::
prepareSample(const cv::Mat&img){
cv::Matroi,sample;
cv::resize(img,roi,cv::Size(10,10));
roi.reshape(1,1).convertTo(sample,CV_32F);
return sample;
}
然后,構建兩個字段_samples和_responses。_samples包含所有已經(jīng)成功通過訓練過程的特性(prepare-Sample的結果)。字段_responses包含訓練器針對每個特性的相關“響應”——即對應的數(shù)字。接下來運行實施互動訓練程序:
intKNearestOcr::learn(const cv::Mat&img){
cv::imshow('Learn',img);
int key=cv::waitKey(0);
if(key>'0'&&key<'9'){
_responses.push_back
(cv::Mat(1,1,CV_32F,(float)key-'0'));
_samples.push_back(prepareSample(img));
}
return key;
}
第一個cv::imshow()顯示數(shù)字的圖像。然后cv::waitKey()等待coach的輸入。如果這是一個有效的數(shù)字,那么它將與相關的特性一起寫入_responses和_samples。
用戶可以使用鍵‘q’或‘s’隨時終止訓練過程。在‘s’的情況下,saveTrainingData()方法將字段_samples和_responses寫入文件。
首先,KNearestOcr::loadTrainingData()初始化模型。
該模型現(xiàn)在能夠對使用prepareSample()準備的任何圖像進行分類,方法是確定最近的鄰居特征并返回相關的、學習到的響應。
recognize()使用find_nearest()來確定兩個最近的鄰居及其到原始對象的距離。只有當兩個值都匹配且距離低于閾值時,函數(shù)才返回一個有效的字符。需要花些時間來確定可配置的閾值ocrMaxDist。小的值會導致拒絕實際正確識別的值,并在捕獲的數(shù)據(jù)中造成更長的差距。相反,如果數(shù)值太高,結果會有很多誤差。對于本次的特定環(huán)境,作者發(fā)現(xiàn)使用值600000是最優(yōu)的。
charKNearestOcr::recognize(
const cv::Mat&img){
charcres='?';
cv::Mat results,
neighborResponses,dists;
float result=_pModel->find_nearest(
prepareSample(img),2,
results,neighborResponses,dists);
if(0==
int(neighborResponses.at
-
neighborResponses.at
&&
dists.at
<
_config.getOcrMaxDist()){
cres='0'+(int)result;
}
returncres;
}
經(jīng)終端設備識別分析后的儀表讀數(shù)通過MQTT協(xié)議發(fā)送到云端的服務器,云端提供管理員使用的管理平臺,通過管理平臺可以檢查、管理接入平臺的所有儀表,分析儀表歷史數(shù)值,并可設置閾值,平臺將在儀表讀數(shù)超出閾值后向儀表所綁定的管理員進行多管道的通知,如:App推送通知、短信通知、電話呼叫通知。由此組成功能完整的數(shù)字儀表遠程監(jiān)控系統(tǒng)。
基于KNN算法的儀表實時監(jiān)控邊緣平臺的實物以及部署場景如圖2所示。其中,攝像頭以及補光燈實時采集照片,通過樹莓派微型計算系統(tǒng)實時向云端傳輸圖像。在云服務器端利用OpenCV集成的算法對圖像中的數(shù)字進行識別、切割、提取。訓練KNearestOcr模型,利用KNN算法進行數(shù)字的識別。
圖2 實時監(jiān)控邊緣平臺的實物及部署場景
綜上所述,該方法有效解決了部分舊儀表盤無法就地更換新型數(shù)字儀表盤的問題,實現(xiàn)了對舊儀表盤的數(shù)字化、智能化監(jiān)控。通過此系統(tǒng)的設計與實現(xiàn),驗證了利用攝像頭采集數(shù)字圖像進行分析、監(jiān)控、統(tǒng)計、報警是具有可行性的。該系統(tǒng)具有較好的推廣價值,其實現(xiàn)成本較低,但結果識別的性能較高,經(jīng)過對KNN分類模型的簡單重新訓練,即可以方便地移植到不同現(xiàn)實場景下的各類舊式儀表系統(tǒng)所在的工作場所。