news 2026/4/28 8:47:21

OpencvSharp 算子学习教案之 - Cv2.CartToPolar

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpencvSharp 算子学习教案之 - Cv2.CartToPolar

OpencvSharp 算子学习教案之 - Cv2.CartToPolar

大家好,Opencv在很多工程项目中都会用到,而OpencvSharp则是以C#开发与实现的Opencv操作库,对.NET开发人员友好,但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳,因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案,供大家参考学习。

Cv2.CartToPolar

  • 教案版本:V1.0
  • 面向对象:OpenCvSharp 初学者
  • 所属模块:core
  • 源码位置:OpenCvSharp/Cv2/Cv2_core.cs:1799

摘要:CartToPolar 会把 x/y 分量逐元素转换成幅值和角度。本文用坐标轴上的四个向量演示长度和方向如何被恢复,并解释 angleInDegrees 的输出单位。

1. 函数名称(带参数签名)

publicstaticvoidCartToPolar(InputArrayx,InputArrayy,OutputArraymagnitude,OutputArrayangle,boolangleInDegrees=false)

2. 函数用途

Cv2.CartToPolar的作用,是把直角坐标里的 x/y 分量转换成极坐标里的幅值和角度。

这个重载最常见的用途有:

  1. 从向量分量恢复长度和方向。
  2. 把图像中的位移、梯度或流场转成更容易理解的形式。
  3. 和 PolarToCart 一起学习坐标之间的互相转换。

OpenCV 的文档语义还说明了:xy必须有相同的尺寸和类型;输出的magnitudeangle会和输入保持同样的尺寸与类型。

3. 函数公式

如果把 x 分量记为xxx,y 分量记为yyy,那么:

magnitude=x2+y2 magnitude = \sqrt{x^2 + y^2}magnitude=x2+y2

angle=atan2⁡(y,x) angle = \operatorname{atan2}(y, x)angle=atan2(y,x)

如果angleInDegrees = true,那么角度会以度数形式输出;否则会以弧度形式输出。

4. 函数原理说明

CartToPolar的处理过程可以理解为:

  1. 读取当前位置的 x 分量。
  2. 读取当前位置的 y 分量。
  3. 用勾股定理算出向量长度。
  4. atan2算出向量角度。
  5. 把结果分别写入幅值矩阵和角度矩阵。

对初学者来说,最重要的是把“长度”和“方向”拆开理解,这样后面学习 Phase 时会更轻松。

5. 参数含义解析

参数名类型必填含义
xInputArray输入 x 分量矩阵
yInputArray输入 y 分量矩阵
magnitudeOutputArray输出幅值矩阵
angleOutputArray输出角度矩阵
angleInDegreesbooltrue 表示角度按度数输出,false 表示按弧度输出

补充说明:

  1. xy必须同尺寸、同类型。
  2. magnitudeangle的尺寸、类型会与输入保持一致。
  3. 如果你需要更直观地理解角度,通常会把angleInDegrees设为 true。
  4. 这个函数特别适合和 PolarToCart 做成一对来学习。

6. 应用场景列表

场景名场景说明典型用途
场景A:向量恢复从 x/y 恢复长度和方向几何分析、运动估计
场景B:梯度分析把分量变成幅值和角度图像边缘、光流
场景C:逆向学习和 PolarToCart 对照理解OpenCvSharp 入门

7. 函数使用示例

下面的 Console 程序演示Cv2.CartToPolar。为了让数值更容易理解,我们让输入向量刚好落在坐标轴上,这样输出角度会非常直观。

usingSystem.Globalization;usingSystem.Text;usingOpenCvSharp;internalstaticclassProgram{/// <summary>/// 程序入口。/// </summary>privatestaticvoidMain(){// 让控制台正确显示中文。Console.OutputEncoding=Encoding.UTF8;RunCartToPolarScenario();}/// <summary>/// 演示 CartToPolar 的逐元素坐标恢复。/// </summary>privatestaticvoidRunCartToPolarScenario(){constboolangleInDegrees=true;varxData=newdouble[,]{{1.0,0.0},{-3.0,0.0},};varyData=newdouble[,]{{0.0,2.0},{0.0,-4.0},};usingvarx=CreateMat(xData);usingvary=CreateMat(yData);usingvarmagnitude=newMat();usingvarangle=newMat();// CartToPolar 会把每个位置的 x/y 分量转换成幅值和角度。Cv2.CartToPolar(x,y,magnitude,angle,angleInDegrees);varsamplePoints=new[]{newPoint(0,0),newPoint(1,0),newPoint(0,1),newPoint(1,1),};PrintHeader("CartToPolar 逐元素坐标恢复","本示例使用度数作为角度单位,这样可以直接读出 0、90、180、270 度的方向。\n");PrintMatrix("x",xData);PrintMatrix("y",yData);PrintMatrix("magnitude",ReadMatrix(magnitude));PrintMatrix("angle",ReadMatrix(angle));foreach(varpointinsamplePoints){varxValue=xData[point.Y,point.X];varyValue=yData[point.Y,point.X];varactualMagnitude=magnitude.At<double>(point.Y,point.X);varactualAngle=angle.At<double>(point.Y,point.X);varexpected=PolarFromCartesian(xValue,yValue);PrintComparison("幅值",point,actualMagnitude,expected.Magnitude);PrintComparison("角度",point,actualAngle,expected.AngleDegrees);}Console.WriteLine("教学结论:CartToPolar 适合把向量分量恢复成“有多长、朝哪个方向”这两个最基础的量。\n");}/// <summary>/// 把二维数组写入 Mat。/// </summary>/// <param name="values">二维数组。</param>/// <returns>CV_64FC1 矩阵。</returns>privatestaticMatCreateMat(double[,]values){returnMat.FromPixelData(values.GetLength(0),values.GetLength(1),MatType.CV_64FC1,values);}/// <summary>/// 手工计算直角坐标到极坐标的结果。/// </summary>/// <param name="x">x 分量。</param>/// <param name="y">y 分量。</param>/// <returns>幅值和角度(度)。</returns>privatestatic(doubleMagnitude,doubleAngleDegrees)PolarFromCartesian(doublex,doubley){varmagnitude=Math.Sqrt(x*x+y*y);varangleRadians=Math.Atan2(y,x);if(angleRadians<0){angleRadians+=Math.PI*2.0;}return(magnitude,angleRadians*180.0/Math.PI);}/// <summary>/// 把 Mat 读回 double[,] 二维数组。/// </summary>/// <param name="source">输入矩阵。</param>/// <returns>double 二维数组。</returns>privatestaticdouble[,]ReadMatrix(Matsource){varresult=newdouble[source.Rows,source.Cols];for(varrow=0;row<source.Rows;row++){for(varcol=0;col<source.Cols;col++){result[row,col]=source.At<double>(row,col);}}returnresult;}/// <summary>/// 打印程序标题。/// </summary>/// <param name="title">标题。</param>/// <param name="description">说明。</param>privatestaticvoidPrintHeader(stringtitle,stringdescription){Console.WriteLine(title);Console.WriteLine(description);Console.WriteLine(newstring('-',40));}/// <summary>/// 打印一个矩阵。/// </summary>/// <param name="title">标题。</param>/// <param name="matrix">矩阵。</param>privatestaticvoidPrintMatrix(stringtitle,double[,]matrix){Console.WriteLine(title);Console.WriteLine(FormatMatrixText(matrix));}/// <summary>/// 打印采样点比较结果。/// </summary>/// <param name="label">说明标签。</param>/// <param name="point">采样点。</param>/// <param name="actual">实际结果。</param>/// <param name="expected">期望结果。</param>privatestaticvoidPrintComparison(stringlabel,Pointpoint,doubleactual,doubleexpected){Console.WriteLine(label);Console.WriteLine($"采样点:({point.X},{point.Y})");Console.WriteLine($"实际结果:{FormatValue(actual)}");Console.WriteLine($"期望结果:{FormatValue(expected)}");Console.WriteLine($"是否一致:{Math.Abs(actual-expected)<=1e-6}");Console.WriteLine();}/// <summary>/// 把双精度数值格式化成更适合阅读的字符串。/// </summary>/// <param name="value">待格式化的值。</param>/// <param name="numericFormat">格式字符串。</param>/// <returns>格式化后的字符串。</returns>privatestaticstringFormatValue(doublevalue,stringnumericFormat="F6"){returnvalue.ToString(numericFormat,CultureInfo.InvariantCulture);}/// <summary>/// 把矩阵打印成多行文本。/// </summary>/// <param name="matrix">二维矩阵。</param>/// <param name="numericFormat">格式字符串。</param>/// <returns>矩阵文本。</returns>privatestaticstringFormatMatrixText(double[,]matrix,stringnumericFormat="F3"){varsb=newStringBuilder();for(varrow=0;row<matrix.GetLength(0);row++){sb.Append("[");for(varcol=0;col<matrix.GetLength(1);col++){sb.Append(matrix[row,col].ToString(numericFormat,CultureInfo.InvariantCulture));if(col<matrix.GetLength(1)-1){sb.Append(", ");}}sb.AppendLine("]");}returnsb.ToString();}}

8. 注意事项

  1. xy必须同尺寸、同类型。
  2. 输出的 magnitude 和 angle 会和输入保持同样的尺寸和类型。
  3. atan2会自动处理象限,所以角度比手动用Math.Atan(y / x)更稳妥。
  4. 如果你要和 PolarToCart 对照,最好统一角度单位。

9. 调优建议

  1. 先用坐标轴上的向量做示例,最容易看懂。
  2. 如果你关心方向,先看 angle;如果你关心长度,先看 magnitude。
  3. 和 Phase 放在一起看,可以很快理解它们的区别。
  4. 先看 WPF 预览,再看控制台数字,理解会更快。

10. 运行说明

  1. 如果你在控制台工程里运行本文示例,直接把代码放进Program.cs即可。
  2. 如果你在本仓库里学习,请直接打开 WPF 控件Cv2.CartToPolar,点击按钮查看结果。
  3. WPF 示例会把 x、y、magnitude、angle 四个矩阵并排展示出来。

11. 常见错误排查

  1. 把 CartToPolar 当成统计函数,它其实是逐元素变换。
  2. 忘记 x 和 y 必须同尺寸、同类型。
  3. 把弧度和度数混淆,导致角度解释错误。
  4. 以为输出会变成一个标量,其实输出仍然是矩阵。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/28 8:43:53

Android 高级工程师面试参考答案:网络、存储与安全

这一篇最容易出现一个误区&#xff1a;很多人背得出 HTTP/HTTPS、SP/MMKV、签名和混淆&#xff0c;但一到项目里就讲不清“为什么要这样设计”。高级岗位面试更看重你对边界和风险的理解。 1. HTTP 和 HTTPS 的区别&#xff0c;面试怎么答更完整&#xff1f; 参考答案 HTTP …

作者头像 李华
网站建设 2026/4/28 8:41:20

加拿大2026版EE重磅改革!内部官方文件分析!

&#x1f4e3;4月8日&#xff0c;加拿大移民圈传来重磅消息&#xff1a;快速通道&#xff08;Express Entry&#xff09;将迎来一次彻底的系统重构&#xff0c;底层逻辑几乎推倒重来。&#x1f6ce;️当地时间4月22日&#xff0c;IRCC&#xff08;加拿大移民局&#xff09;专门…

作者头像 李华
网站建设 2026/4/28 8:32:54

【避坑指南】Qwen2.5-VL-7B-Instruct RTX 4090版常见问题与解决方案

【避坑指南】Qwen2.5-VL-7B-Instruct RTX 4090版常见问题与解决方案 1. 镜像概述与环境准备 1.1 镜像核心特性 Qwen2.5-VL-7B-Instruct RTX 4090版是针对高性能显卡优化的多模态大模型工具&#xff0c;主要特点包括&#xff1a; 原生适配RTX 4090 24GB显存默认启用Flash At…

作者头像 李华
网站建设 2026/4/28 8:31:57

FPGA实现PCIe数据通信培训课程,提供工程源码+视频教程+FPGA开发板

目录 1、FPGA实现PCIe数据通信现状分析2、本FPGAPCIe数据通信培训优势亮点架构全起点高实用性强项目应用级别细节恐怖工程源码清晰 3、本FPGA图像处理培训内容介绍FPGA过PCIe到PC框架框架工程源码1详细介绍工程源码2、3详细介绍工程源码4、5详细介绍工程源码6、7、8、9详细介绍…

作者头像 李华