python计算机视觉opencv矩形轮廓顶点位置确定
作者:qq_47150350 发布时间:2022-06-07 16:30:44
一、问题的引入
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
猜你喜欢
- 看到很多站长工具网,都提供了通过域名获取网站IP的方法。自己也想做一个,网上查了不少代码。有说用WSHSHELL,也有说用ASPPING组件
- # -*- coding: utf-8 -*-import random#数字类class NumberItem: &
- xhEditor简介xhEditor是一个基于jQuery开发的简单迷你并且高效的可视化HTML编辑器,基于网络访问并且兼容IE 6.0+,
- 我想要向您介绍能想像到的开始 GUI 编程的最简单方法,就是使用 Scriptics 的 TK 和 Tkinter 封装器。我们将与 dev
- 概念第一步:计算一个梯度 Ix,Iy第二步:整合矩阵,计算特征值第三步:比较特征值的大小第四步: 非极大值抑制,把真正的角点留下来,角点周围
- 日期的转换及计算对于日期,有时需执行不同时间单位的转换,或者接受字符串格式的日期,转换为 datetime 对象。有时需计算日期的范围,以及
- 由于众所周知的原因,ACCESS在大型站点应用中都靠不上边,主要问题就是数据量大了以后几乎无法索引。当ACCESS里数据过万后,明显可以感觉
- 修改镜像源的原因是pip和conda默认国外镜像源,所以每次安装模块pip install ×××或者 conda install ×××的
- 从github上下载,链接为:https://github.com/jhao104/proxy_pool下载好之后解压文件,然后将文件夹目录
- 前言本文将记录学习基于 Socket 通信机制建立 TCP 反向连接,借助 Python 脚本实现主机远程控制的目的。我们在传输数据时,可以
- 目录1.随机取小数:2.整数的随机选取:3.随机列表取数,元素打乱:总结1.随机取小数:import randomprint(random.
- python 字符串和日期之间转换 StringAndDate &nb
- 本篇已得到原作者Steve Dennis的翻译准予,在此Jorux表示感谢!本教程主要参考Creating a CSS Layo
- 一、使用xlrd对excel进行数据读取excel表格示例:安装xlrd库pip install xlrd导入xlrd库import xlr
- bcp是SQL Server中负责导入导出数据的一个命令行工具,它是基于DB-Library的,并且能以并行的方式高效地导入导出大批量的数据
- 有时候导入本地模块或者py文件时,下方会出现红色的波浪线,但不影响程序的正常运行,但是在查看源函数文件时,会出现问题问题如下:解决方案:1.
- python excel文件(.xls文件)如何处理xlrd 用于读取文件,xlwt 用于写入文件,xlutils 是两个工具包的桥梁,也就
- 本文实例讲述了PHP队列用法。分享给大家供大家参考。具体分析如下:什么是队列,是先进先出的线性表,在具体应用中通常用链表或者数组来实现,队列
- 一、简介从Python2.6开始,新增了str.format(),它增强了字符串格式化的功能。基本语法是通过 {} 和 : 来代替以前的 %
- 因此计划先把数据转插入一个临时表,再对临时表的数据进行分析。 问题点是如何动态创建临时表。原先Insus.NET使用下面代码实现: 代码如下