opencv矩形輪廓頂點的具體位置確定的兩種實現(xiàn)方法
一、問題的引入
opencv在圖像處理方面有著非常強大的功能,當(dāng)我們需要使用opencv進(jìn)行一些圖像的矯正工作時,我們通常需要找到原圖的一些關(guān)鍵點,然后計算變換后的圖像坐標(biāo),最后通過仿射變換或者透視變換獲得自己想要的矯正圖像,比如將一張拍歪了的紙進(jìn)行矯正,我們的首要任務(wù)就是找到原圖的一些關(guān)鍵點,通常的做法就是找紙張的4個頂點。
二、問題的解決方法
第一步我們肯定要找到紙張相應(yīng)的矩形輪廓,這里可以二值化再找,也可以使用一些算子查找,而本文的重點是解決怎樣根據(jù)矩形輪廓去確定它具體的4個頂點的位置。
方法一:
使用線性規(guī)劃的方法,在opencv的坐標(biāo)系下使用x+y=z1和x-y=z2兩條直線去切輪廓,分別當(dāng)z1取最大時(x,y)是右下點,最小時是左上點;當(dāng)z2取最大時(x,y)是右上點,最小時是左下點,如下圖:
這個方法單獨從輪廓的角度來說,只要旋轉(zhuǎn)的角度不要剛剛好是45°或者135°,這個方法就沒有問題,它得到的就是輪廓相對應(yīng)的右下點、左上點、右上點、左下點,但不是原目標(biāo)的相應(yīng)點,就好像當(dāng)紙張旋轉(zhuǎn)超過45°時,這個方法得到的對于輪廓來說是正確的,但對于紙張來說就不對了,如下圖:
這個時候如果按之前的一樣進(jìn)行矯正就會得到一個橫放的紙張,這樣里面的字都是橫的,就不是我們想要的了所以這個方法要用來矯正的話,就需要對圖像的旋轉(zhuǎn)角度有一個計算和判斷,可以通過下面代碼獲取角度:
#cnt:輸入輪廓,angle:返回角度 (x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
方法二
這個方法首先要使用輪廓獲得其最小面積矩,然后觀察研究矩形的性質(zhì)可以根據(jù)當(dāng)前的形狀給出適合的x,y判斷式,觀察下圖:
#找輪廓最小矩 cnt:輪廓 box:4個點無規(guī)律 rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect)
對于這樣一個高比寬長的矩形,我們的方法是先將4個點按y從小到大進(jìn)行排序,再取前兩個按x從小到大進(jìn)行排序,小的那個是左下,大的那個是右下;最后取后兩個也按x從小到大進(jìn)行排序,小的那個是左上,大的那個是右上。假如是一個寬比高長的矩形,我們就可以先按x的大小進(jìn)行排序。這個從代碼角度實現(xiàn)可能更為簡潔,適用特定輪廓,對角度要求就更寬泛了些,除非旋轉(zhuǎn)到了像上圖右邊一樣的狀況,而這種矯正一般出現(xiàn)的機率非常小。
三、一些實現(xiàn)代碼
1、下面是使用方法一實現(xià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) #按輪廓長度選取需要輪廓 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實現(xiàn)的頂點定位
def getpoints(binary: np.ndarray , num: int ): # 搜索輪廓 contours, hierarchy = cv2.findContours( binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) #按輪廓位置最左(x最?。┻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ū)分矩形頂點位置 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)
到此這篇關(guān)于opencv矩形輪廓頂點的具體位置確定的兩種實現(xiàn)方法的文章就介紹到這了,更多相關(guān)opencv矩形輪廓頂點內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用Selenium進(jìn)行元素定位的步驟和方法
在使用Selenium進(jìn)行網(wǎng)頁自動化測試時,正確且高效地定位目標(biāo)元素是至關(guān)重要的,以下是詳細(xì)的步驟和方法,幫助你全面掌握如何使用Selenium進(jìn)行元素定位,需要的朋友可以參考下2025-06-06Pycharm創(chuàng)建python文件自動添加日期作者等信息(步驟詳解)
這篇文章主要介紹了Pycharm創(chuàng)建python文件自動添加日期作者等信息(步驟詳解),本文分步驟給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02Python實現(xiàn)圖的廣度和深度優(yōu)先路徑搜索算法
圖是一種抽象數(shù)據(jù)結(jié)構(gòu),本質(zhì)和樹結(jié)構(gòu)是一樣的。圖與樹相比較,圖具有封閉性,可以把樹結(jié)構(gòu)看成是圖結(jié)構(gòu)的前生。本文將利用Python實現(xiàn)圖的廣度和深度優(yōu)先路徑搜索算法,感興趣的可以學(xué)習(xí)一下2022-04-04關(guān)于Python去除字符串中空格的方法總結(jié)
用Python處理字符串時會經(jīng)常要去掉字符串首、尾或者中間的空白,以得到我們想要的結(jié)果,下面這篇文章主要給大家介紹了關(guān)于Python去除字符串中空格的相關(guān)資料,需要的朋友可以參考下2022-12-12Python 異步之如何保護(hù)任務(wù)免于取消詳解
這篇文章主要為大家介紹了Python 異步之如何保護(hù)任務(wù)免于取消示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Pandas數(shù)據(jù)分析多文件批次聚合處理實例解析
這篇文章主要為大家介紹了Pandas數(shù)據(jù)分析多文件批次聚合處理實例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Django基礎(chǔ)CBV裝飾器和中間件的應(yīng)用示例
這篇文章主要為大家介紹了Django基礎(chǔ)CBV裝飾器和中間件的應(yīng)用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03