OpenCV:圖像透視變換

文章目錄

  • 一、透視變換是什么?
  • 二、透視變換的核心原理
    • 1. 關鍵概念:透視變換矩陣
    • 2. 核心條件:4對對應點
  • 三、OpenCV實現透視變換的關鍵步驟
    • 步驟1:讀取并預處理圖像
    • 步驟2:尋找目標物體的4個頂點
    • 步驟3:計算透視變換矩陣
    • 步驟4:執行透視變換
  • 四、實戰:用透視變換矯正發票圖像
    • 1. 準備工作
    • 2. 完整代碼解析
    • 3. 效果對比
  • 五、常見問題與解決方案
    • 1. 找不到目標物體的 4 個頂點?
    • 2. 矯正后的圖像有拉伸或變形?
    • 3. 透視變換后圖像邊緣有黑邊?
  • 六、透視變換的應用場景

在計算機視覺領域,我們經常會遇到拍攝角度不佳導致圖像變形的問題,比如傾斜的發票、扭曲的文檔等。這時候,圖像透視變換就成了“救星”。它能將傾斜、變形的圖像矯正為正視角,為后續的文字識別、信息提取等操作掃清障礙。今天,我們就從原理入手,結合實戰案例,帶大家全面掌握圖像透視變換。


一、透視變換是什么?

透視變換(Perspective Transformation),也叫投影變換,是一種將圖像從一個二維坐標系映射到另一個三維坐標系的非線性變換。簡單來說,它能模擬人眼視角的變化,把傾斜拍攝的“斜視圖”轉換成正面拍攝的“正視圖”。

比如我們拍攝一張放在桌面上的發票,由于拍攝角度不是正上方,得到的發票圖像可能是梯形或不規則四邊形;而通過透視變換,就能將其矯正為標準的矩形,讓發票上的文字、數字恢復正常的比例和角度。


二、透視變換的核心原理

1. 關鍵概念:透視變換矩陣

透視變換的實現依賴于透視變換矩陣(3×3矩陣) ,通過這個矩陣,可以將圖像中任意一個像素點的坐標(x,y)(x,y)(x,y)映射到新的坐標(x′,y′)(x',y')(x,y)。其數學表達式如下:
[x′y′w′]=[a00a01a02a10a11a12a20a21a22][xy1]\begin{bmatrix} x' \\ y' \\ w' \end{bmatrix}= \begin{bmatrix} a_{00} & a_{01} & a_{02} \\ a_{10} & a_{11} & a_{12} \\ a_{20} & a_{21} & a_{22} \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} ?xyw??=?a00?a10?a20??a01?a11?a21??a02?a12?a22????xy1??
其中,w′w'w是齊次坐標的縮放因子,最終的像素坐標需要通過x′=x′/w′x'=x'/w'x=x/wy′=y′/w′y'=y'/w'y=y/w計算得到。

這個3×3矩陣包含了9個參數,但由于齊次坐標的特性,實際只需要8個獨立參數就能確定變換關系——而這8個參數,恰好可以通過4對對應點(變換前圖像的4個頂點和變換后圖像的4個頂點)來求解。

2. 核心條件:4對對應點

透視變換的前提是找到變換前圖像的4個頂點(通常是目標物體的邊界角點)變換后圖像的4個頂點(通常是標準的矩形頂點) 。這4對對應點必須滿足:

  • 變換前的4個點不共線(比如發票的4個角,不能在同一條直線上);
  • 變換后的4個點通常構成標準矩形(方便后續處理,如文字識別)。

三、OpenCV實現透視變換的關鍵步驟

在OpenCV中,實現透視變換主要依賴兩個核心函數,整個流程可分為4步:

步驟1:讀取并預處理圖像

首先讀取原始圖像,根據需求進行縮放(降低圖像尺寸可提高后續操作的速度)、灰度化、邊緣檢測等預處理,為后續尋找目標物體的4個頂點做準備。

步驟2:尋找目標物體的4個頂點

通過輪廓檢測找到目標物體(如發票)的輪廓,再通過輪廓近似,提取出目標物體的4個頂點。這一步是透視變換的關鍵——如果頂點找錯,后續的矯正效果會大打折扣。

步驟3:計算透視變換矩陣

使用cv2.getPerspectiveTransform(src, dst)函數計算變換矩陣。其中:

  • src:變換前的4個頂點坐標(需按“左上、右上、右下、左下”的順序排列);
  • dst:變換后的4個頂點坐標(通常是標準矩形的頂點,如[[0,0], [width,0], [width,height], [0,height]])。

步驟4:執行透視變換

使用cv2.warpPerspective(src, M, dsize)函數完成透視變換。其中:

  • src:原始圖像;
  • M:步驟3計算得到的透視變換矩陣;
  • dsize:變換后輸出圖像的尺寸(通常由dst的頂點計算得到)。

