最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python利用OpenCV實(shí)現(xiàn)文檔圖像自動矯正的方法

 更新時間:2026年03月19日 09:33:30   作者:Westward-sun.  
在日常生活中,用手機(jī)拍攝的文檔照片往往因?yàn)榕臄z角度而產(chǎn)生透視畸變,原本方正的紙張變成了不規(guī)則的四邊形,導(dǎo)致文字歪斜,影響閱讀和OCR識別,本文將基于你提供的完整Python代碼,深入解析利用OpenCV實(shí)現(xiàn)自動文檔矯正的每一步,需要的朋友可以參考下

1. 引言

在日常生活中,用手機(jī)拍攝的文檔照片往往因?yàn)榕臄z角度而產(chǎn)生透視畸變——原本方正的紙張變成了不規(guī)則的四邊形,導(dǎo)致文字歪斜,影響閱讀和OCR識別。透視變換技術(shù)可以將圖像中任意四邊形區(qū)域“拉正”為矩形,完美解決這一問題。本文將基于你提供的完整Python代碼,深入解析利用OpenCV實(shí)現(xiàn)自動文檔矯正的每一步,從圖像預(yù)處理、輪廓檢測到透視變換,并詳細(xì)講解核心函數(shù)的原理與參數(shù)含義。

2. 透視變換核心原理

透視變換是一種將圖像從一個平面投影到另一個平面的幾何變換。它用一個 3×3 的單應(yīng)性矩陣 描述,需要至少4對對應(yīng)點(diǎn)才能求解。在文檔矯正場景中,這4對點(diǎn)就是原始圖像中文檔的四個頂點(diǎn)和矯正后矩形的四個頂點(diǎn)。OpenCV提供了兩個核心函數(shù):

  • cv2.getPerspectiveTransform(src, dst):根據(jù)源點(diǎn)和目標(biāo)點(diǎn)計算變換矩陣。
  • cv2.warpPerspective(src, M, dsize):應(yīng)用變換矩陣到圖像。

3. 環(huán)境準(zhǔn)備

  • Python 3.x
  • OpenCV (pip install opencv-python)
  • NumPy (pip install numpy)

4. 代碼逐段詳解

4.1 導(dǎo)入庫

import numpy as np
import cv2
  • numpy:用于高效的數(shù)組運(yùn)算和數(shù)學(xué)計算(如距離、求和)。
  • cv2:OpenCV庫,提供圖像處理、輪廓檢測、透視變換等功能。

4.2 輔助函數(shù)

4.2.1 圖像顯示函數(shù)cv_show

def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
  • 作用:方便在調(diào)試過程中隨時顯示圖像,按下任意鍵后關(guān)閉窗口并釋放資源。
  • cv2.waitKey(0) 等待按鍵,參數(shù)0表示無限等待。
  • cv2.destroyAllWindows() 關(guān)閉所有OpenCV創(chuàng)建的窗口。

4.2.2 圖像等比例縮放函數(shù)resize

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    resized = cv2.resize(image, dim, interpolation=inter)
    return resized
  • 作用:按指定寬度或高度等比例縮放圖像,保持寬高比,避免圖像變形。
  • 參數(shù):
    • width、height:指定目標(biāo)寬度或高度,只需提供一個,另一個自動計算。
    • inter:插值方法,默認(rèn)為cv2.INTER_AREA,適合縮小圖像。
  • 原理:根據(jù)提供的尺寸計算縮放比例 r,然后生成新尺寸 dim,最后調(diào)用cv2.resize完成縮放。

4.2.3 頂點(diǎn)排序函數(shù)order_points

def order_points(pts):
    # 一共4個坐標(biāo)點(diǎn)
    rect = np.zeros(shape=(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
  • 為什么要排序? 透視變換要求源點(diǎn)和目標(biāo)點(diǎn)的順序必須一一對應(yīng)(例如左上對左上)。而輪廓檢測得到的四個點(diǎn)順序是隨機(jī)的,需要重新排序?yàn)?nbsp;左上、右上、右下、左下。
  • 排序原理
    • 左上角的點(diǎn)具有最小的 x+y 值(靠近原點(diǎn))。
    • 右下角的點(diǎn)具有最大的 x+y 值。
    • 右上角的點(diǎn)具有最小的 y-x 值(因?yàn)閥和x接近)。
    • 左下角的點(diǎn)具有最大的 y-x 值(x小y大)。
  • 代碼解析:
    • pts.sum(axis=1):計算每個點(diǎn)的 (x, y) 和,得到一維數(shù)組。
    • np.argmin(s) 和 np.argmax(s) 分別找出和最小及最大的點(diǎn)的索引,分別賦值給左上和右下。
    • np.diff(pts, axis=1):計算每個點(diǎn)的 y - x(因?yàn)閐iff是后減前,即 x[:,1] - x[:,0],注意這里實(shí)際是 y - x 取決于pts的列順序,通常pts是 (x, y),所以diff得到 (y - x))。
  • 同理,找出差最小和最大的點(diǎn)作為右上和左下。

