【问题标题】:How do I Draw Logarithmic Axis on Bitmap Image如何在位图图像上绘制对数轴
【发布时间】:2016-09-11 14:52:21
【问题描述】:

我正在创建一个频谱图,其中 y 轴是输入文件的频率响应。 基于最小和最大频率(根据 fs 变化),我将如何:

  1. 以有意义的方式根据对数分布绘制频率的 y 轴,如下面的示例图所示。 log10(f),下图中频率在x轴上,仅用于说明一个点

图 1

上一张图片换成了一张更适合表示对数刻度的图片

  1. 沿 y 轴提供许多带注释的参考点,这些参考点与值直接相关,即 100Hz、1kHz、5kHz(在 1/3 倍频程波段中,如 here 所述)

  2. 定义像素与频率映射比率方法以绘制频率,其中沿 y 轴有 n 个频率箱

最后,虽然我已经能够使用以下代码创建一个基本图形,但对于如何最好地在位图图像中实现对数比例,我有点茫然:

    Bitmap spectrogram = new Bitmap(xAxisImageSize, yAxisImageSize);
    // Mmake the Image BG Colour Black
    using (Graphics graph = Graphics.FromImage(spectrogram))
    {
        Rectangle ImageSize = new Rectangle(0, 0, xAxisImageSize, yAxisImageSize);
        graph.FillRectangle(Brushes.Black, ImageSize);
        Pen whitePen = new Pen(Color.White, 3);
        // x axis
        graph.DrawLine(whitePen, 124, 900, 634, 900);
        // x axis label
        graph.DrawString("Time", new Font("Arial", 12), Brushes.White, new PointF(600, 924));
        // y axis
        graph.DrawLine(whitePen, 124, 900, 124, 388);
        // y axis label
        graph.DrawString("f (Hz)", new Font("Arial", 12), Brushes.White, new PointF(24, 388));
        // y axis top frequency
        graph.DrawString("20k", new Font("Arial", 12), Brushes.White, new PointF(75, 388));
        // y axis top marker
        graph.DrawLine(whitePen, 110, 388, 124, 388);
        // x axis Zero Point
        graph.DrawString("0", new Font("Arial", 12), Brushes.White, new PointF(124, 924));
        // y axis Zero Point
        graph.DrawString("0", new Font("Arial", 12), Brushes.White, new PointF(75, 886));
    }

我目前创建的图像的缩放渲染如下所示。

频谱图中的每个(单色)点都将使用以下 sn-p 绘制:

spectrogram.SetPixel(x, y, Color.FromArgb(255, colour, colour, colour));

我有所有必要的数据来绘制以下轴:

  1. x 时间(线性)
  2. y 频率(对数)
  3. z 强度(对数)

另一个挑战是图像是从左上角而不是右下角渲染的,所以如果你能告诉我一个合理的方法来管理这个,我会非常感激。

这是一个使用 .NET 4.5.2 的 c# 控制台应用程序

更新

通过希望澄清问题,我希望实现的是类似于图表对数比例模式并在位图图形轴而不是图表控件上实现它:

axis.IsLogarithmic = true;

因此取 log10(frequency) (在我的示例中)在 0 Hz 和 21963 Hz 之间有 256 个点/频率区间,然后将其映射到 y 轴上,在 y 轴上使用常见的 1/3 倍频程中心频率符号作为如下图:

请注意,上面的图片取自this post,其中 OP 向我请求类似的信息,但在图表控件上,由于未使用图表对象,我无法使用其答案。

为了澄清我所说的 256 点/频率箱的含义,请参见下文:

Frequency Bin 0: 0
Frequency Bin 1: 86
Frequency Bin 2: 172
Frequency Bin 3: 258
Frequency Bin 4: 344
Frequency Bin 5: 430
Frequency Bin 6: 516
Frequency Bin 7: 602
Frequency Bin 8: 689
Frequency Bin 9: 775
Frequency Bin 10: 861
Frequency Bin 11: 947
Frequency Bin 12: 1033
Frequency Bin 13: 1119
.....
Frequency Bin 242: 20844
Frequency Bin 243: 20930
Frequency Bin 244: 21016
Frequency Bin 245: 21102
Frequency Bin 246: 21188
Frequency Bin 247: 21274
Frequency Bin 248: 21360
Frequency Bin 249: 21447
Frequency Bin 250: 21533
Frequency Bin 251: 21619
Frequency Bin 252: 21705
Frequency Bin 253: 21791
Frequency Bin 254: 21877
Frequency Bin 255: 21963

【问题讨论】:

  • 对于大量绘图,不要使用SetPixel,与LockBits相比,它非常慢,然后针对返回的BitmapData进行绘图。
  • 字体名称是“Arial”,而不是“Ariel”。
  • @ScottChamberlain,我会调查LockBits,谢谢。 @Andrew,大声笑#fontfail 我会更新那个错字!
  • @Majickal 如果您使用具有有意义名称的变量而不是 124、900、634、900 等数字,这会更容易提供帮助。 Dim originOffset As New Point(124, 634).
  • @AndrewMorton 如果您指的是 drawline 方法 (msdn.microsoft.com/en-us/library/…),数字仅表示起始 x,y 坐标和目标 x,y 坐标,它们之间的线由笔定义。颜色被绘制。提供此代码纯粹是作为我已经取得的成就的演示,我用来实现这一目标的当前方法以及我想从哪里继续的起点。

标签: c# graphics fft spectrogram


【解决方案1】:

要在两个值之间创建对数刻度,让 V0V1 取以 10 为底的对数 log(V1)log(V2) 并重新缩放以映射到绘图上所需的坐标,让 X0X1

X = X0 + (X1 - X0)(log(V) - log(V0))/(log(V1) - log(V0))

要以简单值绘制刻度,首先确定跨越的完整十年,从 10^floor(log(V0))10^floor(log(V1)),然后通过

获得最高有效数字
ceil(10^(log(V0) - floor(log(V0)))
floor(10^(log(V1) - floor(log(V1)))

获取这几十年的开始/结束数字。

例如,从 19 到 3410,十进制从 10/100 到 1000/10000,包括第 2 位到第 3 位。

【讨论】:

  • 您好 Yves,我很难理解您在这里的意思,您能否将其分解并为我进一步解释。我认为这是我没有真正得到的第一段。 V,Vn & X,Xn分别代表什么?
  • @Majickal V 代表值,X 代表横坐标。所有你需要知道的都在那里。
  • 是的,在查看 abscissa 的实际含义后,这更有意义,对于像我这样不知道可能正在阅读本文的人来说稍后:(在坐标系中)从点到垂直或 y 轴的距离,平行于水平或 x 轴测量; x 坐标。 -Google 搜索结果
猜你喜欢
  • 1970-01-01
  • 2016-06-24
  • 1970-01-01
  • 2016-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多