四、實戰:用透視變換矯正發票圖像

接下來,我們以“發票矯正”為例,結合代碼詳細講解透視變換的實現過程。

1. 準備工作

  • 環境:Python 3.x + OpenCV(版本3.4.18.65,安裝命令:pip install opencv-python==3.4.18.65);
  • 素材:一張傾斜的發票圖像(fapiao.jpg,圖像內容包含發票的文字、數字和邊界)。

2. 完整代碼解析

import numpy as np
import cv2# 1. 輔助函數定義
def cv_show(name, img):"""顯示圖像,按任意鍵關閉窗口"""cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyWindow(name)def order_points(pts):"""將4個頂點按“左上、右上、右下、左下”的順序排列"""rect = np.zeros((4, 2), dtype="float32")  # 存儲排序后的坐標# 計算每個點的x+y之和:左上點之和最小,右下點之和最大s = pts.sum(axis=1)rect[0] = pts[np.argmin(s)]  # 左上rect[2] = pts[np.argmax(s)]  # 右下# 計算每個點的y-x之差:右上點之差最小,左下點之差最大diff = np.diff(pts, axis=1)rect[1] = pts[np.argmin(diff)]  # 右上rect[3] = pts[np.argmax(diff)]  # 左下return rectdef four_point_transform(image, pts):"""執行透視變換,返回矯正后的圖像"""# 獲取排序后的4個頂點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))# 定義矯正后圖像的4個頂點(標準矩形)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))return warpeddef resize(image, height=None, inter=cv2.INTER_AREA):"""按高度縮放圖像,保持寬高比"""(h, w) = image.shape[:2]if height is None:return image# 計算縮放比例r = height / float(h)dim = (int(w * r), height)# 執行縮放resized = cv2.resize(image, dim, interpolation=inter)return resized# 2. 讀取并預處理圖像
# 讀取原始發票圖像
image = cv2.imread('fapiao.jpg')
cv_show('原始圖像', image)# 按高度縮放為500像素(降低尺寸,提高處理速度)
ratio = image.shape[0] / 500  # 記錄縮放比例(后續恢復原始尺寸用)
orig = image.copy()  # 保存原始圖像
image = resize(orig, height=500)
cv_show('縮放后圖像', image)# 3. 尋找發票的4個頂點
# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 二值化(OTSU自動閾值,突出邊緣)
edged = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('二值化圖像', edged)# 輪廓檢測(尋找圖像中的所有輪廓)
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
# 繪制所有輪廓(紅色,線寬1)
image_contours = cv2.drawContours(image.copy(), cnts, -1, (0, 0, 255), 1)
cv_show('所有輪廓', image_contours)# 篩選出面積最大的輪廓(發票的輪廓)
screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
# 輪廓近似(將不規則輪廓近似為多邊形,epsilon=0.05*周長,控制近似精度)
peri = cv2.arcLength(screenCnt, True)  # 計算輪廓周長(True表示閉合輪廓)
screenCnt = cv2.approxPolyDP(screenCnt, 0.05 * peri, True)# 繪制發票的輪廓(紅色,線寬2)
image_invoice_contour = cv2.drawContours(image.copy(), [screenCnt], -1, (0, 0, 255), 2)
cv_show('發票輪廓', image_invoice_contour)# 4. 執行透視變換
# 恢復原始尺寸的頂點坐標(之前縮放了圖像,需乘以縮放比例)
pts = screenCnt.reshape(4, 2) * ratio
# 執行透視變換
warped = four_point_transform(orig, pts)# 5. 后處理(二值化,方便后續文字識別)
warped_gray = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
# 二值化(白底黑字)
ref = cv2.threshold(warped_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# 按寬度縮放為900像素,方便查看
ref = resize(ref, width=900)
cv_show('矯正后的發票', ref)# 6. 保存結果
cv2.imwrite('corrected_invoice.jpg', ref)
print("矯正完成,結果已保存為 corrected_invoice.jpg")

3. 效果對比

  • 原始圖像:發票傾斜,文字和數字有透視變形;
  • 矯正后圖像:發票變為標準矩形,文字、數字恢復正常比例,可直接用于 OCR 文字識別(如提取發票金額、編號等信息)。

五、常見問題與解決方案

1. 找不到目標物體的 4 個頂點?

  • 原因:圖像噪聲過多、邊緣檢測不完整、輪廓篩選錯誤;
  • 解決方案:
    • 增加圖像預處理步驟,如使用高斯濾波(cv2.GaussianBlur)去除噪聲;
    • 調整二值化閾值(可手動設置閾值,而非依賴 OTSU 自動閾值);
    • 優化輪廓近似的精度(調整epsilon參數,如0.02*peri0.08*peri)。

2. 矯正后的圖像有拉伸或變形?

  • 原因:4 個頂點的順序錯誤、dst(變換后頂點)的尺寸計算不準確;
  • 解決方案:
    • 確保order_points函數正確排序頂點(按 “左上、右上、右下、左下”);
    • 重新計算maxWidthmaxHeight,確保取到正確的寬度和高度最大值。

3. 透視變換后圖像邊緣有黑邊?

  • 原因:變換矩陣計算時,部分像素超出了輸出圖像的范圍;
  • 解決方案:
    • cv2.warpPerspective中添加borderMode=cv2.BORDER_CONSTANTborderValue=(255,255,255)(白色填充黑邊);
    • 示例:warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight), borderMode=cv2.BORDER_CONSTANT, borderValue=(255,255,255))

