首先
首先,请注意,this问题中给出的答案不适用于所有灰度图像,还请注意,this other问题中可接受的答案根本无法解释如何确定图像是否为灰度图像,但无论如何,它不符合我的需求,因为它似乎仅涵盖JPEG和TIFF图像,并假定它们将包含EXIF元数据和其中的必填字段。 (我不明白为什么人们认为我链接的第一个问题也是我链接的第二个问题的“重复” ...)
最后,this last接受的答案缺少一个有效的说明性代码示例,但无论如何都无济于事,因为作者使用Bitmap.GetPixel()
函数引用了缓慢且已弃用的方法,但是我们应该使用Bitmap.LockBits()
函数代替更高的性能优势。
场景
我有一些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;
}
}
}
最佳答案
我建议使用Presentation Core的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
在解码Image文件流时,正确的解码器将从抽象类转换为特定类。
解码的图像帧强制转换为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
视为灰度。 DeepScanOptions
枚举器用于确定如何执行扫描。“样本用法”部分中的更多详细信息。
public enum GrayScaleInfo : int {
None = 0,
Partial,
GrayScale,
Undefined
}
public ImagingBitmapInfo.GrayScaleInfo IsGrayScaleFrames()
报告框架面板的状态。它可能会返回:
None
:图像没有灰度框Partial
:某些框架为灰度GrayScale
:所有框架都有一个灰度调色板Undefined
:图像可能没有调色板信息。图像像素格式由PixelFormat
属性报告public ImagingBitmapInfo.GrayScaleStats GrayScaleSimilarity();
此方法考虑到图像的所有内部调色板的颜色,执行统计评估(平均值,(Sum(Min)<=> Sum(Max)),以验证可以将多少内部彩色表示同化为灰度图案。
它返回一个
ImagingBitmapInfo.GrayScaleStats
,它公开了这些属性:int Palettes
:评估的调色板数量float AverageMaxDistance
:RGB分量之间的平均距离(最大)float AverageMinDistance
:RGB分量之间的平均距离(最小)float AverageLogDistance
:RGB分量之间的平均逻辑距离float GrayScalePercent
:相似百分比float GrayScaleAveragePercent
:逻辑相似度百分比List<FrameStat> PerFrameValues
:报告每个调色板条目的计算结果的类。它公开了这些属性:int ColorEntries
:当前调色板中的颜色数float DistanceMax
:RGB分量之间的距离(最大)float DistanceMin
:RGB分量之间的距离(最小值)float DistanceAverage
:RGB分量之间的平均距离public void FrameSourceAddRange(BitmapFrame[] bitmapFrames)
将所有图像帧信息插入
FramesInfo
类。它在内部使用,但是在创建主类实例
ImagingBitmapInfo
时可以手动填充。公开以下属性:FramesTotalNumber
:图像中包括的总od帧数FramesColorNumber
:具有调色板的帧数FramesGrayscaleNumber
:灰度帧数FramesBlackWhiteNumber
:黑白帧数List<Frames>
:所有帧的类列表。 FramesInfo
类对象具有以下属性:FrameSize
:框架的大小FrameDpi
:框架的DpiX和DpiYPixelFormat
:帧的PixelFormatIsColorFrame
:框架具有调色板IsGrayScaleFrame
:框架具有灰度调色板IsBlackWhiteFrame
:框架具有黑白调色板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]);
要验证Image是否具有GrayScale
PixelFormat
,请调用IsGrayScale(ImagingBitmapInfo.DeepScanOptions)
方法,并指定必须检索此信息。ImagingBitmapInfo.DeepScanOptions.Default
该类根据图像像素格式决定是否对图像调色板进行深度扫描(如果存在调色板)。如果像素格式已经报告了灰度图像(例如
PixelFormats.Gray32Float
,PixelFormats.Gray16
等),则不会执行深度扫描。如果像素格式是索引格式,则执行扫描;否则,将执行扫描。如果PixelFormat是彩色格式,则不执行扫描。请注意,某些图片(大多数为Gif图片)可能会报告颜色
PixelFormat
,而内部格式(调色板)可能是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
枚举器值之一:None
,Partial
,GrayScale
,Undefined
。如果结果为
GrayScale
,则所有内部框架的灰度均为PixelFormat
。Undefined
表示图像没有调色板信息。要创建“调色板”的“颜色”条目的灰度相似度的统计表示,请调用
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 +中还有一个令人讨厌的bug,与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,因为此Post正文缺少空间。
关于c# - 如何确定图像在C#或VB.NET中是否为灰度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49474158/