C#+OpenCV基础(十)_灰度变化与直方图

1、灰度图的线性变换

/// <summary>
/// 灰度图的线性变换
/// OpenCVHelper.GRAY_LinearTransform(srcMat, 1.2, 40)
/// </summary>
/// <param name="grayMat">灰度图片</param>
/// <param name="a">乘数</param>
/// <param name="b">常数</param>
/// <returns></returns>
public static Mat GRAY_LinearTransform(Mat grayMat, double a, int b)
{
    Mat dstMat = new Mat();
    grayMat.CopyTo(dstMat);

    for (int w = 0; w < grayMat.Width; w++)
    {
        for (int h = 0; h < grayMat.Height; h++)
        {
            byte color = grayMat.At<byte>(h, w);
            int colorNew = Convert.ToInt32(a * color + b);
            colorNew = colorNew > 255 ? 255 : colorNew;

            dstMat.At<byte>(h, w) = Convert.ToByte(colorNew);
        }
    }

    return dstMat;
}

2、灰度图的分段线性变换

/// <summary>
/// 灰度图的分段线性变换
/// OpenCVHelper.GRAY_DividedLinearTransform(srcMat, 70, 200, 100, 200)
/// </summary>
/// <param name="grayMat">灰度图片</param>
/// <param name="fStart">分段区间起点</param>
/// <param name="fEnd">分段区间终点</param>
/// <param name="fSOut">映射区间起点</param>
/// <param name="fEOut">映射区间终点</param>
/// <returns></returns>
public static Mat GRAY_DividedLinearTransform(Mat grayMat, float fStart, float fEnd, float fSOut, float fEOut)
{
    Mat dstMat = Mat.Zeros(grayMat.Size(), grayMat.Type());

    // 计算直线参数
    // L1
    float fK1 = fSOut / fStart;
    // L2
    float fK2 = (fEOut - fSOut) / (fEnd - fStart);
    float fC2 = fSOut - fK2 * fStart;
    // L3
    float fK3 = (255.0f - fEOut) / (255.0f - fEnd);
    float fC3 = 255.0f - fK3 * 255.0f;

    // 建立查询表
    byte[] loolUpTable = new byte[256];
    for (int m = 0; m < 256; m++)
    {
        if (m < fStart)
        {
            loolUpTable[m] = Convert.ToByte(m * fK1);
        }
        else if (m > fEnd)
        {
            loolUpTable[m] = Convert.ToByte(m * fK3 + fC3);
        }
        else
        {
            loolUpTable[m] = Convert.ToByte(m * fK2 + fC2);
        }
    }

    // 灰度映射
    for (int w = 0; w < grayMat.Width; w++)
    {
        for (int h = 0; h < grayMat.Height; h++)
        {
            int index = grayMat.At<byte>(h, w);
            dstMat.At<byte>(h, w) = loolUpTable[index];
        }
    }

    return dstMat;
}

3、直方图 - 多通道合并

/// <summary>
/// 计算图片的直方图 - 多通道合并
/// OpenCVHelper.CalcHist(srcMat, [0, 1, 2], null,1, [256], [new Rangef(0, 256)])
/// </summary>
/// <param name="mat">图片</param>
/// <param name="channels">需要统计的通道索引;灰度图就是[0],BGR就是[0][1][2]; new int[3] { 0, 1, 2 }</param>
/// <param name="mask">操作掩码;用于统计出统计直方图的数据元素个数</param>
/// <param name="dims">需要收集的数据数量;直方图一般只需要收集灰度级一种,所以一般为1</param>
/// <param name="histSize">存放每个直方图尺寸的数组,一般为256; new int[] { 256 }</param>
/// <param name="ranges">像素值范围常为[0 256]; new Rangef[] { new Rangef(0, 256) }</param>
/// <param name="uniform">指示直方图是否均匀;默认为true</param>
/// <param name="accumulate">累计标识符;默认为false</param>
/// <returns>输出的图片直方图</returns>
public static Mat CalcHist(Mat mat, int[] channels, InputArray? mask, int dims,
    int[] histSize, Rangef[] ranges, bool uniform = true, bool accumulate = false)
{
    Mat[] mats = Cv2.Split(mat);

    Mat hist = new Mat();
    Cv2.CalcHist(mats, channels, mask, hist, dims, histSize, ranges, uniform, accumulate);
    Cv2.Normalize(hist, hist, 0, 256, NormTypes.MinMax);  // 归一化

    // 画直方图
    Cv2.MinMaxLoc(hist, out double minVal, out double maxVal);
    int height = 512;
    int width = 512;

    hist = hist * (maxVal != 0 ? height / maxVal : 0.0);

    Mat histImage = new Mat(512, 512, MatType.CV_8UC3, new Scalar(100, 100, 100));  // 直方图画布
    int binW = (int)((double)width / histSize[0]);

    for (int i = 0; i < histSize[0]; i++)
    {
        histImage.Rectangle(
            new Point(i * binW, histImage.Rows - (int)hist.Get<float>(i)),
            new Point((i + 1) * binW, histImage.Rows),
            new Scalar(255, 255, 255),
            -1);
    }

    return histImage;
}

