سلام دوستان! امیدوارم حالتان خوب باشد. این اولین جلسه از فصل چهارم، یعنی فصل آخر دورهی ماست. در این جلسه میخواهم درباره آرایههایی که مربوط به تصاویر رنگی هستند صحبت کنم.
در یکی از مثالهایی که در جلسات اولیه مطرح کردم، به این اشاره کردم که میتوانیم تصاویر را بهصورت آرایههای چندبعدی در نظر بگیریم. مثلاً اگر یک تصویر ده در ده پیکسل داشته باشیم، میتوانیم بگوییم که ده ردیف و ده ستون دارد و تقاطع هرکدام از این ردیفها و ستونها یک پیکسل میشود.
هر پیکسل یک رنگ مشخص دارد. رنگها در کامپیوتر با منطقی به نام RGB نمایش داده میشوند. در این منطق، هر رنگ بهصورت یک آرایه سهتایی تعریف میشود. عدد اول مربوط به رنگ قرمز (Red)، عدد دوم مربوط به رنگ سبز (Green)، و عدد سوم مربوط به رنگ آبی (Blue) است.
این اعداد در بازه صفر تا ۲۵۵ قرار میگیرند، به این معنا که هرکدام از این رنگها میتوانند ۲ به توان ۸ حالت مختلف داشته باشند. برای مثال، فرض کنید رنگ یک پیکسل اول صفر، صفر، صفر باشد (مشکی). رنگ پیکسل کناریش میتواند صفر، صفر، ۱۰ باشد و همینطور در راستای محور اول تغییر کند تا رنگ آبی افزایش پیدا کند.
منطق ساخت آرایههای RGB اینطور کار میکند: شما یک آرایه سهبعدی دارید که بعد اول و دومش موقعیت پیکسلها را مشخص میکند و بعد سومش رنگ هر پیکسل را تعریف میکند. حالا بیایید جلوتر ببینیم چطور میشود با این منطق کار کرد.
قبل از هر چیز، من کتابخانه numpy
را ایمپورت میکنم. به matplotlib
هم نیاز داریم که بعداً توضیح میدهم به چه دردی میخورد.
Import numpy as np
Import matplotlib as plt
تبدیل آرایه به تصویر
چطور میتوانیم یک آرایهی آرجیبی بسازیم؟ فرض کنید من میخواهم همین شکلی که در اینجا دارم را بسازم.
فرض کنید میخواهیم یک شکل سه در سه بسازیم. این شکل را به سه قسمت تقسیم میکنیم: سه تای بالایی کاملاً قرمز هستند. یعنی در منطق RGB، اولین عدد آنها ۲۵۵ و دو عدد بعدی صفر هستند. این تنظیمات رنگ قرمز کامل را به ما میدهند.
سه تای بعدی کاملاً سبز هستند. یعنی عدد اول صفر، عدد دوم ۲۵۵ و عدد سوم صفر است. سه تای آخر هم کاملاً آبی هستند؛ یعنی صفر، صفر، ۲۵۵.
در ضمن، اگر همه مقادیر یک پیکسل صفر باشند، رنگ مشکی و اگر همه مقادیر ۲۵۵ باشند، رنگ سفید خواهیم داشت. این نکته را در ذهن داشته باشید.
حال بیایید شروع کنیم. اولین چیزی که نیاز داریم، یک آرایه سه در سه است. من این آرایه را به صورت یک لیست تعریف میکنم. فرض کنید آرایه ما به نام rgb_list
تعریف شده است. حالا باید دونهدونه این باکسها را تعریف کنیم.
سه تای اول قرمز هستند: [255, 0, 0]
. سه تای بعدی سبز هستند: [0, 255, 0]
. و سه تای آخر آبی هستند: [0, 0, 255]
. چیزی که ساختیم دقیقاً با توضیحات بالا مطابقت دارد.
Rgb_list = [
[[255,0,0] , [255,0,0] , [255,0,0]],
[[0,255,0] , [0,255,0] , [0,255,0]],
[[0,0,255] , [0,0,255] , [0,0,255]]
]
اولین عنصری که اینجا داریم، کاملاً قرمز میشود یا آخرین عنصری که داریم، مقدار [0, 0, 255]
میگیرد. یا ردیف آخر رنگی در تصویر که آبی است، میشود این ردیف: [[0, 0, 255], [0, 0, 255], [0, 0, 255]]
و هرکدام از این درایهها متناظر با رنگهای تصویر بالا هستند.
حالا این را تبدیل میکنیم به یک آرایهی nd
:
Rgb_array = np.array(rgb_list)
راههای مختلفی برای نمایش تصاویری که به صورت آرایه هستند وجود دارد. کار اصلی کتابخانهی نامپای این است که فایلهای تصویری را با منطقی که اینجا توضیح دادم، به یک آرایه تبدیل میکند. کتابخانههای مختلفی مانند matplotlib
این کار را انجام میدهند و فریمورکهای پیشرفتهتری مانند OpenCV
نیز این قابلیت را دارند. حالا میخواهم تصویر این کد را نشان دهم و از matplotlib
استفاده میکنم که با اسم plt
ایمپورت کردهام. یک تابع در plt
به نام imshow
وجود دارد که میتوانم اسم آرایهام را به آن بدهم و این تابع، آرایه را به صورت تصویر به من نمایش میدهد. اسم فایل من هم rgb_array
بود.
plt.imshow(rgb_array)
اگر من plt.show()
را اجرا کنم، همین تصویری که در بالا میخواستم بسازم را برای من میکشد:
plt.show()
این کار سادهای بود که ما اینجا خواستیم انجام دهیم. حالا بیایید کمی پیچیدهترش کنیم.
اگر بخواهم این تصویر را بسازم، چه کار باید بکنم؟!
برای نوشتن کد این تصویر مطابق منطقی که در گذشته داشتیم، شروع میکنیم. همانطور که مشاهده میکنید، کدها در تصویر موجود هستند.
آرایه اول کاملاً قرمز است: [255, 0, 0]
آرایه آخر کاملاً آبی است: [0, 0, 255]
یک آرایه کاملاً مشکی داریم: [0, 0, 0]
یک آرایه کاملاً سفید داریم: [255, 255, 255]
و بقیه آرایهها با ترکیبهای مختلف این رنگها وجود دارند.
برای تمرین بیشتر، اینجا یک کد دیگر میخواهم بنویسم. یک آرایه سه در سه که رنگهای رندوم داشته باشد.
برای شروع، یک سری کد رنگ نیاز دارم، یعنی از صفر تا دویست و پنجاه و پنج. اسمش را rgb_code
میگذارم و به کمک arange
و با step=15
(که به دویست و پنجاه و پنج هم بخشپذیر باشد) کدنویسی میکنم:
Rgb_code = np.arange(256 , step=15)
خب، حالا من یک آرایه دارم که هر چیزی از صفر تا دویست و پنجاه و پنج را با استپ پانزده تا ذخیره کردهام. حالا میخواهم از این یک آرایه سه در سه بسازم که این اعداد را به صورت رندوم در آن بچینم.
در جلسات قبل متد choice
را معرفی کرده بودیم که من از آن استفاده میکنم و ازش میخواهم که این اعداد را در یک شیپ سه در سه بچیند:
Rgb_data = np.random.choice()
حالا چیزی که به من نمایش داده میشود، به این صورت است:
با انتخاب رندوم، هر بار رنگهای جدید به من نمایش داده میشود.
ذخیره تصویر
همانطور که قبلاً راجع به آن صحبت کردیم، ما میتوانیم با استفاده از فرمت .npy
به کمک کتابخانهی نامپای دادههای آرایهای خود را ذخیره کنیم. البته میتوانیم این RGBها را در فرمتهای دیگری مانند .csv
، .txt
و یا حتی .pkl
نیز ذخیره کنیم که در این صورت به کمک کتابخانهی pickle
میتوانیم آنها را لود کرده و از آنها استفاده کنیم. اما چون ما با نامپای کار میکنیم، از امکانات نامپای برای ذخیرهسازی استفاده خواهیم کرد.
#save
np.save(“./random_rgb.npy” , rgb_data )
عد از اجرا، فایل random_rgb.npy
در اکسپلورر ساخته شد. به این معنی که اعدادی که اینجا ساخته شدهاند، در قالب این تصویر برای من ذخیره شدند.
با عملیات لود چه اتفاقی میافتد؟ با استفاده از اسم my_rgb
آن را لود میکنم و این بار فقط آدرس فایل را میدهم:
#Load
my_rgb = np.load(“random_rgb.npy”)
plt.imshow(my_rgb)
plt.show()
میبینید که آن عکسی که ذخیره کرده بودم، حالا بارگذاری شده است. البته با توجه به تغییرات رندوم و تغییر عکس در حالت قبل از ذخیره، عکس ذخیرهشده تغییر نمیکند؛ زیرا عکس ذخیرهشده از فایل خوانده میشود.
تبدیل تصویر به آرایه
کتابخانهی matplotlib یک تابع دیگر به نام imread دارد که تصویر را از دایرکتوری مورد نظر گرفته و آن را به یک آرایه تبدیل کرده و ذخیره میکند. این عمل برعکس کاری است که ما در حال حاضر انجام دادهایم. به عبارت دیگر، من میتوانم مثلاً بنویسم:
My_pic = plt.imread()
اینبار باید آدرس فایل را بدهم. من یک فایل لوگو از سکان آکادمی دارم که مسیر آن را ثبت میکنم:
My_pic = plt.imread("./logo.png")
شیپ تصویر را نیز با استفاده از دستور زیر میگیرم:
My_pic.shape
اگر بخواهم آن را نمایش دهم، My_pic
به صورت یک فایل 500×500 چهار بعدی ذخیره شده است.
گاهی اوقات فایلهای تصویری یک درایهی اضافی دارند که به جای سه درایهی RGB، به عنوان چهارمین درایه میزان شفافیت (ترانسپرنسی) آنها را نشان میدهد.
اگر بخواهید تصویر لوگو را نمایش دهید، میتوانید از کد زیر استفاده کنید:
plt.imshow(My_pic)
این دستور تصویر موجود در متغیر My_pic
را نمایش میدهد.
خوب، از این بحث میگذریم. ما میتوانیم فایلهای تصویری را به اجزای رنگی آنها تفکیک کنیم و روی هرکدام از این رنگها بهصورت جداگانه کار کرده و تغییرات اعمال کنیم. چگونه؟ به تصویر زیر نگاه کنید:
تمام این اجزای اولیه که مانند تصویر زیر مشخص شدهاند، شامل رنگهای قرمز و طیفهای مختلف از تنهای قرمز هر پیکسل هستند.
یا مثلاً اجزای آخر نشاندهنده میزان آبی بودن هر پیکسل هستند. ما میتوانیم هرکدام از این اجزا را جدا کنیم یا تغییراتی در آنها اعمال کنیم تا مثلاً رنگ تصویر دچار تفاوت شود. ابتدا بیایید این اجزا را کمی جدا کنیم و ببینیم چگونه میتوان این کار را انجام داد!
مثلاً میتوانم اینگونه بنویسم:
Red_array = my_rgb[:, :, 0]
خط کد بالا یعنی از تمام ردیفها و تمام ستونها، مقدار مربوط به ایندکس صفرم (رنگ قرمز) را بردار و ذخیره کن.
برای رنگهای آبی (ایندکس یکم، یعنی عبارت وسط) و سبز (ایندکس دوم، یعنی عبارت آخر) نیز این عمل را تکرار میکنم:
Red_array = my_rgb[:, :, 0]
Blue_array = my_rgb[:, :, 1]
Green_array = my_rgb[:, :, 2]
با اجرای red_array
تمام مولفه اول ها (0) رو خواهیم داشت:
قبل از انجام این عملیات، آرایهی rgb
را پرینت کنید تا محتوای آن را بررسی کنید. (این کار میتواند به شما کمک کند تا ساختار داده و مقادیر موجود در آن را بهتر درک کنید.)
اکنون تمام مقادیر مربوط به کانال قرمز (عبارتهای اولی) که در آرایهی my_rgb
وجود دارند، به ترتیب در Red_array
ذخیره شدهاند و میتوانید آنها را مشاهده کنید:
اما شاید لازم باشد برخی از این مقادیر را تغییرات کوچکی بدهیم. مثلاً فرض کنید در این ستون مربوط به قرمز بخواهیم تغییراتی ایجاد کنیم و آنها را بهروزرسانی کنیم. در این صورت چه کاری میتوانیم انجام دهیم؟
اگر یادتان باشد، ما یک تابع داشتیم به نام where
که برای جستجو و اعمال تغییرات استفاده میشد. این تابع این قابلیت را داشت که برخی از مقادیر را جابجا کند. چطور این کار انجام میشود؟ مثلاً فرض کنید میخواهم رنگی که در اینجا دارم را کمی تیرهتر کنم.
رنگش خیلی روشن است! میخواهم میزان قرمزش را کم کنم تا تیرهتر شود. چه کار باید بکنم؟
اسم عملیات را dark_pic
میگذارم و از np.where()
استفاده میکنم که میتواند یک آرایه جدید به ما برگرداند. تابع where
نیاز به یک شرط دارد:
از تابع where
میخواهم که به my_rgb
برود و هر جا مقدار 255 را پیدا کرد، آنها را بردارد و به جایش 50 بگذارد. در غیر این صورت، مقدار همان عدد باقی بماند.
Drak_pic = np.where(my_rgb==255 , 50, my_rgb)
حالا نمایشش میدهم!
Plt.imshow(dark_pic)
Plt.show()
خب، اگر مقادیر تغییر زیادی نکردهاند، احتمالاً دویست و پنجاه و پنج زیاد در آنها نبوده است. حالا تصمیم میگیرم که هر جا مقدار بیشتر از 100 بود، آن را به 50 تغییر دهم.
خروجی کد بالا به صورت زیر است:
برای تمرین، من یک فایل .ipynb
مربوط به لوگو سکان آکادمی قرار دادهام که میتوانید همهی مواردی که تا کنون آموخته اید را در آن تمرین کنید.