---
title: "Get image histogram statistics in C#"
url: https://recursiveai.org/oneimage/cookbook/inspect-image-histogram/
description: "Read image histogram bins, mean, min, max, and population standard deviation in C#. Analyze individual TIFF pages or animation frames with OneImage."
version: "1.11.1"
---

# Get image histogram statistics in C#

**OneImage** is a free, open-source image library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneImage) · [GitHub](https://github.com/recursive-ai-oss/oneimage-csharp) · [Docs](https://recursiveai.org/oneimage/docs/) · [Download example (.zip)](https://recursiveai.org/oneimage/cookbook/inspect-image-histogram/inspect-image-histogram.zip)

A histogram counts pixels in value ranges. Use it with channel statistics to measure an image without changing its pixels.

```shell
dotnet add package RecursiveAI.OneImage
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using OneImage;

// samples.tif is in the example zip.
Image image = Image.Load("samples.tif");
Console.WriteLine($"Bin 0 count: {image.Histogram()[0, 0]}");
Console.WriteLine($"Mean: {image.Statistics().Channels[0].Mean}");
```

```text
Bin 0 count: 2
Mean: 127.5
```

Unzip [the example](https://recursiveai.org/oneimage/cookbook/inspect-image-histogram/inspect-image-histogram.zip), then `dotnet run`.

## The full program

`samples.tif` is a small two-page grayscale TIFF (in the zip). Each page is 2 × 2 pixels: page 0 has rows `[0, 0]` and `[255, 255]`; page 1 has rows `[64, 64]` and `[128, 128]`. The full program reads each page separately and sums its histogram bins.

```csharp
using OneImage;
using System.Globalization;

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
Image image = Image.Load("samples.tif");
for (int i = 0; i < image.FrameCount; i++)
{
    ImageHistogram histogram = image.Frames[i].Histogram();
    ChannelStatistics stats = image.Frames[i].Statistics().Channels[0];
    long total = 0;
    foreach (long count in histogram.Channel(0)) total += count;
    Console.WriteLine($"Frame {i}: {total} samples; bin 0={histogram[0, 0]}; bin 255={histogram[0, 255]}");
    Console.WriteLine($"Min={stats.Min}, Max={stats.Max}, Mean={stats.Mean:F2}, StdDev={stats.StdDev:F2}");
}
```

`dotnet run` prints:

```text
Frame 0: 4 samples; bin 0=2; bin 255=2
Min=0, Max=255, Mean=127.50, StdDev=127.50
Frame 1: 4 samples; bin 0=0; bin 255=0
Min=64, Max=128, Mean=96.00, StdDev=32.00
```

Analysis decodes pixels immediately; corrupt image data throws `ImageFormatException`, and Lab images are refused.

## Variations

**Analyze another frame with fewer bins.** Page 1 has two samples in the 64–127 range and two in the 128–191 range.

```csharp
using OneImage;

Image image = Image.Load("samples.tif");
var histogram = image.Frames[1].Histogram(bins: 4);
for (int bin = 0; bin < 4; bin++)
    Console.WriteLine($"{bin}: {histogram[0, bin]}");
```

```text
0: 0
1: 2
2: 2
3: 0
```

## Related recipes

- [Split a multipage TIFF](https://recursiveai.org/oneimage/cookbook/split-multipage-tiff/)
- [Convert an image to grayscale](https://recursiveai.org/oneimage/cookbook/convert-to-grayscale/)

## The short answer

Use `Image.Histogram()` for bin counts and `Image.Statistics()` for per-channel count, minimum, maximum, mean, and population standard deviation. They read pixels without modifying the image. The default histogram has 256 bins per channel.

Both methods on `Image` analyze frame 0 only. For an animated image or multipage TIFF, call the methods on `image.Frames[i]`, as the full program does. Ignoring this distinction can give a correct result for the wrong page.

## What does an image histogram tell you?

It tells you how often pixel values occur, not where they occur. Two images can have identical histograms with completely different arrangements of pixels. A histogram can help you choose a threshold or notice concentrations of dark and light samples. The [University of Edinburgh’s intensity histogram explanation](https://homepages.inf.ed.ac.uk/rbf/HIPR2/histgram.htm) illustrates threshold selection and why illumination gradients can make a single threshold unsuitable.

OneImage returns counts rather than a chart image. In the sample’s first page, bin 0 contains two pixels and bin 255 contains two. Summing all bins yields four, the page’s pixel count. There is only one stored channel because this fixture is grayscale. On an RGB image, channels are red, green and blue; alpha, when present, is last. CMYK channels follow their stored C, M, Y, K order.

The analysis uses stored samples. It does not convert profiles, compute perceptual brightness, or undo premultiplication. An RGB red-channel histogram is not a luminance histogram. If you need analysis in a particular color space, make that interpretation explicit before measuring.

## How to get the histogram of an image?

Load the image and call `Histogram()`. Index the result with `[channel, bin]` to read a count, or use `Channel(channel)` to walk the channel’s bins. The full program uses that span to calculate the total without assuming a particular distribution.

For 8-bit samples, the bin index is `floor(value × bins / 256)`. With four bins, values 0–63 fall in bin 0, 64–127 in bin 1, 128–191 in bin 2, and 192–255 in bin 3. The variation demonstrates this mapping on the second TIFF page. The allowed bin count is 1 through 65,536.

Analysis computes the entire selected frame immediately, unlike a lazy edit pipeline. Do not use it as a header-only file probe. If you need only dimensions, identify the image instead of requesting its pixels. For animations, frame pixels are fully composited; TIFF pages can each have their own dimensions. Compare totals against the selected frame, not an assumed shared size.

## How are image histogram statistics calculated?

`Statistics()` reports summaries in the stored channel’s units. Eight-bit channels use 0–255, 16-bit channels use 0–65,535, and floating-point channels use 0–1 as their full scale. The `FullScale` property identifies that scale. Do not compare raw means across these representations without accounting for units.

The example’s first page has mean 127.5 and population standard deviation 127.5. Every sample is equally far from the mean. Its second page has mean 96 and population standard deviation 32. These are population values, not the sample estimate that divides squared deviations by one less than the count.

By default, transparent pixels remain part of the measurement. Both analysis APIs offer `skipTransparent: true` to ignore pixels whose alpha is zero; partially transparent pixels are not discarded by that setting. See the [analysis documentation](https://recursiveai.org/oneimage/docs/guide/#operations) for the stored-value semantics. Measuring a histogram does not equalize it: histogram equalization is a separate operation that changes pixels.