4、直方图 - BGR三通道拆分

/// <summary>
/// 计算BGR图片的三色直方图 - BGR三通道拆分
/// OpenCVHelper.CalcHist_BGR(srcMat, null)
/// </summary>
/// <param name="mat">图片</param>
/// <param name="mask">操作掩码;用于统计出统计直方图的数据元素个数</param>
/// <param name="uniform">指示直方图是否均匀;默认为true</param>
/// <param name="accumulate">累计标识符;默认为false</param>
/// <returns>输出的图片直方图</returns>
public static Mat CalcHist_BGR(Mat mat, InputArray? mask, bool uniform = true, bool accumulate = false)
{
    Mat[] mats = Cv2.Split(mat);
    Mat[] mats0 = [mats[0]];  // B
    Mat[] mats1 = [mats[1]];  // G
    Mat[] mats2 = [mats[2]];  // R

    Mat[] hists = [new Mat(), new Mat(), new Mat()];

    int histSize = 256;
    Cv2.CalcHist(mats0, [0], mask, hists[0], 1, [histSize], [new Rangef(0, 256)], uniform, accumulate);
    Cv2.CalcHist(mats1, [0], mask, hists[1], 1, [histSize], [new Rangef(0, 256)], uniform, accumulate);
    Cv2.CalcHist(mats2, [0], mask, hists[2], 1, [histSize], [new Rangef(0, 256)], uniform, accumulate);
    Cv2.Normalize(hists[0], hists[0], 0, 256, NormTypes.MinMax);  // 归一化
    Cv2.Normalize(hists[1], hists[1], 0, 256, NormTypes.MinMax);  // 归一化
    Cv2.Normalize(hists[2], hists[2], 0, 256, NormTypes.MinMax);  // 归一化

    // 画直方图
    Cv2.MinMaxLoc(hists[0], out double minVal0, out double maxVal0);
    Cv2.MinMaxLoc(hists[1], out double minVal1, out double maxVal1);
    Cv2.MinMaxLoc(hists[2], out double minVal2, out double maxVal2);

    double minVal = Math.Min(minVal0, Math.Min(minVal1, minVal2));
    double maxVal = Math.Max(maxVal0, Math.Max(maxVal1, maxVal2));

    int height = 512;
    int width = 512;

    hists[0] = hists[0] * (maxVal != 0 ? height / maxVal : 0.0);
    hists[1] = hists[1] * (maxVal != 0 ? height / maxVal : 0.0);
    hists[2] = hists[2] * (maxVal != 0 ? height / maxVal : 0.0);

    Mat histImage = new Mat(512, 512, MatType.CV_8UC3, new Scalar(100, 100, 100));  // 直方图画布
    int binW = (int)((double)width / histSize);

    for (int i = 0; i < histSize; i++)
    {
        histImage.Rectangle(
            new Point(i * binW, histImage.Rows - (int)hists[0].Get<float>(i)),
            new Point((i + 1) * binW, histImage.Rows),
            new Scalar(255, 0, 0),
            -1);
        histImage.Rectangle(
            new Point(i * binW, histImage.Rows - (int)hists[1].Get<float>(i)),
            new Point((i + 1) * binW, histImage.Rows),
            new Scalar(0, 255, 0),
            -1);
        histImage.Rectangle(
            new Point(i * binW, histImage.Rows - (int)hists[2].Get<float>(i)),
            new Point((i + 1) * binW, histImage.Rows),
            new Scalar(0, 0, 255),
            -1);
    }

    return histImage;
}

5、直方图 - 均衡化

/// <summary>
/// 直方图均衡化
/// </summary>
/// <param name="grayMat">灰度图片</param>
/// <returns></returns>
public static Mat EqualizeHist(Mat grayMat)
{
    Mat dst = new Mat();
    Cv2.EqualizeHist(grayMat, dst);
    return dst;
}
posted @ 2024-07-10 17:03  ꧁执笔小白꧂  阅读(66)  评论(0编辑  收藏  举报