python計(jì)算機(jī)視覺(jué)opencv矩形輪廓頂點(diǎn)位置確定
一、問(wèn)題的引入
opencv在圖像處理方面有著非常強(qiáng)大的功能,當(dāng)我們需要使用opencv進(jìn)行一些圖像的矯正工作時(shí),我們通常需要找到原圖的一些關(guān)鍵點(diǎn),然后計(jì)算變換后的圖像坐標(biāo),最后通過(guò)仿射變換或者透視變換獲得自己想要的矯正圖像,比如將一張拍歪了的紙進(jìn)行矯正,我們的首要任務(wù)就是找到原圖的一些關(guān)鍵點(diǎn),通常的做法就是找紙張的4個(gè)頂點(diǎn)。
二、問(wèn)題的解決方法
第一步我們肯定要找到紙張相應(yīng)的矩形輪廓,這里可以二值化再找,也可以使用一些算子查找,而本文的重點(diǎn)是解決怎樣根據(jù)矩形輪廓去確定它具體的4個(gè)頂點(diǎn)的位置。
方法一:
使用線(xiàn)性規(guī)劃的方法,在opencv的坐標(biāo)系下使用x+y=z1和x-y=z2兩條直線(xiàn)去切輪廓,分別當(dāng)z1取最大時(shí)(x,y)是右下點(diǎn),最小時(shí)是左上點(diǎn);當(dāng)z2取最大時(shí)(x,y)是右上點(diǎn),最小時(shí)是左下點(diǎn),如下圖:

這個(gè)方法單獨(dú)從輪廓的角度來(lái)說(shuō),只要旋轉(zhuǎn)的角度不要?jiǎng)倓偤檬?5°或者135°,這個(gè)方法就沒(méi)有問(wèn)題,它得到的就是輪廓相對(duì)應(yīng)的右下點(diǎn)、左上點(diǎn)、右上點(diǎn)、左下點(diǎn),但不是原目標(biāo)的相應(yīng)點(diǎn),就好像當(dāng)紙張旋轉(zhuǎn)超過(guò)45°時(shí),這個(gè)方法得到的對(duì)于輪廓來(lái)說(shuō)是正確的,但對(duì)于紙張來(lái)說(shuō)就不對(duì)了,如下圖:

這個(gè)時(shí)候如果按之前的一樣進(jìn)行矯正就會(huì)得到一個(gè)橫放的紙張,這樣里面的字都是橫的,就不是我們想要的了所以這個(gè)方法要用來(lái)矯正的話(huà),就需要對(duì)圖像的旋轉(zhuǎn)角度有一個(gè)計(jì)算和判斷,可以通過(guò)下面代碼獲取角度:
#cnt:輸入輪廓,angle:返回角度 (x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
方法二
這個(gè)方法首先要使用輪廓獲得其最小面積矩,然后觀(guān)察研究矩形的性質(zhì)可以根據(jù)當(dāng)前的形狀給出適合的x,y判斷式,觀(guān)察下圖:

#找輪廓最小矩 cnt:輪廓 box:4個(gè)點(diǎn)無(wú)規(guī)律 rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect)
對(duì)于這樣一個(gè)高比寬長(zhǎng)的矩形,我們的方法是先將4個(gè)點(diǎn)按y從小到大進(jìn)行排序,再取前兩個(gè)按x從小到大進(jìn)行排序,小的那個(gè)是左下,大的那個(gè)是右下;最后取后兩個(gè)也按x從小到大進(jìn)行排序,小的那個(gè)是左上,大的那個(gè)是右上。假如是一個(gè)寬比高長(zhǎng)的矩形,我們就可以先按x的大小進(jìn)行排序。這個(gè)從代碼角度實(shí)現(xiàn)可能更為簡(jiǎn)潔,適用特定輪廓,對(duì)角度要求就更寬泛了些,除非旋轉(zhuǎn)到了像上圖右邊一樣的狀況,而這種矯正一般出現(xiàn)的機(jī)率非常小。
三、一些實(shí)現(xiàn)代碼
1、下面是使用方法一實(shí)現(xiàn)的頂點(diǎn)定位
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)
#按輪廓長(zhǎng)度選取需要輪廓
len_list = []
for i in range(len(contours)):
len_list.append(len(contours[i]))
#選第二長(zhǎng)的
sy = np.argsort(np.array(len_list))[-n]
#尋找頂點(diǎ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實(shí)現(xiàn)的頂點(diǎn)定位
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):
#區(qū)分矩形頂點(diǎn)位置
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、下面是一些展示代碼
#展示頂點(diǎn)
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)
以上就是python計(jì)算機(jī)視覺(jué)opencv矩形輪廓頂點(diǎn)位置確定的詳細(xì)內(nèi)容,更多關(guān)于python opencv矩形輪廓頂點(diǎn)定位的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
遠(yuǎn)程部署工具Fabric詳解(支持Python3)
這篇文章主要介紹了遠(yuǎn)程部署神器 Fabric,支持Python3 ,Fabric 出場(chǎng)了。Fabric 是一個(gè)遠(yuǎn)程部署神器,它可以在本地執(zhí)行遠(yuǎn)程服務(wù)器的命令。,需要的朋友可以參考下2019-07-07
一文教你掌握Python中Lambda表達(dá)式的5種實(shí)用技巧
在Python編程的宇宙里,有一個(gè)強(qiáng)大而靈活的工具經(jīng)常被高效的程序員所利用——那就是Lambda表達(dá)式,下面就讓我們深入了解Lambda表達(dá)式的妙用吧2024-01-01
python實(shí)現(xiàn)驗(yàn)證碼識(shí)別功能
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)驗(yàn)證碼識(shí)別功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
Python爬取qq music中的音樂(lè)url及批量下載
這篇文章主要給大家介紹了利用Python爬取qq music中的音樂(lè)url及實(shí)現(xiàn)批量下載的相關(guān)資料,文中給出了詳細(xì)的介紹和示例代碼,相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-03-03
通過(guò)Plotly實(shí)現(xiàn)交互式數(shù)據(jù)可視化的流程步驟
在數(shù)據(jù)科學(xué)和數(shù)據(jù)分析領(lǐng)域,數(shù)據(jù)可視化是一種非常重要的技術(shù),Plotly 是一個(gè)功能強(qiáng)大的 Python 可視化庫(kù),它可以幫助我們創(chuàng)建交互式的數(shù)據(jù)可視化圖表,本文將介紹如何使用 Plotly 實(shí)現(xiàn)交互式數(shù)據(jù)可視化,需要的朋友可以參考下2024-05-05

