OpenCvSharp函数:Threshold二值化、AdaptiveThreshold自适应二值化

图像二值化

黑色(0)表示背景

白色(1-255)表示对象

Threshold二值化

//函数原型
double Threshold(InputArray src, 
    OutputArray dst, 
    double thresh, 
    double maxval, 
    ThresholdTypes type)

Threshold图像二值化

函数返回值:返回二值化的thresh,type为Ostu与Triangle时,计算得到,其它时与参数thresh一致

参数

说明

InputArray src

输入图像:8位或32位浮点型多通道(使用OTSU或TRIANGLE时,只能8位单通道)

OutputArray dst

输出图像:与输入图像相同的大小、类型和通道数

double thresh

阈值:type为Otsu或Triangle时,此参数忽略

double maxval

最大值

ThresholdTypes type

二值化类型:Ostu与Triangle可以其它组合使用

参数ThresholdTypes说明

取值

说明

Binary

src(x,y)>thresh时为maxval;否则为0

BinaryInv

src(x,y)>thresh时为0;否则为maxval

Trunc

src(x,y)>thresh时为thresh;否则为src(x,y)

Tozero

src(x,y)>thresh时为0;否则为src(x,y)

TozeroInv

src(x,y)>thresh时为src(x,y);否则为0

Otsu

使用大津法计算thresh,再二值化

Triangle

使用三角法计算thresh,再二值化

各种ThresholdType结果示例

AdaptiveThreshold自适应二值化

//函数原型
void AdaptiveThreshold(InputArray src, 
    OutputArray dst, 
    double maxValue, 
    AdaptiveThresholdTypes adaptiveMethod, 
    ThresholdTypes thresholdType, 
    int blockSize, 
    double c)

AdaptiveThreshold自适应阈值

参数

说明

InputArray src

输入图像:8位单通道

OutputArray dst

输出图像:与输入图像相同的大小、类型和通道数

double maxValue

最大值:二值化后的最大值

AdaptiveThresholdTypes adaptiveMethod

适应方式

ThresholdTypes thresholdType

阈值类型:THRESH_BINARY 或 THRESH_BINARY_INV

int blockSize

块大小:大于等于3的奇数(经验值25?)

double c

C常量:用于平均值或加权平均值减去值,正负0均可(经验值10?)

源码示例

public void Run()
{
    using var src = Cv2.ImRead(ImagePath.LenaColor, ImreadModes.Grayscale);
    if (src.Empty()) throw new Exception("图像读取有误");

    using var dst = new Mat();
    double thresh = 127;
    double maxVal = 255;
    Cv2.Threshold(src, dst, thresh, maxVal, ThresholdTypes.Binary);
    Cv2.ImShow($"Threshold-Binary :{thresh}", dst);

    //计算图像的均值
    thresh = Cv2.Mean(src).ToDouble();
    Cv2.Threshold(src, dst, thresh, maxVal, ThresholdTypes.Binary);
    Cv2.ImShow($"Threshold-Binary:{thresh}", dst);

    //三角法:对直方图有一个峰的处理结果较优;第三个参数,不影响结果
    thresh = Cv2.Threshold(src, dst, 0, maxVal, ThresholdTypes.Triangle | ThresholdTypes.Binary);
    Cv2.ImShow($"Threshold-Triangle|Binary: {thresh}", dst);

    //大津法:对直方图有两个峰的处理结果较优;第三个参数,不影响结果
    thresh = Cv2.Threshold(src, dst, 0, maxVal, ThresholdTypes.Otsu | ThresholdTypes.Binary);
    Cv2.ImShow($"Threshold-Ostu|Binary: {thresh}", dst);

    Cv2.Threshold(src, dst, thresh, maxVal, ThresholdTypes.BinaryInv);
    Cv2.ImShow($"Threshold BinaryInv: {thresh}", dst);

    Cv2.Threshold(src, dst, thresh, maxVal, ThresholdTypes.Trunc);
    Cv2.ImShow($"Threshold Trunc: {thresh}", dst);

    Cv2.Threshold(src, dst, thresh, maxVal, ThresholdTypes.Tozero);
    Cv2.ImShow($"Threshold Tozero: {thresh}", dst);

    Cv2.Threshold(src, dst, thresh, maxVal, ThresholdTypes.TozeroInv);
    Cv2.ImShow($"Threshold TozeroInv: {thresh}", dst);

    var wName = "AdaptiveThreshold Demo";
    Cv2.NamedWindow(wName, WindowFlags.AutoSize);

    var tbBlockSize = "blockSize";
    var tbC = "C-255";
    var tbMaxValue = "maxValue";

    int blockSize = 25;
    int adaptiveC = 10 + 255;
    int maxvalue = 255;
    Cv2.CreateTrackbar(tbBlockSize, wName, ref blockSize, 255, tbOnChanged);
    Cv2.CreateTrackbar(tbC, wName, ref adaptiveC, 255 * 2, tbOnChanged);
    Cv2.CreateTrackbar(tbMaxValue, wName, ref maxvalue, 255, tbOnChanged);

    while (true)
    {
        if (Cv2.WaitKey(1) == (int)Keys.Escape) break;
        if (tbChanged)
        {
            if (blockSize % 2 == 0)//必须为正奇数
            {
                Cv2.SetTrackbarPos(tbBlockSize, wName, blockSize + 1);
                continue;
            }
            if (blockSize == 1) continue;//不能为1
            //GaussianC,
            Cv2.AdaptiveThreshold(src, dst, maxvalue, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, blockSize, adaptiveC - 255);
            dst.PutText("GaussianC", new Point(30, 50), HersheyFonts.HersheySimplex, 0.8, Scalar.Black);
            Cv2.Line(dst, new Point(dst.Width - 1, 0), new Point(dst.Width - 1, dst.Height), Scalar.Black);

            //MeanC
            using var dst1 = new Mat();
            Cv2.AdaptiveThreshold(src, dst1, maxvalue, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, blockSize, adaptiveC - 255);
            dst1.PutText("MeanC", new Point(30, 50), HersheyFonts.HersheySimplex, 0.8, Scalar.Black);
            Cv2.HConcat(new[] { dst, dst1 }, dst);
            
            Cv2.ImShow(wName, dst);
            tbChanged = false;
        }
    }
    DrawThresholdTypesDemo();
    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}
