PDA

View Full Version : تبدیل آرایه ای از بایت ها به عکس



Arcsinos
شنبه 14 تیر 1393, 10:38 صبح
با سلام
دوستان عزیز من یه آرایه از نوع بایت دارم که طولش برابر است با 2*480*640= 614400 . که در واقع این یه عکسه که طول و عرضش 640*480 هست و به ازای هر پیکسل 2 بایت استفاده شده. فرض کنید که این آرایه یه عکس سیاه و سفید هست. یعنی هر دو بایت نشون دهنده ی یک عدد بین 0 تا 255 هست. حالا من میخوام این آرایه رو به یه عکس (Bitmap یا Image) تبدیل کنم. البته با MemoryStream قبلا کار کردم و تو این مورد جواب نمیده چون هیچ اطلاعاتی از عکس توی آرایه ی بایت ها وجود نداره و موقع تبدیل توسط MemoryStream نمیشه تشخصی داد که واقعا سایز عکس و فرمت اون چیه. اگه کمکی از دستتون بر میاد بگید که استفاده کنیم. با تشکر از همه ی دوستان

hafez_ka
شنبه 14 تیر 1393, 11:13 صبح
سلام
خسته نباشید
این لینک ها می تونن بهتون کمک کنن.

http://www.codeproject.com/Articles/15460/C-Image-to-Byte-Array-and-Byte-Array-to-Image-Conv
http://www.morgantechspace.com/2013/11/Convert-Image-to-Byte-Array-and-Byte-Array-to-Image-in-csharp.html
http://stackoverflow.com/questions/9173904/bytearray-to-image-conversion
http://stackoverflow.com/questions/17352061/fastest-way-to-convert-image-to-byte-array
http://stackoverflow.com/questions/14360257/convert-byte-to-image

در مورد این موضوع قبلا خیلی در سایت بحث شده است که سرچ کنید پیدا می کنید.

Arcsinos
شنبه 14 تیر 1393, 11:38 صبح
سلام
خسته نباشید
این لینک ها می تونن بهتون کمک کنن.

http://www.codeproject.com/Articles/15460/C-Image-to-Byte-Array-and-Byte-Array-to-Image-Conv
http://www.morgantechspace.com/2013/11/Convert-Image-to-Byte-Array-and-Byte-Array-to-Image-in-csharp.html
http://stackoverflow.com/questions/9173904/bytearray-to-image-conversion
http://stackoverflow.com/questions/17352061/fastest-way-to-convert-image-to-byte-array
http://stackoverflow.com/questions/14360257/convert-byte-to-image

در مورد این موضوع قبلا خیلی در سایت بحث شده است که سرچ کنید پیدا می کنید.

با تشکر از شما دوست عزیز. تمامی لینک هایی که شما قرار دادید قبلا بررسی شده اند، عرض کردم که این یک تبدیل معمولی نیست، یعنی header عکس در آرایه قرار ندارد بنابراین نمی توان به صورت مستقیم از MemoryStream استفاده کرد. لینک هایی که داده اید تماما از memorystream استفاده کرده اند.

plus
شنبه 14 تیر 1393, 12:23 عصر
کدی که شما لازم دارین چیزی شبیه این هست:

int width = 100;
int height = 100;
int bytesPerPixel = 2;
byte[] bytes = new byte[width * height * bytesPerPixel];
using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format16bppGrayScale)) {
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
Marshal.Copy(bytes, 0, bd.Scan0, bytes.Length);
bitmap.UnlockBits(bd);
}

