欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Python和OpenCV實現(xiàn)實時文檔掃描與矯正系統(tǒng)

 更新時間:2025年05月19日 08:29:29   作者:知舟不敘  
在日常工作和學(xué)習(xí)中,我們經(jīng)常需要將紙質(zhì)文檔數(shù)字化,手動拍攝文檔照片常常會出現(xiàn)角度傾斜、透?視變形等問題,影響后續(xù)使用,本文將介紹如何使用Python和OpenCV構(gòu)建一個實時文檔掃描與矯正系統(tǒng),能夠通過攝像頭自動檢測文檔邊緣并進(jìn)行透?視變換矯正,需要的朋友可以參考下

一、系統(tǒng)概述

該系統(tǒng)主要實現(xiàn)以下功能:

  1. 實時攝像頭捕獲圖像
  2. 邊緣檢測和輪廓查找
  3. 文檔輪廓識別
  4. 透 視變換矯正文檔
  5. 二值化處理增強(qiáng)可讀性

二、核心代碼解析

1. 導(dǎo)入必要庫

import numpy as np
import cv2

我們主要使用NumPy進(jìn)行數(shù)值計算,OpenCV進(jìn)行圖像處理。

2. 輔助函數(shù)定義

首先定義了一個簡單的圖像顯示函數(shù),方便調(diào)試:

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(10)

3. 坐標(biāo)點排序函數(shù)

order_points函數(shù)用于將檢測到的文檔四個角點按順序排列(左上、右上、右下、左下):

def order_points(pts):
    rect = np.zeros((4,2),dtype="float32")
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]  # 左上點(x+y最小)
    rect[2] = pts[np.argmax(s)]  # 右下點(x+y最大)
    diff = np.diff(pts,axis=1)
    rect[1] = pts[np.argmin(diff)]  # 右上點(y-x最小)
    rect[3] = pts[np.argmax(diff)]  # 左下點(y-x最大)
    return rect

這個函數(shù)的作用是對給定的4個二維坐標(biāo)點進(jìn)行排序,使其按照左上、右上、右下、左下的順序排列。這在文檔掃描、圖像矯正等應(yīng)用中非常重要,因為我們需要知道每個角點的確切位置才能正確地進(jìn)行透視變換。

函數(shù)詳細(xì)解析

(1)排序邏輯說明

  1. 左上點(rect[0]):選擇x+y值最小的點

    • 因為左上角在坐標(biāo)系中 x 和 y 值都較小,相加結(jié)果最小
  2. 右下點(rect[2]):選擇x+y值最大的點

    • 因為右下角在坐標(biāo)系中 x 和 y 值都較大,相加結(jié)果最大
  3. 右上點(rect[1]):選擇y-x值最小的點

    • 右上角的特點是 y 相對較小而 x 相對較大,所以 y-x 值最小
  4. 左下點(rect[3]):選擇y-x值最大的點

    • 左下角的特點是 y 相對較大而 x 相對較小,所以 y-x 值最大

(2)示例

假設(shè)有4個點:

	A(10, 20)  # 假設(shè)是左上
	B(50, 20)  # 右上
	C(50, 60)  # 右下
	D(10, 60)  # 左下

計算過程:

  1. x+y值:[30, 70, 110, 70]

    • 最小30 → A(左上)
    • 最大110 → C(右下)
  2. y-x值:[10, -30, 10, 50]

    • 最小-30 → B(右上)
    • 最大50 → D(左下)

最終排序結(jié)果:[A, B, C, D] 即 [左上, 右上, 右下, 左下]

(3)為什么這種方法有效

這種方法利用了二維坐標(biāo)點的幾何特性:

  • 在標(biāo)準(zhǔn)坐標(biāo)系中,左上角的x和y值都較小
  • 右下角的x和y值都較大
  • 右上角的x較大而y較小
  • 左下角的x較小而y較大

通過簡單的加減運(yùn)算就能可靠地區(qū)分出各個角點,不需要復(fù)雜的幾何計算。

4. 透視變換函數(shù)

four_point_transform函數(shù)實現(xiàn)了文檔矯正的核心功能:

def four_point_transform(image,pts):
    rect = order_points(pts)
    (tl,tr,br,bl) = rect
    
    # 計算變換后的寬度和高度
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA),int(widthB))
    
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA),int(heightB))
    
    # 定義目標(biāo)圖像坐標(biāo)
    dst = np.array([[0,0],[maxWidth - 1,0],
                    [maxWidth - 1,maxHeight - 1],[0,maxHeight - 1]],dtype="float32")

    # 計算透視變換矩陣并應(yīng)用
    M = cv2.getPerspectiveTransform(rect,dst)
    warped = cv2.warpPerspective(image,M,(maxWidth,maxHeight))
    
    return warped

這個函數(shù)實現(xiàn)了透視變換(Perspective Transformation),用于將圖像中的任意四邊形區(qū)域矯正為一個矩形(即"去透視"效果)。

函數(shù)詳細(xì)解析

  • 輸入?yún)?shù)
def four_point_transform(image, pts):
  • image: 原始圖像
  • pts: 包含4個點的數(shù)組,表示要轉(zhuǎn)換的四邊形區(qū)域
  • 坐標(biāo)點排序
rect = order_points(pts)
(tl, tr, br, bl) = rect  # 分解為左上(top-left)、右上(top-right)、右下(bottom-right)、左下(bottom-left)

使用之前介紹的order_points函數(shù)將4個點按順序排列

  • 計算輸出圖像的寬度
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))  # 底邊長度
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))  # 頂邊長度
maxWidth = max(int(widthA), int(widthB))  # 取最大值作為輸出圖像寬度

計算四邊形底部和頂部的邊長,選擇較長的作為輸出寬度

  • 計算輸出圖像的高度
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))  # 右邊高度
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))  # 左邊高度
maxHeight = max(int(heightA), int(heightB))  # 取最大值作為輸出圖像高度

計算四邊形右側(cè)和左側(cè)的邊長,選擇較長的作為輸出高度

  • 定義目標(biāo)矩形坐標(biāo)
dst = np.array([
    [0, 0],  # 左上
    [maxWidth - 1, 0],  # 右上
    [maxWidth - 1, maxHeight - 1],  # 右下
    [0, maxHeight - 1]  # 左下
], dtype="float32")

定義變換后的矩形角點坐標(biāo)(從(0,0)開始的正矩形)

  • 計算透視變換矩陣并應(yīng)用
M = cv2.getPerspectiveTransform(rect, dst)  # 計算變換矩陣
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))  # 應(yīng)用變換
  • getPerspectiveTransform: 計算從原始四邊形到目標(biāo)矩形的3x3變換矩陣
  • warpPerspective: 應(yīng)用這個變換矩陣到原始圖像
  • 返回結(jié)果
return warped

返回矯正后的矩形圖像

  • 透視變換原理圖示
原始圖像中的四邊形               變換后的矩形
   tl--------tr                    0--------maxWidth
    \        /                      |        |
     \      /                       |        |
      bl----br                       maxHeight
  1. 為什么需要這樣計算寬度和高度?

取最大值的原因

  • 原始四邊形可能有透視變形,兩條對邊長度可能不等
  • 選擇較大的值可以確保所有內(nèi)容都能包含在輸出圖像中

減1的原因

  • 圖像坐標(biāo)從0開始,所以寬度為maxWidth的圖像,最大x坐標(biāo)是maxWidth-1

5. 主程序流程

主程序?qū)崿F(xiàn)了實時文檔檢測和矯正的完整流程:

  1. 初始化攝像頭
cap = cv2.VideoCapture(0)
if not cap.isOpened():
    print("Cannot open camera")
    exit()
  • 實時處理循環(huán)
while True:
    flag = 0
    ret,image = cap.read()
    orig = image.copy()
    if not ret:
        print("不能讀取攝像頭")
        break
  • 圖像預(yù)處理
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(5,5),0)  # 高斯濾波降噪
edged = cv2.Canny(gray,75,200)  # Canny邊緣檢測
  • 輪廓檢測與篩選
