Python حرفه‌ای: پردازش تصاویر چیست؟

Professional Python: Image Processing

24 اسفند 1399
درسنامه درس 25 از سری پایتون حرفه‌ای
Python حرفه ای: پردازش تصاویر چیست؟ (قسمت 25)

Image Processing چیست؟

scripting یا اسکریپت نویسی همان کدنویسی است؛ یعنی ما با استفاده از قدرت کامپیوترها کار خاصی را اسکریپت نویسی می کنیم تا کامپیوتر آن را به صورت خودکار برایمان انجام بدهد. ما در این مقاله و مقالات بعدی به چندین و چند مثال مختلف از اسکریپت نویسی نگاهی می اندازیم و پروژه های کوچکی را انجام خواهیم داد. اولین پروژه ما image processing یا پردازش تصویر است. یک مثال ساده و قابل درک از پردازش تصویر، اینستاگرام است. زمانی که شما یک تصویر را در حساب کاربری خودتان پست می کنید، اینستاگرام این تصویر را از شما گرفته و پردازش می کند (به طور مثال اگر حجم بسیار زیادی داشته باشد، آن را فشرده سازی می کند یا اگر سایز مناسبی نداشته باشد قسمت های اضافه را کات می کند و الی آخر).

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

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

تقریبا تمام وب سایت های موجود در اینترنت این کار را انجام می دهند و در سرورهای خود منطقی از پردازش تصاویر را دارند.

نصب کتابخانه pillow

طبیعتا زمانی که صحبت از پردازش تصاویر می شود به کتابخانه ای نیاز داریم که با استفاده از آن، کار خود را انجام بدهیم. پردازش تصاویر به صورت دستی و بدون هیچ کتابخانه ای، تقریبا غیرممکن است چرا که باید همه چیز را از صفر نوشته و ماه ها زمان روی یک پروژه ساده بگذاریم. یکی از محبوب ترین کتابخانه های پایتون برای پردازش تصاویر، کتابخانه pillow است و ما می خواهیم از آن در این بخش استفاده کنیم. برای نصب این کتابخانه ابتدا به صفحه pillow.readthedocs.io/en/stable/installation.html مراجعه می کنیم. در این صفحه توصیه شده است که ابتدا نسخه PIP خود را با دستور زیر به روز رسانی کنیم. حتما می دانید که باید این دستور را در ترمینال (یا CMD برای کاربران ویندوز) وارد کنید:

python3 -m pip install --upgrade pip

با اجرای این دستور ممکن است نتیجه زیر را بگیرید:

Collecting pip

Downloading pip-20.3.3-py2.py3-none-any.whl (1.5 MB)

|████████████████████████████████| 1.5 MB 191 kB/s

Installing collected packages: pip

Successfully installed pip-20.3.3

این گزارش به معنی به روز رسانی PIP است. در مرحله بعدی با دستور زیر کتابخانه pillow را نصب می کنیم:

python3 -m pip install --upgrade Pillow

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

مهارت یادگیری ۶#

به بخش ششم از سری مهارت یادگیری خوش آمدید. این بخش در ارتباط با انتخاب کتابخانه درست است! منظور ما از کتابخانه درست چیست؟ ما در بخش قبلی کتابخانه pillow را نصب کردیم اما باید اطلاعاتی از این کتابخانه را داشته باشیم. به صفحه نصب pillow به آدرس زیر بروید:

pillow.readthedocs.io/en/stable/installation.html

در این صفحه چند warning (هشدار) را مشاهده می کنید که یکی از آن ها به شکل زیر است:

Pillow and PIL cannot co-exist in the same environment. Before installing Pillow, please uninstall PIL.

ترجمه: Pillow و PIL نمی توانند به صورت همزمان در یک محیط توسعه وجود داشته باشند. لطفا قبل از نصب Pillow، کتابخانه PIL را حذف کنید.

چرا این هشدار را دریافت کرده ایم؟ به صفحه اصلی Pillow به آدرس زیر بروید:

