Farthest Point(数学)

在给定圆的条件下,通过计算x轴边界并确定每个横坐标对应的纵坐标范围,找到最远的点。算法涉及ceil和floor函数以及平方根计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目1 : Farthest Point

时间限制:5000ms
单点时限:1000ms
内存限制:256MB

描述

Given a circle on a two-dimentional plane.

Output the integral point in or on the boundary of the circle which has the largest distance from the center.

输入

One line with three floats which are all accurate to three decimal places, indicating the coordinates of the center x, y and the radius r.

For 80% of the data: |x|,|y|<=1000, 1<=r<=1000

For 100% of the data: |x|,|y|<=100000, 1<=r<=100000

输出

One line with two integers separated by one space, indicating the answer.

If there are multiple answers, print the one with the largest x-coordinate.

If there are still multiple answers, print the one with the largest y-coordinate.


样例输入
1.000 1.000 5.000
样例输出
6 1

这题题意很简单,我们对于给定的一个圆,坐标为(x,y)半径为r,可以求出满足点的x轴边界,即ceil(x-r),floor(x+r)(ceil表示

取向下取整,floor表示向上取整)。遍历ceil(x-r)到floor(x+r),对于给定的横坐标dx,它的纵坐标为floor(y+sqrt(r*r-(x-dx)*(x-dx))),

ceil(y-sqrt(r*r-(x-dx)*(x-dx)))。然后就可以取最优的那个了。

#include<iostream>
#include<cstdio>
#include<string.h>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
struct Node
{
	int x,y;
	double dis;
}N[200005*2];
bool cmp(Node a,Node b)
{
	if(a.dis!=b.dis)
	{
		return a.dis>b.dis;
	}
	else if(a.x!=b.x)
	{
		return a.x>b.x;
	}
	else
	{
		return a.y>b.y;
	}
}
int main()
{
	double x,y,rr;
	while(~scanf("%lf%lf%lf",&x,&y,&rr))
	{
		double left=ceil(x-rr);
		double right=floor(x+rr);
		int nnn=0;
		for(int i=left;i<=right;i++)
		{
			double xx;
			if(i<x)
				xx=x-i;
			else
				xx=i-x;
			double yy=sqrt(rr*rr-xx*xx);
			N[nnn++].x=i;
			N[nnn-1].y=floor(yy+y);
			
			double t1,t2;
			t1=x-N[nnn-1].x;
			t2=y-N[nnn-1].y;
			N[nnn-1].dis=sqrt(t1*t1+t2*t2);
			N[nnn++].x=i;
			N[nnn-1].y=ceil(y-yy);
			t1=x-N[nnn-1].x;
			t2=y-N[nnn-1].y;
			N[nnn-1].dis=sqrt(t1*t1+t2*t2);
		}
		sort(N,N+nnn,cmp);
		cout<<N[0].x<<" "<<N[0].y<<endl;
	}
}



