پردازش تصویر دیجیتال به معنای پردازش دیجیتالی تصویر با کمک کامپیوتر است. با استفاده از پردازش تصویر می‌توانیم عملیاتی مانند بهبود تصویر، محو کردن تصویر، استخراج متن از تصاویر و بسیاری از عملیات‌های دیگر را انجام دهیم. روش های مختلفی برای پردازش تصاویر دیجیتالی وجود دارد که ما قصد داریم به ماژول Pillow پایتون بپردازیم. Pillow بر روی PIL (کتابخانه تصویر پایتون) ساخته شده است. Pillow از بسیاری از فرمت های فایل تصویری از جمله BMP، PNG، JPEG و TIFF پشتیبانی می کند. Pillow به صورت پیش فرض همراه پایتون ارایه نمی شود و خودتان باید آن را نصب کنید. برای نصب آن دستور زیر را در ترمینال تایپ کنید:

pip install pillow

باز کردن و نمایش تصویر

به عنوان اولین برنامه قصد داریم یک فایل تصویری را باز کنیم و نمایش دهیم. برنامه به این صورت است:

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
img.show()

نتیجه اجرای برنامه به شکل زیر است:

pillow

در خط اول کلاس Image را از ماژول PIL وارد می کنیم. این کلاس برای باز کردن، دستکاری و ذخیره فایل های تصویری به کار می رود.

خط دوم ماژول OS را وارد می کند که راهی برای تعامل با سیستم عامل فراهم می کند.

خط سوم مسیر مطلق دایرکتوری حاوی اسکریپت پایتون را که در حال حاضر اجرا می شود، دریافت می کند. از آنجا که فایل تصویری را در فولدر حاوی برنامه پایتون ذخیره کرده ایم به این مسیر نیاز خواهیم داشت.

خط چهارم فایل تصویری به نام kara.jpeg را در دایرکتوری مشخص شده توسط currentDir باز می کند. متد Image.open یک شی Image را که تصویر را نشان می دهد برمی گرداند که نام آن را img گذاشته ایم.

خط آخر با استفاده از نمایشگر تصویر پیش فرض سیستم عامل شما، تصویر را در یک پنجره جدید نمایش می دهد.

چرخاندن تصویر

در این بخش می خواهیم تصاویر را با زوایای مختلف بچرخانیم و خروجی مربوطه را بررسی کنیم. با استفاده از تابع rotate برای چرخاندن تصویر 90 درجه شروع می کنیم.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
rotated_image = img.rotate(90)
rotated_image.show()

با اجرای برنامه بالا شکل زیر نمایش داده می شود:

pillow

همان طور که می بینید بعد از چرخش عکس شامل حاشیه های مشکی است و همچنین بخشهایی از تصویر برش خورده است. حالا بیایید عکس را 90 درجه بچرخانیم و هم زمان از تابع expand استفاده کنیم.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
rotated_image = img.rotate(90, expand = 1)
rotated_image.show()

آنچه که تابع Expand اساسا انجام می دهد، تعویض ابعاد ارتفاع و عرض است. اگر یک تصویر را بچرخانید، مرزهای ارتفاع و عرض تغییر نمی کند. این باعث می‌شود بخشی از تصویر بریده شوند و قسمت‌هایی سیاه شود که تصویر دیگر در آن قرار ندارد. تفاوت تصویر نهایی را می توانید ببینید:

pillow

برعکس کردن تصویر

برای برگرداندن تصویر در Python Pillow، می‌توانید از متد transpose کلاس Image استفاده کنید.

برای برعکس کردن یک تصویر به صورت افقی، از ثابت Image.Transpose.FLIP_LEFT_RIGHT به عنوان آرگومان برای transpose استفاده می کنیم.

برای چرخاندن یک تصویر به صورت عمودی، از ثابت Image.Transpose.FLIP_TOP_BOTTOM به عنوان آرگومان برای transpose استفاده می کنیم.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
horizontal_flipped = img.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
horizontal_flipped.show()
vertical_flipped = img.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
vertical_flipped.show()
pillow
pillow

ذخیره تصویر در فرمت های مختلف

حالا بیایید تصویری که 90 درجه چرخاندیم را در فرمت bmp ذخیره کنیم.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
rotated_image = img.rotate(90, expand = 1)
rotated_image.save(currentDir + '/kara.bmp')

پیدا کردن اندازه تصویر

پیدا کردن اندازه یک تصویر با استفاده از pillow کار ساده ای است که در برنامه زیر مشخص شده است:

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
print(img.size)

تغییر اندازه تصویر

برنامه زیر یک فایل تصویری را باز می کند و اندازه آن را تغییر می دهد:

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
resized_image = img.resize((400,300))
resized_image.show()

نتیجه را در زیر می بینید:

خط پنجم اندازه تصویر را به عرض 400 پیکسل و ارتفاع 300 پیکسل تغییر می دهد. متد resize یک شی Image جدید را برمی گرداند که نشان دهنده تصویر تغییر یافته است. نام آن را resized_image گذاشته ایم.

اگر دقت کنید نسبت عرض به ارتفاع تصویر جدید کمی متفاوت است. این باعث ایجاد اعوجاج جزئی می شود که کیفیت را خراب می کند. یک راه ساده برای حفظ نسبت ابعاد این است که هر دو بعد را با یک مقدار یا کسری ضرب کنیم.

در مثال زیر، با فراخوانی مستقیم ویژگی‌های عرض و اندازه برای تصویر، و ضرب آنها در 0.5، ابعاد را به طور دقیق  نصف کرده‌ایم.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
resized_image = img.resize((round(img.width * 0.5), round(img.height * 0.5)))
resized_image.show()

همان طور که می بینید تنها خط مربوط به resize تغییر کرده است.

برش تصویر

برش یکی از عملیات های مهم پردازش تصویر برای حذف بخش های ناخواسته یک تصویر است.

تابع crop کلاس image در Pillow تصویر را به صورت مستطیل برش می دهد. قسمت مستطیلی که باید از یک تصویر برش داده شود به عنوان یک تاپل چهار عنصری مشخص می شود و قسمت مستطیلی تصویر را که برش داده شده است به عنوان یک شی تصویر برمی گرداند.

گوشه سمت چپ بالا در تصویر اولیه مختصات (0، 0) دارد. مثال زیر نحوه برش تصویر با استفاده از pillow پایتون را نشان می دهد:

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
left = 100
right = 700
top = 200
bottom = 600
cropped_image = img.crop((left, top, right, bottom))
cropped_image.show()

شکل برش خورده به صورت زیر دیده می شود:

pillow

تغییر حالت عکس:

فرض کنید که قصد داریم یک عکس رنگی را به خاکستری یا grayscale تبدیل کنیم. برای این کار باید از تابع convert استفاده نماییم:

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
new_img = img.convert('L')
new_img.show()

نتیجه به شکل زیر دیده می شود:

pillow

به جای ‘L’ می توان هر یک از مقادیر زیر را قرار داد:

1: پیکسل های 1 بیتی، سیاه و سفید

L: پیکسل های 8 بیتی، در مقیاس خاکستری

P: پیکسل های 8 بیتی، با استفاده از یک پالت رنگ به هر حالت دیگری نگاشت شده است

RGB: پیکسل 3×8 بیت، رنگ واقعی

RGBA: پیکسل 4×8 بیت، رنگ واقعی با ماسک شفافیت

CMYK: پیکسل های 4×8 بیتی، تفکیک رنگ

YCbCr: پیکسل 3×8 بیت، فرمت ویدیوی رنگی

LAB: پیکسل های 3×8 بیتی، فضای رنگی Lab

HSV: پیکسل های 3×8 بیتی، رنگ، اشباع، فضای رنگی مقدار

I: پیکسل های عدد صحیح بدون 32 بیتی

F: پیکسل های اعشاری 32 بیتی

چسباندن یک عکس روی عکس دیگر

تابع paste در کتابخانه Pillow به ما این امکان را می دهد که یک تصویر را روی دیگری قرار دهیم. می توان از آن به عنوان راهی برای ترکیب دو تصویر با هم در یک تصویر استفاده نمود.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
background = Image.open(currentDir + '/kara.jpeg')
foreground = Image.open(currentDir + '/logo.png')
background.paste(foreground, (100, 200))
background.show()

برنامه بالا لوگو را روی عکس پس زمینه قرار می دهد طوری که گوشه بالای چپ لوگو در مختصات 100و200 پس زمینه قرار بگیرد.

pillow

حالا فرض کنیم که تصویر لوگو دارای پس زمینه شفاف یا transparent باشد. اگر از برنامه زیر استفاده کنیم لوگو بدون نمایش زمینه سفید روی پس زمینه قرار خواهد گرفت.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
background = Image.open(currentDir + '/kara.jpeg')
foreground = Image.open(currentDir + '/transparent-logo.png')
foreground = foreground.convert("RGBA")
background.paste(foreground, (100, 200), foreground)
background.show()
pillow

در paste باید تصویر را با پس زمینه شفاف به پارامتر سوم منتقل کنیم. توجه کنید که موقع استفاده از convert از RGB استفاده نکرده ایم، بلکه از RGBA استفاده کرده ایم. حرف “A” نشان دهنده کانال آلفا است که شفافیت را کنترل می کند.

اعمال یک تابع بر روی پیکسلهای یک تصویر

متد point در pillow هر پیکسل از یک تصویر را از طریق تابعی که یک آرگومان واحد می گیرد، نگاشت می کند. سپس جدول به دست آمده بر روی تمام باندهای تصویر اعمال می شود.

در برنامه زیرمتد point بر روی یک شی image فراخوانی می شود و هر پیکسل تصویر را از طریق تابعی که آن را در 0.5 ضرب می کند، تغییر می دهد. تصویر حاصل در یک متغیر جدید به نام new_image ذخیره می شود.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
def my_func(i):
    return i * 0.5
new_image = img.point(my_func)
new_image.show()
pillow

اعمال فیلتر روی تصویر

نسخه فعلی کتابخانه مجموعه زیر از فیلترهای بهبود تصویر از پیش تعریف شده را ارائه می دهد:

·  BLUR

·  CONTOUR

·  DETAIL

·  EDGE_ENHANCE

·  EDGE_ENHANCE_MORE

·  EMBOSS

·  FIND_EDGES

·  SHARPEN

·  SMOOTH

·  SMOOTH_MOR

در اینجا یکی از فیلترها را روی تصویر اعمال می کنیم.

from PIL import Image, ImageFilter
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
filtered_image = img.filter(ImageFilter.GaussianBlur(2))
filtered_image.show()
pillow

همان طور که می بینید در ابتدای برنامه ImageFilter را هم به برنامه اضافه کرده ایم. در خط پنجم می توان با تغییر دادن عددی که به GaussianBlur می دهیم محوشدگی تصویر نهایی را کم و زیاد کنیم.

تغییر باندهای رنگی RGB

برای تغییر باندهای رنگی یک تصویر در Pillow، می‌توانید از متد split کلاس Image استفاده کنید تا تصویر را به باندهای رنگی جداگانه تقسیم کنید، باند دلخواه را تغییر دهید و سپس باندها را دوباره با هم ادغام کنید. در اینجا مثالی از نحوه انجام این کار آورده شده است:

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
r, g, b = img.split()
r = r.point(lambda x: 0)
new_img = Image.merge("RGB", (r, g, b))
new_img.show()
pillow

در این مثال، از متد split برای تقسیم تصویر به باندهای رنگی جداگانه استفاده می شود. سپس از متد point برای اصلاح باند قرمز با تنظیم تمام مقادیر پیکسل آن بر روی 0 استفاده می شود. در نهایت، متد merge برای ادغام باندهای اصلاح شده با هم در یک تصویر جدید استفاده می شود.

تغییر کنتراست تصویر

برای تغییر کنتراست تصویر در Python Pillow می توانید از ماژول ImageEnhance استفاده کنید. در اینجا مثالی از نحوه انجام این کار آورده شده است:

from PIL import Image, ImageEnhance
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
enhancer = ImageEnhance.Contrast(img)
new_img = enhancer.enhance(1.5)
new_img.show()
pillow

در این مثال از متد ImageEnhance.Contrast برای ایجاد یک ارتقادهنده کنتراست برای تصویر استفاده شده است. سپس از متد () enhance برای افزایش کنتراست تصویر با ضریب 1.5 استفاده می شود. در نهایت از متد show برای نمایش تصویر اصلاح شده استفاده می شود.

می توانید کنتراست تصویر را با تغییر فاکتور ارسال شده به متد () enhance تنظیم کنید. ضریب 1 تصویر اصلی را نشان می دهد، در حالی که فاکتورهای کمتر به معنای کنتراست کمتر و فاکتورهای بالاتر به معنای کنتراست بیشتر است.

تغییر روشنایی تصویر

برای تغییر روشنایی تصویر در Pillow نیز می توانید از ماژول ImageEnhance استفاده کنید. در اینجا مثالی از نحوه انجام این کار آورده شده است:

from PIL import Image, ImageEnhance
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
enhancer = ImageEnhance.Brightness(img)
new_img = enhancer.enhance(1.8)
new_img.show()

