news 2026/5/27 3:30:04

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

作者头像

张小明

前端开发工程师

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

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

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

Cv2.Log

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

摘要:Log 会对每个像素逐元素计算自然对数,输出和源图保持相同的尺寸与类型。本文使用 1、2、4、8 作为输入,演示对数压缩如何让较大的数值变化变得更温和。

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

publicstaticvoidLog(InputArraysrc,OutputArraydst)

2. 函数用途

Cv2.Log的作用,是对输入矩阵中的每一个元素单独计算自然对数,然后把结果写入dst

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

  1. 把指数域的数据压缩到更小的范围。
  2. 在频域、统计和亮度处理中做对数变换。
  3. 帮助初学者理解“对数会压缩大数值差异”。

这里需要注意,OpenCV 的语义是log(abs(src)),所以本页示例选择正数输入,避免额外干扰。

3. 函数公式

对于输入矩阵src,这个重载返回的是:

dst(x,y)=ln⁡(∣src(x,y)∣) dst(x, y) = \ln(|src(x, y)|)dst(x,y)=ln(src(x,y))

当输入值为正时,它就等价于普通的自然对数。

4. 函数原理说明

Cv2.Log的处理过程可以理解成:

  1. 读取当前像素值。
  2. 对这个值求自然对数。
  3. 把结果写入目标矩阵。
  4. 对整张图的每个位置重复这个过程。

对初学者来说,最重要的是区分:

  1. 这是逐元素对数运算,不是全局统计。
  2. 输入值越大,输出增长越慢,这就是对数压缩。
  3. 本页示例避免使用 0 和负数,先把基础语义讲清楚。
  4. 输出结果仍然是一张图,不是一个标量。

5. 参数含义解析

参数名类型必填含义
srcInputArray输入矩阵,建议使用正数浮点数
dstOutputArray输出结果矩阵

补充说明:

  1. dst的尺寸和类型会与src保持一致。
  2. 由于log(0)没有有限结果,所以示例避免使用 0。
  3. OpenCV 语义里使用的是绝对值对数。
  4. 这个函数特别适合解释动态范围压缩。

6. 应用场景列表

场景名场景说明典型用途
场景A:动态范围压缩让大数值差异变得更温和图像增强、频谱显示
场景B:指数逆变换作为 Exp 的反向操作对数域恢复
场景C:基础数学变换学习逐元素单输入运算OpenCvSharp 入门

7. 函数使用示例

下面的 Console 程序演示Cv2.Log。为了让输出更容易看懂,我们使用 1、2、4、8 作为四个象限的输入值,这样对数结果依次变成 0、0.693、1.386、2.079。

