OpenCV子矩阵Mat调用ForEachAsByte遍历像素计数每次运行均不一致
问题根因
你遇到的计数不稳定问题核心来自多线程并行遍历的竞态条件:
- OpenCVSharp的
ForEachAsByte/ForEachAsInt16这类方法默认是多线程并行执行的,会将图像切分成多个块由不同线程同时处理 - 你定义的
pixelcounter是普通int类型,多线程同时执行pixelcounter++操作时,该操作不是原子操作,会出现多个线程同时读取到同一个值、各自累加后回写导致计数丢失的情况,每次丢失的数量不固定,所以最终结果随机且始终小于预期值 - 你提到的
IsContinuous=False(子矩阵非连续)不是问题原因,ForEachAs*方法本身兼容非连续矩阵的遍历,会自动处理行步长跳位逻辑
修复方案
方案1:使用原子操作保证累加线程安全
将累加逻辑替换为Interlocked.Increment,原子操作不会出现多线程竞争丢失的问题:
var ridgeImageRoi = new Mat(ridgeImage, new Rect(roi.MinPoint.X, roi.MinPoint.Y, roi.MaxPoint.X - roi.MinPoint.X, roi.MaxPoint.Y - roi.MinPoint.Y)); unsafe { int pixelcounter = 0; ridgeImageRoi.ForEachAsByte((byte* pixel, int* position) => { Interlocked.Increment(ref pixelcounter); }); Console.WriteLine(pixelcounter); }
方案2:改用单线程逐行遍历(性能更可控,无线程开销)
如果不需要并行加速,直接逐行读取指针遍历更稳定:
var ridgeImageRoi = new Mat(ridgeImage, new Rect(roi.MinPoint.X, roi.MinPoint.Y, roi.MaxPoint.X - roi.MinPoint.X, roi.MaxPoint.Y - roi.MinPoint.Y)); int pixelcounter = 0; for (int y = 0; y < ridgeImageRoi.Rows; y++) { unsafe { byte* rowPtr = (byte*)ridgeImageRoi.Ptr(y); for (int x = 0; x < ridgeImageRoi.Cols; x++) { byte pixelValue = rowPtr[x]; pixelcounter++; // 其他像素处理逻辑 } } } Console.WriteLine(pixelcounter);
额外注意
如果你要切换为ForEachAsInt16遍历,需要确保当前Mat的类型是CV_16UC1/CV_16SC1,你当前的Mat是CV_8UC1,用ForEachAsByte是匹配的,强行用ForEachAsInt16会出现指针越界、取值错误的问题。
内容的提问来源于stack exchange,提问作者Roel Balink
相关产品推荐
相关产品推荐

