热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

pythonopencv椭圆拟合并求交点

一、用到的函数1.cv2.findContours()image,contours,hierarchycv2.findContours(image,mode,method[,c
一、用到的函数

1.cv2.findContours()

image,contours,hierarchy =
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])

输入:
image:输入图像;

mode:轮廓的检索模式
1.cv2.RETR_EXTERNAL表示只检测外轮廓
  2.cv2.RETR_LIST检测的轮廓不建立等级关系
 3.cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
 4.cv2.RETR_TREE建立一个等级树结构的轮廓。

method:为轮廓的近似办法
 1.cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
 2.cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标

输出
image:与输入image类似的一张二值图;

contours:list结构,列表中每个元素代表一个边沿信息。每个元素是(x,1,2)的三维向量,x表示该条边沿里共有多少个像素点,第三维的那个“2”表示每个点的横、纵坐标;
注意:如果输入选择cv2.CHAIN_APPROX_SIMPLE,则contours中一个list元素所包含的x点之间应该用直线连接起来,这个可以用cv2.drawContours()函数观察一下效果。

hierarchy:返回类型是(x,4)的二维ndarray。x和contours里的x是一样的意思。如果输入选择cv2.RETR_TREE,则以树形结构组织输出,hierarchy的四列分别对应下一个轮廓编号、上一个轮廓编号、父轮廓编号、子轮廓编号,该值为负数表示没有对应项。

2.ellipse = cv2.fitEllipse(cnt)

输入
cnt即1中所获取的轮廓点集
输出
ellipse = [ (x, y) , (a, b), angle ]
其中(x,y)为中心点位置,a为长轴长度,b为短轴长度,angle为中心旋转角度

3. cv2.ellipse(image, centerCoordinates, axesLength, angle, startAngle, endAngle, color [, thickness[, lineType[, shift]]])

输入
image:它是要在其上绘制椭圆的图像。
centerCoordinates:它是椭圆的中心坐标。坐标表示为两个值的元组,即(X坐标值,Y坐标值)。
axesLength:它包含两个变量的元组,分别包含椭圆的长轴和短轴(长轴长度,短轴长度)。
angle:椭圆旋转角度,以度为单位。
startAngle:椭圆弧的起始角度,以度为单位。
endAngle:椭圆弧的终止角度,以度为单位。
color:它是要绘制的形状边界线的颜色。对于BGR,我们通过一个元组。例如:(255,0,0)为蓝色。
thickness:是形状边界线的粗细像素。厚度-1像素将用指定的颜色填充形状。
lineType:这是一个可选参数,它给出了椭圆边界的类型。
shift:这是一个可选参数。它表示中心坐标中的小数位数和轴的值。

二、代码实现

import cv2
import numpy as np
import PIL.Image as Image
import math
from skimage.draw import linedef FitEll(image_path):image_uf = cv2.imread(image_path)print("image的形状{}".format(image_uf.shape))binary = cv2.Canny(image_uf, 50, 150)cnt, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)image_f = np.zeros(image_uf.shape, dtype=np.uint8)step = 0for i in range(len(cnt)):ellipse = cv2.fitEllipse(cnt[i])# 绘制椭圆 cv2.fitEllipse(cnt) cnt为一组轮廓点,返回值ellipse = [(x, y) , (a, b), angle] a,b为长短轴,angle为中心旋转角度cv2.ellipse(image_f,ellipse,(255-step*40,255-step*40,255-step*40),-1)(x, y), (a, b), ang = ellipsestep = step+1cv2.imshow('out',image_f)cv2.waitKey(0)image_f = Image.fromarray(cv2.cvtColor(image_f,cv2.COLOR_BGR2RGB))res_image_f = image_f.convert('P')return res_image_fif __name__ == '__main__':image_path = "test/test.png"res_image_f = FitEll(image_path)res_image_f.save("test/test_result.png")

左侧为原图,右侧为椭圆拟合结果

三、加料内容

如上图所示的两个椭圆,求经过小椭圆右端点且与小椭圆长轴垂直的直线与大椭圆的第一个交点位置。
直接上代码

import cv2
import numpy as np
import PIL.Image as Image
import math
from skimage.draw import linedef FitEll(image_path):image_uf = cv2.imread(image_path)print("image的形状{}".format(image_uf.shape))binary = cv2.Canny(image_uf, 50, 150)cnt, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)image_f = np.zeros(image_uf.shape, dtype=np.uint8)step = 0cnt = sorted(cnt, key=lambda x: len(x))max_index = len(cnt)-1for i in range(len(cnt)):ellipse = cv2.fitEllipse(cnt[i])# 绘制椭圆 cv2.fitEllipse(cnt) cnt为一组轮廓点,返回值ellipse = [(x, y) , (a, b), angle] a,b为长短轴,angle为中心旋转角度cv2.ellipse(image_f,ellipse,(255-step*40,255-step*40,255-step*40),-1)(x, y), (a, b), ang = ellipseif i!=max_index:p_l_x = x - (b / 2 * math.sin(ang * (math.pi) / 180))p_l_y = y + (b / 2 * math.cos(ang * (math.pi) / 180))p_r_x = x + (b / 2 * math.sin(ang * (math.pi) / 180))p_r_y = y - (b / 2 * math.cos(ang * (math.pi) / 180))cv2.circle(image_f, (int(p_l_x),int(p_l_y)), 8, (255,0,0), -1)cv2.circle(image_f, (int(p_r_x),int(p_r_y)), 8, (255, 0, 0), -1)else:x_b, y_b, w_b, h_b = cv2.boundingRect(cnt[i])#cv2.rectangle(image_f, (x_b, y_b), (x_b + w_b, y_b + h_b), (255, 0, 0), 1)if p_r_y!=p_l_y:k_l = -(p_r_x-p_l_x)/(p_r_y-p_l_y)b_l = -k_l*p_r_x+p_r_ypa, pb = (x_b, int(k_l * x_b + b_l)), ((x_b + w_b), int(k_l * (x_b + w_b) + b_l))else:pa, pb = (int(p_r_x), y_b), (int(p_r_x), y_b + h_b)# 枚举2点之间的线段点for pt in zip(*line(*pa, *pb)):#dis = cv2.pointPolygonTest(cnt[i], pt, True)if cv2.pointPolygonTest(cnt[i], pt, False) == 0: # 若点在轮廓上cv2.circle(image_f, pt, 8, (0, 0, 255), -1)cv2.line(image_f,(int(p_r_x),int(p_r_y)),pt,(0,255,0),4)breakstep = step+1cv2.imshow('out',image_f)cv2.waitKey(0)image_f = Image.fromarray(cv2.cvtColor(image_f,cv2.COLOR_BGR2RGB))res_image_f = image_f.convert('P')return res_image_fif __name__ == '__main__':image_path = "test/test.png"res_image_f = FitEll(image_path)res_image_f.save("test/test_result.png")

在这里插入图片描述
这里主要用了一个cv2.pointPolygonTest(cnt[i], pt, False)函数,cnt即为最前面提取到的轮廓点集,pt为遍历线段上某一点坐标,返回值0(在轮廓上),1(在轮廓内),-1(在轮廓外),当返回值为0时,pt即为交点坐标。

求交点部分参考这位朋友的博客
(https://javis486.blog.csdn.net/article/details/109542852)


推荐阅读
author-avatar
美好生活的日子
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有