using System; using System.Collections.Generic; using System.Linq; using Telerik.Windows.Controls; using Telerik.Windows.Controls.ChartView; namespace XP.Common.Controls.ImageHistogram { /// /// RadChartView 渲染适配器 | RadChartView rendering adapter /// 负责将直方图频次数据渲染到 Telerik RadCartesianChart 控件 /// internal sealed class ChartRenderer { private readonly RadCartesianChart _chart; private readonly BarSeries _barSeries; private readonly LinearAxis _xAxis; /// /// 16 位数据聚合因子 | 16-bit data aggregation factor /// private const int AggregationFactor = 256; /// /// 构造函数,接收 RadCartesianChart 实例 | Constructor, receives RadCartesianChart instance /// /// 图表控件实例 | Chart control instance /// 柱状图系列 | Bar series /// X 轴 | X axis public ChartRenderer(RadCartesianChart chart, BarSeries barSeries, LinearAxis xAxis) { _chart = chart ?? throw new ArgumentNullException(nameof(chart)); _barSeries = barSeries ?? throw new ArgumentNullException(nameof(barSeries)); _xAxis = xAxis ?? throw new ArgumentNullException(nameof(xAxis)); } /// /// 更新直方图数据 | Update histogram data /// /// 频次数组(256 或 65536 长度)| Frequency array (256 or 65536 length) /// 是否使用对数 Y 轴 | Whether to use logarithmic Y axis public void UpdateData(long[] histogram, bool isLogarithmic) { if (histogram == null || histogram.Length == 0) return; // 确定是否需要聚合(16 位数据)| Determine if aggregation needed (16-bit data) long[] displayData; int xAxisMax; if (histogram.Length == 65536) { // 16 位数据聚合为 256 个柱体 | Aggregate 16-bit data to 256 bars displayData = Aggregate16BitHistogram(histogram); xAxisMax = 65535; } else { // 8 位数据直接显示 | Display 8-bit data directly displayData = histogram; xAxisMax = 255; } // 设置 X 轴范围 | Set X axis range _xAxis.Minimum = 0; _xAxis.Maximum = xAxisMax; // 构建数据点 | Build data points var dataPoints = new List(); if (isLogarithmic) { // 对数模式:频次为 0 的不绘制 | Logarithmic mode: skip zero frequency for (int i = 0; i < displayData.Length; i++) { if (displayData[i] > 0) { double xValue = histogram.Length == 65536 ? i * AggregationFactor + AggregationFactor / 2.0 : i; dataPoints.Add(new HistogramDataPoint { GrayLevel = xValue, Frequency = displayData[i] }); } } } else { // 线性模式:所有灰度级别都绘制 | Linear mode: draw all gray levels for (int i = 0; i < displayData.Length; i++) { double xValue = histogram.Length == 65536 ? i * AggregationFactor + AggregationFactor / 2.0 : i; dataPoints.Add(new HistogramDataPoint { GrayLevel = xValue, Frequency = displayData[i] }); } } // 更新图表数据 | Update chart data _barSeries.ItemsSource = dataPoints; // 设置 Y 轴范围 | Set Y axis range UpdateYAxis(displayData, isLogarithmic); } /// /// 清空图表,恢复初始状态 | Clear chart, restore initial state /// public void Clear() { _barSeries.ItemsSource = null; // X 轴范围重置为 0-255 | Reset X axis range to 0-255 _xAxis.Minimum = 0; _xAxis.Maximum = 255; // Y 轴范围重置为 0-1 | Reset Y axis range to 0-1 SetYAxisRange(0, 1, isLogarithmic: false); } /// /// 获取当前数据点数量 | Get current data point count /// public int DataPointCount { get { if (_barSeries.ItemsSource is ICollection collection) return collection.Count; if (_barSeries.ItemsSource is IEnumerable enumerable) return enumerable.Count(); return 0; } } /// /// 将 65536 长度的频次数组聚合为 256 个柱体 | Aggregate 65536-length array to 256 bars /// private static long[] Aggregate16BitHistogram(long[] histogram) { var aggregated = new long[256]; for (int i = 0; i < 256; i++) { long sum = 0; int startIndex = i * AggregationFactor; for (int j = 0; j < AggregationFactor; j++) { sum += histogram[startIndex + j]; } aggregated[i] = sum; } return aggregated; } /// /// 更新 Y 轴范围 | Update Y axis range /// private void UpdateYAxis(long[] displayData, bool isLogarithmic) { long maxValue = 0; for (int i = 0; i < displayData.Length; i++) { if (displayData[i] > maxValue) maxValue = displayData[i]; } if (maxValue == 0) maxValue = 1; SetYAxisRange(0, maxValue, isLogarithmic); } /// /// 设置 Y 轴范围和刻度类型 | Set Y axis range and scale type /// private void SetYAxisRange(double minimum, double maximum, bool isLogarithmic) { // 获取或创建 Y 轴 | Get or create Y axis var verticalAxis = _chart.VerticalAxis; if (isLogarithmic) { // 对数刻度 | Logarithmic scale if (verticalAxis is LogarithmicAxis logAxis) { logAxis.Minimum = 1; logAxis.Maximum = maximum; logAxis.LogarithmBase = 10; } else { // 需要切换为对数轴 | Need to switch to logarithmic axis var newLogAxis = new LogarithmicAxis { Minimum = 1, Maximum = maximum, LogarithmBase = 10 }; _chart.VerticalAxis = newLogAxis; } } else { // 线性刻度 | Linear scale if (verticalAxis is LinearAxis linearAxis) { linearAxis.Minimum = minimum; linearAxis.Maximum = maximum; } else { // 需要切换为线性轴 | Need to switch to linear axis var newLinearAxis = new LinearAxis { Minimum = minimum, Maximum = maximum }; _chart.VerticalAxis = newLinearAxis; } } } } /// /// 直方图数据点模型 | Histogram data point model /// internal class HistogramDataPoint { /// /// 灰度级别(X 轴值)| Gray level (X axis value) /// public double GrayLevel { get; set; } /// /// 像素频次(Y 轴值)| Pixel frequency (Y axis value) /// public long Frequency { get; set; } } }