六、透視變換的應用場景

除了發票矯正,透視變換在計算機視覺中還有很多實用場景:

  • 文檔掃描:將傾斜的紙質文檔矯正為正視圖,提升掃描質量;
  • 車牌識別:矯正傾斜拍攝的車牌,提高識別準確率;
  • 圖像拼接:在全景圖拼接中,通過透視變換統一多幅圖像的視角;
  • AR 增強現實:將虛擬物體映射到真實場景的指定平面(如將虛擬海報貼在真實墻壁上)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96962.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96962.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96962.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

commons-csv

maven依賴<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-csv --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-csv</artifactId><version>1.14.1</version></dependency…

LeetCode 1446.連續字符

給你一個字符串 s &#xff0c;字符串的「能量」定義為&#xff1a;只包含一種字符的最長非空子字符串的長度。 請你返回字符串 s 的 能量。 示例 1&#xff1a; 輸入&#xff1a;s “leetcode” 輸出&#xff1a;2 解釋&#xff1a;子字符串 “ee” 長度為 2 &#xff0c;只包…

CTFHub SSRF通關筆記9:302跳轉 Bypass 原理詳解與滲透實戰

目錄 一、SSRF與302跳轉 1、SSRF 2、302響應 3、SSRF與302結合 &#xff08;1&#xff09;SSRF源碼分析 &#xff08;2&#xff09;攻擊鏈條&#xff08;Flow of Exploit&#xff09; 二、滲透實戰 1、打開靶場 2、嘗試127.0.0.1訪問 3、file協議分析源碼 &#xff…

Windows-Use實戰:AI驅動的Windows自動化

Windows-Use實戰:AI驅動的Windows自動化 前言 項目介紹與準備工作 Windows-Use是什么? 系統要求 必需環境 步驟一:安裝Python和基礎環境 1.1 安裝Python 檢查Python版本 Python安裝步驟 1.2 創建項目目錄 步驟二:安裝Windows-Use 2.1 使用pip安裝(推薦) 步驟三:運行和基…

STM32-FreeRTOS操作系統-二值信號量與計數信號量

引言在嵌入式開發領域&#xff0c;任務同步與通信是系統穩定運行的核心。STM32配合FreeRTOS操作系統&#xff0c;為開發者提供了強大的工具支持。其中&#xff0c;二值信號量和計數信號量作為FreeRTOS的關鍵同步機制&#xff0c;分別用于任務間的簡單同步和資源計數控制。二值信…

MarTech營銷技術全景解析:概念、圖譜與最新實踐案例

一、引言&#xff1a;為什么企業越來越依賴MarTech&#xff1f;在數字化浪潮下&#xff0c;企業營銷環境正發生深刻變化&#xff1a;客戶觸點增加&#xff1a;從官網、社交媒體到短視頻、展會&#xff0c;信息渠道呈指數級增長。決策鏈條復雜&#xff1a;B2B客戶通常需要多輪調…

服務器 - 從一臺服務器切換至另一臺服務器(損失數十條訪客記錄)

服務器 - 從一臺服務器切換至另一臺服務器(損失數十條PV記錄為代價) 看著四年的服務器正式到期&#xff0c;沒什么轟轟烈烈的告別&#xff0c;就像目送老朋友轉身走遠&#xff0c;只默默記下&#xff1a;哦&#xff0c;原來它陪了我這么久啊。 前言 一臺陪伴了我4年的服務器昨…

《云原生邊緣與AI訓練場景:2類高頻隱蔽Bug的深度排查與架構修復》

在云原生技術向邊緣計算與AI訓練場景滲透的過程中&#xff0c;基礎設施層的問題往往會被場景特性放大——邊緣環境的弱網絡、異構硬件&#xff0c;AI訓練的高資源依賴、分布式協作&#xff0c;都可能讓原本隱藏的Bug以“業務故障”的形式爆發。這些問題大多不具備直觀的報錯信息…

【51單片機】【protues仿真】基于51單片機數控直流穩壓電源系統

