OpencvSharp 算子学习教案之 - Cv2.Min 重载3重载3Min(Mat src1, double src2, Mat dst)大家好Opencv在很多工程项目中都会用到而OpencvSharp则是以C#开发与实现的Opencv操作库对.NET开发人员友好但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案供大家参考学习。Cv2.Min教案版本V1.0面向对象OpenCvSharp 初学者所属模块core源码位置OpenCvSharp/Cv2/Cv2_core.cs:1573摘要这个重载会把一个固定标量和矩阵逐元素比较保留更小的那个值。它很适合用来理解阈值裁剪和“上限封顶”的思路。1. 函数名称带参数签名publicstaticvoidMin(Matsrc1,doublesrc2,Matdst)2. 函数用途Cv2.Min的这个重载会把矩阵中的每一个元素和同一个标量进行比较然后把较小的那个值写入结果图。这个重载最常见的用途有做上限封顶让数值不要超过某个阈值。保留较暗区域或较小的数值。在图像处理前后做固定参考值的裁剪。和前两个重载相比这里不再需要第二张矩阵而是拿一个固定常量作为比较对象。3. 函数公式对于输入矩阵src1和标量src2这个重载返回的是dst(x,y)min(src1(x,y),src2) dst(x, y) \min(src1(x, y), src2)dst(x,y)min(src1(x,y),src2)这里的标量会被看成“整张图都使用同一个参考值”。4. 函数原理说明Cv2.Min(Mat, double, Mat)的工作方式可以理解成下面四步读取当前像素值。把它和固定标量进行比较。如果像素更小就保留像素本身。如果标量更小就把标量写进结果图。对初学者来说最重要的是理解这个标量不是“某个位置上的值”而是对整张图所有像素都生效的固定参考值。5. 参数含义解析参数名类型必填含义src1Mat是输入矩阵src2double是用于逐元素比较的标量值dstMat是输出结果矩阵补充说明src1和dst的尺寸通常要一致。这个重载特别适合在固定阈值下做数值裁剪。如果你要对两张图做比较请改用前两个重载。当src2作为标量使用时可以把它理解成“一整张常量图”。6. 应用场景列表场景名场景说明典型用途场景A上限封顶把超过阈值的像素压回阈值亮度裁剪场景B保留较暗像素与固定参考值比较后保留更小值阈值控制场景C固定参考值比较让标量成为整图统一的比较标准初学者教学7. 函数使用示例下面的 Console 程序演示Min(Mat, double, Mat)。这个重载非常适合先让初学者理解“一个固定标量和整张矩阵逐元素比较”的想法。usingSystem.Text;usingOpenCvSharp;internalstaticclassProgram{/// summary/// 程序入口。/// /summaryprivatestaticvoidMain(){// 让控制台正确显示中文。Console.OutputEncodingEncoding.UTF8;RunScalarScenario();}/// summary/// 演示 Min 的标量重载。/// /summaryprivatestaticvoidRunScalarScenario(){constbytescalarValue150;varsourceDatanewbyte[,]{{60,60,120,120},{60,60,120,120},{180,180,240,240},{180,180,240,240},};usingvarsourceCreateMat(sourceData);usingvardestinationnewMat(source.Size(),source.Type());// 这里传入的 scalarValue 会被当成整张图的统一参考值。Cv2.Min(source,scalarValue,destination);varexpectedComputeExpectedMin(sourceData,scalarValue);varsamplePointsnew[]{newPoint(1,1),newPoint(3,1),newPoint(1,3),newPoint(3,3),};PrintHeader(Min 标量重载,这个重载会把矩阵和一个固定标量逐元素比较。);PrintMatrix(source,sourceData);PrintMatrix(scalar reference,CreateFilledMatrix(sourceData.GetLength(0),sourceData.GetLength(1),scalarValue));PrintMatrix(destination,ReadMatrix(destination));foreach(varpointinsamplePoints){PrintPointComparison(point,sourceData,scalarValue,expected,destination);}}/// summary/// 把二维托管数组写入 OpenCV Mat。/// /summaryprivatestaticMatCreateMat(byte[,]values){returnMat.FromPixelData(values.GetLength(0),values.GetLength(1),MatType.CV_8UC1,values);}/// summary/// 创建一个纯色矩阵用来把标量值可视化出来。/// /summaryprivatestaticbyte[,]CreateFilledMatrix(introws,intcols,bytevalue){varresultnewbyte[rows,cols];for(varrow0;rowrows;row){for(varcol0;colcols;col){result[row,col]value;}}returnresult;}/// summary/// 手工计算逐元素最小值。/// /summaryprivatestaticbyte[,]ComputeExpectedMin(byte[,]source,bytescalarValue){varresultnewbyte[source.GetLength(0),source.GetLength(1)];for(varrow0;rowsource.GetLength(0);row){for(varcol0;colsource.GetLength(1);col){result[row,col]source[row,col]scalarValue?source[row,col]:scalarValue;}}returnresult;}/// summary/// 把 Mat 读回托管数组便于打印和对照。/// /summaryprivatestaticbyte[,]ReadMatrix(Matsource){varresultnewbyte[source.Rows,source.Cols];for(varrow0;rowsource.Rows;row){for(varcol0;colsource.Cols;col){result[row,col]source.Atbyte(row,col);}}returnresult;}/// summary/// 打印程序标题。/// /summaryprivatestaticvoidPrintHeader(stringtitle,stringdescription){Console.WriteLine(title);Console.WriteLine(description);Console.WriteLine(newstring(-,40));}/// summary/// 打印一个矩阵。/// /summaryprivatestaticvoidPrintMatrix(stringtitle,byte[,]matrix){Console.WriteLine(title);Console.WriteLine(FormatMatrixText(matrix));}/// summary/// 打印逐元素对比结果。/// /summaryprivatestaticvoidPrintPointComparison(Pointpoint,byte[,]source,bytescalarValue,byte[,]expected,Matactual){varactualValueactual.Atbyte(point.Y,point.X);varexpectedValueexpected[point.Y,point.X];Console.WriteLine($采样点({point.X},{point.Y}));Console.WriteLine($source{source[point.Y,point.X]});Console.WriteLine($scalar{scalarValue});Console.WriteLine($实际结果{actualValue});Console.WriteLine($期望结果{expectedValue});Console.WriteLine($是否一致{actualValueexpectedValue});Console.WriteLine();}/// summary/// 把矩阵打印成多行文本便于阅读。/// /summaryprivatestaticstringFormatMatrixText(byte[,]matrix){varsbnewStringBuilder();for(varrow0;rowmatrix.GetLength(0);row){sb.Append([);for(varcol0;colmatrix.GetLength(1);col){sb.Append(matrix[row,col]);if(colmatrix.GetLength(1)-1){sb.Append(, );}}sb.AppendLine(]);}returnsb.ToString();}}8. 注意事项这个重载返回的是逐元素最小值不是最小值的位置。标量会被当作整张图的统一参考值。结果写回dst所以源图不会被修改。当你想做“上限封顶”时Min的标量重载很实用。9. 调优建议先把标量想成一张纯色参考图再理解逐元素比较。先从灰度图开始练习图像结构越简单越容易看懂结果。如果你在做阈值裁剪先确认输入值和阈值的数值方向。对比本页和前两个重载时重点看“比较对象是不是固定常量”。10. 运行说明如果你在控制台工程里运行本文示例直接把代码放进Program.cs即可。如果你在本仓库里学习请直接打开 WPF 控件Cv2.Min点击按钮查看三个场景的差异。WPF 示例把两个输入、标量参考图和结果图放在同一张预览里方便横向比较。11. 常见错误排查把 Min 误当成 MinMaxLoc。以为标量只作用于某一个像素其实它会作用于整张图。以为标量场景返回的是一个数其实返回的是一张图。忘记 Min 是逐元素最小值而不是全局最小值。忽略输入矩阵和输出矩阵的尺寸一致性。
OpencvSharp 算子学习教案之 - Cv2.Min 重载3
OpencvSharp 算子学习教案之 - Cv2.Min 重载3重载3Min(Mat src1, double src2, Mat dst)大家好Opencv在很多工程项目中都会用到而OpencvSharp则是以C#开发与实现的Opencv操作库对.NET开发人员友好但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案供大家参考学习。Cv2.Min教案版本V1.0面向对象OpenCvSharp 初学者所属模块core源码位置OpenCvSharp/Cv2/Cv2_core.cs:1573摘要这个重载会把一个固定标量和矩阵逐元素比较保留更小的那个值。它很适合用来理解阈值裁剪和“上限封顶”的思路。1. 函数名称带参数签名publicstaticvoidMin(Matsrc1,doublesrc2,Matdst)2. 函数用途Cv2.Min的这个重载会把矩阵中的每一个元素和同一个标量进行比较然后把较小的那个值写入结果图。这个重载最常见的用途有做上限封顶让数值不要超过某个阈值。保留较暗区域或较小的数值。在图像处理前后做固定参考值的裁剪。和前两个重载相比这里不再需要第二张矩阵而是拿一个固定常量作为比较对象。3. 函数公式对于输入矩阵src1和标量src2这个重载返回的是dst(x,y)min(src1(x,y),src2) dst(x, y) \min(src1(x, y), src2)dst(x,y)min(src1(x,y),src2)这里的标量会被看成“整张图都使用同一个参考值”。4. 函数原理说明Cv2.Min(Mat, double, Mat)的工作方式可以理解成下面四步读取当前像素值。把它和固定标量进行比较。如果像素更小就保留像素本身。如果标量更小就把标量写进结果图。对初学者来说最重要的是理解这个标量不是“某个位置上的值”而是对整张图所有像素都生效的固定参考值。5. 参数含义解析参数名类型必填含义src1Mat是输入矩阵src2double是用于逐元素比较的标量值dstMat是输出结果矩阵补充说明src1和dst的尺寸通常要一致。这个重载特别适合在固定阈值下做数值裁剪。如果你要对两张图做比较请改用前两个重载。当src2作为标量使用时可以把它理解成“一整张常量图”。6. 应用场景列表场景名场景说明典型用途场景A上限封顶把超过阈值的像素压回阈值亮度裁剪场景B保留较暗像素与固定参考值比较后保留更小值阈值控制场景C固定参考值比较让标量成为整图统一的比较标准初学者教学7. 函数使用示例下面的 Console 程序演示Min(Mat, double, Mat)。这个重载非常适合先让初学者理解“一个固定标量和整张矩阵逐元素比较”的想法。usingSystem.Text;usingOpenCvSharp;internalstaticclassProgram{/// summary/// 程序入口。/// /summaryprivatestaticvoidMain(){// 让控制台正确显示中文。Console.OutputEncodingEncoding.UTF8;RunScalarScenario();}/// summary/// 演示 Min 的标量重载。/// /summaryprivatestaticvoidRunScalarScenario(){constbytescalarValue150;varsourceDatanewbyte[,]{{60,60,120,120},{60,60,120,120},{180,180,240,240},{180,180,240,240},};usingvarsourceCreateMat(sourceData);usingvardestinationnewMat(source.Size(),source.Type());// 这里传入的 scalarValue 会被当成整张图的统一参考值。Cv2.Min(source,scalarValue,destination);varexpectedComputeExpectedMin(sourceData,scalarValue);varsamplePointsnew[]{newPoint(1,1),newPoint(3,1),newPoint(1,3),newPoint(3,3),};PrintHeader(Min 标量重载,这个重载会把矩阵和一个固定标量逐元素比较。);PrintMatrix(source,sourceData);PrintMatrix(scalar reference,CreateFilledMatrix(sourceData.GetLength(0),sourceData.GetLength(1),scalarValue));PrintMatrix(destination,ReadMatrix(destination));foreach(varpointinsamplePoints){PrintPointComparison(point,sourceData,scalarValue,expected,destination);}}/// summary/// 把二维托管数组写入 OpenCV Mat。/// /summaryprivatestaticMatCreateMat(byte[,]values){returnMat.FromPixelData(values.GetLength(0),values.GetLength(1),MatType.CV_8UC1,values);}/// summary/// 创建一个纯色矩阵用来把标量值可视化出来。/// /summaryprivatestaticbyte[,]CreateFilledMatrix(introws,intcols,bytevalue){varresultnewbyte[rows,cols];for(varrow0;rowrows;row){for(varcol0;colcols;col){result[row,col]value;}}returnresult;}/// summary/// 手工计算逐元素最小值。/// /summaryprivatestaticbyte[,]ComputeExpectedMin(byte[,]source,bytescalarValue){varresultnewbyte[source.GetLength(0),source.GetLength(1)];for(varrow0;rowsource.GetLength(0);row){for(varcol0;colsource.GetLength(1);col){result[row,col]source[row,col]scalarValue?source[row,col]:scalarValue;}}returnresult;}/// summary/// 把 Mat 读回托管数组便于打印和对照。/// /summaryprivatestaticbyte[,]ReadMatrix(Matsource){varresultnewbyte[source.Rows,source.Cols];for(varrow0;rowsource.Rows;row){for(varcol0;colsource.Cols;col){result[row,col]source.Atbyte(row,col);}}returnresult;}/// summary/// 打印程序标题。/// /summaryprivatestaticvoidPrintHeader(stringtitle,stringdescription){Console.WriteLine(title);Console.WriteLine(description);Console.WriteLine(newstring(-,40));}/// summary/// 打印一个矩阵。/// /summaryprivatestaticvoidPrintMatrix(stringtitle,byte[,]matrix){Console.WriteLine(title);Console.WriteLine(FormatMatrixText(matrix));}/// summary/// 打印逐元素对比结果。/// /summaryprivatestaticvoidPrintPointComparison(Pointpoint,byte[,]source,bytescalarValue,byte[,]expected,Matactual){varactualValueactual.Atbyte(point.Y,point.X);varexpectedValueexpected[point.Y,point.X];Console.WriteLine($采样点({point.X},{point.Y}));Console.WriteLine($source{source[point.Y,point.X]});Console.WriteLine($scalar{scalarValue});Console.WriteLine($实际结果{actualValue});Console.WriteLine($期望结果{expectedValue});Console.WriteLine($是否一致{actualValueexpectedValue});Console.WriteLine();}/// summary/// 把矩阵打印成多行文本便于阅读。/// /summaryprivatestaticstringFormatMatrixText(byte[,]matrix){varsbnewStringBuilder();for(varrow0;rowmatrix.GetLength(0);row){sb.Append([);for(varcol0;colmatrix.GetLength(1);col){sb.Append(matrix[row,col]);if(colmatrix.GetLength(1)-1){sb.Append(, );}}sb.AppendLine(]);}returnsb.ToString();}}8. 注意事项这个重载返回的是逐元素最小值不是最小值的位置。标量会被当作整张图的统一参考值。结果写回dst所以源图不会被修改。当你想做“上限封顶”时Min的标量重载很实用。9. 调优建议先把标量想成一张纯色参考图再理解逐元素比较。先从灰度图开始练习图像结构越简单越容易看懂结果。如果你在做阈值裁剪先确认输入值和阈值的数值方向。对比本页和前两个重载时重点看“比较对象是不是固定常量”。10. 运行说明如果你在控制台工程里运行本文示例直接把代码放进Program.cs即可。如果你在本仓库里学习请直接打开 WPF 控件Cv2.Min点击按钮查看三个场景的差异。WPF 示例把两个输入、标量参考图和结果图放在同一张预览里方便横向比较。11. 常见错误排查把 Min 误当成 MinMaxLoc。以为标量只作用于某一个像素其实它会作用于整张图。以为标量场景返回的是一个数其实返回的是一张图。忘记 Min 是逐元素最小值而不是全局最小值。忽略输入矩阵和输出矩阵的尺寸一致性。