如何确定图像是否是C#或VB.NET中的灰度?

时间:2018-03-25 09:02:26

标签: c# .net vb.net image-processing grayscale

第一个

首先,请注意this问题中给出的答案对所有灰度图像都不起作用,并且还注意到this other问题中接受的答案根本不解释如何确定图像是否为灰度,但无论如何它都不符合我的需要,因为它似乎只涵盖JPEG和TIFF图像,并假设它们将具有EXIF元数据及其中的必需字段。 (我无法理解为什么人们确定我链接的第一个问题是我所链接的第二个问题的“重复”......)

最后,this last接受的答案缺乏一个工作和示范代码示例,但无论如何都无济于事,因为作者使用Bitmap.GetPixel()函数引用了缓慢且弃用的方法,但我们应该使用Bitmap.LockBits()代替了更高的性能优势。

SCENARIO

我有一些GIF,JPG,BMP和PNG图像,我需要确定它们是灰度图像还是不是灰度图像。对于GIF文件,我只关心分析第一帧。

我对图像的数据结构,像素颜色位和那些东西没有多少经验/意识,我只知道非常基础。所以,如果我错过了重要的信息,我应该提供我将要测试的图像的任何信息,那么请问我,但无论如何要考虑到我想为“所有”类型的图像创建一个通用的解决方案好吧,不是全部,但至少是这些格式:BMP,JPG,GIF和PNG。

在提到的那些图像格式中,我的最高优先级是GIF图像,我将意味着如果能够确定GIF图像是否为灰度的方法不能与分析其他类型的图像的方法相同,那么我将接受一个仅涵盖GIF图像像素处理的答案。

问题

我认为我的需求很明确:如何确定图像是否为灰度?

如果一点都不清楚,为了避免这种情况我可以浪费你的时间:

  • 解决方案必须至少适用于GIF图像。 (记住,我只关心GIF中的第一帧),但如果提供的解决方案对BMP,JPG和PNG也有效,那么它当然总是更好。

  • 解决方案必须关注 PixelFormat.Format32bppRgb 灰度图像。

  • 解决方案不得使用Bitmap.GetPixel()功能,而必须使用Bitmap.LockBits()

  • 我不是要求解释,伪代码也没有外部链接到关于图像结构/格式/像素等的文档,我要求一个有效的代码示例(当然,如果作者涵盖了除了代码之外,图像结构/像素技术提供必要的解释。

  • 在C#或VB.NET中,选择并不重要。

研究

这是我到目前为止所做的。我试图理解确定图像是否为灰度的点,我也不确定我的bytesPerPixel变量条件是否合适以及我的RGB值分配是否正确因为我从一开始就说我不是图像处理专家所以我可能错过了重要的事情......

VB.NET

Public Shared Function IsImageGrayScale(ByVal img As Image) As Boolean

    Select Case img.PixelFormat

        Case PixelFormat.Format16bppGrayScale
            Return True

        Case Else
            Dim pixelCount As Integer = (img.Width * img.Height)
            Dim bytesPerPixel As Integer = (Image.GetPixelFormatSize(img.PixelFormat) \ 8)

            If (bytesPerPixel <> 3) AndAlso (bytesPerPixel <> 4) Then
                Throw New NotImplementedException(message:="Only pixel formats that has 3 or 4 bytes-per-pixel are supported.")

            Else
                Dim result As Boolean

                ' Lock the bitmap's bits.
                Dim bmp As Bitmap = DirectCast(img, Bitmap)
                Dim rect As New Rectangle(Point.Empty, bmp.Size)
                Dim data As BitmapData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat)

                ' Get the address of the first line.
                Dim ptr As IntPtr = data.Scan0

                ' Declare an array to hold the bytes of the bitmap. 
                Dim numBytes As Integer = (data.Stride * bmp.Height)
                Dim rgbValues As Byte() = New Byte(numBytes - 1) {}

                ' Copy the RGB values into the array.
                Marshal.Copy(ptr, rgbValues, 0, numBytes)

                ' Unlock the bitmap's bits.
                bmp.UnlockBits(data)

                ' Iterate the pixels.
                For i As Integer = 0 To (rgbValues.Length - bytesPerPixel) Step bytesPerPixel

                    Dim c As Color =
                        Color.FromArgb(red:=rgbValues(i + 2),
                                       green:=rgbValues(i + 1),
                                       blue:=rgbValues(i))

                    ' I don't know what kind of comparison I need to do with the pixels, 
                    ' so I don't know how to proceed here to determine whether the image is or is not grayscale.
                    ' ...

                Next i

                Return result
            End If

    End Select

