【发布时间】:2014-02-11 17:29:57
【问题描述】:
我创建了一个只有黑白颜色的位图图像(白色背景,上面写着黑色字符)。我可以通过逐行扫描从整个图像中读取黑色像素(我的角色)和白色像素(背景)的总数。我的问题是如何将每个黑色像素的位置保存到一个数组中,并从这些黑色像素中随机将其中一半变为白色并保存新的位图图像。
【问题讨论】:
-
您的位图是否开启了抗锯齿功能?我可以想象黑色和白色之间的值(由于插值模式)会使您的方法无效。
我创建了一个只有黑白颜色的位图图像(白色背景,上面写着黑色字符)。我可以通过逐行扫描从整个图像中读取黑色像素(我的角色)和白色像素(背景)的总数。我的问题是如何将每个黑色像素的位置保存到一个数组中,并从这些黑色像素中随机将其中一半变为白色并保存新的位图图像。
【问题讨论】:
您可以使用以下代码行:
Bitmap myBitmap = new Bitmap("yourimage.jpg");
List<Point> BlackList = new List<Point>();
List<Point> WhileList = new List<Point>();
// Get the color of a pixel within myBitmap.
Color pixelColor = myBitmap.GetPixel(x, y);
if (pixelColor = Color.Black)
{
//Add it to black pixel collection
BlackList.Add(new Point(x,y));
}
else
{
//Add it to white pixel collection
WhiteList.Add(new Point(x,y));
}
您可以在此处设置一个 for 循环,逐个获取每个像素位置并将它们设置为您的黑白像素集合。而要存储位置,您可以使用泛型集合。
此外,stackoverflow 上的 this question 还将帮助您解决问题。
【讨论】:
伪代码:
通过计算位图的宽度和高度来创建双 for 循环。如果我没记错的话,是image.Width/image.Height,或者image.X/image.Y。
如果像素是黑色的,则将i-th 和j-th 索引作为您的坐标保存到黑色像素坐标的List 中。我建议使用一维字符串数组。
如果像素为白色,则将i-th 和j-th 索引保存为您的坐标,放入白色像素坐标的List。
【讨论】:
以下是满足您需要的代码:
public Image Process(Image image)
{
Random rnd = new Random();
Bitmap b = new Bitmap(image);
BitmapData bData = b.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, b.PixelFormat);
int bitsPerPixel = Image.GetPixelFormatSize(bData.PixelFormat);
/*the size of the image in bytes */
int size = bData.Stride * bData.Height;
/*Allocate buffer for image*/
byte[] data = new byte[size];
/*This overload copies data of /size/ into /data/ from location specified (/Scan0/)*/
System.Runtime.InteropServices.Marshal.Copy(bData.Scan0, data, 0, size);
for (int i = 0; i < size; i += bitsPerPixel / 8)
{
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0)
{
var shouldChange = rnd.Next(0, 100) >= 50;
if (shouldChange)
{
data[i] = 255;
data[i + 1] = 255;
data[i + 2] = 255;
}
}
}
/* This override copies the data back into the location specified */
System.Runtime.InteropServices.Marshal.Copy(data, 0, bData.Scan0, data.Length);
b.UnlockBits(bData);
return b;
}
请注意,此代码使用 LockBits,因此它的执行速度明显快于使用 GetPixel/SetPixel 函数的代码。
【讨论】:
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0) 检查黑色像素,var shouldChange = rnd.Next(0, 100) >= 50; 随机决定是否应更改像素,data[i] = 255;data[i + 1] = 255;data[i + 2] = 255; 将像素更改为白色。