Skip to content

Commit

Permalink
发布!
Browse files Browse the repository at this point in the history
  • Loading branch information
GarthTB committed Dec 7, 2024
1 parent 4d86dae commit f78799e
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 96 deletions.
2 changes: 1 addition & 1 deletion LightCurve/Core/Help.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal static void Show()
var help = sb.AppendLine("欢迎使用像素值统计工具!\n")
.AppendLine("本工具会统计一组图片或一段视频中,")
.AppendLine("特定区域像素的被测指标的平均值,")
.AppendLine("然后输出为一个列表,或绘制为一个折线图。")
.AppendLine("然后绘制为一个折线图,或输出为一个列表。")
.AppendLine("详见README.md。\n")
.AppendLine($"版本号:{version}")
.AppendLine("作者:GarthTB\n")
Expand Down
18 changes: 3 additions & 15 deletions LightCurve/Core/ImgAna.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,14 @@ internal void Run()
var values = new double[files.Count];
_ = Parallel.For(0, values.Length, i =>
{
using var image = Cv2.ImRead(files[i].FullName);
using var roi = ImgProc.GetROI(image, x, y, w, h);
using Mat image = Cv2.ImRead(files[i].FullName);
using Mat roi = ImgProc.GetROI(image, x, y, w, h);
values[i] = ImgProc.GetValue(roi, channel);
});

var outName = Tools.File.GenOutName(files);
outName = ValCvt.AppendSuff(outName, channel);
switch (outputType)
{
case 0:
Tools.File.OutputTxt(values, outputDir, outName);
break;
case 1:
Tools.File.OutputPlot(values, outputDir, outName);
break;
default:
Tools.File.OutputTxt(values, outputDir, outName);
Tools.File.OutputPlot(values, outputDir, outName);
break;
}
Tools.File.OutputValues(outputType, values, outputDir, outName);

Tools.MsgB.OkInfo("分析完成", "提示");
}
Expand Down
2 changes: 1 addition & 1 deletion LightCurve/Core/ImgProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal static Mat GetROI(Mat image, uint? x, uint? y, uint? w, uint? h)
return image; // 直接返回全帧
if (x + w > image.Cols || y + h > image.Rows)
throw new ArgumentException("选区超出图像范围");
Rect roi = new((int)x, (int)y, (int)w, (int)h);
Rect roi = new((int)x, (int)y, (int)w, (int)h); // 若无法转换,应该会在上一步筛掉
return new Mat(image, roi);
}

Expand Down
35 changes: 30 additions & 5 deletions LightCurve/Core/Tools/File.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal static string SelectOutputDir(int typeIndex)
FileName = "临时文件名,最后会根据原文件名修改",
Filter = typeIndex switch
{
1 => "png图片文件(*.png)|*.png",
0 => "png图片文件(*.png)|*.png",
_ => "txt文本文件(*.txt)|*.txt",
},
};
Expand Down Expand Up @@ -87,8 +87,26 @@ private static string DistinctPath(string dir, string name, string ext)
return path;
}

/// <summary> 将结果输出到指定路径 </summary>
internal static void OutputValues(int outputType, double[] values, string outputDir, string outName)
{
switch (outputType)
{
case 0:
OutputPlot(values, outputDir, outName);
break;
case 1:
OutputTxt(values, outputDir, outName);
break;
default:
OutputPlot(values, outputDir, outName);
OutputTxt(values, outputDir, outName);
break;
}
}

/// <summary> 将结果列表输出到指定路径 </summary>
internal static void OutputTxt(double[] values, string dir, string name)
private static void OutputTxt(double[] values, string dir, string name)
{
var path = DistinctPath(dir, name, "txt");

Expand All @@ -101,7 +119,7 @@ internal static void OutputTxt(double[] values, string dir, string name)
}