4.2.4 透視變換核心函數(shù)four_point_transform

def four_point_transform(image, pts):
    # 獲取輸入坐標(biāo)點(diǎn)
    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)
    # 執(zhí)行透視變換
    warped = cv2.warpPerspective(image, M, dsize=(maxWidth, maxHeight))
    # 返回變換后結(jié)果
    return warped

步驟解析:

  • 排序頂點(diǎn):調(diào)用order_points得到按順序排列的四個點(diǎn) (tl, tr, br, bl)。
  • 計算目標(biāo)矩形尺寸:由于原始四邊形可能不是嚴(yán)格的矩形,上下邊長度可能不同,左右邊長度也可能不同。為了確保矯正后的圖像包含整個文檔內(nèi)容,取上下邊寬度的最大值作為目標(biāo)寬度,左右邊長度的最大值作為目標(biāo)高度。
    • widthA:底部邊(bl→br)的歐氏距離。
    • widthB:頂部邊(tl→tr)的歐氏距離。
    • maxWidth:取兩者較大值并轉(zhuǎn)為整數(shù)。
    • 同理計算高度。
  • 定義目標(biāo)點(diǎn):目標(biāo)矩形四個頂點(diǎn)按順序?yàn)樽笊?0,0)、右上(maxWidth-1,0)、右下(maxWidth-1,maxHeight-1)、左下(0,maxHeight-1)。注意減1是因?yàn)橄袼厮饕龔?開始。
  • 計算變換矩陣cv2.getPerspectiveTransform(rect, dst) 返回3×3變換矩陣M。
  • 應(yīng)用變換cv2.warpPerspective(image, M, (maxWidth, maxHeight)) 輸出矯正后的圖像。

4.3 主程序流程

4.3.1 讀取圖像并顯示原圖

image = cv2.imread('fapiao.jpg')
cv_show('image', image)
  • 讀取圖片 fapiao.jpg,并用自定義函數(shù)顯示。

4.3.2 縮放圖像以加快處理

ratio = image.shape[0] / 500.0  # 計算縮小比率
orig = image.copy()
image = resize(orig, height=500)
cv_show('1', image)
  • ratio:原圖高度除以500,得到縮放比例,后續(xù)用于將檢測到的輪廓坐標(biāo)映射回原圖。
  • orig:保存原始圖像副本,用于最終的高質(zhì)量透視變換。
  • resize(orig, height=500):將圖像高度縮放到500像素,寬度等比例縮放。處理縮小圖能極大提高輪廓檢測速度。
  • 顯示縮放后的圖像(標(biāo)題'1')。

結(jié)果展示:

4.3.3 輪廓檢測

print("STEP 1: 輪廓檢測")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 讀取灰度圖

edged = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]  # 自動尋找閾值二值化
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
image_contours = cv2.drawContours(image.copy(), cnts, -1, color=(0, 0, 255), thickness=1)
cv_show('image_contours', image_contours)
  • 灰度化cv2.cvtColor 將BGR圖像轉(zhuǎn)為灰度圖,便于二值化。
  • 二值化cv2.threshold 使用OTSU算法自動計算最優(yōu)閾值,得到黑白二值圖 edged。參數(shù) cv2.THRESH_BINARY | cv2.THRESH_OTSU 表示采用OTSU自動閾值且輸出為二值圖像。
  • 輪廓檢測cv2.findContours 查找所有輪廓。參數(shù):
    • edged.copy():傳入二值圖副本,避免函數(shù)修改原圖。
    • cv2.RETR_LIST:提取所有輪廓,不建立等級關(guān)系。
    • cv2.CHAIN_APPROX_SIMPLE:壓縮輪廓,只保留端點(diǎn)。
    • [-2]:兼容不同OpenCV版本,確保返回輪廓列表。
  • 繪制輪廓:在圖像副本上用紅色(BGR=(0,0,255))繪制所有輪廓,便于觀察。
  • 顯示結(jié)果。

結(jié)果展示:

4.3.4 獲取最大輪廓并近似為四邊形

