في هذه المقالة سنتحدث عن مكتبة Pillow في بايثون. من المفيد أن يكون لديك بعض الخبرة في معالجة الصور، حيث إنها أساس للعديد من التطبيقات: الصور الفوتوغرافية بعد المعالجة تلقائيًا، وإنشاء صور مصغرة في لغة بايثون للمحتوى عبر الإنترنت، ومعالجة الصور مسبقًا لتعلم الآلة.
وحدة Pillow هي فرع من مكتبة صور Python (PIL). يجب تثبيت Pillow من قبل المستخدم. أسهل طريقة للقيام بذلك هي باستخدام PIP. لمزيد من المعلومات الأساسية أو البرامج التعليمية راجع الوثائق الرسمية.
فتح الصور
هناك العديد من تنسيقات الصور التي يمكنك العمل بها باستخدام وحدة Pillow.
تحتوي الصور النقطية على عدد ثابت من وحدات البكسل اعتمادًا على دقة الصورة، ولكل بكسل لون محدد. إذا قمت بتكبير الصورة النقطية بدرجة كافية، تصبح وحدات البكسل أكثر وضوحًا. يتم تخزين الغالبية العظمى من الصور بهذه الطريقة.
من ناحية أخرى، تستخدم الصور المتجهة منحنيات محددة بواسطة معادلات رياضية لإنشاء الصور. يمكنك الاستمرار في تكبير الصورة المتجهة، وتبقى المنحنيات سلسة. هناك مثالان لتنسيق الملف هذا هما SVG وEPS.
ومع ذلك، قد يكون العمل مع الصور المستندة إلى المتجهات في بايثون أمرًا صعبًا بعض الشيء، لأنه يتضمن استخدام مكتبات متخصصة أخرى. من أجل البساطة، فإننا نقتصر على تنسيق الصورة النقطية المألوف.
لفتح صورة وعرضها باستخدام وحدة Pillow، قم باستيراد وحدة Image وافتح الصورة كما يلي:
>>> from PIL import Image
>>> im = Image.open('image.png', mode='r')
>>> im.show()
تقوم الدالة بإرجاع كائن Image
، والذي يمكنك البدء في تحليله وتعديله. يحدد وضع الكلمة الأساسية الاختياري ما إذا كانت الصورة مفتوحة في وضع القراءة أو الكتابة. تحدد تنسيقات الكلمات الرئيسية الاختيارية الثانية قائمة أو مجموعة من formats
لمحاولة تحميل الملف فيها.
تدعم وحدة Pillow أكثر من 30 نوعًا مختلفًا من الملفات النقطية للقراءة. ومع ذلك، فإن دعم كتابة الملفات أقل شمولاً. إذا كنت تعمل باستخدام JPG، على سبيل المثال، فإن إجراء فتح الملف هو نفس الإجراء الموضح أعلاه. لعرض الصورة، يمكنك استخدام التابع show()
على كائن Image
. يؤدي هذا إلى عرض الصورة في نافذة منفصلة ويكون مفيدًا في الغالب لأغراض تصحيح الأخطاء.
يحتوي الكائن im
على عدة توابع توفر معلومات حول الصورة. توفر كل من format
و mode
و size
بعض المعلومات الأساسية حول صورتك. جربهم لمعرفة المعلومات التي يعودون بها. يمكنك أيضًا العثور على دقة الصورة باستخدام التابع info
، والتي تُرجع قاموسًا يحتوي على المفتاح “dpi
“.
تعديل الصور
تكمن قوة وحدة Pillow في فائدتها في تعديل الصور. يتم تضمين العديد من دوال ما قبل وما بعد المعالجة للصور. أدناه، نلقي نظرة على بعض منها.
نقطة البداية الجيدة هي معرفة حجم صورتك. للقيام بذلك، ما عليك سوى استدعاء التابع size
على كائن Image
، والذي يُرجع صفًا بعرض الصورة وارتفاعها بالبكسل.
يمكنك إنشاء صور مصغرة تلقائيًا في لغة بايثون باستخدام التابع thumbnail()، وهو أمر مفيد إذا كنت تعمل في مجال إنتاج محتوى عبر الإنترنت. يستغرق الأمر size
كوسيطة – صف (width, height
) وresample
كوسيطة اختيارية. لرؤية مثال جيد، بما في ذلك كيفية القيام ببعض معالجة الأخطاء، راجع صفحة البرامج التعليمية في الوثائق.
إذا كنت تريد إعداد عدد كبير من الصور للطباعة، فمن المفيد تحويلها جميعًا إلى نسبة عرض إلى ارتفاع قياسية. تعمل نسبة العرض إلى الارتفاع على تغيير تكوين الصورة وكيفية رؤيتها. تعتبر نسبة العرض إلى الارتفاع 1:1 جيدة لصور الملف الشخصي، كما أن نسبة العرض إلى الارتفاع 3:2 أو 5:4 شائعة في التصوير الفوتوغرافي والمطبوعات الفنية.
لتغيير نسبة العرض إلى الارتفاع لصورك، يمكنك تجربة التابع resize
، والتي تتطلب منك تحديد أبعاد الارتفاع والعرض الجديدة بالبكسل. ومع ذلك، يؤدي ذلك إلى تشويه الصورة إذا تم استخدام نسبة عرض إلى ارتفاع مختلفة.
لا يعد قص الصور في لغة بايثون أكثر صعوبة من القيام بذلك باستخدام برنامج تحرير الصور. لإثبات ذلك، نحتاج أولاً إلى صورة ماعز صغير لطيف. نفترض أنه يحمل اسم “goat.jpg” ويتم حفظه في دليل العمل الخاص بك:
>>> from PIL import Image
>>> im = Image.open('goat.jgp')
>>> im.show()
كما ذكرنا من قبل، يؤدي هذا إلى فتح الصورة التالية في نافذة جديدة.