pillow.readthedocs.io/en/stable/

در خط اول این صفحه توضیح خلاصه ای درباره این کتابخانه مشاهده می کنید:

Pillow is the friendly PIL fork by Alex Clark and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.

این پاراگراف می گوید Pillow یک Fork از PIL است. یعنی چه؟ هم در همین پاراگراف و هم در اینترنت توضیح داده شده است که PIL مخفف Python Imaging Library یکی از کتابخانه های قدیمی زبان پایتون است و زمانی که پایتون ۳ معرفی شد، این کتابخانه به روز رسانی نشد اما Fork کردن یک کتابخانه یعنی چه؟ در برنامه های متن بازی که روی گیت هاب یا گیت لب میزبانی می شوند، گزینه ای به نام fork وجود دارد که به زبان ساده به معنی کپی کردن کل آن کتابخانه برای خودتان است تا هر نوع تغییری را که دوست دارید در آن کتابخانه ایجاد کنید. اینجاست که آقای Alex Clark کتابخانه قدیمی PIL را fork کرده و آن را به پایتون ۳ به روز رسانی می کند.

چرا این مسائل را به شما توضیح دادم؟ به دلیل اینکه با همین توضیحات ساده متوجه می شویم که این کتابخانه قدمتی طولانی دارد بنابراین زمان زیادی روی بهینه سازی و حل مشکلات احتمالی آن صرف شده است. همچنین اگر به اطلاعات صفحه اصلی توجه کنیم می بینیم که 8 هزار ستاره در گیت هاب داشته و ماهانه ۱۳ میلیون بار دانلود می شود. همچنین با بررسی صفحه گیت هاب Pillow می بینیم که آخرین commit (آخرین ویرایش کد) در زمان نگارش این مقاله ۱۷ ژانویه ۲۰۲۱ بوده است بنابراین کتابخانه دائما به روز شده و روی آن کار می شود.

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

استفاده از کتابخانه pillow

با اینکه پردازش تصاویر در برنامه هایی مانند فتوشاپ نیز انجام می شود اما ما نمی توانیم فتوشاپ را روی سرور خود نصب کرده و از آن برای این کار استفاده کنیم بلکه نیاز به کد داریم. همچنین برنامه هایی مانند فتوشاپ به شدت سنگین بوده و سرور ما را درگیر می کنند. کتابخانه Pillow از نظر سرعت و بهینه بودن صد ها قدم از فتوشاپ جلوتر است. من برای شروع کار پوشه ای به نام image-processing را ایجاد می کنم و در آن فایلی به نام main.py را می سازم، سپس در کنار این فایل پوشه ای دیگر به نام pics را ایجاد می کنم که داخلش چند تصویر ساده باشد. شما می توانید از هر تصویری که دوست داشتید استفاده کنید (من چهار تصویر با فرمت jpg دارم).

در قدم اول باید وارد main.py شده و کتابخانه pillow را در آن وارد کنیم:

from PIL import Image

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

from PIL import Image

 

img = Image.open('./pics/pic1.jpg')

 

print(img)

ما از متد open در Image استفاده کرده ایم که آدرس تصویر مورد نظر ما را گرفته و آن را باز می کند. با اجرای کد بالا نتیجه زیر را می گیرید:

<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=260x240 at 0x7F1013C81B20>

همانطور که می بینید یک شیء PIL برایمان برگردانده شده است. این شیء حاوی اطلاعات مختلفی برای ما است که می توانیم از آن استفاده کنیم. به طور مثال اگر بخواهیم فرمت تصویر خود را پیدا کنیم، می گوییم:

from PIL import Image

 

img = Image.open('./pics/pic1.jpg')

 

print(img.format)

خصوصیت format حاوی رشته ای از فرمت فایل است. با اجرای این کد عبارت JPEG برایمان برگردانده می شود که همان فرمت فایل ما است. اطلاعات دیگری نیز بدین شکل وجود دارد:

from PIL import Image

 

img = Image.open('./pics/pic1.jpg')

 

print(img.format)