End Function

C#(代码转换,未经测试)

public static bool IsImageGrayScale(Image img) {

    switch (img.PixelFormat) {

        case PixelFormat.Format16bppGrayScale:
            return true;

        default:
            int pixelCount = (img.Width * img.Height);
            int bytesPerPixel = (Image.GetPixelFormatSize(img.PixelFormat) / 8);

            if ((bytesPerPixel != 3) && (bytesPerPixel != 4)) {
                throw new NotImplementedException(message: "Only pixel formats that has 3 or 4 bytes-per-pixel are supported.");

            } else {
                bool result = false;

                // Lock the bitmap's bits.
                Bitmap bmp = (Bitmap)img;
                Rectangle rect = new Rectangle(Point.Empty, bmp.Size);
                BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);

                // Get the address of the first line.
                IntPtr ptr = data.Scan0;

                // Declare an array to hold the bytes of the bitmap. 
                int numBytes = (data.Stride * bmp.Height);
                byte[] rgbValues = new byte[numBytes];

                // Copy the RGB values into the array.
                Marshal.Copy(ptr, rgbValues, 0, numBytes);

                // Unlock the bitmap's bits.
                bmp.UnlockBits(data);

                // Iterate the pixels.
                for (int i = 0; i <= rgbValues.Length - bytesPerPixel; i += bytesPerPixel) {

                    Color c = Color.FromArgb(red: rgbValues[i + 2], 
                                             green: rgbValues[i + 1], 
                                             blue: rgbValues[i]);

                    // I don't know what kind of comparison I need to do with the pixels, 
                    // so I don't know how to proceed here to determine whether the image is or is not grayscale.
                    // ...

                }

                return result;
            }
    }
}

1 个答案:

答案 0 :(得分:6)

我建议使用Presentation Core&#39; System.Windows.Media.Imaging,它公开了Windows Imaging直接支持的所有解码器的抽象BitmapDecoder class基础:

System.Windows.Media.Imaging.BmpBitmapDecoder
System.Windows.Media.Imaging.GifBitmapDecoder
System.Windows.Media.Imaging.IconBitmapDecoder
System.Windows.Media.Imaging.JpegBitmapDecoder
System.Windows.Media.Imaging.LateBoundBitmapDecoder
System.Windows.Media.Imaging.PngBitmapDecoder
System.Windows.Media.Imaging.TiffBitmapDecoder
System.Windows.Media.Imaging.WmpBitmapDecoder

解码图像文件流时,正确的解码器从抽象类转换为特定类。

解码后的图像帧被转换为BitmapFrame Class,其成员转换为BitmapSource class,它引用了有关图像流的所有已解码信息。

有趣的是,在这种情况下,是BitmapSource.Format属性,它公开System.Windows.Media.PixelFormat Structure及其已识别格式的枚举。

另见PixelFormats Properties

这些格式包括:

PixelFormats.Gray32Float
PixelFormats.Gray16
PixelFormats.Gray8
PixelFormats.Gray4
PixelFormats.Gray2

这些标志可以照常测试。

<小时/> 此类可用于收集有关位图格式的信息 我添加了一个属性 IsGrayscale ,它使用之前列出的PixelFormats返回Image PixelFormat测试结果。

图片格式由 BitmapInfo.Format BitmapInfo.Metadata.Format 属性引用(不同来源,供比较。) 其他属性非常明显。

实现此类的项目必须引用:

PresentationCore
System.Xaml
WindowsBase


属性:

ImageSize            (Size)          => Size of the Image
Dpi                  (Size)          => DpiX and DpiY of the Image
PixelSize            (Size)          => Size in Pixels ot the Image
Masks                (List)          => List of Byte Masks
BitsPerPixel         (int)           => Bits per Pixel
PixelFormat          (PixelFormat)   => Pixel format as reported by the Decoder
ImageType            (string)        => Textual expression of the image format (GIF, JPG etc.)
HasPalette           (bool)          => The Image has a Palette
Palette              (BitmapPalette) => Palette representation of the Image Colors
HasThumbnail         (bool)          => The Image includes a Thumbnail image
Thumbnail            (BitmapImage)   => The Image Thumbnail, in BitmapImage format
Frames               (int)           => Number of frames. Animated Images are represented by a sequence of frames
FramesContent        (FramesInfo)    => Informations about all frame included in this Image
IsMetadataSuppported (bool)          => The Image has Metadata informations
Metadata             (MetadataInfo)  => Class referencing all the Metadata informations a Image contains
AnimationSupported   (bool)          => This Format supports frame Animations
Animated             (bool)          => The Image is a timed sequence of frames


<强>方法:

public enum DeepScanOptions : int  {
    Default = 0,
    Skip,
    Force
}

public bool IsGrayScale(DeepScanOptions DeepScan)

在给定图像内部调色板的情况下,检查图像PixelFormat是否被视为GrayScale。 DeepScanOptions 枚举器用于确定扫描的执行方式 样本使用部分中的更多详细信息。

public enum GrayScaleInfo : int {
    None = 0,
    Partial, 
    GrayScale,
    Undefined
}

public ImagingBitmapInfo.GrayScaleInfo IsGrayScaleFrames()

报告框架选项板的状态。它可能会回归:

None :图片没有灰度帧 Partial :有些帧是GrayScale
GrayScale :所有相框都有一个GrayScale调色板 Undefined :图片可能没有调色板信息。图像像素格式由PixelFormat属性

报告
public ImagingBitmapInfo.GrayScaleStats GrayScaleSimilarity();