باستخدام طريقة size
في كائن Image
، نجد أن حجم الصورة هو (1124، 750)، مما يعطي نسبة عرض إلى ارتفاع تبلغ 3:2. يمكننا تغييرها إلى نسبة العرض إلى الارتفاع 1:1 كما يلي:
>>> height, width = 500, 500
>>> left, upper, right, lower = 60, 200, width+60, height+200
>>> cropped_image = im.crop((left, upper, right, lower))
>>> cropped_image.show()
يُنتج الكود أعلاه الصورة التالية، والتي تؤطر بشكل جيد هذا الرجل الصغير الرائع في المنتصف.

في الكود أعلاه، نحدد المتغيرات left
وupper
وright
وlower
، والتي تحدد إحداثيات البكسل للمنطقة المراد اقتصاصها. لاحظ أنه كان علينا تحديد ذلك يدويًا بحيث يتم تأطير الماعز بشكل جيد. ومع ذلك، من الممكن أتمتة ذلك عن طريق تحديد نقطة في الصورة واقتصاصها.
تأتي مكتبة Pillow مع العديد من الدوال المبرمجة مسبقًا والتي تساعدك على إبراز أفضل ما في صورك. يتضمن ذلك دوال لتحويل الصورة إلى تدرج رمادي ودوال لضبط السطوع والتباين والحدة. تم تضمينها في وحدتي ImageOps
وImageEnhance
.
دعونا نطبق عددًا قليلًا من هذه الدوال على كائن الصورة الذي تم اقتصاصه والذي حددناه أعلاه. نقوم بتحويل الصورة إلى تدرج رمادي ونعزز الحدة بعامل 1.2:
>>> from PIL import ImageOps, ImageEnhance
>>> im_gray = ImageOps.grayscale(cropped_image)
>>> im_sharp = ImageEnhance.Sharpness(im_gray).enhance(1.2)
>>> im_sharp.show()