ولی...تصاویر با فرمت GrayScale 16bpp در NET. پشتیبانی نمیشه و کد فوق خطا میده.شما بایستی از Library های مربوطه برای این کار استفاده کنید.
پ.ن:
مگر اینکه شما بخواین از یک تصویر با فرمتی که پشتیبانی میشه مثلا RGB24bpp استفاده کنید.این در حالت Bitmap ی که میسازین در حقیقت یک تصویر رنگی میشه که شما فقط از طیف های سیاه و سفید (اونم فقط در بازه 0 تا 255 یعنی 8 بیت نه 16 بیست) استفاده میکنید.اینطوری میتونید تصویر رو نمایش بدین و یا اون رو به صورت یک تصویر رنگی ذخیره کنید (نه با فرمت مورد نظر شما).
اگه این حالت برای شما قابل قبول هست، مشکلی که خواهید داشت که که چون فرمت داده های شما با فرمت تصویر یکی نیست نمیتونید مستقیما حافظه رو کپی کنید.
یا مجبورید با استفاده از SetPixel تک تک Pixel ها رو مقداری دهی کنید (از آرایه بخونید و در Bitmap بنویسید، هر دو بایت آرایه میشه یک عدد از 0 تا 255 و یک پیکسل رو مقدار میده) که این روش اصلا پیشنهاد نمیشه به دلیل کندی.
روش دیگه اینکه در حالت unsafe با استفاده pointer ها و به صورت خیلی سریعتر فرمت تصویر رو تبدیل کنید...
اگه در مورد میخواین بگین تا بیشتر توضیح بدم.

Arcsinos
شنبه 14 تیر 1393, 12:25 عصر
این تابع رو نوشتم که کار ما رو راه انداخت، اگه خواستید ازش استفاده کنید. میتونید سایز عکستون و تعداد بایت هایی که به ازای هر پیکس توی آرایه هست رو طبق نیازتون تغییر بدید. همونطور که گفتم عکس بنده 480*640 بود و به ازای هر پیکسل دو بایت در اختیار داشتم که بایت اول رو توی B بایت دوم رو توی G ریختم و R و A رو صفر قرار دادم. موفق باشید


public static Bitmap bytetobit(byte[] myarray)
{
WriteableBitmap colorBitmap;
byte[] colorPixels = new byte[640 * 480 * sizeof(int)];
colorBitmap = new WriteableBitmap(640, 480, 96.0, 96.0, PixelFormats.Bgr32, null);
int colorPixelIndex = 0;
for (int i = 0; i < (640 * 480 * 2); i += 2)
{
colorPixels[colorPixelIndex++] = myarray[i];
colorPixels[colorPixelIndex++] = myarray[i + 1];
colorPixels[colorPixelIndex++] = 0;
++colorPixelIndex;
}
colorBitmap.WritePixels(new Int32Rect(0, 0, 640, 480), colorPixels, colorBitmap.PixelWidth * sizeof(int), 0);


System.Drawing.Bitmap bmp;


using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create((BitmapSource)co lorBitmap));
enc.Save(outStream);
bmp = new System.Drawing.Bitmap(outStream);
}


return bmp;
}

plus
شنبه 14 تیر 1393, 12:35 عصر
این تابع رو نوشتم که کار ما رو راه انداخت، اگه خواستید ازش استفاده کنید. میتونید سایز عکستون و تعداد بایت هایی که به ازای هر پیکس توی آرایه هست رو طبق نیازتون تغییر بدید. همونطور که گفتم عکس بنده 480*640 بود و به ازای هر پیکسل دو بایت در اختیار داشتم که بایت اول رو توی B بایت دوم رو توی G ریختم و R و A رو صفر قرار دادم. موفق باشید

تصویر حاصل سیاه سفیده؟! آخه شما به B و G مقدار دادین و R رو 0 گذاشتین طبیعتا باید رنگ تصویر فسفری بشه...

Arcsinos
شنبه 14 تیر 1393, 12:41 عصر
تصویر حاصل سیاه سفیده؟! آخه شما به B و G مقدار دادین و R رو 0 گذاشتین طبیعتا باید رنگ تصویر فسفری بشه...

سلام دوست عزیز، با تشکر از هر دو پاسخ شما. راستش از این جهت گفتم سیاه و سفید بشه چون نخواستم زیاد درگیر تبدیل 2 بایت، به RGB بشیم و اینکه این آرایه اصلا یه تصویر نیست و فقط میخواستم که یه نمایشی از اون داشته باشم. این آرایه یه Depth Image هست که دستگاه کینکت اونو در اختیار من قرار میده و در ادامه ی داستان قراره پردازشی روی اون انجام بشه. در واقع هر دو بایت نشون دهنده ی عمق اون نقطه توی دنیای واقعی هست که اگه بخواییم به سیاه و سفید تبدیلش کنیم رنگ سفید دورترین نقطه و رنگ سیاه نزدیکترین نقطه میشه.
باز هم ممنون از راهنمایی شما.

