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;
}
本文来自博客园,作者:꧁执笔小白꧂,转载请注明原文链接:https://www.cnblogs.com/qq2806933146xiaobai/p/18294519