/// <summary> 将结果折线图输出到指定路径 </summary>
internal static void OutputPlot(double[] values, string dir, string name)
private static void OutputPlot(double[] values, string dir, string name)
{
var path = DistinctPath(dir, name, "png");

Expand All @@ -111,10 +129,17 @@ internal static void OutputPlot(double[] values, string dir, string name)
plot.XLabel("Frame Number");
plot.YLabel("Value");
plot.ScaleFactor = 2;
plot.Axes.SetLimits(1, indexes[^1], 0, 1);
if (values.Length > 1)
plot.Axes.SetLimits(1, indexes[^1], 0, 1);
plot.Axes.AntiAlias(true);
var plotWidth = values.Length switch
{
<= 80 => 800,
>= 480 => 4800,
_ => values.Length * 10,
};

_ = plot.SavePng(path, 3240, 2000);
_ = plot.SavePng(path, plotWidth, 2000);
}
}
}
80 changes: 25 additions & 55 deletions LightCurve/Core/ValCvt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ internal static class ValCvt
{
/// <summary> 获取单色图像指定通道的均值 </summary>
internal static double MeanValue1(Mat image, int channel)
=> channel is >= 0 and <= 6 ? image.Mean().Val0 : 0;
=> channel is >= 0 and <= 6 ? Cv2.Mean(image).Val0 : 0;

/// <summary> 获取3通道图像指定通道的均值 </summary>
internal static double MeanValue3(Mat image, int channel)
Expand Down Expand Up @@ -50,48 +50,33 @@ internal static string AppendSuff(string name, int channel)
_ => name,
};

/// <summary> 获取Mat图允许的最大值 </summary>
private static double Normalize(double value, int depth)
=> depth switch
/// <summary> 获取单通道图像归一化后的均值 </summary>
private static double NormalizedMean(Mat image)
=> image.Depth() switch
{
MatType.CV_8U => value / 255.0,
MatType.CV_16U => value / 65535.0,
MatType.CV_32F or MatType.CV_64F => value, // 浮点图已经归一化
MatType.CV_8U => Mean(image) / 255.0,
MatType.CV_16U => Mean(image) / 65535.0,
MatType.CV_32F or MatType.CV_64F => Mean(image), // 浮点图已经归一化
_ => throw new ArgumentException("不支持的位深度!")
};

/// <summary> 单通道图像的均值 </summary>
private static double Mean(Mat image) => Cv2.Mean(image).Val0;

/// <summary> 提取R通道的均值 </summary>
private static double MeanR(Mat image)
{
var r = Cv2.Split(image)[2];
var mean = Cv2.Mean(r).Val0;
return Normalize(mean, image.Depth());
}
private static double MeanR(Mat image) => NormalizedMean(Cv2.Split(image)[2]);

/// <summary> 提取G通道的均值 </summary>
private static double MeanG(Mat image)
{
var g = Cv2.Split(image)[1];
var mean = Cv2.Mean(g).Val0;
return Normalize(mean, image.Depth());
}
private static double MeanG(Mat image) => NormalizedMean(Cv2.Split(image)[1]);

/// <summary> 提取B通道的均值 </summary>
private static double MeanB(Mat image)
{
var b = Cv2.Split(image)[0];
var mean = Cv2.Mean(b).Val0;
return Normalize(mean, image.Depth());
}
private static double MeanB(Mat image) => NormalizedMean(Cv2.Split(image)[0]);

/// <summary> 提取CIEL通道的均值 </summary>
private static double MeanCIEL(Mat image)
{
using Mat labImage = new();
Cv2.CvtColor(image, labImage, ColorConversionCodes.BGR2Lab);
var l = Cv2.Split(labImage)[0];
var mean = Cv2.Mean(l).Val0;
return Normalize(mean, image.Depth());
using Mat labImage = image.CvtColor(ColorConversionCodes.BGR2Lab);
return NormalizedMean(Cv2.Split(labImage)[0]);
}

/// <summary> 提取I通道的均值 </summary>
Expand All @@ -101,51 +86,36 @@ private static double MeanI(Mat image)
/// <summary> 提取L通道的均值 </summary>
private static double MeanL(Mat image)
{
using Mat hlsImage = new();
Cv2.CvtColor(image, hlsImage, ColorConversionCodes.BGR2HLS);
var l = Cv2.Split(hlsImage)[1];
var mean = Cv2.Mean(l).Val0;
return Normalize(mean, image.Depth());
using Mat hlsImage = image.CvtColor(ColorConversionCodes.BGR2HLS);
return NormalizedMean(Cv2.Split(hlsImage)[1]);
}

/// <summary> 提取V通道的均值 </summary>
private static double MeanV(Mat image)
{
using Mat hsvImage = new();
Cv2.CvtColor(image, hsvImage, ColorConversionCodes.BGR2HSV);
var v = Cv2.Split(hsvImage)[2];
var mean = Cv2.Mean(v).Val0;
return Normalize(mean, image.Depth());
using Mat hsvImage = image.CvtColor(ColorConversionCodes.BGR2HSV);
return NormalizedMean(Cv2.Split(hsvImage)[2]);
}

