不知道你們會不會有這種感受,常常是以爲本身學的技術沒有用,擔憂本身能不能勝任工做。由於咱們一般學的都是基礎的,老師教完以後作幾道題目會作考試過了表明學過了。html
所以我想找一些「好玩又有用的技術」,咱們共同窗習成長.python
一、 APP 測評git
首先推薦簡單介紹一下這款實用的app,掃描全能王,固然還有其餘相似功能的產品。下圖是它的一個主要功能介紹:github
今天要講解的技術就是這款app的「手機掃描儀」的功能,具體是能夠實現對證件,銀行卡,資料等進行掃描,與普通相機最大不一樣是能夠實現幾何變形的自動矯正,同時還可以實現對文字內容加強(顯示 效果更佳)。bash
二、分析原理app
舉個例子,對於公交卡進行掃描,因爲拍攝人員的技術以及客觀的一些緣由致使拍攝出來的圖片通常狀況下存在這必定的幾何畸變和其餘一些背景的干擾。學習
以下圖所示,拍攝一張公交卡,背景是一張存在條紋的紙張。而咱們不但願有這麼大的幾何變形以及背景干擾,會影響下一步的處理(如OCR識別)。spa
存在的問題:(1)幾何變形.net
(2)背景干擾3d
思路:
對於因爲拍攝視角致使的變換,通常可採用 透視變換 進行矯正。
什麼是透視變換?
透視變換是將圖片投影到一個新的視平面,也稱爲投影映射。
掃描全能王?圖像技術真的簡單又好玩,我也會用了
透視投影的標準模型
這裏不詳細展開透視變換矩陣係數的求法,有興趣的能夠參考下面的連接有詳細的推導過程。
咱們須要明白一點,求解透視變換的矩陣須要四組對應點便可。
下圖展現由發生畸變的四邊形矯正成一個長方形的示意圖
掃描全能王?圖像技術真的簡單又好玩,我也會用了
參考資料:www.cnblogs.com/jsxyhelu/p/… 此時,咱們已經明白咱們須要完成的任務是什麼——找四組對應點。
怎麼找?
從上面的一些分析的圖,咱們能夠大概猜到,是否能夠經過變換先後的四個角點構造四組對應點?
好,對於拍攝圖求角點的方法如何求?
咱們知道,上圖的四個標號序號角點都是相鄰兩條線段之間相交的點。所以能夠經過
(1)霍夫檢測(直線)+求解直接角點 來查找拍攝圖的四個角點,
(2)尋找四邊形的輪廓的四個頂點 來肯定拍攝圖的四個角點。
(3)固然還有其餘辦法,眼神好的小夥伴能夠手動輸入四個頂點的座標。
這裏,咱們已經完成了尋找拍攝圖的四個定點。
那麼對應的點如何獲取?
對於你須要掃描的文件,通常都會事先選型或者說選參數,實際上就是在設置對應點的座標(變換後的四邊形尺寸)。
例如,此時咱們想要掃描公交卡,由百度可知,公交卡的尺寸比例是16:9,所以咱們只要按照比例進行設置座標點,公交卡矯正後的形狀就能基本知足咱們的要求。
這裏,咱們基本上已經知道如何矯正 幾何變換 了。
還剩下的問題是 背景干擾 ?
可是因爲咱們使用透視變換時,所用的點是四邊形的四個角點,這個時候已經將背景剔除在外了,因此背景的干擾天然而然就無需考慮了。
三、代碼實現
思路:
一、讀入圖片並進行預處理
二、尋找拍攝圖的四個角點
三、根據預設的尺寸,設置對應的四個角點,並計算透視變換的矩陣參數
四、對拍攝圖進行透視變換
爲了讓你們閱讀起來更舒服,就不講一些很是基礎的東西,講解裏面的關鍵步驟便可
環境:python3.6,opencv 3.4.2
關鍵步驟一:找四個角點
cnts = cv2.findContours(Image, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# 2、尋找輪廓四個頂點
if len(cnts) > 0:
cnts =sorted(cnts,key=cv2.contourArea,reverse=True)
for c in cnts:
peri = cv2.arcLength(c,True) # 輪廓按大小降序排序
approx = cv2.approxPolyDP(c,0.02 * peri,True) # 獲取近似的輪廓
if len(approx) ==4: # 近似輪廓有四個頂點
docCnt = approx
break
複製代碼
關鍵步驟二:根據預設尺寸計算透視變換矩陣
公交卡的比例是16:9,這裏假設長高(320,180)
注意:因爲並非正方形,因此這裏要先肯定長和高的對應
假設,拍攝致使變形不會大到使長和高的尺寸發生變化
頂點的順序是 左上、左下、右下、右上
分佈計算並比較 左上到左下的距離 左上到右上的距離 肯定長高
if calculate_distance(p[0],p[1])<calculate_distance(p[0],p[3]):
pts2 = np.float32([[0,0],[0,180],[320,180],[320,0]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(image,M,(320,180))
else:
pts2 = np.float32([[0,0],[0,320],[180,320],[180,0]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(image,M,(180,320))
複製代碼
此時便可完成咱們的任務。
看一下最終的效果吧
掃描全能王?圖像技術真的簡單又好玩,我也會用了
完整代碼連接請看https://github.com/DWCTOD/AI_study/tree/master/%E5%90%88%E6%A0%BC%E7%9A%84CV%E5%B7%A5%E7%A8%8B%E5%B8%88/%E5%AE%9E%E6%88%98%E7%AF%87/opencv/%EF%BC%88%E4%B8%80%EF%BC%89%E5%9B%BE%E5%83%8F%E6%89%AB%E6%8F%8F%E5%8A%9F%E8%83%BD%E2%80%94%E2%80%94%E5%87%A0%E4%BD%95%E7%9F%AB%E6%AD%A3