private bool tbChanged = false;
private void tbOnChanged(int pos,IntPtr userData)
{
    tbChanged = true;
}


//二值化示例窗口名
private string winName = "ThresholdTypes Demo";
//当前阈值
private int thresh = 200;
//最大值
private int maxVal = 255;

/// <summary>
/// 生成各种二值化图例
/// </summary>
private void DrawThresholdTypesDemo()
{
    
    using (var srcMat = new Mat(1, 255, MatType.CV_8U, new Scalar(0)))
    {
        //初始待二值化图像
        for (int i = 0; i < 50; i++)
        {
            srcMat.At<byte>(0, i) = (byte)(i * 2 + 150);
        }
        for (int i = 50; i < 170; i++)
        {
            srcMat.At<byte>(0, i) = (byte)(350 - i * 2);
        }
        for (int i = 170; i < 256; i++)
        {
            srcMat.At<byte>(0, i) = (byte)(i * 2.5 - 412);
        }
        Cv2.NamedWindow(winName, WindowFlags.AutoSize);
        Cv2.CreateTrackbar("thresh", winName, ref thresh, 255, OnChanged);
        Cv2.CreateTrackbar("maxVal", winName, ref maxVal, 255, OnChanged);

        while (true)
        {
            if (Cv2.WaitKey(50) == (int)Keys.Escape) break;
            if(posChanged) DrawDemo(srcMat);
        }
        Cv2.DestroyAllWindows();                
    }
}
/// <summary>
/// 示例各种二值化结果
/// </summary>
/// <param name="srcMat"></param>
private void DrawDemo(Mat srcMat)
{
    //不重新获取的话,滚动一会后会失效?
    thresh = Cv2.GetTrackbarPos("thresh", winName);
    maxVal = Cv2.GetTrackbarPos("maxVal", winName);
    using var thresholdMat = new Mat();

    int graphIndex = 0;//行高偏移系数

    var resultImg = new Mat(900, 1530, MatType.CV_8UC3, new Scalar(255, 255, 255));
    //待二值化数据
    DrawLine(resultImg, srcMat, graphIndex, thresh, maxVal, $"Origin,thresh={thresh}");

    graphIndex++;
    Cv2.Threshold(srcMat, thresholdMat, thresh, maxVal, ThresholdTypes.Binary);
    DrawLine(resultImg, thresholdMat, graphIndex, thresh, maxVal, $"Binary,thresh={thresh}");

    graphIndex++;
    Cv2.Threshold(srcMat, thresholdMat, thresh, maxVal, ThresholdTypes.BinaryInv);
    DrawLine(resultImg, thresholdMat, graphIndex, thresh, maxVal, $"BinaryInv,thresh={thresh}");

    graphIndex++;
    Cv2.Threshold(srcMat, thresholdMat, thresh, maxVal, ThresholdTypes.Trunc);
    DrawLine(resultImg, thresholdMat, graphIndex, thresh, maxVal, $"Trunc,thresh={thresh}");

    graphIndex++;
    Cv2.Threshold(srcMat, thresholdMat, thresh, maxVal, ThresholdTypes.TozeroInv);
    DrawLine(resultImg, thresholdMat, graphIndex, thresh, maxVal, $"TozeroInv,thresh={thresh}");

    graphIndex++;
    Cv2.Threshold(srcMat, thresholdMat, thresh, maxVal, ThresholdTypes.Tozero);
    DrawLine(resultImg, thresholdMat, graphIndex, thresh, maxVal, $"Tozero,thresh={thresh}");

    graphIndex++;
    var calcThresh = Cv2.Threshold(srcMat, thresholdMat, thresh, maxVal, ThresholdTypes.Otsu | ThresholdTypes.Binary);
    DrawLine(resultImg, thresholdMat, graphIndex, calcThresh, maxVal, $"Otsu,Binary,thresh={calcThresh}");

    graphIndex++;
    calcThresh = Cv2.Threshold(srcMat, thresholdMat, thresh, maxVal, ThresholdTypes.Triangle | ThresholdTypes.BinaryInv);
    DrawLine(resultImg, thresholdMat, graphIndex, calcThresh, maxVal, $"Triangle,BinaryInv,thresh={calcThresh}");

    Cv2.ImShow(winName, resultImg);
    posChanged = false;
}