cnts = cv2.findContours(edged,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
cnts = sorted(cnts,key=cv2.contourArea,reverse=True)[:3]  # 取面積最大的3個輪廓

for c in cnts:
    peri = cv2.arcLength(c,True)  # 計算輪廓周長
    approx = cv2.approxPolyDP(c,0.05 * peri,True)  # 多邊形近似
    area = cv2.contourArea(approx)
    
    # 篩選四邊形且面積足夠大的輪廓
    if area > 20000 and len(approx) == 4:
        screenCnt = approx
        flag = 1
        break
  • 文檔矯正與顯示
if flag == 1:
    # 繪制輪廓
    image_contours = cv2.drawContours(image,[screenCnt],0,(0,255,0),2)
    
    # 透視變換
    warped = four_point_transform(orig,screenCnt.reshape(4,2))
    
    # 二值化處理
    warped = cv2.cvtColor(warped,cv2.COLOR_BGR2GRAY)
    ref = cv2.threshold(warped,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

三、完整代碼

# 導(dǎo)入工具包
import numpy as np
import cv2

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(10)
def order_points(pts):
    # 一共4個坐標(biāo)點
    rect = np.zeros((4,2),dtype="float32") # 用來存儲排序之后的坐標(biāo)位置
    # 按順序找到對應(yīng)坐標(biāo)0123分別是 左上、右上、右下、左下
    s = pts.sum(axis=1) #對pts矩陣的每一行進(jìn)行求和操作,(x+y)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    diff = np.diff(pts,axis=1) #對pts矩陣的每一行進(jìn)行求差操作,(y-x)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    return rect

def four_point_transform(image,pts):
    # 獲取輸入坐標(biāo)點
    rect = order_points(pts)
    (tl,tr,br,bl) = rect
    # 計算輸入的w和h值
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA),int(widthB))
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA),int(heightB))
    # 變換后對應(yīng)坐標(biāo)位置
    dst = np.array([[0,0],[maxWidth - 1,0],
                    [maxWidth - 1,maxHeight - 1],[0,maxHeight - 1]],dtype="float32")

    M = cv2.getPerspectiveTransform(rect,dst)
    warped = cv2.warpPerspective(image,M,(maxWidth,maxHeight))
    # 返回變換后的結(jié)果
    return warped


# 讀取輸入
import cv2
cap = cv2.VideoCapture(0)  # 確保攝像頭是可以啟動的狀態(tài)
if not cap.isOpened():   #打開失敗
    print("Cannot open camera")
    exit()

while True:
    flag = 0 # 用于標(biāo)時 當(dāng)前是否檢測到文檔
    ret,image = cap.read()  # 如果正確讀取幀,ret為True
    orig = image.copy()
    if not ret: #讀取失敗,則退出循環(huán)
        print("不能讀取攝像頭")
        break
    cv_show("image",image)

    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    # 預(yù)處理
    gray = cv2.GaussianBlur(gray,(5,5),0) # 高斯濾波
    edged = cv2.Canny(gray,75,200)
    cv_show('1',edged)

    # 輪廓檢測
    cnts = cv2.findContours(edged,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]

    cnts = sorted(cnts,key=cv2.contourArea,reverse=True)[:3]
    image_contours = cv2.drawContours(image,cnts,-1,(0,255,0),2)
    cv_show("image_contours",image_contours)
    # 遍歷輪廓
    for c in cnts:
        # 計算輪廓近似
        peri = cv2.arcLength(c,True) # 計算輪廓的周長
        # C 表示輸入的點集
        # epsilon表示從原始輪廓到近似輪廓的最大距離,它是一個準(zhǔn)確度參數(shù)
        # True表示封閉的
        approx = cv2.approxPolyDP(c,0.05 * peri,True) # 輪廓近似
        area = cv2.contourArea(approx)
        # 4個點的時候就拿出來
        if area > 20000 and len(approx) == 4:
            screenCnt = approx
            flag = 1
            print(peri,area)
            print("檢測到文檔")
            break
    if flag == 1:
        # 展示結(jié)果
        # print("STEP 2: 獲取輪廓")
        image_contours = cv2.drawContours(image,[screenCnt],0,(0,255,0),2)
        cv_show("image",image_contours)
        # 透視變換
        warped = four_point_transform(orig,screenCnt.reshape(4,2))
        cv_show("warped",warped)
        # 二值處理
        warped = cv2.cvtColor(warped,cv2.COLOR_BGR2GRAY)
        # ref = cv2.threshold(warped,220,255,cv2.THRESH_BINARY)[1]
        ref = cv2.threshold(warped,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
        cv_show("ref",ref)
cap.release() # 釋放捕捉器
cv2.destroyAllWindows() #關(guān)閉圖像窗口

四、結(jié)語

本文介紹了一個基于OpenCV的實時文檔掃描與矯正系統(tǒng),通過邊緣檢測、輪廓分析和透視變換等技術(shù),實現(xiàn)了文檔的自動檢測和矯正。該系統(tǒng)可以方便地應(yīng)用于日常文檔數(shù)字化工作,提高工作效率。

完整代碼已在上文中給出,讀者可以根據(jù)自己的需求進(jìn)行修改和擴(kuò)展。OpenCV提供了強(qiáng)大的圖像處理能力,結(jié)合Python的簡潔語法,使得開發(fā)這樣的實用系統(tǒng)變得簡單高效。

以上就是使用Python和OpenCV實現(xiàn)實時文檔掃描與矯正系統(tǒng)的詳細(xì)內(nèi)容,更多關(guān)于Python OpenCV文檔掃描與矯正的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python RPA自動化機(jī)器人模擬鼠標(biāo)鍵盤

    Python RPA自動化機(jī)器人模擬鼠標(biāo)鍵盤

    這篇文章主要介紹了Python RPA自動化機(jī)器人模擬鼠標(biāo)鍵盤,RPA,全稱為Robotic Process Automation,即機(jī)器人流程自動化。我們可以利用RPA技術(shù)將工作中可重復(fù)的部分流程化,讓機(jī)器替我們完成這一工作
    2023-02-02
  • Anaconda和Pycharm的安裝配置教程分享

    Anaconda和Pycharm的安裝配置教程分享

    這篇文章主要介紹了Anaconda和Pycharm的安裝配置教程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Python深度學(xué)習(xí)實戰(zhàn)PyQt5信號與槽的連接

    Python深度學(xué)習(xí)實戰(zhàn)PyQt5信號與槽的連接

    本文講解信號與槽的連接機(jī)制,詳細(xì)示范各種類型的信號/槽連接的實現(xiàn)方法,這是圖形用戶界面的核心內(nèi)容。還將介紹面向?qū)ο蟮某绦蛟O(shè)計,這是圖形用戶界面的基本思想
    2021-10-10
  • 跟老齊學(xué)Python之編寫類之一創(chuàng)建實例

    跟老齊學(xué)Python之編寫類之一創(chuàng)建實例

    上兩篇文章雖然已經(jīng)對類有了一點點模糊概念,但是,閱讀前面一講的內(nèi)容的確感到累呀,都是文字,連代碼都沒有。本講就要簡單多了,嘗試走一個類的流程。
    2014-10-10
  • 數(shù)據(jù)驅(qū)動測試DDT之Selenium讀取Excel文件

    數(shù)據(jù)驅(qū)動測試DDT之Selenium讀取Excel文件

    這篇文章主要為大家介紹了數(shù)據(jù)驅(qū)動測試DDT之Selenium讀取Excel文件,
    2021-11-11
  • Cython編譯python為so 代碼加密示例

    Cython編譯python為so 代碼加密示例

    今天小編就為大家分享一篇Cython編譯python為so 代碼加密示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Python如何使用字符打印照片

    Python如何使用字符打印照片

    這篇文章主要介紹了Python如何使用字符打印照片,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • Django 開發(fā)環(huán)境與生產(chǎn)環(huán)境的區(qū)分詳解

    Django 開發(fā)環(huán)境與生產(chǎn)環(huán)境的區(qū)分詳解

    這篇文章主要介紹了Django 開發(fā)環(huán)境與生產(chǎn)環(huán)境的區(qū)分詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • python?中的pycrypto?算法加密

    python?中的pycrypto?算法加密

    這篇文章主要介紹了python?中的pycrypto?算法加密,文章基于python的相關(guān)資料展開對pycrypto?算法加密的詳細(xì)介紹,需要的小伙伴可以參考一下
    2022-04-04
  • 在Python的Flask框架中實現(xiàn)單元測試的教程

    在Python的Flask框架中實現(xiàn)單元測試的教程

    這篇文章主要介紹了在Python的Flask框架中實現(xiàn)單元測試的教程,屬于自動化部署的方面,可以給debug工作帶來諸多便利,需要的朋友可以參考下
    2015-04-04

最新評論