訂閱
糾錯(cuò)
加入自媒體

如何使用Python創(chuàng)建自己的文檔掃描儀

介紹

對(duì)這個(gè)項(xiàng)目的動(dòng)機(jī)很簡(jiǎn)單。我們中的許多人轉(zhuǎn)向了在線工作。隨著在線工作量的增加,人們通常不得不通過(guò)電子郵件或其他方式呈現(xiàn)文檔的數(shù)字化版本。換句話說(shuō),將任何文檔轉(zhuǎn)換為掃描文檔。本文,將介紹如何使用 Python 從頭開(kāi)始創(chuàng)建文檔掃描儀。準(zhǔn)確地說(shuō),是用于圖像/視頻處理的 OpenCV 庫(kù)。事不宜遲,讓我們開(kāi)始吧。文件掃描儀在進(jìn)入編碼部分之前,我們需要了解我們將要做什么。這是在開(kāi)始這個(gè)項(xiàng)目之前問(wèn)自己的一系列問(wèn)題。我們想在這里建造什么?

— 文件掃描儀。好的。但它做什么或應(yīng)該做什么?— 顯然,要掃描文檔。正確的。那么,掃描出來(lái)的文件應(yīng)該是什么樣子的呢?— 好問(wèn)題,對(duì)吧?具體來(lái)看,掃描的文檔應(yīng)該有兩個(gè)特點(diǎn):看起來(lái)像掃描的文檔,黑白 (B&W) 顏色;正確旋轉(zhuǎn)(無(wú)隨機(jī)角度)。讓我們先從簡(jiǎn)單的功能開(kāi)始,并根據(jù)需要增加其他功能。編碼文件掃描儀首先讓我們導(dǎo)入這個(gè)項(xiàng)目需要的所有庫(kù)(我們可能會(huì)根據(jù)需要添加一些東西)import numpy as np
import cv2
from skimage.filters import threshold_local
import math
from scipy import ndimage
print("Imports are Done!")
I. 第一個(gè)屬性:掃描(黑白)視圖讓我們從掃描儀的第一個(gè)屬性開(kāi)始——生成掃描圖像!在這個(gè)例子中,我使用了一張照片,來(lái)自Yuval Noah Harari的書(shū)*“21 Lessons for the 21st Century*。

旁注:它是一本很棒的書(shū)。本系列的其他兩本書(shū)(“Sapiens: A Brief History of Humankind”和“Homo Deus: A Brief History of Tomorrow”)都建議閱讀!回到我們的文檔掃描儀,我們希望通過(guò)更改配色方案使該圖像看起來(lái)清晰明快。讓我們將此操作稱(chēng)為  Scan_view()。為了使它成為一個(gè)完整的應(yīng)用程序項(xiàng)目,讓我們創(chuàng)建一個(gè)名為Scanner的類(lèi),其中Scan_view() 將是其方法。class Scanner:
def __init__(self, img):
 self.img = img

def Scan_View(self):
 print("Scanned View")
 # read the original image, copy it,
 # apply threshold to "scannify" it
 image = cv2.imread(self.img)
 orig = image.copy()
 
 # convert our image to grayscale, apply threshold
 # to create scanned view effect
 image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 thr = threshold_local(image, 11, offset = 10, method = "gaussian")
 image = (image > thr).a(chǎn)stype("uint8") * 255
 # show the original image and the edge detected image
 #cv2.imshow("orig", orig)
 #cv2.imshow("Scanned", image)
 #cv2.waitKey(0)
 #cv2.destroyAllWindows()
 print(np.shape(orig), np.shape(image))
   
 # Saving a B&W image itself
 cv2.imwrite('Part_scan_view.png', image)
 return image
代碼的快速解釋:創(chuàng)建一個(gè)scan具有圖像作為其屬性的對(duì)象。因此,self.img = img在__init__()方法中使用;另外,想要一種負(fù)責(zé)更改此屬性(即圖像/文檔)的方法——更改配色方案、旋轉(zhuǎn)、裁剪、調(diào)整大小等。因此Scan_View()對(duì)它的類(lèi)屬性(即,對(duì)它自己或self)執(zhí)行操作。這個(gè)方法的實(shí)質(zhì)隱藏在threshold_local操作中。這基本上是一種基于像素的局部鄰域計(jì)算閾值掩碼的操作。這也稱(chēng)為自適應(yīng)閾值。閾值是像素的局部鄰域的加權(quán)平均值減去常數(shù)。找到閾值掩碼后,我們只需將前景像素值選擇為image>threshold。我們可以保存新的清晰新鮮的圖像并返回以備進(jìn)一步處理。要運(yùn)行代碼,我們可以簡(jiǎn)單地創(chuàng)建一個(gè)scan對(duì)象并為其提供文檔/照片作為其屬性,如下所示:
if __name__=="__main__":
# Defining the image name
img = "21_Lesson_21th_Century.jpeg"

# Calling the scanner class
scan = Scanner(img)

# Scanning the image -> B&W scheme
scanned_im = scan.Scan_View()
結(jié)果,我們得到了這張圖片:

上述文件的掃描版本。讓我們繼續(xù)進(jìn)行項(xiàng)目的下一部分。II. 第二個(gè)屬性:文檔輪換讓我們繼續(xù)我們的掃描儀的第二個(gè)屬性——文檔旋轉(zhuǎn)!假設(shè),我們以隨機(jī)角度拍攝了一本書(shū)的照片。自動(dòng)旋轉(zhuǎn)它以獲得自上而下的正面視圖不是很好嗎?當(dāng)然會(huì)!問(wèn)題是怎么做?最初,我們正在考慮使用主成分分析 (PCA) 來(lái)確定文檔方向。然而,對(duì)于這個(gè)項(xiàng)目來(lái)說(shuō),這似乎有點(diǎn)過(guò)分了。我們想要一些簡(jiǎn)單但有效的東西。會(huì)自動(dòng)確定文本/邊框線和水平線之間的旋轉(zhuǎn)角度的東西。因此,想出了一個(gè)更簡(jiǎn)單的方法,它基本上利用了霍夫變換。簡(jiǎn)而言之,霍夫變換是一種用于檢測(cè)各種形狀的技術(shù)。在我們的例子中,這將是一組沿著文本行的行!好主意,對(duì)吧?但是為了使這種方法健壯,我們需要確保檢測(cè)到正確的方向。一些線條可能沿著文本出現(xiàn),但其他線條沿著書(shū)籍/文檔邊緣出現(xiàn)——我們不希望那樣。所以,我們想要平均這些變化。換句話說(shuō),要找到所有線角的中值。因此,我們將掃描對(duì)象(Rotation())的新方法定義如下:class Scanner:
def __init__(self, img):
 self.img = img
def Rotation(self):
 print("Rotation")
 # read the original image, copy it,
 # rotate it
 image = cv2.imread(self.img)
 orig = image.copy()
 
 image = cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY)
 img_edges = cv2.Canny(image, 100, 100, apertureSize=3)
 lines = cv2.HoughLinesP(img_edges, rho=1, theta=np.pi / 180.0, threshold=160, minLineLength=100, maxLineGap=10)
 
 # calculate all the angles:
 angles = []
 for [[x1, y1, x2, y2]] in lines:
  angle = math.degrees(math.a(chǎn)tan2(y2 - y1, x2 - x1))
  angles.a(chǎn)ppend(angle)
 
 # average angles
 median_angle = np.median(angles)
 # actual rotation
 image = ndimage.rotate(image, median_angle)
 # Saving an image itself
 cv2.imwrite('Part_rotation.png', image)
 return image
如上所述,這部分應(yīng)用程序的重點(diǎn)是找到正確的霍夫線(HoughLinesP()方法,其中P代表概率,請(qǐng)參閱參考資料以了解有關(guān)此方法的更多信息)我們從每條線獲得角度的中值并將其用于文檔旋轉(zhuǎn)(ndimage.rotate()方法)。我們可以對(duì)清晰的黑白圖像執(zhí)行此操作,如下所示:if __name__=="__main__":
# Defining the image name
img = "Part_scan_view.png"
 
  # Calling the scanner class
scan = Scanner(img)
 
  # Performing Rotation
rotated_im = scan.Rotation()
結(jié)果,我們得到了一個(gè)旋轉(zhuǎn)的圖像:

精彩的掃描、清晰和旋轉(zhuǎn)的圖像!完整代碼對(duì)于感興趣的讀者,這里是一個(gè)GitHub 存儲(chǔ)庫(kù),其中包含每種方法的更多詳細(xì)信息和文檔。h概括在本文中,我們學(xué)習(xí)了如何使用著名的用于圖像/視頻處理的 Python 庫(kù) OpenCV 從頭開(kāi)始構(gòu)建文檔掃描儀的工作原型。未來(lái)發(fā)展將這個(gè)應(yīng)用程序稱(chēng)為文檔掃描儀 (v.1), 因?yàn)橛幸恍┛梢赃M(jìn)一步改進(jìn)它的地方。1.例如,使用另一種(或改進(jìn)的)算法進(jìn)行文檔輪換。由于其性質(zhì),該算法可能并不總是在 100% 的情況下提供完美的俯視圖。一種替代方法可能是使用主成分分析(或 PCA)來(lái)確定文檔的更精確方向。但這超出了本文的范圍。2.關(guān)于旋轉(zhuǎn)本身,我不喜歡旋轉(zhuǎn)圖像上的那些空黑塊。這也可以解決以改進(jìn)此應(yīng)用程序?赡苁鞘顾鼈?yōu)榭?( NaN) 值。3.另一個(gè)可能需要仔細(xì)檢查的操作是黑白顏色轉(zhuǎn)換。我認(rèn)為自適應(yīng)閾值是一個(gè)不錯(cuò)的選擇,但是,可能有更好的方法。


聲明: 本文由入駐維科號(hào)的作者撰寫(xiě),觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

    人工智能 獵頭職位 更多
    掃碼關(guān)注公眾號(hào)
    OFweek人工智能網(wǎng)
    獲取更多精彩內(nèi)容
    文章糾錯(cuò)
    x
    *文字標(biāo)題:
    *糾錯(cuò)內(nèi)容:
    聯(lián)系郵箱:
    *驗(yàn) 證 碼:

    粵公網(wǎng)安備 44030502002758號(hào)