/// <summary>
/// 绘制最大值、阈值及二值化结果
/// </summary>
/// <param name="resultImg">绘制结果</param>
/// <param name="thresholdMat">二值化图像</param>
/// <param name="graphIndex">最几个图例,用于控制绘图位置</param>
/// <param name="thresh">阈值</param>
/// <param name="maxVal">最大值</param>
/// <param name="text">提示文字</param>
private void DrawLine(Mat resultImg, Mat thresholdMat, int graphIndex, double thresh, double maxVal, string text)
{
    var graphWidth = resultImg.Width / 2;//分左右两列
    var graphHeight = 220;

    var binW = Math.Round((double)1D * (graphWidth - 100) / thresholdMat.Width, 2);
    var offsetX = (graphWidth - thresholdMat.Width * binW) / 2 + graphWidth * (graphIndex % 2);
    var binH = 0.5;
    var offsetY = graphIndex / 2 * graphHeight + 50;
    var thickness = 2;
    for (int i = 1; i < thresholdMat.Width; i++)
    {
        var pt1 = new Point2d(binW * (i - 1) + offsetX, binH * (255 - thresholdMat.At<byte>(0, i - 1)) + offsetY);
        var pt2 = new Point2d(binW * i + offsetX, binH * (255 - thresholdMat.At<byte>(0, i)) + offsetY);
        //二值线,黑色
        Cv2.Line(resultImg, (Point)pt1, (Point)pt2, Scalar.Black, thickness, LineTypes.AntiAlias);

        //分隔线
        if ((i - 1) % 25 == 0)
        {
            Cv2.Line(resultImg, new Point(binW * i + offsetX, offsetY), new Point(binW * i + offsetX, binH * 255 + offsetY), Scalar.LightGray);
        }
    }
    var x1 = offsetX;
    var x2 = offsetX + thresholdMat.Width * binW;
    //thresh阈值线,绿色
    Cv2.Line(resultImg, new Point(x1, binH * (255 - thresh) + offsetY),
                        new Point(x2, binH * (255 - thresh) + offsetY), Scalar.Green, 1);
    //maxVal最大阈值线,红色
    Cv2.Line(resultImg, new Point(x1, binH * (255 - maxVal) + offsetY),
                        new Point(x2, binH * (255 - maxVal) + offsetY), Scalar.Red, 1);
    //0值,蓝色
    Cv2.Line(resultImg, new Point(x1, binH * (255 - 0) + offsetY),
                        new Point(x2, binH * (255 - 0) + offsetY), Scalar.Blue, 1);

    Cv2.PutText(resultImg, text+ ",Red:maxval,Green:thresh,Blue:0,Black:result", new Point(offsetX, binH * 280 + offsetY), HersheyFonts.HersheySimplex, 0.5, Scalar.Black);
}

//滚动条是否变过
private bool posChanged = false;
private void OnChanged(int pos,IntPtr userData)
{
    posChanged = true;
}

OpenCvSharp函数示例目录

参考

https://edu.csdn.net/learn/37754/590662

https://docs.opencv.org/

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
OpenMV 是一款基于MicroPython的嵌入式视觉开发板,可以用来进行图像处理和计算机视觉任务。它提供了一系列的图像处理函数,其中就包括自适应二值化自适应二值化是一种图像处理技术,用于将彩色或灰度图像转换为二值图像。与传统的全局阈值二值化不同,自适应二值化可以根据图像中不同区域的亮度进行灵活的阈值选择,从而更好地处理光照不均匀或背景复杂的情况。 在 OpenMV 中,可以使用 `image.adaptive_threshold()` 函数进行自适应二值化操作。该函数需要指定阈值类型、块大小和偏移量等参数。例如,下面的代码片段演示了如何在 OpenMV 上进行自适应二值化: ```python import sensor import image import time sensor.reset() sensor.set_pixformat(sensor.GRAYSCALE) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(time=2000) while True: img = sensor.snapshot() img.binary([threshold],invert=True) img.erode(1) img.dilate(1) img.show() ``` 在上述代码中,首先初始化摄像头并设置图像格式和分辨率。然后进入循环,在每次循环中获取一帧图像,并对其进行自适应二值化操作。在这个例子中,我们使用 `binary()` 函数来进行二值化,并使用 `erode()` 和 `dilate()` 函数对结果进行形态学操作,以去除噪声。最后,使用 `show()` 函数将处理后的图像显示出来。 需要注意的是,这只是一个简单的示例,实际应用中可能需要根据具体的需求进行参数调整和图像处理步骤的优化。你可以根据自己的需求和具体情况对代码进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图南科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值