目錄 一、主要功能 二、使用步驟 三、硬件資源 四、軟件設計 五、實驗現象 一、主要功能 1、數碼管顯示輸出電壓值 2、滑動電阻調節輸出電壓 3、電壓輸出范圍0-15V&#xff0c;步進值1 二、使用步驟 基于51單片機的數控直流穩壓電源是一種通過數字控制實現電壓調節的智…

xtuoj Rectangle

題目思路將矩形間的相交情況通過投影轉化為x、y兩個方向下的線段是否相交&#xff0c;即前面的題目&#xff0c;判斷兩個區間是否相交&#xff0c;x投影的每個區間的左端點是每個矩形x的min&#xff0c;右端點是每個矩形的x的max&#xff0c;y投影情況同理&#xff0c;只要x軸的…

【深度學習踩坑實錄】從 Checkpoint 報錯到 TrainingArguments 精通:QNLI 任務微調全流程復盤

作為一名深度學習初學者&#xff0c;最近在基于 Hugging Face Transformers 微調 BERT 模型做 QNLI 任務時&#xff0c;被Checkpoint 保存和TrainingArguments 配置這兩個知識點卡了整整兩天。從磁盤爆滿、權重文件加載報錯&#xff0c;到不知道如何控制 Checkpoint 數量&#…

Java面試小冊(3)

21【Q】: 什么是Java的SPI機制&#xff1f;【A】&#xff1a;SPI 是一種插件機制&#xff0c;用于在運行時動態加載服務的實現。它通過定義接口&#xff08;服務接口&#xff09;并提供一種可擴展的方式來讓服務的提供著&#xff08;實現類&#xff09;在運行時注入&#xff0c…

P1150 Peter 的煙

記錄20#include <bits/stdc.h> using namespace std; int main(){int n,k;cin>>n>>k;int cnt0;while(n>k){cntk;nn-k1;}cntn;cout<<cnt;return 0; }突破口每吸完一根煙就把煙蒂保存起來&#xff0c;k&#xff08;k>1&#xff09;個煙蒂可以換一個…

Cursor和Hbuilder用5分鐘開發微信小程序

分享一個5分鐘搞定微信小程序開發的技能&#xff0c;需要用到兩個工具&#xff1a;Cursor和Hbuilder。 第1步、下載HBuilder。Hbuilder可以實現一套代碼直接生成安卓、蘋果、鴻蒙各個平臺APP。訪問Hbuilder的官方網站&#xff0c;HBuilderX-高效極客技巧&#xff0c;選擇適合…

k8s的dashboard

找一個裝有docker的機器&#xff0c;在一個rocky linux的虛擬機里弄拉取一個rancher鏡像建立一個目錄&#xff0c;目的&#xff1a;和里面數據做持久化關聯后臺運行&#xff0c;讓他有權限&#xff0c;8080端口和容器80端口映射&#xff0c;443和443做映射查看一下刪掉&#xf…

橋接模式,打造靈活可擴展的日志系統C++

一、為什么用橋接模式在企業開發中&#xff0c;日志系統幾乎是標配。常見需求&#xff1a;日志有多種類型&#xff08;Info、Warning、Error 等&#xff09;&#xff1b;日志需要支持多種輸出方式&#xff08;控制臺輸出、寫文件、遠程上傳、數據庫存儲等&#xff09;。如果把這…

kafka--基礎知識點--5.3--producer事務

1 事務簡介 Kafka事務是Apache Kafka在流處理場景中實現Exactly-Once語義的核心機制。它允許生產者在跨多個分區和主題的操作中&#xff0c;以原子性&#xff08;Atomicity&#xff09;的方式提交或回滾消息&#xff0c;確保數據處理的最終一致性。例如&#xff0c;在流處理中…

利用DeepSeek實現服務器客戶端模式的DuckDB原型

在網上看到韓國公司開發的一款GooseDB&#xff0c;DuckDB? 的功能擴展分支&#xff0c;具有服務器/客戶端、多會話和并發寫入支持&#xff0c;使用 PostgreSQL 有線協議&#xff0c;但它是Freeware而不是開源&#xff0c;所以讓DeepSeek實現之。 首先把readme頁面發給他翻譯&a…

麥當勞APP逆向

版本 V 7.0.17.0反調試 梆梆企業加固 frida反調試部分代碼 headers {"biz_scenario": "500","biz_from": "1004","User-Agent": "mcdonald_Android/7.0.17.0 (Android)","ct": "102","…

大數據畢業設計選題推薦-基于大數據的結核病數據可視化分析系統-Hadoop-Spark-數據可視化-BigData

?作者主頁&#xff1a;IT畢設夢工廠? 個人簡介&#xff1a;曾從事計算機專業培訓教學&#xff0c;擅長Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等項目實戰。接項目定制開發、代碼講解、答辯教學、文檔編寫、降重等。 ?文末獲取源碼? 精彩專欄推薦?…