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

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。这个重载最常见的用途有把指数域的数据压缩到更小的范围。在频域、统计和亮度处理中做对数变换。帮助初学者理解“对数会压缩大数值差异”。这里需要注意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的处理过程可以理解成读取当前像素值。对这个值求自然对数。把结果写入目标矩阵。对整张图的每个位置重复这个过程。对初学者来说最重要的是区分这是逐元素对数运算不是全局统计。输入值越大输出增长越慢这就是对数压缩。本页示例避免使用 0 和负数先把基础语义讲清楚。输出结果仍然是一张图不是一个标量。5. 参数含义解析参数名类型必填含义srcInputArray是输入矩阵建议使用正数浮点数dstOutputArray是输出结果矩阵补充说明dst的尺寸和类型会与src保持一致。由于log(0)没有有限结果所以示例避免使用 0。OpenCV 语义里使用的是绝对值对数。这个函数特别适合解释动态范围压缩。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/// 程序入口。/// /summaryprivatestaticvoidMain(){// 让控制台正确显示中文。Console.OutputEncodingEncoding.UTF8;RunLogScenario();}/// summary/// 演示 Log 的逐元素自然对数运算。/// /summaryprivatestaticvoidRunLogScenario(){varsourceDatanewdouble[,]{{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},};usingvarsourceCreateMat(sourceData);usingvardestinationnewMat();// Log 会对每个元素单独计算自然对数。Cv2.Log(source,destination);varexpectedComputeExpectedLog(sourceData);varsamplePointsnew[]{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。/// /summaryprivatestaticMatCreateMat(double[,]values){returnMat.FromPixelData(values.GetLength(0),values.GetLength(1),MatType.CV_64FC1,values);}/// summary/// 手工计算自然对数结果。/// /summaryprivatestaticdouble[,]ComputeExpectedLog(double[,]source){varresultnewdouble[source.GetLength(0),source.GetLength(1)];for(varrow0;rowsource.GetLength(0);row){for(varcol0;colsource.GetLength(1);col){result[row,col]Math.Log(Math.Abs(source[row,col]));}}returnresult;}/// summary/// 把 Mat 读回托管数组便于打印和对照。/// /summaryprivatestaticdouble[,]ReadMatrix(Matsource){varresultnewdouble[source.Rows,source.Cols];for(varrow0;rowsource.Rows;row){for(varcol0;colsource.Cols;col){result[row,col]source.Atdouble(row,col);}}returnresult;}/// summary/// 打印程序标题。/// /summaryprivatestaticvoidPrintHeader(stringtitle,stringdescription){Console.WriteLine(title);Console.WriteLine(description);Console.WriteLine(newstring(-,40));}/// summary/// 打印一个矩阵。/// /summaryprivatestaticvoidPrintMatrix(stringtitle,double[,]matrix){Console.WriteLine(title);Console.WriteLine(FormatMatrixText(matrix));}/// summary/// 打印逐元素对比结果。/// /summaryprivatestaticvoidPrintPointComparison(Pointpoint,double[,]source,double[,]expected,Matactual){varactualValueactual.Atdouble(point.Y,point.X);varexpectedValueexpected[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/// 把双精度数值格式化成更适合阅读的字符串。/// /summaryprivatestaticstringFormatValue(doublevalue,stringnumericFormatF6){returnvalue.ToString(numericFormat,CultureInfo.InvariantCulture);}/// summary/// 把矩阵打印成多行文本便于阅读。/// /summaryprivatestaticstringFormatMatrixText(double[,]matrix){varsbnewStringBuilder();for(varrow0;rowmatrix.GetLength(0);row){sb.Append([);for(varcol0;colmatrix.GetLength(1);col){sb.Append(matrix[row,col].ToString(F3,CultureInfo.InvariantCulture));if(colmatrix.GetLength(1)-1){sb.Append(, );}}sb.AppendLine(]);}returnsb.ToString();}}8. 注意事项Log 计算的是自然对数不是常用对数。OpenCV 语义里使用的是绝对值对数。输入值应当避免 0便于初学者先看清楚数学含义。输出矩阵和输入矩阵尺寸一致。9. 调优建议先从 1、2、4、8 这样的输入开始看结果。如果你在做动态范围压缩对数变换通常比线性缩放更能保留相对变化。对比本页和 Exp 教案最容易建立指数和对数的互逆关系。先看控制台结果再去看 WPF 预览会更容易理解数值变化。10. 运行说明如果你在控制台工程里运行本文示例直接把代码放进Program.cs即可。如果你在本仓库里学习请直接打开 WPF 控件Cv2.Log点击按钮查看结果。WPF 示例会把源图和结果图并排展示并对浮点值做归一化显示。11. 常见错误排查把 Log 当成常用对数。忽略 OpenCV 使用的是log(abs(src))。使用 0 或负数输入导致数学意义不直观。以为输出会变成一个标量其实输出仍然是一张矩阵。