print(img.size)

print(img.mode)

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

JPEG

(260, 240)

RGB

JPEG فرمت فایل، 260 × 240 ابعاد تصویر ما در پیکسل و نهایت RGB حالت رنگی تصویر است. در صورتی که یادتان باشد تابعی به نام dir را به شما معرفی کردم که تمام خصوصیات و متدهای اشیاء را به ما نشان می داد: dir. بنابراین می توانیم این تابع را روی img صدا بزنیم:

from PIL import Image

 

img = Image.open('./pics/pic1.jpg')

 

print(dir(img))

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

['_Image__transformer', '__array_interface__', '__class__', '__copy__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_close_exclusive_fp_after_loading', '_copy', '_crop', '_dump', '_ensure_mutable', '_exclusive_fp', '_exif', '_expand', '_get_safe_box', '_getexif', '_getmp', '_min_frame', '_new', '_open', '_repr_png_', '_seek_check', '_size', 'alpha_composite', 'app', 'applist', 'bits', 'category', 'close', 'convert', 'copy', 'crop', 'custom_mimetype', 'decoderconfig', 'decodermaxblock', 'draft', 'effect_spread', 'entropy', 'filename', 'filter', 'format', 'format_description', 'fp', 'frombytes', 'get_format_mimetype', 'getbands', 'getbbox', 'getchannel', 'getcolors', 'getdata', 'getexif', 'getextrema', 'getim', 'getpalette', 'getpixel', 'getprojection', 'height', 'histogram', 'huffman_ac', 'huffman_dc', 'icclist', 'im', 'info', 'layer', 'layers', 'load', 'load_djpeg', 'load_end', 'load_prepare', 'load_read', 'mode', 'palette', 'paste', 'point', 'putalpha', 'putdata', 'putpalette', 'putpixel', 'pyaccess', 'quantization', 'quantize', 'readonly', 'reduce', 'remap_palette', 'resize', 'rotate', 'save', 'seek', 'show', 'size', 'split', 'tell', 'thumbnail', 'tile', 'tobitmap', 'tobytes', 'toqimage', 'toqpixmap', 'transform', 'transpose', 'verify', 'width']

این نتیجه، لیستی از تمام خصوصیات و متدهای موجود در img است. در بین این خصوصیات، مقادیری مثل mode و size را نیز می بینید. شما می توانید تمام این خصوصیات و متدها را در documentation رسمی پکیج Pillow پیدا کرده و آن ها را مطالعه کنید اما ما طبیعتا وقت چنین کاری را نداریم.

در مرحله بعدی باید از قسمت ImageFilter پکیج Pillow استفاده کنیم. این بخش به ما اجازه اعمال فیلترهای مختلفی را روی تصاویر می دهد! به طور مثال من می خواهم یکی از تصاویر خودم را مات کنم. برای این کار به شکل زیر عمل می کنیم:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic1.jpg')

 

filtered_image = img.filter(ImageFilter.BLUR)

 

filtered_image.save("blur.png", "png")

من در این قسمت ابتدا تصویر اصلی را باز کرده و در متغیر img قرار داده ام. در مرحله بعدی متغیری به نام filtered_image را ایجاد کرده ایم تا تصویر مات شده را در خود ذخیره کند. من در این قسمت img.filter را صدا زده ام که کارش اعمال یک فیلتر (افکت خاص) روی تصویر است. فیلترهای این پکیج از قبل تعریف شده و متعلق به ImageFilter هستند. من BLUR (بلوری یا مات کردن تصویر) را انتخاب کرده ام. با این کار فیلتر ما اعمال می شود اما روی تصویری که در مموری سیستم بارگذاری شده است! برای اینکه این تصویر مات شده را از مموری به هارد دیسک انتقال بدهیم باید متد save را روی آن صدا بزنیم. متد save دو آرگومان می گیرید: نام فایل به همراه پسوند آن + نوع فایل. توجه داشته باشید که پسوند فایل لزوما به معنای نوع فایل نیست چرا که به صورت دستی قابل ویرایش است. در صورتی که شما یک فایل را انتخاب کرده و پسوند آن را تغییر بدهید، در ماهیت و نوع این فایل تغییری ایجاد نمی شود. به همین دلیل است که باید نوع فایل را به صورت آرگومان دوم پاس بدهیم. با ارجای این کد یک تصویر جدید به نام blur.png در کنار فایل main.py ساخته می شود. با باز کردن این فایل متوجه تفاوت اساسی بین این دو می شوید. فیلترهای دیگری مانند SHARPEN و SMOOTH نیز وجود دارند و شما می توانید لیست کاملی از آن ها را از documentation پیدا کنید.

