C# 使用中点查找矩形的角(Find Corners of Rectangle using mid points)

         考虑一个矩形 ABCD,我们给出了边 AD 和 BC 中点(分别为 p 和 q)的坐标以及它们的长度 L(AD = BC = L)。现在给定参数,我们需要打印 4 个点 A、B、C 和 D 的坐标。

例子: 

输入:p = (1, 0)
        q = (1, 2)
        L = 2

输出:(0,0),(0,2),(2,2),(2,0)

解释:

打印的点形成一个矩形,

满足输入约束。

输入:p = (1, 1)
        q = (-1, -1)
        L = 2*sqrt(2)

输出:(0,2),(-2,0),(0,-2),(2,0)

从问题陈述中可能出现 3 种情况:  

矩形是水平的,即 AD 和 BC 平行于 X 轴

矩形是垂直的,即 AD 和 BC 平行于 Y 轴

矩形与轴线呈一定角度倾斜

        前两种情况很简单,使用基本几何学就可以轻松解决。对于第三种情况,我们需要应用一些数学概念来找到点。

        为了清楚起见,请考虑上图。我们有 p 和 q 的坐标。因此,我们可以找到 AD 和 BC 的斜率(因为 pq 垂直于 AD)。一旦我们有了 AD 的斜率,我们就可以找到通过 AD 的直线方程。现在我们可以应用距离公式来获得沿 X 轴和 Y 轴的位移。 

如果 AD 的斜率 = m,则 m = (px- qx)/(qy- py)

以及沿 X 轴的位移,dx = L/(2*sqrt(1+m*m))

类似地,dy = m*L/(2*sqrt(1+m*m))

现在,我们可以通过简单地加减相应获得的位移来找到 4 个角的坐标。 

下面是实现过程:

// C# program to find corner points of 
// a rectangle using given length and middle 
// points. 
using System; 
 
class GFG 

 
    // Structure to represent a co-ordinate point 
    public class Point 
    { 
 
        public float x, y; 
 
        public Point() 
        { 
            x = y = 0; 
        } 
 
        public Point(float a, float b) 
        { 
            x = a; 
            y = b; 
        } 
    }; 
 
    // This function receives two points and length 
    // of the side of rectangle and prints the 4 
    // corner points of the rectangle 
    static void printCorners(Point p, Point q, float l) 
    { 
        Point a = new Point(), b = new Point(), 
                c = new Point(), d = new Point(); 
 
        // horizontal rectangle 
        if (p.x == q.x) 
        { 
            a.x = (float) (p.x - (l / 2.0)); 
            a.y = p.y; 
 
            d.x = (float) (p.x + (l / 2.0)); 
            d.y = p.y; 
 
            b.x = (float) (q.x - (l / 2.0)); 
            b.y = q.y; 
 
            c.x = (float) (q.x + (l / 2.0)); 
            c.y = q.y; 
        } 
         
        // vertical rectangle 
        else if (p.y == q.y) 
        { 
            a.y = (float) (p.y - (l / 2.0)); 
            a.x = p.x; 
 
            d.y = (float) (p.y + (l / 2.0)); 
            d.x = p.x; 
 
            b.y = (float) (q.y - (l / 2.0)); 
            b.x = q.x; 
 
            c.y = (float) (q.y + (l / 2.0)); 
            c.x = q.x; 
        } 
         
        // slanted rectangle 
        else
        { 
            // calculate slope of the side 
            float m = (p.x - q.x) / (q.y - p.y); 
 
            // calculate displacements along axes 
            float dx = (float) ((l / Math.Sqrt(1 + (m * m))) * 0.5); 
            float dy = m * dx; 
 
            a.x = p.x - dx; 
            a.y = p.y - dy; 
 
            d.x = p.x + dx; 
            d.y = p.y + dy; 
 
            b.x = q.x - dx; 
            b.y = q.y - dy; 
 
            c.x = q.x + dx; 
            c.y = q.y + dy; 
        } 
 
        Console.Write((int)a.x + ", " + (int)a.y + " \n"
                + (int)b.x + ", " + (int)b.y + "\n"
                + (int)c.x + ", " + (int)c.y + " \n"
                + (int)d.x + ", " + (int)d.y + "\n"); 
    } 
 
    // Driver code 
    public static void Main(String[] args) 
    { 
        Point p1 = new Point(1, 0), q1 = new Point(1, 2); 
        printCorners(p1, q1, 2); 
 
        Point p = new Point(1, 1), q = new Point(-1, -1); 
        printCorners(p, q, (float) (2 * Math.Sqrt(2))); 
    } 

 