/// <summary> 提取Sl通道的均值 </summary>
private static double MeanSl(Mat image)
{
using Mat hlsImage = new();
Cv2.CvtColor(image, hlsImage, ColorConversionCodes.BGR2HLS);
var s = Cv2.Split(hlsImage)[2];
var mean = Cv2.Mean(s).Val0;
return Normalize(mean, image.Depth());
using Mat hlsImage = image.CvtColor(ColorConversionCodes.BGR2HLS);
return NormalizedMean(Cv2.Split(hlsImage)[2]);
}

/// <summary> 提取Sv通道的均值 </summary>
private static double MeanSv(Mat image)
{
using Mat hsvImage = new();
Cv2.CvtColor(image, hsvImage, ColorConversionCodes.BGR2HSV);
var s = Cv2.Split(hsvImage)[1];
var mean = Cv2.Mean(s).Val0;
return Normalize(mean, image.Depth());
using Mat hsvImage = image.CvtColor(ColorConversionCodes.BGR2HSV);
return NormalizedMean(Cv2.Split(hsvImage)[1]);
}

/// <summary> 提取H通道的均值 </summary>
private static double MeanH(Mat image)
{
using Mat hsvImage = new();
Cv2.CvtColor(image, hsvImage, ColorConversionCodes.BGR2HSV);
var h = Cv2.Split(hsvImage)[0];
var mean = Cv2.Mean(h).Val0;
return Normalize(mean, image.Depth());
using Mat hsvImage = image.CvtColor(ColorConversionCodes.BGR2HSV);
return NormalizedMean(Cv2.Split(hsvImage)[0]);
}
}
}
16 changes: 2 additions & 14 deletions LightCurve/Core/VidAna.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal void Run()
{
try
{
using var vid = new VideoCapture(file.FullName);
using VideoCapture vid = new(file.FullName);
var values = new double[vid.FrameCount];

Mat frame = new(), roi = new();
Expand All @@ -33,19 +33,7 @@ internal void Run()

var outName = Tools.File.GenOutName([file]);
outName = ValCvt.AppendSuff(outName, channel);
switch (outputType)
{
case 0:
Tools.File.OutputTxt(values, outputDir, outName);
break;
case 1:
Tools.File.OutputPlot(values, outputDir, outName);
break;
default:
Tools.File.OutputTxt(values, outputDir, outName);
Tools.File.OutputPlot(values, outputDir, outName);
break;
}
Tools.File.OutputValues(outputType, values, outputDir, outName);
}
catch (Exception e)
{
Expand Down
2 changes: 1 addition & 1 deletion LightCurve/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@
VerticalAlignment="Top"
VerticalContentAlignment="Center"
SelectedIndex="0">
<ComboBoxItem Content="txt列表" />
<ComboBoxItem Content="png折线" />
<ComboBoxItem Content="txt列表" />
<ComboBoxItem Content="列表和折线" />
</ComboBox>
<Label
Expand Down
4 changes: 3 additions & 1 deletion LightCurve/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,13 @@ private void BtRemovePaths_Click(object sender, RoutedEventArgs e)
paths = files.Select(x => x.FullName).ToList();
LBPaths.ItemsSource = paths;
if (files.Count == 0)
{
mode = 0;
BtRemovePaths.IsEnabled =
BtRun.IsEnabled =
CBOrder.IsEnabled =
CBDescending.IsEnabled = false;
}
}

#endregion
Expand Down Expand Up @@ -177,7 +180,6 @@ private void ReOrderFiles(int orderIndex, bool descending)
files = [.. descending
? files.OrderByDescending(judge)
: files.OrderBy(judge)];

paths = files.Select(x => x.FullName).ToList();
LBPaths.ItemsSource = paths;
}
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@
## 功能

- 统计一组图片或一段视频中,特定区域像素的被测指标的平均值。
- 将这个平均值的变化轨迹输出为一个txt列表,或绘制为一个折线图
- 将这个平均值的变化轨迹绘制为一个折线图,或输出为一个txt列表

## 环境要求

- [.NET 9.0运行时](https://dotnet.microsoft.com/zh-cn/download/dotnet/9.0)

## 注意

- 每一组照片或一个视频文件进行一次统计。照片和视频不能混合处理。多个视频可以并行处理。
- 每一组照片或一个视频文件进行一次统计。照片和视频不能混合处理。
- 选择输出位置时的文件名不是最终的文件名。最终的文件根据原文件来命名。
- 此程序不使用GPU。在统计大文件时可能卡顿。
- 折线图的高度固定为2000像素,宽度在800至4800之间浮动。

## 快捷键

- F1:帮助
- F1:查看帮助和软件信息

## Credits

Expand Down

0 comments on commit f78799e

Please # to comment.