هذا البرنامج التعليمي يُعتبر أساس الرؤية الحاسوبية ويُقدم كـ “الدرس 2” من السلسلة؛ سيأتي المزيد من الدروس التي ستتناول مدى بناء مشاريع الرؤية الحاسوبية القائمة على التعلم العميق الخاصة بك. يمكنك العثور على المنهج الكامل وجدول المحتويات هنا.
النقاط الرئيسية التي يجب استيعابها من هذه المقالة:
- تحميل صورة من القرص.
- الحصول على ‘الارتفاع’ و’العرض’ و’عمق’ الصورة.
- العثور على مكونات R و G و B للصورة.
- الرسم باستخدام OpenCV.
تحميل صورة من القرص
قبل أن نجري أية فعاليات أو تلاعب بالصورة، من المهم أن نقوم بتحميل صورة من اختيارنا إلى القرص. سنقوم بهذه النشاط باستخدام OpenCV. هناك طريقتان يمكننا من خلالهما إجراء عملية التحميل. طريقة واحدة هي تحميل الصورة من خلال تمرير مسار الصورة وملف الصورة إلى وظيفة OpenCV “imread”. الطريقة الأخرى هي تمرير الصورة من خلال وسيط سطر الأوامر باستخدام وحدة Python argparse.
#تحميل الصورة من القرص
import cv2
image = cv2.imread(“C:/Sample_program/example.jpg”)
cv2.imshow(‘Image’, image)
cv2.waitKey(0)
لنقم بإنشاء اسم ملف Loading_image_from_disk.py في نوتي باد. أولاً، نقوم باستيراد مكتبة OpenCV الخاصة بنا، والتي تحتوي على وظائف معالجة الصور. نستورد المكتبة باستخدام السطر الأول من الكود كـ cv2. السطر الثاني من الكود هو المكان الذي نقوم به بقراءة الصورة باستخدام وظيفة cv2.imread في OpenCV، ونقوم بتمرير مسار الصورة كمعامل؛ يجب أن يشتمل المسار أيضًا على اسم الملف مع تمديد الصورة الخاصة به .jpg، .jpeg، .png، أو .tiff.
بناء الجملة — // image=cv2.imread(“مسار/ل/صورتك.jpg”) //
يجب اتخاذ حرص أكبر عند تحديد اسم تمديد الملف. من المحتمل أن نتلقى الخطأ التالي إذا قمنا بتوفير اسم التمديد الخاطئ.
ERROR :
c:\Sample_program>python Loading_image_from_disk.py
Traceback (most recent call last):
File “Loading_image_from_disk.py”, line 4, in <module>
cv2.imshow(‘Image’, image)
cv2.error: OpenCV(4.3.0) C:\projects\opencv-python\opencv\modules\highgui\src\window.cpp:376: error: (-215:Assertion failed) size.width>0 && size.height>0 in function ‘cv::imshow’
السطر الثالث من الكود هو المكان الذي نعرض فيه الصورة المحملة بالفعل. المعامل الأول هو سلسلة، أو “الاسم” لنافذتنا. المعامل الثاني هو الكائن الذي تم تحميل الصورة إليه.
أخيرًا، استدعاء cv2.waitKey يوقف تنفيذ ال스크ربت حتى نضغط على مفتاح على لوحة المفاتيح. استخدام معامل “0” يشير إلى أن أي ضغطة على المفاتيح ستعمل على إلغاء الإيقاف. لا تتردد في تشغيل برنامجك بدون وجود السطر الأخير من الكود في برنامجك لرؤية الفرق.
#قراءة الصورة من القرطاس باستخدام Argparse
import cv2
import argparse
apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())
image = cv2.imread(args[“image”])
cv2.imshow(‘Image’, image)
cv2.waitKey(0)
معرفة قراءة الصورة أو الملف باستخدام وسيطة الأوامر (argparse) هي مهارة مطلوبة تمامًا.
السطرين الأولين من الكود هما لاستيراد المكتبات الضرورية؛ هنا، نستورد OpenCV و Argparse. سنكرر هذا طوال الدورة.
ثلاثة أسطر من التعليمات البرمجية التالية تتعامل مع تحليل وسيطات سطر الأوامر. الوسيطة الوحيدة التي نحتاجها هي — image: مسار الصورة لدينا على القرص. أخيرًا، نقوم بتحليل الوسائط وتخزينها في قاموس يسمى args.
دعونا نستغرق ثانية ونناقش بسرور بالضبط ما هو المفتاح — image. المفتاح — image هو سلسلة نحددها في سطر الأوامر. يخبر هذا المفتاح ملف Loading_image_from_disk.py الخاص بنا ، أين توجد الصورة التي نريد تحميلها على القرص.
تم ناقش آخر ثلاثة أسطر من التعليمات البرمجية في وقت سابق. تأخذ الدالة cv2.imread args[“image”] كمعامل، وهو في الأساس الصورة التي نقدمها في موجه الأوامر. cv2.imshow يعرض الصورة، التي تم تخزينها بالفعل في كائن صورة من السطر السابق. السطر الأخير يوقف تنفيذ البرنامج حتى نضغط على مفتاح على لوحة المفاتيح.
إحدى المزايا الرئيسية لاستخدام argparse — وسيطة سطر الأوامر هي أننا سنتمكن من تحميل الصور من مواقع مجلدات مختلفة دون الحاجة لتغيير مسار الصورة في برنامجنا عن طريق تمرير مسار الصورة بشكل ديناميكي في موجه الأوامر كحجة مثلاً — “C:\CV_Material\image\sample.jpg” في موجه الأوامر عندما نقوم بتنفيذ برنامجنا البرمجي بلغة Python.
c:\Sample_program>python Loading_image_from_disk.py — image C:\CV_Material\session1.JPG
هنا، نقوم بتنفيذ ملف Loading_image_from_disk.py بلغة Python من موقع c:\sample_program عن طريق تمرير المعلمة “-image” إلى جانب مسار الصورة C:\CV_Material\session1.JPG.
الحصول على ‘الارتفاع’، ‘العرض’ و’العمق’ للصورة
منذ أن تم تمثيل الصور كمصفوفات NumPy، يمكننا ببساطة استخدام سمة .shape لفحص العرض والارتفاع وعدد القنوات.
عن طريق استخدام سمة .shape على كائن الصورة الذي تم تحميله للتو. يمكننا العثور على الارتفاع والعرض وعمق الصورة. كما ناقشنا في الدرس السابق الدرس 1، يمكن التحقق من الارتفاع والعرض من خلال فتح الصورة في بينت. انظر إلى الدرس السابق. سنناقش عمق الصورة في الدروس القادمة. العمق يعرف أيضا بقناة الصورة. عادةً ما تكون الصور الملونة من 3 قناة بسبب تكوين RGB في جزيئاتها والصور المخافرة من قناه واحده. هذا شيء ناقشناه في الدرس السابق الدرس 1.
#الحصول على الارتفاع والعرض وعمق الصورة
import cv2
import argparse
apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())
# الفرق الوحيد عن التعليمات البرمجية السابقة - تطبيق سمة shape على كائن الصورة
print(f’(Height,Width,Depth) of the image is: {image.shape}’)
image = cv2.imread(args[“image”])
cv2.imshow(‘Image’, image)
cv2.waitKey(0)
الناتج:
(الارتفاع والعرض وعمق) الصورة هي: (538, 723, 3)
الفرق الوحيد عن التعليمات البرمجية السابقة هو عبارة الطباعة التي تطبق سمة shape على كائن الصورة المحمل. f’ هو سلسلة التوجيه F @ السلسلة المنسقة التي تأخذ المتغيرات بشكل ديناميكي وتطبع.
f’ write anything here that you want to see in the print statement: {variables, variables, object, object.attribute,}’
هنا، استخدمنا {object.attribute} داخل قوس الزهرة لسمة الشكل لحساب ارتفاع وعرض وعمق جسم الصورة.
#الحصول على الارتفاع والعرض والعمق بشكل منفصل
import cv2
import argparse
apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())
image = cv2.imread(args[“image”])
# قطع صفيف NumPy للحصول على الارتفاع والعرض والعمق بشكل منفصل
print(“height: %d pixels” % (image.shape[0]))
print(“width: %d pixels” % (image.shape[1]))
print(“depth: %d” % (image.shape[2]))
cv2.imshow(‘Image’, image)
cv2.waitKey(0)
الناتج:
عرض: 723 بكسل
ارتفاع: 538 بكسل
عمق: 3
هنا، بدلاً من الحصول على (الارتفاع والعرض والعمق) معًا كمجموعة. نقوم بقطع المصفوفة ونحصل على الارتفاع والعرض وعمق الصورة كلًا على حدة. يحتوي الفهرس 0 من المصفوفة على ارتفاع الصورة، والفهرس 1 يحتوي على عرض الصورة، والفهرس 2 يحتوي على عمق الصورة.
العثور على مكونات R و G و B للصورة
الناتج:
قيمة مكون الأزرق والأخضر والأحمر للصورة عند الموضع (321, 308) هي: (238, 242, 253)
لاحظ كيف تم تمرير قيمة الـ y قبل قيمة الـ x – قد يبدو هذا البناء الإنشائي غير بديهي في البداية، لكنه متسق مع كيفية الوصول إلى القيم في مصفوفة: أولاً نحدد رقم الصف، ثم رقم العمود. من هناك، نحصل على مجموعة تمثل مكونات الأزرق والأخضر والأحمر للصورة.
يمكننا أيضًا تغيير لون بكسل عند موضع معين عن طريق عكس العملية.
#العثور على R وB وG للصورة عند موضع (x, y)
import cv2
import argparse
apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())
image = cv2.imread(args[“image”])
# تلقي قيمة الإحداثيات البكسل [y, x] من المستخدم، التي يجب حساب قيم RGB لها
[y,x] = list(int(x.strip()) for x in input().split(‘,’))
# استخراج قيم (الأزرق والأخضر والأحمر) للإحداثيات البكسل المستلمة
(b,g,r) = image[y,x]
print(f’The Blue Green Red component value of the image at position {(y,x)} is: {(b,g,r)}’)
cv2.imshow(‘Image’, image)
cv2.waitKey(0)
(b,g,r) = image[y,x] to image[y,x] = (b,g,r)
هنا نعين اللون في (BGR) على الإحداثيات البكسل للصورة. لنجرب عبر تعيين لون أحمر للبكسل في الموضع (321,308) ونتحقق من ذلك عن طريق طباعة لون BGR للبكسل في الموضع المعطى.
#عكس العملية لتعيين قيمة RGB لبكسل اخترتنا
import cv2
import argparse
apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())
image = cv2.imread(args[“image”])
#تلقي قيمة الإحداثيات البكسل [y,x] من المستخدم، التي يجب حساب قيم RGB لها
[y,x] = list(int(x.strip()) for x in input().split(‘,’))
#استخراج قيم (أزرق,أخضر,أحمر) للإحداثيات البكسل المستلمة
image[y,x] = (0,0,255)
(b,g,r) = image[y,x]
print(f’The Blue Green Red component value of the image at position {(y,x)} is: {(b,g,r)}’)
cv2.imshow(‘Image’, image)
cv2.waitKey(0)
الناتج:
قيم ألوان بلون أزرق وأخضر وأحمر في الصورة في الموضع (321, 308) هي (0, 0, 255)
في الكود أعلاه، نتلقى إحداثيات البكسل من موجه الأوامر عن طريق إدخال القيم كما هو موضح في الشكل 2.6 أدناه، ونعين لون أحمر لإحداثيات البكسل عن طريق تعيين (0,0,255) أي (أزرق, أخضر, أحمر) ونتحقق من ذلك عن طريق طباعة إحداثيات البكسل المدخلة.
الرسم باستخدام OpenCV
دعونا نتعلم كيفية رسم أشكال مختلفة مثل المستطيلات والمربعات والدوائر باستخدام OpenCV عن طريق رسم دوائر لتغطية عيوني، ومستطيلات لتغطية شفتيين، ومستطيلات لتغطية الأسماك الرنجة المتراما بجانبي.
الناتج يجب أن يبدو هكذا:
هذه الصورة مغطاة بأشكال باستخدام MS Paint؛ سنحاول القيام بنفس الشيء باستخدام OpenCV عن طريق رسم دوائر حول عيوني ومستطيلات لتغطية شفتيين وأسماك الرنجة المتراما بجانبي.
نستخدم طريقة cv2.rectangle لرسم مستطيل وطريقة cv2.circle لرسم دائرة في OpenCV.
cv2.rectangle(image, (x1, y1), (x2, y2), (Blue, Green, Red), Thickness)
تأخذ طريقة cv2.rectangle صورة كوسيطتها الأولى على هيئة ذلك نريد رسم مستطيلنا. نريد رسم على كائن الصورة المحمل، لذا نمرره إلى الطريقة. الوسيطة الثانية هي البداية (x1, y1) موضع مستطيلنا — هنا، نبدأ مستطيلنا عند نقاط (156 و 340). ثم، يجب أن نقدم نقطة نهاية (x2, y2) للمستطيل. قررنا إنهاء مستطيلنا عند (360, 450). الوسيطة التالية هي لون المستطيل الذي نريد رسمه؛ هنا، في هذه الحالة، نمرر لون أسود بتنسيق BGR، أي (0,0,0). أخيرًا، الوسيطة الأخيرة التي نمررها هي سمك الخط. نعطي -1 لرسم الأشكال الصلبة، كما هو موضح في الشكل 2.6.
وبالمثل، نستخدم طريقة cv2.circle لرسم الدائرة.
cv2.circle(image, (x, y), r, (Blue, Green, Red), Thickness)
تأخذ طريقة cv2.circle صورة كوسيطتها الأولى على هيئة ذلك نريد رسم مستطيلنا. نريد رسم على كائن الصورة التي قمنا بتحميلها، لذا نمرره إلى الطريقة. الوسيطة الثانية هي مركز (x, y) موضع دائرتنا — هنا، اتخذنا دائرتنا عند النقطة (343, 243). الوسيطة التالية هي نصف قطر الدائرة التي نريد رسمها. الوسيطة التالية هي لون الدائرة؛ هنا، في هذه الحالة، نمرر لون أحمر بتنسيق BGR، أي (0,0,255). أخيرًا، الوسيطة الأخيرة التي نمررها هي سمك الخط. نعطي -1 لرسم الأشكال الصلبة، كما هو موضح في الشكل 2.6.
حسنًا! بمعرفة كل هذا. دعونا نحاول تحقيق ما بدأناه. لرسم الأشكال في الصورة، نحتاج إلى تحديد إحداثيات بداية ونهاية المنطقة المصنفة لتمريرها إلى الطريقة المقابلة.
كيف؟
سنستعين بأداة ميكروسوفت بينت لمرة أخرى. بوضع المؤشر فوق إحدى الإحداثيات (الجزء العلوي الأيسر) أو (الجزء السفلي الأيمن) للمنطقة التي تريد تصنيفها، تظهر الإحداثيات في الجزء المظلل من ميكروسوفت بينت كما هو موضح في الشكل 2.7.
بالمثل، سنأخذ جميع الإحداثيات (x1, y1) (x2, y2) لجميع المناطق المصنفة كما هو موضح في الشكل 2.8.
# رسم باستخدام OpenCV لتصنيف العيون، الفم، والأجسام القريبة
import cv2
import argparse
apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())
image = cv2.imread(args[“image”])
cv2.rectangle(image, (415, 168), (471, 191), (0, 0, 255), -1)
cv2.circle(image, (425, 150), 15, (0, 0, 255), -1)
cv2.circle(image, (457, 154), 15, (0, 0, 255), -1)
cv2.rectangle(image, (156, 340), (360, 450), (0, 0, 0), -1)
# عرض الصورة الناتجة
cv2.imshow(“Output drawing “, image)
cv2.waitKey(0)
النتيجة:

Source:
https://dzone.com/articles/computer-vision-tutorial-2-image-basics