opencv矩形轮廓顶点定位问题怎么解决
Admin 2022-08-26 群英技术资讯 268 次浏览
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)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
matplotlib是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地行制图,下面这篇文章主要给大家介绍了关于matplotlib之pyplot模块添加文本、注解(text和annotate)的相关资料,需要的朋友可以参考下
这篇文章主要介绍了python中进程间通信及设置状态量控制另一个进程,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
split() 方法可以实现将一个字符串按照指定的分隔符切分成多个子串,本文介绍了spilt的具体使用,感兴趣的可以了解一下
测试对象的定位和操作是我们利用 selenium 编写自动化脚本和 webdriver 的核心内容。本文我们就来学习一下常用的元素定位方法有哪些吧
怎样用django生成图形验证码?验证码的应用场景有很多,我们在登录或者注册网络账号的时候都会用到,因此,下面小编就给大家分享如何实现图形验证码功能,包括有,图形验证码获取、验证码文字存储、验证码生成等。感兴趣的朋友就继续往下看吧。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008