各位朋友好,這次來分享一個有意思的圖片分析方式,內容大宗一樣使用到python + opencv,不過這回是希望能讓工作變得輕鬆點而寫的小程式。因為內容屬機密,小弟僅能分享使用到的演算法跟網路文章,以及分析的結果圖片供各位參考,沒辦法公開程式碼,在此致上萬分歉意(,,・ω・,,)
小弟在4年前寫了個用python+opencv分析監視器影像抓老鼠[1]之後,就把python放在旁邊長灰塵了,也很久沒有動手繼續下個python程式。小弟的編程習慣也一樣不好,直到經歷工作中寫php、C#以後,目前小弟的工作上碰到了一些麻煩事。
[1] [Python作品]Python程設初體驗 ~之~ OpenCV分析監視器影像抓老鼠
https://hcyang1227.blogspot.com/2018/04/pypython-opencv.html
因為工作上的需要,小弟要經常用人眼判斷玻璃切割後的肋紋深度與滲透紋路深度,用顯微鏡附帶的電腦拉出深度、抄寫這些深度數據、滕到自己的電腦的excel內。雖然還在新人訓階段,但未來這種事情依然會大量重複操作。身為喜歡偷懶(?)的小弟,當然要想個方法簡化這些操作流程嘍!(ノ>ω<)ノ
所以當初撰寫python的時候,小弟將這個程式功能分成兩部分。第一部分,是分析已經嵌在圖片上的數字(小弟後續還要抄到筆記上再滕到電腦的數據),簡化抄寫流程。第二部分,是直接分析切割肋紋與滲透紋路,簡化人眼辨識流程。因為現在python的應用相當廣泛,隨便google一下就可以找到海量的文章,小弟也不需要一一仔細說明(果然是個懶人XD),真是太棒了d(`・∀・)b
首先,分析的圖片主要分為兩類,一種是圖片中有數字的版本,另一種則是圖片中沒有文字、只有切割肋紋與滲透紋路的版本。
這個比較簡單,平常經常使用3C產品的人,第一個想到的一定就是文字辨識(光學字元識別,Optical Character Recognition,即OCR)了。這個技術也已經成熟,小弟測試結果,辨識成功且正確的機率高達95%以上,已經是信賴性很高的一種分析了。
◆核心:影像分析(opencv)[cv2]
這邊小弟用opencv來讀取圖片、演算出凸顯紅色通道、將圖片灰階化(cv2.cvtColor)、取閥值(cv2.threshold)、在閾值圖像上應用膨脹(cv2.dilate)、尋找輪廓(cv2.findContours)、遍歷識別的輪廓、矩形部分被裁剪並傳遞給pytesseract以從中提取文本。
◆核心:文字辨識(OCR)[pytesseract]
OCR方面,小弟用了pytesseract這個package,它不但可以辨識數字,也可以辨識中文或是英文,可說是相當的全面。輸入方面,只要輸入一個圖像,它就會輸出一串分析出的文字。使用上小弟碰到的難關是,pytesseract需要另外安裝,且要在程式中標出它的所在位置(以小弟的電腦為例,敘述如下),否則程式就會直接GG給你看唷~
pytesseract.pytesseract.tesseract_cmd = 'C:\\Program Files\\Tesseract-OCR\\tesseract.exe'
[2] IT邦幫忙 - Day26-聽過 OCR 嗎? 實作看看吧 -- pytesseract
https://ithelp.ithome.com.tw/articles/10227263
◆核心:正則表達式[re]
有時候因為圖片不夠清晰、或是文字有點模糊,導致pytesseract輸出的文字有時候亂亂的,需要多加一些判定文字的方法。小弟用正則表達式這個方式取出文字裡面有類似um、前面又是小數的文字,再加上replace、find等方式反覆加強判定邏輯,讓辨別出些許錯字的pytesseract能夠再次回到類似123.45um的輸出(*‘ v`*)
[3] Day-27 Python2基本語法 -7
https://ithelp.ithome.com.tw/articles/10209446
這個比較困難,聰明的人也許已經想到很多分析方式了,但小弟比較笨,查了半天的網路文章,也只有開闢出這條分析的道路,辨識成功且正確的機率大概只有6~7成,信賴性不是很高。
◆核心:獲取邊緣[cv2]
這邊小弟用了3種方法來獲取邊緣。其中2種是下面連結提到的canny跟Sobel檢測算子,第3種是下面連結提到的傅立葉轉換。圖片都需要經過灰階化、模糊化、再偵測邊緣。
[4] OPENCV – Edge detection邊緣偵測
https://chtseng.wordpress.com/2016/12/05/opencv-edge-detection%E9%82%8A%E7%B7%A3%E5%81%B5%E6%B8%AC/
[5] 將圖片灰階化、模糊化、傅立葉轉換(Fourier transform)
https://www.gushiciku.cn/pl/gmpa/zh-tw
◆支線:獲取圖片右下角的座標尺[cv2]
這個不難。大致上的邏輯是,將右下角的座標尺裁切出來、用cv2.threshold取閥值、用cv2.findContours取輪廓,用cv2.boundingRect一個矩形將輪廓包圍,取出矩形的寬便是座標尺的像素寬嘍。
◆核心:獲取玻璃邊界、肋紋等直線[cv2]
圖片中最顯著的,也是要最先偵測的,便是玻璃的上下邊界。這點可以透過霍夫變換(cv2.HoughLines)輕鬆達成,只要閥值設定得夠好,也會連同肋紋的直線一起獲得。獲得一大堆直線後,小弟用獨特的演算法分析出玻璃上下邊界跟肋紋線。這樣不但可以獲得肋紋到玻璃的距離,也可在接下來獲得滲透紋路後,計算滲透到玻璃的距離。
[6] python-opencv 直线检测
https://blog.csdn.net/qq_27009517/article/details/103471640
◆核心:尋找肋紋的起始點[cv2]
前面的霍夫變換得到玻璃邊界後,我們有玻璃的rho值跟theta值,透過theta值我們便可旋轉圖片轉正來分析滲透紋路。接著,如果我們還能知道肋紋的起始點,便可從起始點起算一段距離,取該處垂直線下的滲透深度,這也是小弟在工作上需要固定量測滲透的手法。簡而言之,不知道起始部/終了部的x值,小弟就無法獲知滲透深度y。
這邊小弟自己想了個解析圖片的方式,來比對並驗證切割的起始部/終了部在哪裡(這邊小弟寫了約120行程式碼,有點長,一樣不公開),就請各位玩味一下以下的圖片嘍~(*゚∀゚*)
◆核心:擬合出滲透紋路曲線[scipy]
要如何取出若隱若現的滲透紋路已經夠頭疼了,還要在這一堆雜訊中進一步去fitting它?應該不太可能吧。不過,小弟仍然在這裡面,找到了一條可能的道路。這邊小弟使用了其中一種的邊緣偵測,將其輪廓分析並得到一些可以用的數據(這邊小弟寫了約240行程式碼,有點長,一樣不公開)(*゚∀゚*)
在這些程式碼裡面,除了前面有提過的閥值(cv2.threshold)、膨脹(cv2.dilate)、尋找輪廓(cv2.findContours)等基本知識以外,最重要的關鍵在於導入回歸分析跟RANSAC(RANdom SAmple Consensus)。
[7] 曲线拟合教程:Python如何拟合曲线?
https://www.lsbin.com/6510.html
[8] Wikipedia - 隨機抽樣一致
https://zh.wikipedia.org/wiki/%E9%9A%A8%E6%A9%9F%E6%8A%BD%E6%A8%A3%E4%B8%80%E8%87%B4
[9] RANSAC演算法詳解(附Python擬合直線模型代碼)
https://zhuanlan.zhihu.com/p/62238520
§其他分析中使用到的package§
這邊羅列一些分析中使用到的方法,也是幫自己重新複習使用到的演算法。
◆略過各種警示[warnings]
有時候有警示是好事,因為它不會中斷運行,且會提醒使用者目前哪裡可能有出錯危險。有時候有警示是壞事,因為它會破壞使用者print出的畫面,讓原本輸出有序的排版變得雜亂難讀。小弟為了讓command-line畫面變得較易讀,就略過各種警示了(*´艸`*)
[10] How to Fix: RuntimeWarning: overflow encountered in exp
https://www.statology.org/runtimewarning-overflow-encountered-in-exp/
◆彈跳選項視窗功能[tkinter]
為了讓python程式用起來很Windows,稍微加入彈跳選項視窗可說是個必然。在程式中,小弟加入了tkinter,讓程式能夠自動跳個視窗出來詢問使用者要進行A程序還是要進行B程序、並根據選擇結果取得相關數值,不用讓使用者還要去大海般的程式碼改自己想要的數值。
[11] python tkinter的訊息框模組(messagebox,simpledialog)
https://www.796t.com/article.php?id=152287
◆寫入文字檔[python內建]
在分析完圖片文字、肋紋深度、滲透深度後,小弟希望這些文字全部彙整成一個文字檔。python當然也能夠辦到這件事,使用上也不難。小弟在撰寫過程中碰到的問題是,當遇到存入的文字有ascii以外的字元,該怎麼辦?還好,python也允許存成unicode的文字檔(encoding),即便OCR分析的文字有特殊字元,一樣不會在存成文字檔時報錯。
[12] Python 寫檔,寫入 txt 文字檔
https://shengyu7697.github.io/python-write-text-file/
[13] Python 3 Tutorial 第二堂(1)Unicode 支援、基本 I/O
https://openhome.cc/Gossip/CodeData/PythonTutorial/UnicodeBasicIOPy3.html
◆旋轉圖片[cv2]
在這個小程式中,為了讓計算上更加簡單,需要將圖片轉正。小弟根據以下的程式碼進一步修改成自己想要的,在找到圖片的玻璃傾斜角度後,根據這個傾斜角度做圖片轉正,並且"向內"裁切圖片(需要三角函數計算),讓旋轉後的圖片不要有黑框。
[14] 用python进行OpenCV进行图像旋转
https://blog.csdn.net/qq_37674858/article/details/80708393
◆批次讀取圖片檔[os]
以前小弟有寫過了,這邊不再贅述~(^u^)
[1] [Python作品]Python程設初體驗 ~之~ OpenCV分析監視器影像抓老鼠
https://hcyang1227.blogspot.com/2018/04/pypython-opencv.html
◆尋找numpy array中的最大值/最小值[numpy]
為了得到肋紋壓縮y軸後的一維array的最小值出現在哪個x值,小弟用了這個方法,詳細用法請參見資料。
[15] python中找出numpy array数组的最值及其索引
https://blog.csdn.net/songyunli1111/article/details/79322103
◆將data繪製成散佈圖或是折線圖[matplotlib]
有用過matlab的朋友,一定都對它的強大繪圖能力感到驚嘆。在python中,也可以用類似的指令來繪出你所想要的圖喔。上面的許多圖都是用matplotlib繪出的,
[16] Python Matplotlib.pyplot.plot()用法及代碼示例
https://vimsky.com/zh-tw/examples/usage/matplotlib-pyplot-plot-function-in-python.html
◆輪廓距離線段的最短距離[python內建]
在程式中,小弟需要知道滲透的輪廓上的點距離玻璃的邊界直線有多遠,因此參考了以下的文章。順道一提,下面這篇的程式碼有點問題,各位看官請多留意~(幾何數學概念好的話就會發現問題了)(灬ºωº灬)
[17] 【python】檢查輪廓的任何點是否與直線相交的有效方法是什麼?
https://www.796t.com/post/Y2ZjN2U=.html
◆刪除numpy array中的單元、欄、列[numpy]
這個用法在小弟的程式裡,是用在當滲透紋路的雜訊的輪廓跟玻璃邊界接近時,要將太過接近的數據給刪掉,以便更加凸顯滲透紋路本身的輪廓。
[18] np.delete(): Remove items/rows/columns from Numpy Array
https://thispointer.com/delete-elements-rows-or-columns-from-a-numpy-array-by-index-positions-using-numpy-delete-in-python/
◆針對輪廓做排序[cv2]
為了篩選出對自己最有用的大區塊輪廓,小弟這邊需要排列輪廓的大小。詳細的用法可以玩味這篇文章。
[19] Python opencv sorting contours [duplicate]
https://stackoverflow.com/questions/39403183/python-opencv-sorting-contours
◆合併輪廓(numpy array)[numpy]
在小弟的程式碼中,因為要將大部分的輪廓合在一起,這邊用到了numpy.concatenate的用法。
[20] numpy.concatenate
https://www.tutorialspoint.com/numpy/numpy_concatenate.htm
沒有留言:
張貼留言