首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 繪製灰度直方圖完整實現:從像素統計到 GDI+ 繪圖管線

     編輯:關於C#

灰度直方圖統計像素在各灰度級(0-255)的分佈,**直觀反映影像對比度、曝光、動態範圍**,是影像增強(如直方圖均衡化)的基礎。本文提供完整 C# 實現:LockBits 高速統計 + GDI+ 繪製座標軸與柱狀圖。

數學定義

H(k) = 第 k 灰度級像素數,k ∈ [0, 255] (8-bit 灰度圖)。

直方圖公式

核心代碼結構

public partial class HistogramForm : Form {
    private Bitmap _srcBmp;
    private int[] _counts = new int[256];
    private int _maxCount;

    public HistogramForm(Bitmap bmp) {
        InitializeComponent();
        _srcBmp = bmp;
        ComputeHistogram();
    }

    private void ComputeHistogram() {
        // 1. LockBits 複製像素到陣列
        var rect = new Rectangle(0, 0, _srcBmp.Width, _srcBmp.Height);
        var bmpData = _srcBmp.LockBits(rect, ImageLockMode.ReadOnly, _srcBmp.PixelFormat);
        IntPtr ptr = bmpData.Scan0;
        int bytes = _srcBmp.Width * _srcBmp.Height * 3; // 假設 24bpp
        byte[] pixels = new byte[bytes];
        Marshal.Copy(ptr, pixels, 0, bytes);
        _srcBmp.UnlockBits(bmpData);

        // 2. 統計灰度分佈 (取 R 通道即可,灰度圖 RGB 相同)
        Array.Clear(_counts, 0, 256);
        _maxCount = 0;
        foreach (byte v in pixels) {
            int c = ++_counts[v];
            if (c > _maxCount) _maxCount = c;
        }
    }

    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);
        DrawHistogram(e.Graphics);
    }

    private void DrawHistogram(Graphics g) {
        const int marginX = 50, marginY = 30, width = 256, height = 200;
        int x0 = marginX, y0 = marginY + height;
        Pen pen = Pens.Black;

        // 座標軸
        g.DrawLine(pen, x0, y0, x0 + width, y0); // X 軸
        g.DrawLine(pen, x0, y0, x0, marginY);     // Y 軸

        // X 軸刻度與標籤 (每 50)
        for (int k = 0; k <= 250; k += 50) {
            int x = x0 + k;
            g.DrawLine(pen, x, y0, x, y0 + 2);
            g.DrawString(k.ToString(), Font, Brushes.Black, x - 4, y0 + 4);
        }
        // Y 軸最大值標籤
        g.DrawLine(pen, x0 - 2, marginY, x0, marginY);
        g.DrawString(_maxCount.ToString(), Font, Brushes.Black, x0 - 30, marginY - 4);

        // 柱狀圖 (縮放至 height)
        float scale = (float)height / _maxCount;
        for (int k = 0; k < 256; k++) {
            int h = (int)(_counts[k] * scale);
            g.DrawLine(pen, x0 + k, y0, x0 + k, y0 - h);
        }
        pen.Dispose();
    }
}

關鍵技術點

  • LockBits + Marshal.Copy:將非託管像素記憶體高速複製至託管 byte[],**避免 GetPixel 慢速陷阱**。
  • 灰度取樣:灰度影像三通道數值相同,遍歷 pixels 陣列直接統計即可(步長 1),無需按 3 步長取通道。
  • 動態縮放:scale = drawHeight / maxCount 將最高柱映射至繪圖區高度,其餘按比例縮放。
  • OnPaint 重繪:統計結果緩存於欄位,OnPaint 中純繪圖,**視窗縮放/遮擋自動重繪**無需重算。

效果展示

灰度直方圖

完整專案下載

Grey-ScaleMap.rar (含原始碼與測試影像)

擴展應用

  • 直方圖均衡化:依累積分佈函數 (CDF) 重映射灰度,自動增強對比度。
  • RGB 三通道直方圖:分別統計 R/G/B,彩色影像色調分析。
  • 即時影像監控:攝影機串流中每幀計算直方圖,自動曝光/白平衡判斷。

掌握 LockBits 統計與 GDI+ 繪圖管線,即可構建專業級影像分析工具。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved