صورة Greyscale من بيانات YUV420P
-
23-09-2019 - |
سؤال
من ما قرأته على الإنترنت ، فإن قيمة Y هي قيمة النصوع ويمكن استخدامها لإنشاء صورة مقياس رمادي. الرابط التالي: http://www.bobpowell.net/grayscale.htm, ، لديه بعض التعليمات البرمجية C# على العمل على نصوص صورة نقطية:
{
Bitmap bm = new Bitmap(source.Width,source.Height);
for(int y=0;y<bm.Height;y++) public Bitmap ConvertToGrayscale(Bitmap source)
{
for(int x=0;x<bm.Width;x++)
{
Color c=source.GetPixel(x,y);
int luma = (int)(c.R*0.3 + c.G*0.59+ c.B*0.11);
bm.SetPixel(x,y,Color.FromArgb(luma,luma,luma));
}
}
return bm;
}
لدي طريقة تُرجع قيم YUV ولدي بيانات Y في صفيف البايت. لديّ قطعة التعليمات البرمجية الحالية وهي تفشل في Marshal.copy - حاولت قراءة أو كتابة الذاكرة المحمية.
public Bitmap ConvertToGrayscale2(byte[] yuvData, int width, int height)
{
Bitmap bmp;
IntPtr blue = IntPtr.Zero;
int inputOffSet = 0;
long[] pixels = new long[width * height];
try
{
for (int y = 0; y < height; y++)
{
int outputOffSet = y * width;
for (int x = 0; x < width; x++)
{
int grey = yuvData[inputOffSet + x] & 0xff;
unchecked
{
pixels[outputOffSet + x] = UINT_Constant | (grey * INT_Constant);
}
}
inputOffSet += width;
}
blue = Marshal.AllocCoTaskMem(pixels.Length);
Marshal.Copy(pixels, 0, blue, pixels.Length); // fails here : Attempted to read or write protected memory
bmp = new Bitmap(width, height, width, PixelFormat.Format24bppRgb, blue);
}
catch (Exception)
{
throw;
}
finally
{
if (blue != IntPtr.Zero)
{
Marshal.FreeHGlobal(blue);
blue = IntPtr.Zero;
}
}
return bmp;
}
سيكون موضع تقدير أي مساعدة؟
المحلول 3
أحصل على صورة سوداء مع بضع بكسل في الزاوية العلوية اليسرى إذا استخدمت هذا الرمز وهذا مستقر عند التشغيل:
public static Bitmap ToGrayscale(byte[] yData, int width, int height)
{
Bitmap bm = new Bitmap(width, height, PixelFormat.Format32bppRgb);
Rectangle dimension = new Rectangle(0, 0, bm.Width, bm.Height);
BitmapData picData = bm.LockBits(dimension, ImageLockMode.ReadWrite, bm.PixelFormat);
IntPtr pixelStateAddress = picData.Scan0;
int stride = 4 * (int)Math.Ceiling(3 * width / 4.0);
byte[] pixels = new byte[stride * height];
try
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
byte grey = yData[y * width + x];
pixels[y * stride + 3 * x] = grey;
pixels[y * stride + 3 * x + 1] = grey;
pixels[y * stride + 3 * x + 2] = grey;
}
}
Marshal.Copy(pixels, 0, pixelStateAddress, pixels.Length);
bm.UnlockBits(picData);
}
catch (Exception)
{
throw;
}
return bm;
}
نصائح أخرى
أعتقد أنك قمت بتخصيص وحدات البكسل بايت, ، لكنهم ينسخون البكسل طويل, ، وهو 8 أضعاف الذاكرة (الطول هو 64 بت أو 8 بايت في الحجم).
بامكانك ان تحاول:
blue = Marshal.AllocCoTaskMem(Marshal.SizeOf(pixels[0]) * pixels.Length);
قد تحتاج أيضًا إلى استخدام int [] للبكسلات و pixelformat.format32bpprgb في مُنشئ نقطية (لأن كلاهما 32 بت). يمنحك استخدام Long [] 64 بت لكل بكسل وهو ما يتوقعه تنسيق بكسل 24 بت.
قد ينتهي بك الأمر بظلال من اللون الأزرق بدلاً من الرمادي - يعتمد على ما هي قيمك لـ UINT_CONSTANT و Int_constant.
ليست هناك حاجة للقيام "& 0xff" ، لأن Yuvdata [] يحتوي بالفعل على بايت.
إليك مقاربات أخرى يمكنك تجربتها.
public Bitmap ConvertToGrayScale(byte[] yData, int width, int height)
{
// 3 * width bytes per scanline, rounded up to a multiple of 4 bytes
int stride = 4 * (int)Math.Ceiling(3 * width / 4.0);
byte[] pixels = new byte[stride * height];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
byte grey = yData[y * width + x];
pixels[y * stride + 3 * x] = grey;
pixels[y * stride + 3 * x + 1] = grey;
pixels[y * stride + 3 * x + 2] = grey;
}
}
IntPtr pixelsPtr = Marshal.AllocCoTaskMem(pixels.Length);
try
{
Marshal.Copy(pixels, 0, pixelsPtr, pixels.Length);
Bitmap bitmap = new Bitmap(
width,
height,
stride,
PixelFormat.Format24bppRgb,
pixelsPtr);
return bitmap;
}
finally
{
Marshal.FreeHGlobal(pixelsPtr);
}
}
public Bitmap ConvertToGrayScale(byte[] yData, int width, int height)
{
// 3 * width bytes per scanline, rounded up to a multiple of 4 bytes
int stride = 4 * (int)Math.Ceiling(3 * width / 4.0);
IntPtr pixelsPtr = Marshal.AllocCoTaskMem(stride * height);
try
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
byte grey = yData[y * width + x];
Marshal.WriteByte(pixelsPtr, y * stride + 3 * x, grey);
Marshal.WriteByte(pixelsPtr, y * stride + 3 * x + 1, grey);
Marshal.WriteByte(pixelsPtr, y * stride + 3 * x + 2, grey);
}
}
Bitmap bitmap = new Bitmap(
width,
height,
stride,
PixelFormat.Format24bppRgb,
pixelsPtr);
return bitmap;
}
finally
{
Marshal.FreeHGlobal(pixelsPtr);
}
}