網站首頁 Python教程 正文
一、問題的引入
opencv在圖像處理方面有著非常強大的功能,當我們需要使用opencv進行一些圖像的矯正工作時,我們通常需要找到原圖的一些關鍵點,然后計算變換后的圖像坐標,最后通過仿射變換或者透視變換獲得自己想要的矯正圖像,比如將一張拍歪了的紙進行矯正,我們的首要任務就是找到原圖的一些關鍵點,通常的做法就是找紙張的4個頂點。
二、問題的解決方法
第一步我們肯定要找到紙張相應的矩形輪廓,這里可以二值化再找,也可以使用一些算子查找,而本文的重點是解決怎樣根據矩形輪廓去確定它具體的4個頂點的位置。
方法一:
使用線性規劃的方法,在opencv的坐標系下使用x+y=z1和x-y=z2兩條直線去切輪廓,分別當z1取最大時(x,y)是右下點,最小時是左上點;當z2取最大時(x,y)是右上點,最小時是左下點,如下圖:
這個方法單獨從輪廓的角度來說,只要旋轉的角度不要剛剛好是45°或者135°,這個方法就沒有問題,它得到的就是輪廓相對應的右下點、左上點、右上點、左下點,但不是原目標的相應點,就好像當紙張旋轉超過45°時,這個方法得到的對于輪廓來說是正確的,但對于紙張來說就不對了,如下圖:
這個時候如果按之前的一樣進行矯正就會得到一個橫放的紙張,這樣里面的字都是橫的,就不是我們想要的了所以這個方法要用來矯正的話,就需要對圖像的旋轉角度有一個計算和判斷,可以通過下面代碼獲取角度:
#cnt:輸入輪廓,angle:返回角度
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
方法二
這個方法首先要使用輪廓獲得其最小面積矩,然后觀察研究矩形的性質可以根據當前的形狀給出適合的x,y判斷式,觀察下圖:
#找輪廓最小矩 cnt:輪廓 box:4個點無規律
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
對于這樣一個高比寬長的矩形,我們的方法是先將4個點按y從小到大進行排序,再取前兩個按x從小到大進行排序,小的那個是左下,大的那個是右下;最后取后兩個也按x從小到大進行排序,小的那個是左上,大的那個是右上。假如是一個寬比高長的矩形,我們就可以先按x的大小進行排序。這個從代碼角度實現可能更為簡潔,適用特定輪廓,對角度要求就更寬泛了些,除非旋轉到了像上圖右邊一樣的狀況,而這種矯正一般出現的機率非常小。
三、一些實現代碼
1、下面是使用方法一實現的頂點定位
import numpy as np
import cv2
def get4points(img: np.ndarray, thed, n):
"""
:param img the color image which shape is [height, width, depth]
:return 4 point locations in list or tuple, for example: [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]
"""
#灰度和二值化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,thed,255,cv2.THRESH_BINARY)
# 搜索輪廓
contours, hierarchy = cv2.findContours(
binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
#按輪廓長度選取需要輪廓
len_list = []
for i in range(len(contours)):
len_list.append(len(contours[i]))
#選第二長的
sy = np.argsort(np.array(len_list))[-n]
#尋找頂點
sum_list = []
dif_list = []
for i in contours[sy]:
sum = i[0][0]+i[0][1]
sum_list.append(sum)
dif_list.append(i[0][0]-i[0][1])
id_lb = np.argsort(np.array(sum_list))
id_lb2 = np.argsort(np.array(dif_list))
lu_id , rd_id = id_lb[0] , id_lb[-1]
ld_id , ru_id = id_lb2[0] , id_lb2[-1]
points = np.array([contours[sy][lu_id][0],contours[sy][rd_id][0],contours[sy][ld_id][0],contours[sy][ru_id][0]])
return points , contours , sy
2、下面是使用方法2實現的頂點定位
def getpoints(binary: np.ndarray , num: int ):
# 搜索輪廓
contours, hierarchy = cv2.findContours(
binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
#按輪廓位置最左(x最小)選取
x_list = []
for i in contours:
x_sum = 0
for kk in i:
x_sum += kk[0][0]
x_av = x_sum/len(i)
x_list.append(x_av)
sy = np.argsort(np.array(x_list))[num]
cnt = contours[sy]
#找輪廓最小矩
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
return box , contours , sy
def findpoints(points):
#區分矩形頂點位置
point_y=sorted(points,key=lambda t:t[1])
lu, ru =sorted(point_y[:2],key=lambda t:t[0])
ld, rd =sorted(point_y[2:],key=lambda t:t[0])
return [list(lu), list(ld), list(ru),list(rd)]
3、下面是一些展示代碼
#展示頂點
def show_points(img , points):
point_size = 8
point_color = (0, 0, 255) # BGR
thickness = 4 # 可以為 0 、4、8
points_list = [tuple(i) for i in np.int32(points).reshape(-1,2)]
for point in points_list:
cv2.circle(img, point, point_size, point_color, thickness)
img = cv2.resize(img,(808,808))
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# cv2.imwrite('dd.jpg',img)
#展示輪廓
def show_Contour(img , contours , sy):
cv2.drawContours(img, contours , sy , (25, 254, 0), 4)
img = cv2.resize(img,(808,808))
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# cv2.imwrite('mm.jpg',img)
原文鏈接:https://blog.csdn.net/qq_47150350/article/details/123404672
相關推薦
- 2022-07-09 Jquery使用AJAX方法請求數據_jquery
- 2022-05-01 React的三大屬性你都知道嗎_React
- 2023-06-17 解讀C語言非void函數卻沒有return會怎么樣_C 語言
- 2022-12-24 VS2019調試C語言程序(監視操作)的詳細步驟_C 語言
- 2022-03-27 PostgreSQL中的日期/時間函數詳解_PostgreSQL
- 2022-04-24 如何在Python中隱藏和加密密碼示例詳解_python
- 2022-08-29 Python通用驗證碼識別OCR庫ddddocr的安裝使用教程_python
- 2022-07-15 Python?print函數:如何將對象打印輸出_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支