نکته: فیلترهای Pillow در فایل های png پشتیبانی می شوند اما در فایل های jpg بی اثر هستند. به همین دلیل است که در کد بالا، نتیجه را در یک فایل png ذخیره کرده ام.

تابع convert

یکی از توابع موجود در این کتابخانه، تابع convert است که کارش تبدیل تصویر ما به قالب های خاص است. به طور مثال اگر بخواهیم تصویر خود را به صورت grayscale (بدون رنگ) در بیاوریم می توانیم پارامتر L را به آن پاس بدهیم:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic1.jpg')

 

filtered_image = img.convert("L")

 

filtered_image.save("grayscale.png", "png")

با اجرای این کد تصویر جدیدی به نام grayscale.png را دریافت می کنیم که با باز کردن آن متوجه عدم وجود رنگ می شویم (تصویر سیاه و سفید خواهد بود).

تابع show

تابع show همانطور که از نامش مشخص است برای باز کردن و نمایش دادن تصویر است.  به مثال زیر توجه کنید:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic1.jpg')

 

filtered_image = img.convert("L")

 

filtered_image.show()

من در این کد دیگر از متد save استفاده نکرده ام. چرا؟ به دلیل اینکه دیگر نمی خواهم این تصویر را در هارد دیسک خودم ذخیره کنم بلکه می خواهم آن را مستقیما نمایش بدهم. با اجرای این کد image viewer سیستم عامل شما باز شده و تصویر را مشاهده می کنید. من نمی خواهم تک تک فیلترهایی که روی تصویر اعمال می کنیم در هارد دیسک ذخیره شوند بنابراین از اینجا به بعد (به غیر از موارد خاص) از show به جای save استفاده می کنم.

تابع rotate

تابع rotate به شما اجازه می دهد یک تصویر را بچرخانید. به عنوان مثال به کد زیر توجه کنید:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic1.jpg')

 

filtered_image = img.rotate(90)

 

filtered_image.show()

همانطور که می بینید من عد ۹۰ را به تابع rotate داده ام بنابراین تصویر ما ۹۰ درجه در جهت خلاف عقربه های ساعت خواهد چرخید. توجه داشته باشید که شما باید درجه چرخش را حتما به صورت یک عدد و نه یک رشته به rotate پاس بدهید. همچنین در صورتی که می خواهید جهت چرخش در جهت عقربه های ساعت باشد باید عدد را به شکل منفی پاس بدهید:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic1.jpg')

 

filtered_image = img.rotate(-90)

 

filtered_image.show()

توابع resize و thumbnail

احتمالا از نام resize حدس زده اید که کار این تابع تغییر سایز تصویر است. تصویری که من با آن کار می کنم یک تصویر کوچک در ابعاد ۲۴۰ × ۲۶۰ است اما من می خواهم آن را کمی بزرگ تر کنم بنابراین از تابع resize استفاده می کنم:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic1.jpg')

 

filtered_image = img.resize((780, 720))

 

filtered_image.show()

همانطور که می بینید تابع resize یک tuple را می گیرد که به ترتیب width و height (عرض و ارتفاع) تصویر را مشخص می کنند. من در این کد ساده اندازه تصویر خود را تا 780 در 720 بزرگ تر کرده ام. چرا از این اعداد خاص استفاده کرده ام؟ به دلیل اینکه این اعداد مقدار سه برابر شده ابعاد اصلی (۲۶۰ در ۲۴۰) هستند و من می خواهم نسبت طول و عرض تصویر را حفظ کنم تا تصویر کشیده به نظر نرسد. شما می توانید برای تست این موضوع کد زیر را اجرا کنید:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic1.jpg')

 

