計算機視覺進階教學之圖像投影(透視)變換

目錄

簡介

一、了解圖像投影(透視)變換

一、定義與原理

二、應用場景

三、實現方法

二、案例分析

1. 輔助函數定義

1.1.cv_show 函數

1.2.order_points 函數

1.3.four_point_transform 函數

1.4.resize 函數

2. 主程序執行流程

2.1.圖像縮放處理

2.2.輪廓檢測

2.3.獲取最大輪廓(文檔邊緣)

2.4.透視變換并保存結果

3.總結


簡介

????????在計算機視覺的進階學習旅程中,圖像投影(透視)變換是一座連接理論與實戰的關鍵橋梁。無論是實現證件照的智能矯正、自動駕駛中道路場景的視角轉換,還是無人機航拍圖像的地理坐標映射,這一技術都扮演著不可或缺的核心角色。如果你曾困惑于 “為何傾斜拍攝的文檔會出現邊緣變形”“如何讓二維圖像呈現出三維空間的立體感”,或是在項目開發中急需解決圖像視角轉換的技術難題,那么本系列博客將為你提供系統性的解決方案。

一、了解圖像投影(透視)變換

????????圖像的透視變換(Perspective Transformation)是一種在圖像處理中廣泛使用的技術,它通過模擬人眼或相機鏡頭觀看三維空間物體時的透視效果,來改變圖像的視角和形狀。以下是對圖像透視變換的詳細解釋:


一、定義與原理


????????透視變換是一種非線性變換,它可以將一個二維坐標系中的點映射到三維坐標系中的點,然后再將其投影到另一個二維坐標系中的點。這種變換基于幾何學中的透視原理,通過一個3x3的變換矩陣來實現,該矩陣作用于圖像的每個像素坐標,從而進行坐標的映射轉換。透視變換能夠模擬真實世界中的透視效果,使物體看起來更接近、更遠或者從不同角度觀看。

二、應用場景


透視變換在圖像處理和計算機視覺領域有著廣泛的應用,包括但不限于以下幾個方面:

????????圖像校正:通過透視變換可以修正由于視角引起的圖像扭曲,如將拍攝的傾斜書本或建筑物照片校正為正視圖。
????????圖像合成:將兩個圖像中的物體或場景合成在一起,仿佛它們是從同一視角拍攝的。
虛擬現實(VR)和增強現實(AR):在VR和AR應用中,透視變換用于模擬真實世界的視角和深度感,提升用戶體驗。
????????目標檢測與跟蹤:在目標檢測和跟蹤任務中,透視變換可以用于調整圖像視角,以便更準確地識別和跟蹤目標。
????????三維重建:在三維重建過程中,透視變換是連接二維圖像與三維空間的關鍵技術之一。


三、實現方法


在OpenCV等圖像處理庫中,透視變換通常通過以下步驟實現:

????????選擇對應點:在原始圖像和目標圖像上分別選擇四個非共線的對應點。這些點通常是圖像中的顯著特征點,如紙上的角落、建筑物的邊緣等。
????????計算變換矩陣:使用OpenCV中的cv2.getPerspectiveTransform函數根據這些對應點計算透視變換矩陣。
????????應用變換矩陣:使用cv2.warpPerspective函數將計算得到的透視變換矩陣應用于原始圖像,從而得到變換后的圖像。

二、案例分析

了解了枯燥的理論我們用下面這個案例來分析

實現對一個小票進行圖像投影變換

1. 輔助函數定義

1.1.cv_show 函數
def cv_show(name, img):cv2.imshow(name, img)  # 顯示圖像,name是窗口名稱,img是要顯示的圖像cv2.waitKey(0)  # 等待用戶按鍵,0表示無限等待

這是一個簡化圖像顯示操作的函數,封裝了 OpenCV 的imshowwaitKey方法,方便在多個地方調用。