print("STEP 2: 獲取最大輪廓")
screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]  # 獲取面積最大的輪廓
print(screenCnt.shape)
peri = cv2.arcLength(screenCnt, closed=True)  # 計算輪廓周長
screenCnt = cv2.approxPolyDP(screenCnt, 0.05 * peri, closed=True)  # 輪廓近似
print(screenCnt.shape)
image_contour = cv2.drawContours(image.copy(), [screenCnt], -1, (0, 255, 0), thickness=2)

cv2.imshow("image_contour", image_contour)
cv2.waitKey(0)
  • 篩選最大輪廓:假設(shè)文檔是圖像中面積最大的物體,按面積降序排序,取第一個輪廓 screenCnt。
  • 計算周長cv2.arcLength 獲取輪廓周長,closed=True 表示輪廓閉合。
  • 多邊形近似cv2.approxPolyDP 使用道格拉斯-普克算法簡化輪廓。參數(shù) 0.05 * peri 是近似精度,值越小越精細(xì),這里設(shè)為周長的5%,目的是將復(fù)雜輪廓簡化為四邊形。理想情況下,簡化后輪廓應(yīng)包含4個點(diǎn)。
  • 打印形狀:查看簡化前后的頂點(diǎn)數(shù)。
  • 繪制近似輪廓:在圖像副本上用綠色((0,255,0))繪制該輪廓,線條粗細(xì)2。
  • 顯示結(jié)果。

結(jié)果展示:

4.3.5 透視變換

###############
# 透視變換
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
cv2.imwrite('invoice_new.jpg', warped)
cv2.namedWindow('xx', cv2.WINDOW_NORMAL)
cv2.imshow("xx", warped)
cv2.waitKey(0)
  • 坐標(biāo)還原:
    • screenCnt 當(dāng)前形狀可能為 (4, 1, 2),通過 reshape(4, 2) 轉(zhuǎn)換為標(biāo)準(zhǔn)的 (4, 2) 數(shù)組。
    • 乘以縮放比例 ratio,將坐標(biāo)從縮放后的圖像空間映射回原始圖像空間,確保透視變換在原始分辨率下進(jìn)行,保留細(xì)節(jié)。
  • 調(diào)用透視變換four_point_transform(orig, ...) 對原始圖像 orig 進(jìn)行矯正,得到 warped
  • 保存結(jié)果cv2.imwrite 將矯正后的圖像保存為 invoice_new.jpg。
  • 顯示結(jié)果:創(chuàng)建一個可調(diào)整大小的窗口 xx 顯示矯正后的圖像,便于查看細(xì)節(jié)。

運(yùn)行結(jié)果展示:

5. 運(yùn)行結(jié)果