filtered_image = img.resize((500, 800))

 

filtered_image.show()

این کد کار می کند و تصویر را برایتان برمی گرداند اما دیگر نسبت طول و عرض رعایت نشده است بلکه تصویر شما به شدت زشت می شود. در صورتی که می خواهید در هنگام resize کردن همیشه نسبت طول و عرض (aspect ratio) تصویر را حفظ کنیم، می توانیم از تابع thumbnail استفاده کنیم که کار اصلی آن تولید تصاویر بند انگشتی است. البته باید توجه داشته باشید که متد thumbnail نمی تواند تصویر را از اندازه فعلی اش بزرگ تر کند (این کار منحصر به resize است) بنابراین:

from PIL import Image, ImageFilter



img = Image.open('./pics/pic1.jpg')

 

img.thumbnail((2000, 2000))

img.show()

با اینکه من سایز بزرگ ۲۰۰۰ پیکسل را به این تصویر داده ام،‌ با اجرای کد بالا تصویری به ما نمایش داده می شود که سایز آن 240 × 260 است (همان سایز اولیه تصویر). چرا؟ اعدادی که به thumbnail می دهید سایز دقیق تصویر نیستند بلکه حداکثر اندازه تصویر هستند. در مثال بالا ما گفته ایم که عرض یا طول  را روی ۲۰۰۰ پیکسل قرار می دهیم. تابع thumbnail خودش با بررسی سایز تصویر و نسبت طول و عرض (aspect ratio) اندازه صحیح را انتخاب کرده و تصویر شما را تولید می کند. در ضمن در نظر داشته باشید که متد thumbnail چیزی را برنمی گرداند بلکه همان تصویر اصلی را ویرایش می کند. همچنین باید توجه داشت که مسئولیت thumbnail تولید فایل های بند انگشتی است بنابراین ماهیتا با resize متفاوت است.

تابع crop

کراپ کردن یا برش زدن تصاویر با resize متفاوت است. در هنگامی که تصویری را resize می کنیم (حتی در صورتی که نسبت طول و عرض را بهم بزنیم) هیچ پیکسلی از تصویر حذف نمی شود اما در عملیات کراپ دقیقا به دنبال همین کار هستیم. برای درک بهتر می توانید یک تکه کاغذ را فرض کنید؛ در صورتی که آن را تا بزنید یا مچاله کنید resize انجام داده اید اما در صورتی که آن را با قیچی برش بزنید یعنی آن را crop کرده اید. به مثال زیر توجه کنید:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic1.jpg')

 

box = (100, 100, 400, 400)

 

filtered_image = img.crop(box)

 

filtered_image.show()

اعدادی که در tuple بالا (box) مشاهده می کنید به ترتیب نقاط چپ پایین، بالا، راست و نهایتا پایین هستند. این نقاط به موقعیت خاص یک پیکسل اشاره می کنند بنابراین از تفاوت آن ها متوجه می شویم که طول و عرض تصویر کراپ شده ۳۰۰ پیکسل خواهد بود (۱۰۰ - ۴۰۰).  با اجرای این کد تصویر کراپ شده خود را مشاهده خواهید کرد.

فشرده سازی تصاویر

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

من برای این بخش یک تصویر بزرگ (۴ مگابایت حجم و ۵۰۰۰ هزار پیکسل عرض) را آماده کرده ام. شما نیز می توانید با مراجعه به اینترنت و جست و جو برای تصاویر 4K و با کیفیت چنین تصویری را برای خود آماده کنید. اگر بخواهیم این تصویر را کوچک تر کنیم چه کار باید انجام بدهیم؟ طبیعتا اولین پاسخ ما استفاده از resize است تا عرض آن را از 5000 پیکسل کمتر کنیم:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic5.jpg')

 

