遍历图像像素和旋转颜色 [英] Iterate over image pixels and rotate Colors

查看:109
本文介绍了遍历图像像素和旋转颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够遍历一个位图图像与一个保值,增值,但目前的形象来自于内存返回流较差的质量比以前的变化是不顺利的。



 使用(VAR bitMapStream =新的MemoryStream())$ b $私有静态位图CyclePalette(位图原件)
{
b {
original.Save(bitMapStream,格式:ImageFormat.Gif);
变种newBitmap =新位图(bitMapStream);

VAR newPalette = newBitmap.Palette;

为(VAR I = 0; I< newPalette.Entries.Length - 5;我++)
{

VAR oldColor = newPalette.Entries [I] ;
newPalette.Entries [I] = newPalette.Entries第[i + 1];
newPalette.Entries [I + 1] = oldColor;

}
newBitmap.Palette = newPalette;
返回newBitmap;
}
}


解决方案

第一关于GIF文件和原始解决方案字。



这是很简单的,使其运行真正的快,但是当,为了好玩,我就是这样做的,我不得不笑了 - 现在我知道你的质量下降的.. !!



让我解释一下:有在GIF文件的几个选择,但这里最重要的是,无论是抖动。与否



我已经说过,他们只有256色;看起来不错,他们可以在从远处至少,正常的GIF文件使用一个技巧:他们的抖动像素块,以显示颜色的搭配!这工作得很好,但它完全禁止使用彩色旋转调色板..



当然可以关掉的抖动,但其结果不仅看起来很粗糙,像素化;用合适的调色板是可能做到的旋转,但其结果是平庸的最好的。我已经附加代码做,在功能 palRotate



这给我们留下了我原来的建议:忘记GIF去为ARGB颜色旋转!这也可以让你与你已经计算出了全系列的KS工作..但你需要紧代码,使其运行速度快。



下面是一个使用LockBits一个完整的测试平台加载数据,做全彩色自行车和他们在一起。
你需要添加一个图片框,一个按钮定时到表单中。
请注意,你需要保持等于图片框的大小数据的大小。
我已经包含了一个500×500 TESTDATA文件

 使用System.Drawing.Imaging;使用System.Runtime.InteropServices 
;
:使用System.IO;
// ..

//数据数组
INT [,] Ks的;
//骑车
INT偏移koffset = 0;
//颜色
名单℃的名单;颜色>颜色=新的List<颜色>();

公共无效paintKs()
{
如果(KS == NULL)回报;

尺寸S1 = pb_image.ClientSize;
pb_image.Image =新位图(s1.Width,s1.Height);
BMP位图=新位图(pb_image.Image);

的PixelFormat FMT1 = bmp.PixelFormat;
字节BPP1 = 4;

矩形RECT =新的Rectangle(Point.Empty,S1);
的BitmapData bmpData = bmp.LockBits(RECT,ImageLockMode.ReadOnly,FMT1);

INT尺寸1 = bmpData.Stride * bmpData.Height;
字节[]数据=新的字节[尺寸1];
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0,数据,0,尺寸1);

为(INT Y = 0; Y< s1.Height; Y ++)
{
为(INT X = 0; X< s1.Width; X ++)
{
INT指数= Y * bmpData.Stride + X * BPP1;
色彩C =颜色[(Ks的[X,Y] + koffset)%(colors.Count)];
如果(KS [X,Y] == 0)C = Color.Black;
数据[指数+ 0] = C.B;
数据[索引+ 1] = C,G;
数据[索引+ 2] = C.R;
数据[指数+ 3] = 255;
}
}

System.Runtime.InteropServices.Marshal.Copy(数据,0,bmpData.Scan0,data.Length);
bmp.UnlockBits(bmpData);

pb_image.Image = BMP;
}

无效saveKs(字符串数据文件)
{使用
(作家的BinaryWriter =新的BinaryWriter(File.Open(数据文件,FileMode.Create)))
{
为(INT Y = 0; Y< Ks.GetLength(0); Y ++)
的for(int x = 0; X< Ks.GetLength(1); X ++)
writer.Write((Int16的)Ks的[X,Y]);
}
}