معکوس کردن تصویر

برای معکوس کردن یا invert کردن تصویر باید از ImageOps.invert استفاده نمود و برای این کار لازم است در ابتدای برنامه ImageOps را نیز وارد برنامه کنیم. در زیر می توانید یک برنامه نمونه برای معکوس کردن رنگ تصاویر را مشاهده کنید:

from PIL import Image , ImageOps
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
inverted_img = ImageOps.invert(img)
inverted_img.show()
pillow

اضافه کردن متن به تصویر

با استفاده از Pillow می توانید به راحتی متن را روی تصاویر خود قرار دهید. ماژول ImageDraw یک راه ساده برای نمایش اطلاعات روی تصاویر ارائه می دهد. در اینجا یک مثال آورده شده است:

from PIL import Image, ImageDraw, ImageFont
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('arial.ttf', size=100)
draw.text((100, 20), 'Hello Karakit!', fill=(0, 0, 0), font=font)
img.show()
pillow

خط اول برنامه ماژول های لازم را از کتابخانه Pillow وارد می کند: Image، ImageDraw و ImageFont.

خط پنجم یک شی Draw از تصویر با استفاده از متد ImageDraw.Draw ایجاد می کند و آن را به متغیر draw اختصاص می دهد.

خط ششم با استفاده از متد ImageFont.truetype یک شی Font ایجاد می کند و آن را به فونت متغیر اختصاص می دهد. فونت استفاده شده در اینجا arial.ttf با سایز 100 است.

خط هفتم متن “Hello Karakit!” را روی تصویر در موقعیت (100، 20) با استفاده از متد Draw.text نمایش می دهد. متن با رنگ مشکی (0، 0، 0) پر شده و فونت آن arial.ttf با سایز 100 است.

استخراج مقادیر رنگی یک پیکسل در یک تصویر

گاهی اوقات لازم است مشخصات یک یا چند پیکسل در یک تصویر را برای پردازش تصویر استخراج کنیم. با استفاده از برنامه زیر می توان مقادیر رنگی قرمز و سبز و آبی یک پیکسل را استخراج کرد:

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
pixel_value = img.getpixel((300,200))
print(pixel_value)

در برنامه بالا مقادیر رنگی پیکسل با طول 300 و عرض 200 با استفاده از getpixel استخراج شده و در pixel_value ذخیره می شود.

تغییر رنگ یک پیکسل در تصویر

همان طور که می توانیم مقادیر رنگی یک تصویر را استخراج کنیم، می توانیم مقادیر رنگی یک پیکسل را تغییر بدهیم. در برنامه زیر یک نقطه مشکی روی پیکسل با طول 20 و عرض 20 قرار داده می شود.

from PIL import Image
import os
currentDir=os.path.dirname(os.path.abspath(__file__))
img = Image.open(currentDir + '/kara.jpeg')
img.putpixel((20,20),(0,0,0))
img.show()

این کار با استفاده از تابع putpixel و مشخص کردن مکان پیکسل مورد نظر و رنگ دلخواه انجام می شود.

تولید تصویر با استفاده از مقادیر عددی

در پایتون می توان از روش fromarray برای تبدیل آرایه های NumPy به تصویر PIL استفاده نمود.

در اینجا یک نمونه کد ارایه شده است که نحوه ایجاد یک تصویر 64 x 64 بنفش رنگ از یک آرایه NumPy را نشان می دهد:

import numpy as np
from PIL import Image
arr = np.zeros((64, 64, 3), dtype=np.uint8)
arr[:, :, 0] = 255  # Red
arr[:, :, 1] = 0  # Green
arr[:, :, 2] = 255  # Blue
img = Image.fromarray(arr)
img.show()

در این مثال ابتدا یک آرایه NumPy با ابعاد 64 x 64 x 3 ایجاد می کنیم و آن را با مقادیر صفر پر می کنیم. ابعاد 64 x 64 بابت ابعاد تصویر و 3 برای باندهای رنگی قرمز و سبز و آبی است.

سپس قسمت مربوط به رنگ قرمز را با مقادیر 255، قسمت مربوط به رنگ سبز را با مقادیر 0 و قسمت مربوط به رنگ آبی را با مقادیر 255 پر می کنیم.

در مرحله بعد آرایه NumPy را با استفاده از روش fromarray به یک تصویر PIL تبدیل می کنیم. در نهایت با استفاده از متد show() تصویر را نمایش می دهیم.

pillow

آموزش های پردازش تصویر با Pillow