resized_image = img.resize((1870, 1779))

 

resized_image.save('resized_image.jpg', 'JPEG')

با اجرای این کد تصویر جدید من با حجم 140 کیلوبایت ذخیره می شود در حالی که قبلا 4 مگابایت حجم داشت! آیا علاوه بر resize کردن راه دیگری برای کاهش حجم آن وجود دارد؟ بله! دو راه دیگر نیز داریم که می توانیم با resize ترکیب کنیم اما قبل از آن می خواهم در مورد نکته خاصی صحبت کنم.

ما می توانیم در هنگام resize کردن از فیلتر ANTIALIAS استفاده کنیم.  وظیفه ANTIALIAS نرم تر کردن تصویر و جلوگیری از ضمخت شدن زاویه های تند تصویر است تا کاهش کیفیت نامحسوس تر باشد بنابراین کمی سایز تصویر را بالا می برد اما یکی دو کیلوبایت برای ما اهمیتی ندارد.

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic5.jpg')

 

resized_image = img.resize((1870, 1779), Image.ANTIALIAS)

 

resized_image.save('resized_image.jpg', 'JPEG')

با اجرای این کد حجم تصویر من از 149 کیلوبایت به 151 کیلوبایت می رسد. حالا می توانیم در مورد دو روش دیگر برای کاهش سایز تصویر صحبت کنیم. اولین نکته این است که باید optimize را در هنگام save پاس بدهیم تا کتابخانه Pillow چند بار پیکسل ها را بررسی کند و در صورت امکان آن ها را به صورت بهینه تری فشرده کند:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic5.jpg')

 

resized_image = img.resize((1870, 1779), Image.ANTIALIAS)

 

resized_image.save('resized_image.jpg', 'JPEG', optimize=True)

تصویر ما قبل از اجرای این کد ۱۵۱ کیلوبایت بود و پس از اجرای این کد ۱۳۳ کیلوبایت است! به همین سادگی تصویر خود را بهینه سازی کرده ایم. طبیعتا اگر این کار را برای هزاران تصویر انجام بدهیم، فضای زیادی را حفظ می کنیم.

آخرین روشی که می توانیم با آن کیفیت تصویر را تغییر بدهیم، گزینه quality یا «کیفیت» تصویر است. این خصوصیت به صورت پیش فرض روی 75 قرار دارد که یعنی کیفیت تصویر در هنگام resize نباید افت شدیدی داشته باشد اما معمولا می توانیم بدون آنکه کیفیت تصویر به طور محسوسی افت داشته باشد، آن را تا مقادیر بیشتری نیز پایین بیاوریم. به مثال زیر توجه کنید:

from PIL import Image, ImageFilter

 

img = Image.open('./pics/pic5.jpg')

 

resized_image = img.resize((1870, 1779), Image.ANTIALIAS)

 

resized_image.save('resized_image.jpg', 'JPEG', optimize=True, quality=55)

من در این قسمت quality را روی ۵۵ گذاشته ام. با اجرای این کد تصویری با حجم 85 کیلوبایت دریافت می کنیم که کیفیت بدی ندارد. به همین سادگی توانسته ایم حجم تصاویر خود را کاهش بدهیم.

نکته: در کتابخانه Pillow کیفیت تصاویر بین ۹۵ (بهترین کیفیت) تا ۱ (بدترین کیفیت) می باشد و همانطور که گفتم مقدار پیش فرض ۷۵ است. توصیه می شود هیچ گاه کیفیت بالاتر از ۹۵ را انتخاب نکنید چرا که کیفیت هایی مانند ۱۰۰ باعث غیر فعال شدن الگوریتم های فشرده سازی در JPEG می شوند و نتیجه یک فایل بسیار بزرگ خواهد بود که تفاوت چندانی با کیفیت های زیر ۹۵ ندارد.

تمرین برای جلسه بعدی

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

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری پایتون حرفه‌ای توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.