无效loadKs(字符串数据文件)
{
INT W = pb_image.ClientSize.Width;
如果(KS == NULL)= Ks的新INT [W,W] Y'LT; Ks.GetLength使用(BinaryReader读卡器=新BinaryReader(File.Open(数据文件,FileMode.Open)))
{
的for(int y = 0

(0); Y ++)
表示(中间体X = 0; X&下; Ks.GetLength(1); X ++)
Ks的[X,Y] = reader.ReadInt16();
}

}

私人无效Test_Click(对象发件人,EventArgs五)
{
loadKs(fractalData021.dat);
的for(int i = 0; I< 256;我++)
{
//一个非常简单的,相当可怕的调色板!
的for(int i = 0; I< 256;我++)
colors.Add(Color.FromArgb(255,我,我,255 - i)段);
的for(int i = 0; I< 100;我++)
colors.Add(Color.FromArgb(255,我+ 100,255 -i,155 - i)段);
的for(int i = 0; I< 100;我++)
colors.Add(Color.FromArgb(255,我+ I + 50,255 - 我 - 我,155 - I / 2)) ;
}
paintKs();
timer1.Intervall = 33; // 30 fps的
timer1.Start();
}

私人无效timer1_Tick(对象发件人,EventArgs五)
{
koffset ++;
如果(koffset> = colors.Count)koffset = 0 ;;
paintKs();
}

下面是测试数据的几个文件;测试文件的大小为500×500像素:



http://www.file-upload.net/download-9796723/fractalData021.dat.html



<一个HREF =htt​​p://www.file-upload.net/download-9796722/fractalData021.jpg.html相对=nofollow> http://www.file-upload.net/download-9796722/fractalData021.jpg html的



http://www.file-upload.net/download-9796721/fractalData021.txt.html



更新:



下面是代码做在非抖动GIF文件一个plaette转动。

 无效palRotate()
{
BMP位=(位图)pb_image.Image;
变种PAL = bmp.Palette;
的for(int i = 0; I< 256;我++)pal.Entries [(I + koffset)256%] =颜色[I]
bmp.Palette = PAL;
pb_image.Image = BMP;
}

有关准备这些调用将提取原始的调色板颜色到颜色列表:

  pb_image.Image =新位图(D:\\fff.gif); 
BMP位=(位图)pb_image.Image;
变种PAL = bmp.Palette;
的for(int i = 0; I< 256;我++)colors.Add(pal.Entries [I]);

有关这个看什么,但完全蹩脚的调色板就必须有某种秩序;但即使如此,像素化图像会显得可怜。



这会以类似的方式从一个定时器另一个旋转代码,推进 koffset 变量。


I am wanting to be able to iterate over a bitmap image and increase the value by one, but currently the image comes back from the memory stream a poorer quality than before and the change is not smooth at all.

    private static Bitmap CyclePalette(Bitmap original)
    {
        using (var bitMapStream = new MemoryStream())
        {
            original.Save(bitMapStream, format: ImageFormat.Gif);
            var newBitmap = new Bitmap(bitMapStream);

            var newPalette = newBitmap.Palette;

            for (var i = 0; i < newPalette.Entries.Length - 5; i++)
            {

                var oldColor = newPalette.Entries[i];
                newPalette.Entries[i] = newPalette.Entries[i + 1];
                newPalette.Entries[i + 1] = oldColor;

            }
            newBitmap.Palette = newPalette;
            return newBitmap; 
        }
    }

解决方案

First a word about GIF files and your original solution.

It is pretty simple to make it run real fast, but when, for fun, I did just that I had to laugh - now I know what you meant by the quality degraded..!!

Let me explain: There are a few options in GIF files, but here the important one is whether it is dithered or not.

I have already mentioned that they have only 256 colors; to look nice, which they can, at least from a distance, the normal GIF files use a trick: They dither blocks of pixels to show a mix of colors! This works pretty well, but it completely prohibits to use the palette for color rotation..

Of course one can switch off dithering but the result not only looks pretty coarse and pixelated; with a suitable palette it is possible to do the rotation but the result is mediocre at best. I have appended code to do that in the function palRotate.

Which leaves us with my original suggestion: Forget GIF and go for for ARGB-color rotation! This also allows you to work with the full range of Ks you have calculated.. But you need tight code to make it run fast.

Here is a complete testbed using LockBits to load data and do full color cycling with them. You need to add a PictureBox, a Button and a Timer to your form. Note that you need to keep the size of the data equal to the size of the PictureBox. I have included a 500x500 testdata file.