<think>我们针对用户提供的OpenCV代码中的轮廓检测部分进行数学公式推导。该部分代码在霍夫直线变换失败时被调用,用于检测管道轮廓并计算弯曲点、方向和角度。###1.轮廓提取首先,使用Canny边缘检测得到二值边缘图像$E$,其中边缘点为1,非边缘点为0。然后使用轮廓提取算法:$$\text{contours},\_=\text{cv2.findContours}(E,\text{RETR\_EXTERNAL},\text{CHAIN\_APPROX\_SIMPLE})$$该函数返回所有外部轮廓$\{\mathcal{C}_1,\mathcal{C}_2,\dots,\mathcal{C}_n\}$,其中每个轮廓$\mathcal{C}_i$由一系列点组成:$\mathcal{C}_i=\{\mathbf{p}_1,\mathbf{p}_2,\dots,\mathbf{p}_m\}$,$\mathbf{p}_j=(x_j,y_j)$。###2.轮廓筛选选择面积最大的轮廓作为管道轮廓:$$\mathcal{C}_{\text{pipe}}=\arg\max_{\mathcal{C}\in\{\mathcal{C}_i\}}\text{Area}(\mathcal{C})$$其中轮廓面积通过格林公式计算:$$\text{Area}(\mathcal{C})=\frac{1}{2}\left|\sum_{j=1}^{m-1}(x_jy_{j+1}-x_{j+1}y_j)+(x_my_1-x_1y_m)\right|$$###3.最小外接矩形计算对管道轮廓$\mathcal{C}_{\text{pipe}}$计算最小外接矩形。最小外接矩形定义为包含轮廓所有点的最小面积矩形。该问题等价于寻找旋转角度$\theta$使得矩形面积最小:$$\min_{\theta\in[0,\frac{\pi}{2})}\text{Area}(\theta)$$其中,对于给定$\theta$,轮廓点集在旋转$\theta$后在新坐标系下的投影区间为:$$x'_{\min}(\theta)=\min_i(x_i\cos\theta+y_i\sin\theta)$$$$x'_{\max}(\theta)=\max_i(x_i\cos\theta+y_i\sin\theta)$$$$y'_{\min}(\theta)=\min_i(-x_i\sin\theta+y_i\cos\theta)$$$$y'_{\max}(\theta)=\max_i(-x_i\sin\theta+y_i\cos\theta)$$矩形面积为:$$\text{Area}(\theta)=[x'_{\max}(\theta)-x'_{\min}(\theta)]\times[y'_{\max}(\theta)-y'_{\min}(\theta)]$$通过旋转卡壳法或梯度下降法求解最优$\theta^*$,得到最小外接矩形参数:中心点$\mathbf{c}=(c_x,c_y)$、宽度$w$、高度$h$和旋转角度$\theta$。###4.弯曲点定位代码中直接使用矩形中心作为弯曲点:$$\mathbf{b}=(b_x,b_y)=(c_x,c_y)$$###5.角度计算在轮廓检测回退方案中,角度被固定为90度:$$\theta_{\text{bend}}=90^\circ$$这是基于L型管道的先验知识。###6.方向判断方向判断基于弯曲点$\mathbf{b}$在图像中的位置。设图像宽度为$W$,高度为$H$,将图像分为四个象限:-第一象限:$x<W/2,y<H/2$→"Up-Left"-第二象限:$x\geqW/2,y<H/2$→"Up-Right"-第三象限:$x<W/2,y\geqH/2$→"Down-Left"-第四象限:$x\geqW/2,y\geqH/2$→"Down-Right"###优化方向(数学推导)####弯曲点精确定位实际弯曲点应为轮廓的凹点。通过计算轮廓的凸包,并分析凸缺陷(convexitydefects)可定位凹点。凸包$\mathcal{H}$为包含轮廓所有点的最小凸多边形。凸缺陷定义为凸包与轮廓之间的差异区域。对于L型管道,最大深度的凸缺陷点即为弯曲点:$$\text{defect}_k=(\mathbf{s}_k,\mathbf{e}_k,\mathbf{f}_k,d_k)$$其中$\mathbf{f}_k$为轮廓上离凸包边$\mathbf{s}_k\mathbf{e}_k$最远的点,$d_k$为该点到边的距离。弯曲点为:$$\mathbf{b}_{\text{actual}}=\mathbf{f}_{k^*}\quad\text{其中}\quadk^*=\arg\max_kd_k$$####角度精确计算对轮廓的两个分支分别进行直线拟合:-步骤1:使用凸缺陷将轮廓分为两个分支$\mathcal{B}_1,\mathcal{B}_2$-步骤2:对每个分支应用最小二乘直线拟合:对于分支$\mathcal{B}=\{(x_i,y_i)\}_{i=1}^N$,拟合直线$y=ax+b$,其中:$$a=\frac{N\sumx_iy_i-\sumx_i\sumy_i}{N\sumx_i^2-(\sumx_i)^2},\quadb=\frac{\sumy_i-a\sumx_i}{N}$$-步骤3:计算两直线方向向量:$$\mathbf{v}_1=(1,a_1),\quad\mathbf{v}_2=(1,a_2)$$-步骤4:计算夹角:$$\theta_{\text{bend}}=\cos^{-1}\left(\frac{\mathbf{v}_1\cdot\mathbf{v}_2}{\|\mathbf{v}_1\|\|\mathbf{v}_2\|}\right)=\cos^{-1}\left(\frac{1+a_1a_2}{\sqrt{1+a_1^2}\sqrt{1+a_2^2}}\right)$$###完整改进方案伪代码```python#在轮廓检测部分contours,_=cv2.findContours(edges,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)contours=sorted(contours,key=cv2.contourArea,reverse=True)pipe_contour=contours[0]#计算凸包和凸缺陷hull=cv2.convexHull(pipe_contour,returnPoints=False)defects=cv2.convexityDefects(pipe_contour,hull)#找到最大深度的凸缺陷点作为弯曲点ifdefectsisnotNone:max_defect=max(defects,key=lambdax:x[0][3])_,_,farthest_idx,_=max_defect[0]bend_point=tuple(pipe_contour[farthest_idx][0])else:#回退到最小外接矩形中心rect=cv2.minAreaRect(pipe_contour)bend_point=np.int0(rect[0])#分割轮廓为两个分支(以弯曲点为界)#此处需实现轮廓分割算法...#对每个分支进行直线拟合vx1,vy1,x1,y1=cv2.fitLine(branch1,cv2.DIST_L2,0,0.01,0.01)vx2,vy2,x2,y2=cv2.fitLine(branch2,cv2.DIST_L2,0,0.01,0.01)#计算两直线方向向量vec1=(vx1,vy1)vec2=(vx2,vy2)#计算夹角dot_product=vec1[0]*vec2[0]+vec1[1]*vec2[1]angle_rad=np.arccos(dot_product)#假设向量已归一化angle=np.degrees(angle_rad)#方向判断(同上)```此方案通过凸缺陷和直线拟合显著提升了弯曲点和角度的计算精度[^1][^2]。§§相关问题§§1.凸缺陷检测的数学原理和OpenCV实现细节是什么?2.如何高效地将管道轮廓分割为两个直线分支?3.最小二乘直线拟合在OpenCV中如何实现?有哪些优化方法?</think>### OpenCV轮廓检测中管道弯曲点、方向和角度的数学推导 #### 1. 轮廓提取与筛选 **数学原理**: - Canny边缘检测后,轮廓提取使用Freeman链码表示轮廓: $$\mathcal{C} = \{p_1, p_2, \dots, p_n\} \quad \text{其中} \quad p_i = (x_i, y_i)$$ - 轮廓面积通过格林公式计算: $$\text{Area}(\mathcal{C}) = \frac{1}{2} \left| \sum_{i=1}^{n} (x_i y_{i+1} - x_{i+1} y_i) \right| \quad \text{(边界条件:} x_{n+1}=x_1,\ y_{n+1}=y_1\text{)}$$ - 最大轮廓选择: $$\mathcal{C}_{\text{pipe}} = \arg\max_{\mathcal{C} \in \{\mathcal{C}_i\}} \text{Area}(\mathcal{C})$$ #### 2. 最小外接矩形计算 **数学推导**: - OpenCV使用旋转卡壳算法求解最小面积矩形: $$\min_{\theta \in [0,\pi/2)} \left[ \max_{p \in \mathcal{C}} (p \cdot u_\theta) - \min_{p \in \mathcal{C}} (p \cdot u_\theta) \right] \times \left[ \max_{p \in \mathcal{C}} (p \cdot v_\theta) - \min_{p \in \mathcal{C}} (p \cdot v_\theta) \right]$$ 其中: - $u_\theta = (\cos\theta, \sin\theta)$ 为旋转向量 - $v_\theta = (-\sin\theta, \cos\theta)$ 为垂直向量 - 矩形参数: $$\text{rect} = \left( \underbrace{(c_x, c_y)}_{\text{中心点}},\ \underbrace{(w, h)}_{\text{宽高}},\ \underbrace{\theta}_{\text{旋转角}} \right)$$ #### 3. 弯曲点定位(简化方法) **数学表示**: - 直接采用矩形中心: $$\mathbf{b} = (b_x, b_y) = (c_x, c_y)$$ - 实际L型管道的精确弯曲点应为轮廓的曲率极大值点: $$\kappa(p_i) = \frac{\det(p_{i+1}-p_i,\ p_i-p_{i-1})}{\|p_{i+1}-p_i\|^3} \quad \text{(离散曲率公式)}$$ $$\mathbf{b}_{\text{actual}} = \arg\max_{p_i \in \mathcal{C}} \kappa(p_i)$$ #### 4. 角度计算(简化方法) **数学假设**: - 固定90度假设: $$\theta_{\text{bend}} = 90^\circ$$ - 实际角度应由轮廓分支方向向量计算: $$\cos\theta = \frac{\mathbf{v}_1 \cdot \mathbf{v}_2}{\|\mathbf{v}_1\|\|\mathbf{v}_2\|} \quad \text{其中} \quad \mathbf{v}_k \text{为分支方向向量}$$ #### 5. 方向判断 **象限划分原理**: 设图像域 $\Omega = [0, W] \times [0, H]$,划分函数: $$Q(x,y) = \begin{cases} \text{Up-Left} & x < W/2,\ y < H/2 \\ \text{Up-Right} & x \geq W/2,\ y < H/2 \\ \text{Down-Left} & x < W/2,\ y \geq H/2 \\ \text{Down-Right} & x \geq W/2,\ y \geq H/2 \end{cases}$$ 方向决策: $$\text{direction} = Q(b_x, b_y)$$ #### 6. 优化方法:凸缺陷定位弯曲点 **数学推导**: 1. 计算轮廓凸包 $\mathcal{H} = \text{conv}(\mathcal{C})$ 2. 凸缺陷定义为: $$\text{defect}_k = (\mathbf{s}_k, \mathbf{e}_k, \mathbf{f}_k, d_k)$$ 其中: - $\mathbf{s}_k, \mathbf{e}_k$:凸包相邻顶点 - $\mathbf{f}_k$:轮廓上离边 $\overline{\mathbf{s}_k\mathbf{e}_k}$ 最远的点 - $d_k$:$\mathbf{f}_k$ 到边的距离 3. 弯曲点选择: $$\mathbf{b} = \mathbf{f}_{k^*} \quad \text{其中} \quad k^* = \arg\max_k d_k$$ #### 7. 优化方法:轮廓分支角度计算 **数学过程**: 1. 以弯曲点 $\mathbf{b}$ 分割轮廓: $$\mathcal{C} = \mathcal{B}_1 \cup \{\mathbf{b}\} \cup \mathcal{B}_2$$ 2. 对分支线性拟合: $$\min_{a_k,b_k} \sum_{(x,y)\in\mathcal{B}_k} (y - a_k x - b_k)^2$$ 3. 方向向量计算: $$\mathbf{v}_k = (1, a_k)$$ 4. 实际弯曲角度: $$\theta_{\text{bend}} = \cos^{-1}\left( \frac{\mathbf{v}_1 \cdot \mathbf{v}_2}{\|\mathbf{v}_1\|\|\mathbf{v}_2\|} \right)$$ #### 完整数学流程 ```mermaid graph LR A[轮廓提取] --> B[面积最大化筛选] B --> C[最小外接矩形计算] C --> D[弯曲点=矩形中心] C --> E[角度=90°] D --> F[象限方向判断] ``` 优化后: ```mermaid graph LR A[轮廓提取] --> B[凸包计算] B --> C[凸缺陷分析] C --> D[弯曲点=最深缺陷点] A --> E[轮廓分割] E --> F[分支直线拟合] F --> G[向量角度计算] D & G --> H[精确方向判断] ``` 此数学框架显著提升了管道特征检测的精度[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值