1.2.order_points 函數
def order_points(pts):# 初始化一個4x2的矩陣存儲排序后的坐標rect = np.zeros(shape=(4, 2), dtype="float32")# 按順序找到對應坐標:左上,右上,右下,左下s = pts.sum(axis=1)  # 對每個點的x和y坐標求和rect[0] = pts[np.argmin(s)]  # 最小的和對應左上角(x+y最小)rect[2] = pts[np.argmax(s)]  # 最大的和對應右下角(x+y最大)diff = np.diff(pts, axis=1)  # 計算每個點的y-x差值rect[1] = pts[np.argmin(diff)]  # 最小的差值對應右上角(y-x最小)rect[3] = pts[np.argmax(diff)]  # 最大的差值對應左下角(y-x最大)return rect

這個函數用于對四邊形的四個頂點進行排序,確保它們按 "左上→右上→右下→左下" 的順序排列,為后續的透視變換做準備。

1.3.four_point_transform 函數
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))# 定義變換后的目標坐標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 warped

這是核心函數,實現了圖像的透視變換,將傾斜的四邊形區域轉換為正面矩形視圖,模擬了從不同角度拍攝的文檔轉換為正視圖的效果。

1.4.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

這個函數用于按比例調整圖像大小,避免圖像過大處理困難或過小影響精度。

2. 主程序執行流程

import cv2
import numpy as np# 讀取輸入圖像
image = cv2.imread('fapiao.jpg')
cv_show('image', image)  # 顯示原始圖像
2.1.圖像縮放處理
# 計算縮小比率(以高度為基準縮放到500像素)
ratio = image.shape[0] / 500.0
orig = image.copy()  # 保存原始圖像副本
image = resize(orig, height=500)  # 按比例縮小圖像
cv_show('1', image)  # 顯示縮小后的圖像

將圖像按比例縮小到高度為 500 像素,便于后續處理,同時記錄縮放比例,以便后期恢復原始尺寸。

2.2.輪廓檢測
print("STEP 1: 輪廓檢測")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 轉換為灰度圖
# 自動閾值二值化處理(OTSU算法)
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)

這一步將圖像轉為灰度圖,再通過二值化處理突出邊緣,最后檢測出圖像中的所有輪廓。

2.3.獲取最大輪廓(文檔邊緣)
print("STEP 2: 獲取最大輪廓")
# 按輪廓面積排序,取最大的那個(通常是文檔的邊緣)
screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
print(screenCnt.shape)  # 輸出輪廓形狀# 輪廓近似(將不規則輪廓近似為多邊形)
peri = cv2.arcLength(screenCnt, closed=True)  # 計算輪廓周長
# 用Douglas-Peucker算法近似輪廓,0.05*peri是近似精度
screenCnt = cv2.approxPolyDP(screenCnt, 0.05 * peri, closed=True)
print(screenCnt.shape)  # 輸出近似后的輪廓形狀# 繪制最大輪廓并顯示
image_contour = cv2.drawContours(image.copy(), [screenCnt], -1, color=(0, 255, 0), thickness=2)
cv2.imshow("image_contour", image_contour)
cv2.waitKey(0)

文檔通常是圖像中面積最大的矩形物體,所以這里通過面積排序找到最大輪廓,并通過輪廓近似算法將其轉換為四邊形。

2.4.透視變換并保存結果
# 應用四點透視變換,注意要將坐標還原到原始圖像尺寸
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
# 保存變換后的圖像
cv2.imwrite(filename='invoice_new.jpg', img=warped)
# 顯示變換后的圖像
cv2.namedWindow('xx', cv2.WINDOW_NORMAL)  # 創建可調整大小的窗口
cv2.imshow("xx", mat=warped)
cv2.waitKey(0)

3.總結

整個程序的核心思想是:

  1. 讀取圖像并適當縮放
  2. 通過圖像處理技術找到文檔的邊緣輪廓
  3. 利用透視變換將傾斜的文檔轉換為正視圖
  4. 保存和顯示處理結果

最后我們還可以通過之前學習的旋轉、閾值處理和圖像形態學等讓圖片中的文字更加突出