using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.IO;
//..

// the data array
int[,] Ks;
// the offset for cycling
int koffset = 0;
// a list of colors
List<Color> colors = new List<Color>();

public void paintKs()
{
    if (Ks == null) return;

    Size s1 = pb_image.ClientSize;
    pb_image.Image = new Bitmap(s1.Width, s1.Height);
    Bitmap bmp = new Bitmap(pb_image.Image);

    PixelFormat fmt1 = bmp.PixelFormat;
    byte bpp1 = 4;

    Rectangle rect = new Rectangle(Point.Empty, s1);
    BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt1);

    int size1 = bmpData.Stride * bmpData.Height;
    byte[] data = new byte[size1];
    System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, size1);

    for (int y = 0; y < s1.Height; y++)
    {
        for (int x = 0; x < s1.Width; x++)
        {
            int index = y * bmpData.Stride + x * bpp1;
            Color c = colors[(Ks[x, y] + koffset) % (colors.Count)];
            if (Ks[x, y] == 0) c = Color.Black;
            data[index + 0] = c.B;
            data[index + 1] = c.G;
            data[index + 2] = c.R;
            data[index + 3] = 255;
        }
    }

    System.Runtime.InteropServices.Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
    bmp.UnlockBits(bmpData);

    pb_image.Image = bmp;
}

void saveKs(string dataFile)
{
   using (BinaryWriter writer = new BinaryWriter(File.Open(dataFile, FileMode.Create)))
   {
        for (int y = 0; y < Ks.GetLength(0); y++)
            for (int x = 0; x < Ks.GetLength(1); x++)
                writer.Write((Int16)Ks[x, y]);
   }
}

void loadKs(string dataFile)
{
   int w = pb_image.ClientSize.Width;
   if (Ks == null) Ks = new int[w, w];

   using (BinaryReader reader = new BinaryReader(File.Open(dataFile, FileMode.Open)))
   {
        for (int y = 0; y < Ks.GetLength(0); y++)
            for (int x = 0; x < Ks.GetLength(1); x++)
                 Ks[x, y] = reader.ReadInt16();
   }

}

private void Test_Click(object sender, EventArgs e)
{
    loadKs("fractalData021.dat");
    for (int i = 0; i < 256; i++)
    {
        // a very simple and rather awful palette!
        for (int i = 0; i < 256; i++)  
             colors.Add(Color.FromArgb(255, i, i, 255 - i));
        for (int i = 0; i < 100; i++) 
             colors.Add(Color.FromArgb(255, i + 100, 255 -i, 155 - i));
        for (int i = 0; i < 100; i++) 
             colors.Add(Color.FromArgb(255, i + i+ 50, 255 - i - i, 155 - i/2));
    }
    paintKs();
    timer1.Intervall = 33;  // 30 fps
    timer1.Start();
}

private void timer1_Tick(object sender, EventArgs e)
{
    koffset++;
    if (koffset >= colors.Count) koffset = 0;;
    paintKs();
}

Here are a few files with test data; the test file has a size of 500x500 pixels:

http://www.file-upload.net/download-9796723/fractalData021.dat.html

http://www.file-upload.net/download-9796722/fractalData021.jpg.html

http://www.file-upload.net/download-9796721/fractalData021.txt.html

Update:

Here is code to do a plaette rotation on a non-dithered GIF file.

void palRotate()
{
    Bitmap bmp = (Bitmap)pb_image.Image;
    var pal = bmp.Palette;
    for (int i = 0; i < 256; i++)  pal.Entries[(i + koffset) % 256] = colors[i];
    bmp.Palette = pal;
    pb_image.Image = bmp;
}

For preparation these calls would extract the original palette colors into the colors list:

pb_image.Image = new Bitmap("d:\\fff.gif");
Bitmap bmp = (Bitmap)pb_image.Image;
var pal = bmp.Palette;
for (int i = 0; i < 256; i++) colors.Add(pal.Entries[i]);

For this to look anything but totally crappy the pallete would have to have some sort of order; but even then the pixelated image will look pathetic..

It would be called in a similar way as the other rotation code from a Timer which advances the koffset variable.

这篇关于遍历图像像素和旋转颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