توجد مجموعة أخرى مفيدة من الأدوات في وحدة ImageFilter
. ستجد بعض دوال معالجة الصور المفيدة إذا كنت مهتمًا بتعلم الآلة باستخدام بيانات الصورة.
كما قلنا من قبل، تعد لغة بايثون رائعة لمشاريع تعلم الآلة. على سبيل المثال، إذا كنت تقوم ببرمجة تطبيق لاكتشاف الكائنات، فإن استخدام EDGE_ENHANCE
أو FIND_EDGES
على الصور المدخلة قد يساعد في زيادة دقة تطبيقك. تحقق من الوثائق إذا كنت مهتمًا بالحصول على مزيد من المعلومات حول هذه المرشحات.
المزيد من معالجة الصور المتقدمة
عندما نقوم بتحميل صورتنا باستخدام وحدة Pillow، يتم تخزين قيم البكسل الفردية في بنية البيانات. وهذا يعني أنه يمكننا التعامل مع بكسل صورتنا ببكسل، مما يفتح مجموعة كاملة من الاحتمالات المثيرة للاهتمام مثل إنشاء مرشحات مخصصة.
يمكننا الوصول إلى قيم البكسل لصورتنا التي تم اقتصاصها على النحو التالي:
>>> pixels = list(cropped_image.getdata())
يقوم التابع get_data
بإرجاع كائن تسلسلي تم تسويته ليحتوي على قيم البكسل واحدة تلو الأخرى. المتغير pixels
عبارة عن قائمة من الصف، ويحتوي كل صف على قيم RGB لكل بكسل. يحتوي التابع على وسيط اختياري، النطاق، الذي يسمح لك بإرجاع نطاق واحد من صورة RGB من خلال توفير فهرس: 0 للنطاق “R”، و1 للنطاق “G”، و2 للنطاق “B” . يبلغ طول قائمة 250.000
pixels
، وهو ما يتوافق مع حجمها 500 × 500
(الارتفاع × العرض).
لنفترض أننا نريد إنشاء مرشح مخصص عن طريق تعديل قيم البكسل. لجعل ما نفعله هنا أكثر وضوحًا، نفصل القنوات باستخدام LIST COMPREHENSION ونعيد صياغتها كمصفوفات باستخدام NumPy:
>>> import numpy as np
>>> input_R = np.array([pix[0] for pix in pixels])
>>> input_G = np.array([pix[1] for pix in pixels])
>>> input_B = np.array([pix[2] for pix in pixels])
الآن، لإنشاء مرشح، نقوم بتعديل القنوات على النحو التالي:
>>> output_R = (input_R*0.6358) + (input_G*0.4614) + (input_B*0.1134)
>>> output_G = (input_R*0.2093) + (input_G*0.8116) + (input_B*0.1008)
>>> output_B = (input_R*0.1324) + (input_G*0.3204) + (input_B*0.4786)
دعونا نتأكد من أن النتيجة لها الشكل الصحيح (الارتفاع والعرض والقنوات):
>> new_pixels = np.array([output_R, output_G, output_B]).T.reshape(500, 500, 3)
في وضع RGB، يتم تمثيل كل قناة لون بعدد صحيح بين 0 و255. نحتاج إلى تحديد قيم البكسل في هذا النطاق ثم تحويل عناصر المصفوفة إلى نوع البيانات الصحيح:
>>> new_pixels[new_pixels>255]=255
>>> new_pixels = new_pixels.astype(np.uint8)
الخطوة الأخيرة هي تحويل مجموعة قيم البكسل إلى كائن Image
وإلقاء نظرة على عملنا الشاق:
>>> new_image = Image.fromarray(np.array(new_pixels))
>>> new_image.show()

أين أذهب من هنا؟
هناك المزيد حول Pillow مما يمكننا تغطيته في هذه المقالة. نود أن نشجعك على الاستفادة مما تعلمته هنا والبدء في تجربة صورك الخاصة. ربما يمكنك ابتكار مرشح الصور الخاص بك أو أتمتة المعالجة اللاحقة لصورك الفوتوغرافية.
وكما ذكرنا، يجب على علماء البيانات الطموحين استخدام هذا كأساس لبدء استكشاف تصنيف الصور أو اكتشاف الكائنات. حظ سعيد!
اكتشاف المزيد من بايثون العربي
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.