import cv2
import numpy as npimg=cv2.imread('invoice_new.jpg')
img=cv2.resize(img,dsize=None,fx=0.4,fy=0.4)
rotated_image1 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
cv2.imshow('ni90',rotated_image1)
cv2.waitKey(0)ret, binary = cv2.threshold(rotated_image1,  125,   255, cv2.THRESH_BINARY)
cv2.imshow(  'binary', binary) # 偏白的變純白,偏黑的變純黑
cv2.waitKey(0)kernel = np.ones((2,2),np.uint8)  # 這里kernel大小,修改為5*5試試
erosion_1 = cv2.erode(binary,kernel,iterations=1)  #iterations改為5試試
cv2.imshow('erosion_1',erosion_1)
cv2.waitKey(0)

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

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

相關文章

Java面試問題記錄(二)

三、系統設計與問題排查1、假設你要設計一個 “秒殺系統”,需要考慮高并發、高可用、防超賣等問題,你的整體技術方案是什么?從前端、接口層、服務層、存儲層分別說說核心設計點。秒殺系統設計設計核心:瞬時高并發,庫存…

k8s部署kafka三節點集群

本來認為部署kafka很簡單,沒想到也折騰了2-3天,這水平沒治了~ kafka從3.4.0版本之后,可以不依賴zookeeper直接使用KRaft模式部署,也就是說部署kafka可以不安裝zookeeper直接部署。 在官網上沒有找到如何使用yaml文件…

在公用同一公網IP和端口的K8S環境中,不同域名實現不同訪問需求的解決方案

目錄 1. 訪問需求 2. 解決方案 3. 具體配置 3.1 允許互聯網訪問的域名(a.lmzf.com) 3.2 需IP白名單訪問的域名(b.lmzf.com) 3.3 關鍵參數說明 3.4 測試驗證 1. 訪問需求 在騰訊云TKE環境中,多個域名解析到同一…

FlinkCDC 達夢數據庫實時同步

一、Flink部署 1.1、JAVA環境 vi /etc/profile export JAVA_HOME/data/flinkcdc/jdk1.8.0_181 export CLASSPATH$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar export PATH$JAVA_HOME/bin:$PATHsource /etc/profilevi ~/.bash_profileexport FLINK_HOME/data/flinkcdc/fli…

Eip開源主站EIPScanner在Linux上的調試記錄(二 多生產者連接)

目錄 一、背景 二、可行性驗證 三、開發調試 一、背景 在一般場景下,只需一路IO連接,但稍微復雜的場景,就需要不同通訊周期的連接,這就需要有多組IO連接。 而大于一組的連接調試方法是一樣的,因此主要解決2組連接的…

Oracle APEX 利用卡片實現翻轉(方法二)

目錄 0. 以 Oracle 的標準示例表 EMP 為例,實現卡片翻轉 1. 創建卡片區域 (Cards Region) 2. 定義卡片的 HTML 結構 3. 添加 CSS 實現樣式和翻轉動畫 4. 創建動態操作觸發翻轉 5. 運行效果 0. 以 Oracle 的標準示例表 EMP 為例,實現卡片翻轉 目標如…

低代碼拖拽實現與bpmn-js詳解

低代碼平臺中的可視化拖拽功能是其核心魅力所在,它讓構建應用變得像搭積木一樣直觀。下面我將為你梳理其實現原理,并詳細介紹 vue-draggable 這個常用工具。 🧱 一、核心架構:三大區域與數據驅動 低代碼編輯器界面通常分為三個核心…

【科研繪圖系列】R語言繪制模型預測與數據可視化

禁止商業或二改轉載,僅供自學使用,侵權必究,如需截取部分內容請后臺聯系作者! 文章目錄 介紹 加載R包 數據下載 函數 導入數據 數據預處理 畫圖 總結 系統信息 介紹 本文介紹了一種利用R語言進行海洋微生物群落動態分析的方法,該方法通過構建多個統計模型來預測不同環境…

TODO的面試(dw三面、sqb二面、ks二面)

得物的前端三面(通常是技術終面)會深入考察你的技術深度、項目經驗、解決問題的思路以及職業素養。下面我結合搜索結果,為你梳理一份得物前端三面的常問問題及詳解,希望能助你一臂之力。 🧠 得物前端三面常問問題及詳解…

開發 PHP 擴展新途徑 通過 FrankenPHP 用 Go 語言編寫 PHP 擴展