此方法执行统计评估(平均值,(Sum(Min)&lt; =&gt; Sum(Max)),考虑图像的所有内部调色板的颜色,以验证内部颜色表示可以多少同化为灰度模式。
它返回ImagingBitmapInfo.GrayScaleStats,公开这些属性:

int Palettes :评估的调色板数量
float AverageMaxDistance :RGB分量之间的平均距离(最大值) float AverageMinDistance :RGB分量之间的平均距离(最小值) float AverageLogDistance :RGB组件之间的平均逻辑距离
float GrayScalePercent :相似度的百分比
float GrayScaleAveragePercent :逻辑相似度的百分比

List<FrameStat> PerFrameValues :报告每个Palette条目的计算结果的类。它暴露了这些属性:

int ColorEntries :当前调色板中的颜色数量
float DistanceMax :RGB组件之间的距离(最大)
float DistanceMin :RGB分量之间的距离(最小)
float DistanceAverage :RGB分量之间的平均距离

public void FrameSourceAddRange(BitmapFrame[] bitmapFrames)

将所有图像帧信息插入FramesInfo类 它在内部使用,但可以在创建主要类 ImagingBitmapInfo 的实例时手动填充。公开这些属性:

FramesTotalNumber :图片中包含的总帧数 FramesColorNumber :具有调色板的帧数 FramesGrayscaleNumber :GrayScale帧的数量
FramesBlackWhiteNumber :B&amp; W帧数

List<Frames> :所有帧的班级列表。 FramesInfo Class对象公开这些属性:

FrameSize :框架的尺寸
FrameDpi :框架的DpiX和DpiY PixelFormat :框架的PixelFormat IsColorFrame :框架有一个调色板
IsGrayScaleFrame :框架有一个GrayScale调色板 IsBlackWhiteFrame :该框架有一个B&amp; W Palette

public System.Drawing.Bitmap ThumbnailToBitmap()

转换System.Windows.Media.Imaging BitmapImage格式System.Drawing Bitmap格式,可以在WinForms控件/类中使用。 (此时未经过适当测试)。

<小时/> 样本用法:
主要类ImagingBitmapInfo已初始化,并将BitmapFormatInfo()方法传递给文件路径或文件流。

ImagingBitmapInfo BitmapInfo = BitmapFormatInfo(@"[ImagePath]");
//or 
ImagingBitmapInfo BitmapInfo = BitmapFormatInfo([FileStream]);

要验证图片是否具有GrayScale PixelFormat,请调用IsGrayScale(ImagingBitmapInfo.DeepScanOptions)方法,指定必须检索此信息。

<强> ImagingBitmapInfo.DeepScanOptions.Default
该类根据图像像素格式决定是否对图像调色板执行深度扫描(如果存在调色板)。如果像素格式已经报告了GrayScale图像(例如PixelFormats.Gray32FloatPixelFormats.Gray16等),则不执行深度扫描。如果像素格式是索引格式,则执行扫描;如果PixelFormat是彩色格式,则不执行扫描。

  

请注意,某些图片(主要是Gif)可能会报告颜色PixelFormat,   而内部格式(Palette)可能是GrayScale。

<强> ImagingBitmapInfo.DeepScanOptions.Force
无论图像解码器报告PixelFormat是什么,都指示对所有帧的选项板执行深度扫描。
用于发现报告的彩色图像是否具有一个或多个灰度帧。

<强> ImagingBitmapInfo.DeepScanOptions.Skip
鉴于像素格式,指示不执行调色板的深度扫描,即使它正常执行。

System.Windows.Media.PixelFormat pixelFormat = BitmapInfo.PixelFormat;
bool BitmapIsGrayscale = BitmapInfo.IsGrayScale(ImagingBitmapInfo.DeepScanOptions.Force);


如果结果与预期的结果不同,则可以执行完整的图像帧PixelFormat检查,调用:

ImagingBitmapInfo.GrayScaleInfo GrayScaleFrames = BitmapInfo.IsGrayScaleFrames();

此方法执行所有帧的完整检查,并报告任何内部帧是否具有GrayScale PixelFormat。结果可以是GrayScaleInfo枚举器值之一:
NonePartialGrayScaleUndefined 如果结果为GrayScale,则所有内部框架都具有GrayScale PixelFormat Undefined表示图像没有调色板信息。

创建图像调色板的灰度相似度的统计表示&#39;颜色条目,调用 GrayScaleSimilarity() 方法:

ImagingBitmapInfo.GrayScaleStats Stats = BitmapInfo.GrayScaleSimilarity();

float GrayScalePercent = Stats.GrayScalePercent
float RGBAverageDistancePercent = Stats.GrayScaleAveragePercent
float RGBPatternMaxDistance = Stats.AverageMaxDistance


using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

public class ImagingBitmapInfo
{
    FramesInfo framesInfo;

    public ImagingBitmapInfo()
    {
        this.framesInfo = new FramesInfo();
        this.Metadata = new MetadataInfo();
        this.Metadata.ApplicationName = string.Empty;
        this.Metadata.Author = new List<string>() {  };
        this.Metadata.CameraManufacturer = string.Empty;
        this.Metadata.CameraModel = string.Empty;
        this.Metadata.Comment = string.Empty;
        this.Metadata.Copyright = string.Empty;
        this.Metadata.DateTaken = string.Empty;
        this.Metadata.Subject = string.Empty;
        this.Metadata.Title = string.Empty;
    }

    public Size ImageSize { get; set; }
    public Size Dpi { get; set; }
    public Size PixelSize { get; set; }
    public List<PixelFormatChannelMask> Masks { get; set; }
    public int BitsPerPixel { get; set; }
    public PixelFormat PixelFormat { get; set; }
    public string ImageType { get; set; }
    public bool HasPalette { get; set; }
    public BitmapPalette Palette { get; set; }
    public bool HasThumbnail { get; set; }
    public BitmapImage Thumbnail { get; set; }
    public int Frames { get; set; }
    public FramesInfo FramesContent
    { get { return this.framesInfo; } }
    public bool IsMetadataSuppported { get; set; }
    public MetadataInfo Metadata { get; set; }
    public bool AnimationSupported { get; set; }
    public bool Animated { get; set; }

    public enum DeepScanOptions : int
    {
        Default = 0,
        Skip,
        Force
    }

    public enum GrayScaleInfo : int
    {
        None = 0,
        Partial, 
        GrayScale,
        Undefined
    }

    public System.Drawing.Bitmap ThumbnailToBitmap()
    {
        if (this.Thumbnail == null)
            return null;
        using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(
                         this.Thumbnail.DecodePixelWidth, 
                         this.Thumbnail.DecodePixelHeight))
        using (MemoryStream outStream = new MemoryStream())
        {
            BitmapEncoder encoder = new BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(this.Thumbnail));
            encoder.Save(outStream);
            return (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(outStream);
        }
    }

    public void FrameSourceAddRange(BitmapFrame[] bitmapFrames)
    {
        if (bitmapFrames == null) return;

        this.framesInfo.Frames.AddRange(bitmapFrames.Select(bf => new FramesInfo.Frame() 
        { 
            Palette = bf.Palette,
            FrameSize = new Size(bf.PixelWidth, bf.PixelHeight),
            FrameDpi = new Size(bf.DpiX, bf.DpiY),
            PixelFormat = bf.Format,
            IsGrayScaleFrame = CheckIfGrayScale(bf.Format, bf.Palette, DeepScanOptions.Force),
            IsBlackWhiteFrame = (bf.Format == PixelFormats.BlackWhite)
        }));

        this.framesInfo.Frames.Where(f => (!f.IsGrayScaleFrame & !f.IsBlackWhiteFrame))
                              .All(f => f.IsColorFrame = true);
    }

    public GrayScaleInfo IsGrayScaleFrames()
    {
        if (this.framesInfo.Frames.Count == 0)
            return GrayScaleInfo.Undefined;
        if (this.framesInfo.FramesGrayscaleNumber > 0)
            return (this.framesInfo.FramesGrayscaleNumber == this.framesInfo.FramesTotalNumber)
                ? GrayScaleInfo.GrayScale : GrayScaleInfo.Partial;
        return GrayScaleInfo.None;
    }

    public bool IsGrayScale(DeepScanOptions DeepScan)
    {
        return CheckIfGrayScale(this.PixelFormat, this.Palette, DeepScan);
    }

    private bool CheckIfGrayScale(PixelFormat pixelFormat, BitmapPalette palette, DeepScanOptions DeepScan)
    {
        if (pixelFormat == PixelFormats.Gray32Float ||
            pixelFormat == PixelFormats.Gray16 ||
            pixelFormat == PixelFormats.Gray8 ||
            pixelFormat == PixelFormats.Gray4 ||
            pixelFormat == PixelFormats.Gray2)
        {
            if (palette == null || (DeepScan != DeepScanOptions.Force)) { return true; }
        }

        if (pixelFormat == PixelFormats.Indexed8 ||
            pixelFormat == PixelFormats.Indexed4 ||
            pixelFormat == PixelFormats.Indexed2)
        {
            DeepScan = (DeepScan != DeepScanOptions.Skip) ? DeepScanOptions.Force : DeepScan;
        }

        if ((DeepScan != DeepScanOptions.Skip) & palette != null)
        {
            List<Color> IndexedColors = palette.Colors.ToList();
            return IndexedColors.All(rgb => (rgb.R == rgb.G && rgb.G == rgb.B && rgb.B == rgb.R));
        }
        return false;
    }

    public GrayScaleStats GrayScaleSimilarity()
    {
        if (!this.HasPalette) return null;

        GrayScaleStats stats = new GrayScaleStats();
        float AccumulatorMax = 0F;
        float AccumulatorMin = 0F;
        float AccumulatorAvg = 0F;
        float[] Distance = new float[3];

        stats.Palettes = this.Frames;

        foreach (FramesInfo.Frame frame in this.framesInfo.Frames)
        {
            GrayScaleStats.FrameStat framestat = new GrayScaleStats.FrameStat() 
            { ColorEntries = frame.Palette.Colors.Count };

            foreach (Color pEntry in frame.Palette.Colors)
            {
                if (!(pEntry.R == pEntry.G && pEntry.G == pEntry.B && pEntry.B == pEntry.R))
                {
                    Distance[0] = Math.Abs(pEntry.R - pEntry.G);
                    Distance[1] = Math.Abs(pEntry.G - pEntry.B);
                    Distance[2] = Math.Abs(pEntry.B - pEntry.R);
                    AccumulatorMax += (float)(Distance.Max());
                    AccumulatorMin += (float)(Distance.Min());
                    AccumulatorAvg += (float)(Distance.Average());
                }
            }
            framestat.DistanceMax = (float)((AccumulatorMax / 2.56) / framestat.ColorEntries);
            framestat.DistanceMin = (float)((AccumulatorMin / 2.56) / framestat.ColorEntries);
            framestat.DistanceAverage = (float)((AccumulatorAvg / 2.56) / framestat.ColorEntries);
            stats.PerFrameValues.Add(framestat);
            AccumulatorMax = 0F;
            AccumulatorMin = 0F;
            AccumulatorAvg = 0F;
        }
        stats.AverageMaxDistance = stats.PerFrameValues.Max(mx => mx.DistanceMax);
        stats.AverageMinDistance = stats.PerFrameValues.Min(mn => mn.DistanceMin);
        stats.AverageLogDistance = stats.PerFrameValues.Average(avg => avg.DistanceAverage);
        stats.GrayScaleAveragePercent = 100F - stats.AverageLogDistance;
        stats.GrayScalePercent = 100F - ((stats.AverageMaxDistance - stats.AverageMinDistance) / 2);
        return stats;
    }

    public class GrayScaleStats
    {
        public GrayScaleStats()
        {
            this.PerFrameValues = new List<FrameStat>();
        }

        public List<FrameStat> PerFrameValues { get; set; }
        public int Palettes { get; set; }
        public float AverageMaxDistance { get; set; }
        public float AverageMinDistance { get; set; }
        public float AverageLogDistance { get; set; }
        public float GrayScalePercent { get; set; }
        public float GrayScaleAveragePercent { get; set; }

        public class FrameStat
        {
            public int ColorEntries { get; set; }
            public float DistanceMax { get; set; }
            public float DistanceMin { get; set; }
            public float DistanceAverage { get; set; }
        }
    }

    public class FramesInfo
    {
        public FramesInfo()
        {
            this.Frames = new List<Frame>();
        }

        public int FramesTotalNumber
        {
            get { return (this.Frames != null) ? this.Frames.Count() : 0; }
            private set { }
        }

        public int FramesColorNumber
        {
            get { return (this.Frames != null) ? this.Frames 
                              .Where(f => f.IsColorFrame == true)
                              .Count() : 0; }
            private set { }
        }
        public int FramesGrayscaleNumber
        {
            get {return (this.Frames != null) ? this.Frames
                             .Where(f => f.IsGrayScaleFrame == true)
                             .Count() : 0; }
            private set { }
        }

        public int FramesBlackWhiteNumber
        {
            get { return (this.Frames != null) ? this.Frames
                              .Where(f => f.IsBlackWhiteFrame == true)
                              .Count() : 0; }
            private set { }
        }

        public List<Frame> Frames { get; private set; }

        internal class Frame
        {
            public BitmapPalette Palette { get; set; }
            public Size FrameSize { get; set; }
            public Size FrameDpi { get; set; }
            public PixelFormat PixelFormat { get; set; }
            public bool IsColorFrame { get; set; }
            public bool IsGrayScaleFrame { get; set; }
            public bool IsBlackWhiteFrame { get; set; }
        }
    }

    public class MetadataInfo
    {
        public string ApplicationName { get; set; }
        public List<string> Author { get; set; }
        public string Copyright { get; set; }
        public string CameraManufacturer { get; set; }
        public string CameraModel { get; set; }
        public string Comment { get; set; }
        public string Format { get; set; }
        public string Subject { get; set; }
        public string Title { get; set; }
        public string DateTaken { get; set; }
        public int Rating { get; set; }
    }
}