usingSystem.Globalization;usingSystem.Text;usingOpenCvSharp;internalstaticclassProgram{/// <summary>/// 程序入口。/// </summary>privatestaticvoidMain(){// 让控制台正确显示中文。Console.OutputEncoding=Encoding.UTF8;RunLogScenario();}/// <summary>/// 演示 Log 的逐元素自然对数运算。/// </summary>privatestaticvoidRunLogScenario(){varsourceData=newdouble[,]{{1.0,1.0,2.0,2.0},{1.0,1.0,2.0,2.0},{4.0,4.0,8.0,8.0},{4.0,4.0,8.0,8.0},};usingvarsource=CreateMat(sourceData);usingvardestination=newMat();// Log 会对每个元素单独计算自然对数。Cv2.Log(source,destination);varexpected=ComputeExpectedLog(sourceData);varsamplePoints=new[]{newPoint(1,1),newPoint(3,1),newPoint(1,3),newPoint(3,3),};PrintHeader("Log 逐元素自然对数","这个示例演示每个像素计算自然对数后的结果。");PrintMatrix("source",sourceData);PrintMatrix("destination",ReadMatrix(destination));foreach(varpointinsamplePoints){PrintPointComparison(point,sourceData,expected,destination);}Console.WriteLine("教学结论:Log 适合压缩动态范围,也常常和 Exp 配合使用。\n");}/// <summary>/// 把二维托管数组写入 OpenCV Mat。/// </summary>privatestaticMatCreateMat(double[,]values){returnMat.FromPixelData(values.GetLength(0),values.GetLength(1),MatType.CV_64FC1,values);}/// <summary>/// 手工计算自然对数结果。/// </summary>privatestaticdouble[,]ComputeExpectedLog(double[,]source){varresult=newdouble[source.GetLength(0),source.GetLength(1)];for(varrow=0;row<source.GetLength(0);row++){for(varcol=0;col<source.GetLength(1);col++){result[row,col]=Math.Log(Math.Abs(source[row,col]));}}returnresult;}/// <summary>/// 把 Mat 读回托管数组,便于打印和对照。/// </summary>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>privatestaticvoidPrintHeader(stringtitle,stringdescription){Console.WriteLine(title);Console.WriteLine(description);Console.WriteLine(newstring('-',40));}/// <summary>/// 打印一个矩阵。/// </summary>privatestaticvoidPrintMatrix(stringtitle,double[,]matrix){Console.WriteLine(title);Console.WriteLine(FormatMatrixText(matrix));}/// <summary>/// 打印逐元素对比结果。/// </summary>privatestaticvoidPrintPointComparison(Pointpoint,double[,]source,double[,]expected,Matactual){varactualValue=actual.At<double>(point.Y,point.X);varexpectedValue=expected[point.Y,point.X];Console.WriteLine($"采样点:({point.X},{point.Y})");Console.WriteLine($"source:{FormatValue(source[point.Y,point.X])}");Console.WriteLine($"实际结果:{FormatValue(actualValue)}");Console.WriteLine($"期望结果:{FormatValue(expectedValue)}");Console.WriteLine($"是否一致:{Math.Abs(actualValue-expectedValue)<=1e-6}");Console.WriteLine();}/// <summary>/// 把双精度数值格式化成更适合阅读的字符串。/// </summary>privatestaticstringFormatValue(doublevalue,stringnumericFormat="F6"){returnvalue.ToString(numericFormat,CultureInfo.InvariantCulture);}/// <summary>/// 把矩阵打印成多行文本,便于阅读。/// </summary>privatestaticstringFormatMatrixText(double[,]matrix){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("F3",CultureInfo.InvariantCulture));if(col<matrix.GetLength(1)-1){sb.Append(", ");}}sb.AppendLine("]");}returnsb.ToString();}}

8. 注意事项

  1. Log 计算的是自然对数,不是常用对数。
  2. OpenCV 语义里使用的是绝对值对数。
  3. 输入值应当避免 0,便于初学者先看清楚数学含义。
  4. 输出矩阵和输入矩阵尺寸一致。

9. 调优建议

  1. 先从 1、2、4、8 这样的输入开始看结果。
  2. 如果你在做动态范围压缩,对数变换通常比线性缩放更能保留相对变化。
  3. 对比本页和 Exp 教案,最容易建立指数和对数的互逆关系。
  4. 先看控制台结果,再去看 WPF 预览,会更容易理解数值变化。

10. 运行说明

  1. 如果你在控制台工程里运行本文示例,直接把代码放进Program.cs即可。
  2. 如果你在本仓库里学习,请直接打开 WPF 控件Cv2.Log,点击按钮查看结果。
  3. WPF 示例会把源图和结果图并排展示,并对浮点值做归一化显示。

11. 常见错误排查

  1. 把 Log 当成常用对数。
  2. 忽略 OpenCV 使用的是log(abs(src))
  3. 使用 0 或负数输入,导致数学意义不直观。
  4. 以为输出会变成一个标量,其实输出仍然是一张矩阵。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/27 3:20:59

为什么你越帮人,别人越不领情?《易经》一句话点醒你

你有没有过这样的经历&#xff1f;同事向你借钱&#xff0c;你二话不说就转了。朋友找你帮忙&#xff0c;你熬夜帮他搞定。可到头来&#xff0c;他不但没感谢你&#xff0c;反而觉得理所当然&#xff0c;甚至你一次没帮&#xff0c;他就翻脸了。你委屈得要死&#xff1a;“我对…

作者头像 李华
网站建设 2026/5/27 3:17:00

[智能体-96]:向量是信息的载体,时序是连接方式,模型最终目标都是穿透表层干扰,提取序列背后的本质信息(语义 / 行为)。

从模型的角度看&#xff0c;一个单词的词向量与一张图片的像素向量类似。多个时间上连续的词向量&#xff08;单词&#xff09;&#xff0c;组成了连续的语言文字&#xff1b;多个时间上连续的像素向量&#xff08;图片&#xff09;组成了连续的视频&#xff1b;三、两套体系的…

作者头像 李华