通過 FrankenPHP 用 Go 語言編寫 PHP 擴展 在 PHPVerse 2025 大會上(JetBrains 為紀念 PHP 語言 30 周年而組織的會議),FrankenPHP 開發者 Kvin Dunglas 做了一個開創性的宣布:通過 FrankenPHP,可以使用 Go 語言創建 …

完美解決:應用版本更新,增加字段導致 Redis 舊數據反序列化報錯

完美解決:應用版本更新,增加字段導致 Redis 舊數據反序列化報錯 前言 在敏捷開發和快速迭代的今天,我們經常需要為現有的業務模型增加新的字段。但一個看似簡單的操作,卻可能給正在穩定運行的系統埋下“地雷”。 一個典型的場景是…

66-python中的文件操作

1. 文件的編碼 UTF-8 GBK GB2312 Big5 GB18030 2. 文件讀取 文件操作步驟: 打開文件 讀\寫文件 關閉文件 open(name,mode,encoding) name:文件名字符串 “D:/haha.txt” mode: 只讀、寫入、追加 r:以只讀方式打開 w: 只用于寫 a :用于追加 encoding:編碼方式 # -*- coding: utf…

FPGA實例源代碼集錦:27個實戰項目

本文還有配套的精品資源,點擊獲取 簡介:FPGA是一種可編程邏輯器件,允許用戶根據需求配置硬件功能。本壓縮包提供27個不同的FPGA應用實例源代碼,旨在幫助初學者深入學習FPGA設計,并為專業工程師提供靈感。內容涵蓋了…

基于 Vue+Mapbox 的智慧礦山可視化功能的技術拆解

01、項目背景 在全球礦業加速向 “高端化、智能化、綠色化” 轉型的浪潮下,傳統礦業面臨的深地開采難題、效率瓶頸與安全隱患日益凸顯。 在礦業轉型的迫切需求與政策、技術支撐的背景下依托 GIS 技術,開展了 “中國智礦” GIS 開發項目,旨在…

進程狀態(Linux)

進程狀態Linux進程狀態Linux進程狀態進程描述R運行狀態S睡眠狀態D磁盤休眠狀態T停止狀態t被追蹤狀態(調試狀態)X死亡狀態Z僵死狀態其實大致也就可以分為三種運行,阻塞,掛起。運行狀態每個cpu里都有一個運行隊列,進程在運行隊列里,…

物聯網領域中PHP框架的最佳選擇有哪些?

物聯網(IoT)作為近年來快速發展的技術領域,已經滲透到智能家居、工業自動化、智慧城市等方方面面。作為Web開發中廣泛使用的語言,PHP憑借其易學易用、開發效率高和生態豐富的特點,也在物聯網領域找到了用武之地。 本文…

java反射(詳細教程)

我們平常創建類的實例并調用類中成員需要建立在一個前提下,就是已經知道類名和類中成員的信息,靈活性大大降低。甚至在一些項目中還需要修改源碼來滿足使用條件,大大降低了操作的靈活性。Java 反射(Reflection)是 Java…

消息隊列-初識kafka

優缺點 消息隊列的優點: 實現系統解耦: :::color5 系統解耦解釋 有 MQ 時是 “服務 A 發消息到隊列,其他服務從隊列拿消息,新增服務接隊列就行”;無 MQ 時是 “服務 A 直接調其他服務的接口 / 依賴,新增 / …

實踐《數字圖像處理》之Canny邊緣檢測、霍夫變換與主動二值化處理在短線段清除應用中的實踐

在最近的圖像處理項目中,其中一個環節:圖片中大量短線(不是噪聲),需要在下一步處理前進行清除。在確定具體實現時,碰到了Canny邊緣檢測、霍夫變換與主動二值化處理的辯證使用,相關邏輯從圖片灰度…

vue3與ue5通信-工具類

工具 ue5-simple.js /*** UE5 通信工具* 兩個核心方法:發送消息和接收消息*/// 確保全局對象存在 if (typeof window ! undefined) {window.ue window.ue || {};window.ue.interface window.ue.interface || {}; }/*** 生成 UUID*/ function generateUUID() {retu…