Мне нужно пройти через изображение .gif и определить значение RGB для каждого пикселя, x и y координат. Может ли кто-нибудь дать мне обзор того, как я могу это сделать? (методология, в которой используются пространства имен и т.д.)
Как я могу перебирать каждый пиксель в формате .gif?
Ответ 1
Это полный пример с обоими методами, используя LockBits() и GetPixel(). Помимо проблем доверия с LockBits() вещи могут легко получить волосатые.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace BitmapReader
{
class Program
{
static void Main(string[] args)
{
//Try a small pic to be able to compare output,
//a big one to compare performance
System.Drawing.Bitmap b = new
System.Drawing.Bitmap(@"C:\Users\vinko\Pictures\Dibujo2.jpg");
doSomethingWithBitmapSlow(b);
doSomethingWithBitmapFast(b);
}
public static void doSomethingWithBitmapSlow(System.Drawing.Bitmap bmp)
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
Color clr = bmp.GetPixel(x, y);
int red = clr.R;
int green = clr.G;
int blue = clr.B;
Console.WriteLine("Slow: " + red + " "
+ green + " " + blue);
}
}
}
public static void doSomethingWithBitmapFast(System.Drawing.Bitmap bmp)
{
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect,
System.Drawing.Imaging.ImageLockMode.ReadOnly,
bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = bmpData.Stride * bmp.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr,
rgbValues, 0, bytes);
byte red = 0;
byte green = 0;
byte blue = 0;
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
//See the link above for an explanation
//of this calculation
int position = (y * bmpData.Stride) + (x * Image.GetPixelFormatSize(bmpData.PixelFormat)/8);
blue = rgbValues[position];
green = rgbValues[position + 1];
red = rgbValues[position + 2];
Console.WriteLine("Fast: " + red + " "
+ green + " " + blue);
}
}
bmp.UnlockBits(bmpData);
}
}
}
Ответ 2
Вы можете загрузить изображение с помощью new Bitmap(filename)
, а затем повторно использовать Bitmap.GetPixel
. Это очень медленно, но просто. (См. Ответ Vinko для примера.)
Если производительность важна, вы можете использовать Bitmap.LockBits
и небезопасный код. Очевидно, это уменьшает количество мест, в которых вы сможете использовать решение (с точки зрения уровней доверия) и, как правило, более сложно, но это может быть намного быстрее.
Ответ 3
Если ваш gif не анимирован, используйте это:
Image img = Image.FromFile("image.gif");
for (int x = 0; x < img.Width; x++)
{
for (int y = 0; y < img.Height; y++)
{
// Do stuff here
}
}
(Непроверенные)
В противном случае используйте это для циклического прохождения всех кадров:
Image img = Image.FromFile("animation.gif");
FrameDimension frameDimension = new FrameDimension(img.FrameDimensionsList[0]);
int frames = img.GetFrameCount(frameDimension);
for (int f = 0; f < frames; f++)
{
img.SelectActiveFrame(frameDimension, f);
for (int x = 0; x < img.Width; x++)
{
for (int y = 0; y < img.Height; y++)
{
// Do stuff here
}
}
}
(Непроверенные)