// This code has been contributed by 29AjayKumar 

输出: 

0,0
0、2
2,2
2,0

0、2
-2,0
0、-2
2,0

时间复杂度: O(1) 

辅助空间: O(1)

<think>我们讨论的是在HALCON中使用Sojka算子进行点检测。根据提供的引用[1][2],HALCON中有一个名为`points_sojka`的算子用于检测Sojka点。引用[1]中给出了`points_sojka`算子的调用方式:points_sojka(Image,9,2.5,0.75,5*Index,10,0.5,'false',Row3,Column3)引用[2]中也有类似的调用:points_sojka(Image,9,2.5,0.75,30,90,0.5,'true',RowSojka,ColSojka)在引用[3]中,我们也可以看到`points_sojka`被列为一个点检测算子。因此,使用Sojka算子进行点检测的关键是正确调用`points_sojka`算子。根据引用[1][2],我们可以整理出该算子的参数列表:Image(输入对象):输入图像MaskSize(输入控制):滤波器的大小(奇数)SigmaW(输入控制):与点候选点距离的权重函数的Sigma(用于空间加权)SigmaD(输入控制):拖曳到理想灰度边缘的权重函数的Sigma(用于梯度方向加权?)MinGrad(输入控制):梯度幅值的阈值(低于此阈值的梯度将被忽略)MinApparentness(输入控制):表观阈值(用于筛选点)MinAngle(输入控制)点方向变化的最小角度(弧度)Subpix(输入控制):是否进行亚像素精确计算('true'或'false')Row,Column(输出控制):检测到的点的行坐标列坐标具体步骤:1.读取图像。2.调用`points_sojka`算子,并设置相应的参数。3.获取输出的点坐标。然后,我们可以将检测到的点显示出来,通常用十字交叉线标记(如引用[1][2]中的`gen_cross_contour_xld`)。下面是一个示例代码(基于HALCON的HDevelop语言):假设图像变量为Image,检测结果存在RowColumn中。引用[1]中的示例参数:MaskSize=9SigmaW=2.5SigmaD=0.75MinGrad=30(引用[2]中为30,而引用[1]中为5*Index,可能是动态的,但一般用一个固定值,如30)MinApparentness=90(引用[2]中为90,引用[1]中为10,可能根据不同情况调整)MinAngle=0.5(弧度)Subpix='true'(引用[2])或'false'(引用[1])注意:参数需要根据具体图像调整。示例代码:read_image(Image,'文件名')*将图像转为单通道灰度图(如果必要)rgb1_to_gray(Image,GrayImage)*调用Sojka算子points_sojka(GrayImage,9,2.5,0.75,30,90,0.5,'true',Row,Column)*生成十字标记gen_cross_contour_xld(Cross,Row,Column,30,0.785398)//30是十字的大小,0.785398是角度(45度)*显示图像点dev_display(GrayImage)dev_display(Cross)注意:参数MinGrad(梯度阈值)、MinApparentness(表观阈值)、MinAngle(角度阈值)对结果影响较大,需要根据实际图像调整。解释:-MaskSize:通常是一个奇数,例如9,表示考虑一个9x9的邻域。-SigmaWSigmaD:用于定义权重函数的高斯标准差,分别控制空间距离灰度差异的权重衰减。-MinGrad:梯度幅值的下限,低于该值的点不予考虑。-MinApparentness:点“明显性”的阈值,该值越大,检测到的点越少,但更可能是明显的点。-MinAngle:两条边缘之间的最小夹(弧度),用于剔除那些角度过小的点(比如接近180度的,实际可能是直线上的点)。-Subpix:如果为'true',则计算亚像素精度的点位置。引用[4]中提到了其他图像处理算子,但与我们这里的问题不直接相关。因此,使用Sojka算子进行点检测的关键是调整这些参数以适应具体图像。下面我们将这个步骤用中文描述出来。</think> ### 如何使用Sojka算子进行点检测 在HALCON中,`points_sojka`算子专门用于实现Sojka点检测算法。该算法基于两个非共线灰度边缘的交点定义点特征[^1][^2][^3]。以下是详细的操作流程: --- #### 1. **基本调用语法** ```python points_sojka(Image, // 输入图像 MaskSize, // 检测掩码尺寸(奇数,如9) SigmaW, // 距离权重函数的Sigma值(空间权重) SigmaD, // 灰度边缘权重函数的Sigma值(强度权重) MinGrad, // 梯度幅值阈值(低于此值忽略) MinApparentness,// 表观阈值(点显著性) MinAngle, // 方向变化阈值(弧度) Subpix, // 亚像素精度开关('true'或'false') Rows, // 输出:点行坐标 Columns) // 输出:点列坐标 ``` --- #### 2. **参数选择指南** | 参数 | 典型值 | 作用 | |------|--------|------| | `MaskSize` | 9 | 检测邻域尺寸,必须是奇数[^1] | | `SigmaW` | 2.5 | 控制点候选点周围的空间加权范围[^1] | | `SigmaD` | 0.75 | 控制理想灰度边缘的加权范围[^1] | | `MinGrad` | 30 | 梯度幅值下限(过滤弱边缘)[^2] | | `MinApparentness` | 90 | 点显著性阈值(值越大点越少)[^2] | | `MinAngle` | 0.5 | 最小方向变化(弧度),过滤伪点[^1] | | `Subpix` | 'true' | 启用亚像素精度定位[^2] | --- #### 3. **完整操作流程(HALCON代码示例)** ```python * 读取图像 read_image (Image, 'mreut') * 执行Sojka点检测 points_sojka (Image, 9, 2.5, 0.75, 30, 90, 0.5, 'true', Row, Column) * 生成十字标记可视化 gen_cross_contour_xld (Cross, Row, Column, 60, 0.785398) * 显示结果 dev_display (Image) dev_display (Cross) disp_message (WindowHandle, 'Sojka点检测', 'window', 12, 12, 'black', 'true') ``` --- #### 4. **关键原理解析** 1. **点判定**: - 检测两个非共线灰度边缘的交点 - 在 $MaskSize \times MaskSize$ 邻域内验证点条件[^1] 2. **梯度过滤**: - 梯度幅值 $|\nabla I|$ 低于 `MinGrad` 的点直接被忽略 - 梯度方向变化角度需超过 `MinAngle` 弧度 3. **权重计算**: - 空间权重函数:$w_s = e^{-\frac{\| \mathbf{x} - \mathbf{c} \|^2}{2\sigma_w^2}}$ - 灰度权重函数:$w_i = e^{-\frac{(I(\mathbf{x}) - I(\mathbf{c}))^2}{2\sigma_d^2}}$ 4. **亚像素优化**: - 当 `Subpix='true'` 时,使用插值技术实现亚像素级定位[^2] --- #### 5. **实际应用技巧** - **工业检测**:适用于PCB焊点定位[^3]、机械零件点识别 - **参数调试**: - 噪声较多时提高 `MinApparentness`(如120) - 精细结构检测时减小 `MaskSize`(如7) - **预处理**: - 高噪声图像建议先进行高斯滤波 - 低对比度图像可增强灰度梯度:$I' = I \ast \nabla G_\sigma$ [^1]: Sojka算子核心参数定义与点判定逻辑 [^2]: 亚像素精度实现与可视化方法 [^3]: 工业检测中的典型应用场景
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hefeng_aspnet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值