rahnema1
شنبه 14 تیر 1393, 17:18 عصر
سلام
به این صورت مبشه انجام داد
pixelarray هم داده های شماست
باید به WindowsBase و PresentationCore و System.Xaml رفرنس بدید

using System.Runtime.InteropServices;
using System.Windows.Media;
using System.Windows.Media.Imaging;
int width=640,height=480;
byte[] pixelarray= new byte[width*height*2];
int stride=(int)(Math.Ceiling( width/2.0)*4);
int size = Marshal.SizeOf(pixelarray[0]) * stride*height;
IntPtr pnt = Marshal.AllocHGlobal(size);
IntPtr pnt2=pnt;
byte[] bytearray= new byte[stride*height];
try
{
for (int i = 0; i < height; i++) {
Marshal.Copy(pixelarray, i*width, pnt2, width);
pnt2+=stride;
}
Marshal.Copy(pnt, bytearray, 0, bytearray.Length);
}
finally
{
Marshal.FreeHGlobal(pnt);
}
BitmapSource bs=BitmapSource.Create( width,height,72,72, System.Windows.Media.PixelFormats.Gray16 ,BitmapPalettes.Gray16,bytearray ,stride);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Frames.Add( BitmapFrame.Create(bs));
System.IO.Stream imageStreamSource = new System.IO.FileStream( "myfile.tif", System.IO.FileMode.Create);
encoder.Save(imageStreamSource);

Arcsinos
شنبه 14 تیر 1393, 17:22 عصر
سلام
به این صورت مبشه انجام داد
pixelarray هم داده های شماست
باید به WindowsBase و PresentationCore و System.Xaml رفرنس بدید


با تشکر از شما دوست عزیز. تو کدی که گذاشتم تقریبا همین کار انجام شده. ممنون

rahnema1
شنبه 14 تیر 1393, 17:31 عصر
اگه پهنای تصویر همیشه 640 باشه این طور بهتره

int width=640,height=480;
byte[] pixelarray= new byte[width*height*2];
int stride=(int)(Math.Ceiling( width/2.0)*4);
BitmapSource bs=BitmapSource.Create( width,height,72,72, System.Windows.Media.PixelFormats.Gray16 ,BitmapPalettes.Gray16,pixelarray ,stride);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Frames.Add( BitmapFrame.Create(bs));
System.IO.Stream imageStreamSource = new System.IO.FileStream( "myfile.tif", System.IO.FileMode.Create);
encoder.Save(imageStreamSource);

rahnema1
شنبه 14 تیر 1393, 17:46 عصر
با تشکر از شما دوست عزیز. تو کدی که گذاشتم تقریبا همین کار انجام شده. ممنون

آخه کاری که شما کردید میاد 16 بیت را تبدیل می کنه به دو تا 8 بیت 8 بیت اول را می ریزه توی آبی و 8 بیت دوم را می ریزه توی سبز .تصویر ایجاد شده اولا اشباع میشه ( در مقدار 255) و ثانیا ترکیب سبز و آبی با هم یه چیز داغون میشه :)

plus
شنبه 14 تیر 1393, 19:32 عصر
آخه کاری که شما کردید میاد 16 بیت را تبدیل می کنه به دو تا 8 بیت 8 بیت اول را می ریزه توی آبی و 8 بیت دوم را می ریزه توی سبز .تصویر ایجاد شده اولا اشباع میشه ( در مقدار 255) و ثانیا ترکیب سبز و آبی با هم یه چیز داغون میشه :)
ظاهرا ایشون فقط میخوان یه نمایشی از تصویر داشته باشن و زیاد دقیق بودن رنگ پیکسل ها براشون مهم نیست.