آموزش کتابخانه Numpy با تمرکز بر روی کاربرد آن در OpenCV
[این نوشته ایده گرفته و ترجمهی آزادی از این مطلب و آموزش خود Numpy است.]
مقدمه:
قبل از این که وارد بحث شیم بگم که ما Numpy رو هنگام کار با OpenCV و همچنین برنامههای مربوط به یادگیری ماشین، شناسایی الگو و … زیاد میبینیم و استفاده خواهیم کرد، اینجا با تمرکز بر روی OpenCV در مورد Numpy صحبت خواهم کرد.
Numpy چیه؟ یک کتابخونهی پایتون که برای محاسبات عددی بهینه شده. تمام ساختارهای آرایه OpenCV به آرایهی Numpy تبدیل میشن و یا از Numpy اومدن، بنابر این تمام عملیاتی که توسط Numpy قابل انجام است رو میشه با OpenCV ترکیب کرد، همچین از SciPyو Matplotlib و … که Numpy رو ساپورت میکنن میتونیم استفاده کنیم. میشه گفت برای اینکه کدهای بهینهی OpenCV-Python بنویسیم لازمه تا شناخت خوبی از Numpy داشته باشیم.
آرایهها در Numpy:
بیاید دستهامون رو کثیف کنیم و شروع کنیم با مثال جلو رفتن! اول از همه اگر تا الان Numpy رو نصب نکردید با استفاده از این دستور نصبش کنید (توجه! من از اوبونتو 17.10 و Python 3.6 دارم استفاده میکنم.):
pip3 install numpy
بیاید وارد محیط پایتون بشیم [من از ipython استفاده میکنم] و یک آرایهی یک بعدی مثل [1,2,3,4,5] بسازیم:
import numpy as np arr = np.array([1, 2, 3, 4, 5])
اگر بخوایم نوع آرایهای که ساختم رو ببینیم از این دستور استفاده میکنیم:arr.dtype
برای دیدن شکل آرایه:arr.shape
برای مثال بخوایم عضو اول آرایه رو ببینیم (اینجا هم ایندکس از 0 شروع میشه):arr[0]
دیدن تعداد کل اعضای آرایه:arr.size
دستورات بالا رو با هم ببینیم:
بیاید یک آرایهی دو بعدی بسازیم و نتایج دستورات قبل رو روش ببینیم:
# Create a 2 dimensional array twoArr = np.array([[1,2],[3,4],[5,6]]) # To print the shape of the array. print (twoArr.shape) # Prints "(3,2)" # Accessing the values stored and printing them. print (twoArr[0, 0], twoArr[0, 1], twoArr[1, 1]) # Prints "1 2 4" # To print the whole array. print (twoArr) # Prints "[[1 2] [3 4] [5 6]]"
چندتا مثال دیگه:
In [1]: import numpy as np In [2]: a = np.arange(15).reshape(3, 5) In [3]: a Out[3]: array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) In [4]: print(a.shape) (3, 5) In [5]: print (a.ndim) 2 In [6]: print(a.itemsize) 8 In [7]: print(a.size) 15 In [8]: type(a) Out[8]: numpy.ndarray
در خط دوم کد بالا ما یک آریهی 5*3 در رنج صفر تا 15 ساختیم (در اصل ما آرایهی یک بعدی از 0 تا 15 رو ساختیم و بعد شکل اون رو به یک آرایهی 3 در 5 تغییر دادیم).
.ndim
بعد آرایه رو می گه ( number of axes (dimensions) of the array)
برای ساخت یک آرایه از اعداد مختلط:
In [1]: import numpy as np In [2]: a = np.array( [ [1,2], [3,4] ], dtype=complex ) In [3]: print(a) [[1.+0.j 2.+0.j] [3.+0.j 4.+0.j]]
بخوایم آرایهای از صفرها، یکها و آرایهی خالی بسازیم:
In [1]: import numpy as np In [2]: a = np.zeros( (3,4) ) In [3]: print (a) [[0. 0. 0. 0.] [0. 0. 0. 0.] [0. 0. 0. 0.]] In [4]: b = np.ones((2,3,4), dtype = np.int16) In [5]: print(b) [[[1 1 1 1] [1 1 1 1] [1 1 1 1]] [[1 1 1 1] [1 1 1 1] [1 1 1 1]]] In [6]: c = np.empty((2,3)) In [7]: print(c) [[6.92989625e-310 6.92989625e-310 0.00000000e+000] [0.00000000e+000 4.94065646e-324 1.75505793e-316]]
و اگر بخواهیم یک دنباله از اعداد با گامهای مشخص داشته باشیم:
In [1]: import numpy as np In [2]: a = np.arange(1, 10, 2) In [3]: print (a) [1 3 5 7 9] In [4]: b = np.arange(1,10, .3) In [5]: print (b) [1. 1.3 1.6 1.9 2.2 2.5 2.8 3.1 3.4 3.7 4. 4.3 4.6 4.9 5.2 5.5 5.8 6.1 6.4 6.7 7. 7.3 7.6 7.9 8.2 8.5 8.8 9.1 9.4 9.7]
در انتها به عنوان مثال بخواهیم بین ۱ تا ۳ (با احتساب ۱ و ۳) ۷ تا عدد با فاصلهی مساوی داشته باشیم:
In [1]: import numpy as np In [2]: a = np.linspace(1,3,7) In [3]: print(a) [1. 1.33333333 1.66666667 2. 2.33333333 2.66666667 3. ]
تفاوت دستور arange با linspace در اینه که در دستور اول ما میام و گامها رو مشخص میکنیم اما در دستور دوم تعداد اعدادی که میخواهیم رو مشخص میکنیم.
بریم سراغ کاربرد Numpy در OpenCV:
ما با کتابخانهی OpenCv تصویر رو میخونیم و برای انجام برخی تبدیلات روی اون از Numpy اسفاده میکنیم (میتونید آموزش نصب OpenCV روی اوبونتو رو از این لینک پیدا کنید):
لود کردن کردن یک عکس در OpenCV:
In [1]: import cv2 In [2]: img = cv2.imread('1.jpg',1)
دستور imread دوتا پارامتر میگیره، پارامتر اول اسم و آدرس عکسی که قراره لود کنیم و پارامتر دوم نوع عکس رو مشخص میکنه:
- cv2.IMREAD_COLOR : Loads a color image. Any transparency of image will be neglected. It is the default flag.
- cv2.IMREAD_GRAYSCALE : Loads image in grayscale mode
- cv2.IMREAD_UNCHANGED : Loads image as such including alpha channel
نکته تنبلی: بجای سه تا فلگ بالا خیلی ساده میتونیم از 1، 0 و -1 استفاده کنیم.
توجه: عکسی که میخوایم لود کنیم یا در پوشهی برنامه موجود در این صورت تنها اسم عکس رو به تابع میدیم (مثال بالا) یا اگر در جای دیگهای بجز پوشهی برنامه ذخیره شده باید آدرس اون رو همراه با اسم به وروردی تابع بدیم.
توجه: اگر عکسی که میخواهیم لود کنیم موجود نباشه تابع imread خطا ای به ما نمیدهد و دستور print(img) مقدار None رو بر میگردونه. (میشه گفت یک عکس خالی رو میخونه، با چیزی که همیشه داشتم یکم فرق داره، نه؟)
اگر بخواهیم کپیای از عکس داشته باشیم از دستور زیر استفاده میکنیم:
# Import OpenCV import cv2 # Load a color image in grayscale img = cv2.imread('1.jpg',0) # Assigning the image stored in numpy array img to # another numpy array img_copy img_copy = img.copy()
بخواهیم بخشی از عکس رو کپی کنیم (به عنوان مثال صورت یک نفر رو در عکس تشخیص دادهایم و حالا میخوایم کپیای از صورت داشته باشیم و روی اون کار کنیم):
# Import OpenCV import cv2 # Load a color image in grayscale img = cv2.imread('1.jpg',0) # Copies from rows 100 to 150 and columns 100 to 250 cropped = img[100:150,100:250]
برای پیدا کردن تعداد سطرها، ستونها و کانالهای عکس میتونیم از همون متد shape در Numpy استفاده کنیم:
# Import OpenCV # Load a color image in BGR img = cv2.imread('1.jpg',1) # Find the number of rows in the image imgRows = img.shape[0] # Find the number of columns in the image imgCols = img.shape[1] # Find the number of channels in the image Channels = img.shape[2]
شکل دیگه استفاده از دستور بالا:
# Import OpenCV import cv2 # Load a color image in BGR img = cv2.imread('1.jpg',1) # Find the number of rows, columns and Channels in the image imgRows, imgCols, Channels = cropped.shape # pirnt number of rows, columns and Channels print (imgRows,imgCols, Channels)
توجه: برای عکسهای سیاه و سفید shape تنها دو پارامتر تعداد سطرها و ستونهای عکس رو بر میگردونه.
خیلی وقتها برای افزایش دقت محاسبات ما فرمت اعداد عکس رو از int به float تبدیل میکنیم و بعد از پایان محاسبات برای نمایش عکس و یا ذخیرهی اون عکس تبدیلات قبل رو باید انجام بدیم، تکه کد زیر نحوهی انجام این کارها رو نشون میده(بالاخره واقعا از Numpy استفاده کردیم :-D):
# Import numpy and OpenCV import numpy as np import cv2 # Load an color image in BGR img = cv2.imread('1.jpg',1) # Prints image data type print (img.dtype) # prints 'uint8' # Convert from uint8 to float32 img = np.float32(img) # Prints float32 print (img.dtype) # Convert from float32 to uint8 img = np.uint8(img) # Prints uint8 print (img.dtype)
نویسنده: محمد حسین سالاری.