public static ImagingBitmapInfo BitmapPixelFormat(string FileName)
{
    using (FileStream stream = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None))
    {
        return BitmapPixelFormat(stream);
    }
}

public static ImagingBitmapInfo BitmapPixelFormat(FileStream stream)
{
    ImagingBitmapInfo imageInfo = new ImagingBitmapInfo();
    var bitmapDecoder = BitmapDecoder.Create(stream, 
                                                BitmapCreateOptions.PreservePixelFormat, 
                                                BitmapCacheOption.Default);

    BitmapSource bitmapSource = bitmapDecoder.Frames[0];
    ImageMetadata imageMetadata = bitmapSource.Metadata;
    BitmapMetadata bitmapMetadata = (BitmapMetadata)bitmapSource.Metadata;

    try
    {
        imageInfo.Frames = bitmapDecoder.Frames.Count();
        if (imageInfo.Frames > 0)
            imageInfo.FrameSourceAddRange(bitmapDecoder.Frames.ToArray());

        imageInfo.ImageType = bitmapMetadata.Format.ToUpperInvariant();
        imageInfo.PixelFormat = bitmapSource.Format;
        imageInfo.HasPalette = ((bitmapSource.Palette != null) && (bitmapSource.Palette.Colors.Count > 0)) ? true : false;
        imageInfo.Palette = bitmapSource.Palette;
        imageInfo.ImageSize = new Size((float)bitmapSource.Height, (float)bitmapSource.Width);
        imageInfo.Dpi = new Size((float)bitmapSource.DpiX, (float)bitmapSource.DpiY);
        imageInfo.PixelSize = new Size(bitmapSource.PixelHeight, bitmapSource.PixelWidth);
        imageInfo.Masks = bitmapSource.Format.Masks.ToList();
        imageInfo.BitsPerPixel = bitmapSource.Format.BitsPerPixel;
        imageInfo.AnimationSupported = bitmapDecoder.CodecInfo.SupportsAnimation;
        imageInfo.Animated = (imageInfo.AnimationSupported && (imageInfo.Frames > 1)) ? true : false;
        imageInfo.HasThumbnail = bitmapDecoder.Thumbnail != null;
        if (imageInfo.HasThumbnail)
            imageInfo.Thumbnail = (BitmapImage)bitmapDecoder.Thumbnail.CloneCurrentValue();


        imageInfo.Metadata.Format = bitmapMetadata.Format;
        //If not supported, Catch and set imageInfo.SetMetadataNonSupported()
        imageInfo.Metadata.ApplicationName = bitmapMetadata.ApplicationName;
        imageInfo.Metadata.Author = (bitmapMetadata.Author != null) 
                                  ? bitmapMetadata.Author.ToList<string>() 
                                  : null;
        imageInfo.Metadata.CameraModel = bitmapMetadata.CameraModel;
        imageInfo.Metadata.CameraManufacturer = bitmapMetadata.CameraManufacturer;
        imageInfo.Metadata.CameraModel = bitmapMetadata.Comment;
        imageInfo.Metadata.Copyright = bitmapMetadata.Copyright;
        imageInfo.Metadata.Subject = bitmapMetadata.Subject;
        imageInfo.Metadata.Title = bitmapMetadata.Title;
        imageInfo.Metadata.Rating = bitmapMetadata.Rating;
        imageInfo.Metadata.Format = bitmapMetadata.Format;
        imageInfo.Metadata.DateTaken = bitmapMetadata.DateTaken;

    }
    catch (System.NotSupportedException)
    { imageInfo.IsMetadataSuppported = false; }

    catch (System.Exception ex) { /* Log ex */ throw ex; }

    return imageInfo;
}

<强>更新

这或多或少是相同的设置,但面向 WinForms
这意味着只使用了System.Drawing组件。

System.Drawing.Imaging选项较少(GDI +中也存在一个令人讨厌的错误,与Bitmap Encoders相关,从未纠正过)并且某些信息无法直接获取。
相关部分无论如何都在那里。

尽可能正确地检测灰度图像。

  

要注意的是,如果图像具有索引调色板(例如Gif格式),则报告的ImageFlags标记ColorSpaceGRAY永远不会   正确。也不是PixelFormat.Format16bppGrayScale。唯一的   可能的方式(我发现)验证图像是否是灰度   在这种情况下,一个是解析调色板。尽管如此,只需要几个Ticks即可完成,令人讨厌   它可以正常使用其他格式。

与之前列出的程序相同。
可以这样使用:

ImagingBitmapInfo BitmapInfo = BitmapPixelFormat(@"[ImagePath]");
bool BitmapIsGrayscale = BitmapInfo.IsGrayScale();

ImagingBitmapInfo BitmapInfo = BitmapPixelFormat([ImageStream]);
bool BitmapIsGrayscale = BitmapInfo.IsGrayScale();


Code moved to PasteBin因为邮政遗体缺乏空间。