輸入圖像 fapiao.jpg 是一張傾斜拍攝的發(fā)票,程序?qū)⒁来物@示:

  • 原圖
  • 縮放后的圖像(高度500)
  • 所有輪廓(紅色)
  • 檢測到的最大輪廓近似結(jié)果(綠色四邊形)
  • 最終矯正后的正面圖像(保存為 invoice_new.jpg

矯正后的圖像將呈現(xiàn)標(biāo)準(zhǔn)的矩形,文字方向變正,極大方便后續(xù)OCR識別。

6. 總結(jié)與注意事項

6.1 總結(jié)

本文通過一個完整的OpenCV案例,詳細(xì)講解了如何利用透視變換自動矯正傾斜的文檔圖像。核心步驟包括:

  • 圖像縮放加速處理
  • 灰度化與OTSU二值化
  • 輪廓檢測與篩選
  • 多邊形近似獲取四個頂點(diǎn)
  • 頂點(diǎn)排序與透視變換

代碼結(jié)構(gòu)清晰,函數(shù)封裝良好,便于復(fù)用和擴(kuò)展。

6.2 注意事項

  • 頂點(diǎn)近似精度cv2.approxPolyDP 的 epsilon 參數(shù)(0.05 * peri)需要根據(jù)實(shí)際圖像調(diào)整。若無法得到4個點(diǎn),可適當(dāng)減小或增大該值。
  • 最大輪廓假設(shè):代碼假設(shè)文檔是面積最大的輪廓,如果圖像中包含其他更大物體(如桌面、背景雜物),可能導(dǎo)致誤檢。可增加篩選條件(如輪廓長寬比、面積范圍)提高魯棒性。
  • 坐標(biāo)映射screenCnt.reshape(4, 2) * ratio 必須在調(diào)用透視變換前執(zhí)行,確保使用原始圖像坐標(biāo)。
  • 圖像方向:如果矯正后圖像方向不對(例如旋轉(zhuǎn)了90度),可用 cv2.rotate 進(jìn)行修正。

通過理解和掌握這段代碼,你可以輕松將其應(yīng)用到車牌矯正、名片掃描、增強(qiáng)現(xiàn)實(shí)等更多場景中。如果在實(shí)踐中遇到問題,歡迎留言交流!

以上就是Python利用OpenCV實(shí)現(xiàn)文檔圖像自動矯正的方法的詳細(xì)內(nèi)容,更多關(guān)于Python OpenCV文檔圖像自動矯正的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python 中 Shutil 模塊詳情

    Python 中 Shutil 模塊詳情

    這篇文章主要介紹了 Python 中 Shutil 模塊,shutil可以簡單地理解為sh + util,shell工具的意思。shutil模塊是對os模塊的補(bǔ)充,主要針對文件的拷貝、刪除、移動、壓縮和解壓操作。下面來看文章詳細(xì)內(nèi)容
    2021-11-11
  • 優(yōu)化Python代碼使其加快作用域內(nèi)的查找

    優(yōu)化Python代碼使其加快作用域內(nèi)的查找

    這篇文章主要介紹了優(yōu)化Python代碼使其加快作用域內(nèi)的搜索,文中介紹了CPython相關(guān)的C代碼來對查找功能進(jìn)行優(yōu)化,加快搜索的速度,需要的朋友可以參考下
    2015-03-03
  • Python3爬蟲里關(guān)于Splash負(fù)載均衡配置詳解

    Python3爬蟲里關(guān)于Splash負(fù)載均衡配置詳解

    在本篇文章里小編給大家分享了關(guān)于Python3爬蟲里關(guān)于Splash負(fù)載均衡配置的相關(guān)內(nèi)容,需要的朋友們可以學(xué)習(xí)參考下。
    2020-07-07
  • 如何使用Pytorch完成圖像分類任務(wù)詳解

    如何使用Pytorch完成圖像分類任務(wù)詳解

    如果你剛剛開始學(xué)習(xí) PyTorch,并想學(xué)習(xí)如何做一些基本的圖像分類,可以看看本文,這篇文章主要給大家介紹了關(guān)于如何使用Pytorch完成圖像分類任務(wù)的相關(guān)資料,需要的朋友可以參考下
    2022-08-08
  • Pycharm沒有報錯提示(誤觸ignore)的完美解決方案

    Pycharm沒有報錯提示(誤觸ignore)的完美解決方案

    這篇文章主要介紹了Pycharm沒有報錯提示(誤觸ignore)的解決方案,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-12-12
  • 關(guān)于數(shù)據(jù)分析Pandas的Series用法總結(jié)

    關(guān)于數(shù)據(jù)分析Pandas的Series用法總結(jié)

    這篇文章主要介紹了關(guān)于數(shù)據(jù)分析Pandas的Series用法總結(jié),Series序列,是一種一維的結(jié)構(gòu),類似于一維列表和ndarray中的一維數(shù)組,但是功能比他們要更為強(qiáng)大,Series由兩部分組成:索引index和數(shù)值values,本篇對其用法做出總結(jié)
    2023-07-07
  • 用Python寫一個簡易版彈球游戲

    用Python寫一個簡易版彈球游戲

    這篇文章主要介紹了用Python寫一個簡易版彈球游戲,文中有很多實(shí)用代碼,對正在學(xué)習(xí)python的小伙伴們有很大的幫助.需要的朋友可以參考下
    2021-04-04
  • Python中Timedelta轉(zhuǎn)換為Int或Float方式

    Python中Timedelta轉(zhuǎn)換為Int或Float方式

    這篇文章主要介紹了Python中Timedelta轉(zhuǎn)換為Int或Float方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 深入了解Python的異常處理機(jī)制

    深入了解Python的異常處理機(jī)制

    這篇文章主要為大家介紹了Python的異常處理機(jī)制,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • 對Python3中的print函數(shù)以及與python2的對比分析

    對Python3中的print函數(shù)以及與python2的對比分析

    下面小編就為大家分享一篇對Python3中的print函數(shù)以及與python2的對比分析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05

最新評論

遂宁市| 友谊县| 万州区| 嘉荫县| 镇康县| 江城| 牡丹江市| 崇义县| 饶河县| 玉树县| 息烽县| 嘉黎县| 社旗县| 乌兰察布市| 隆尧县| 宣化县| 恩施市| 平阴县| 读书| 绵竹市| 昭平县| 沅陵县| 林口县| 衡阳县| 和林格尔县| 金坛市| 柳州市| 五峰| 胶南市| 封开县| 伊宁市| 芜湖县| 兴仁县| 河间市| 高唐县| 栾川县| 昌吉市| 富阳市| 驻马店市| 乐业县| 宝鸡市|