تشخیص لبه در پایتون – به زبان ساده
در این مطلب، مباحث تئوری و پیادهسازی تشخیص لبه در پایتون (Edge Detection in Python) همراه با ارائه مثالهایی، مورد بررسی قرار گرفته است.
دلایل تشخیص لبه
اولین پرسشی در این راستا مطرح میشود این است که «چرا باید تشخیص لبه انجام داد؟». صرف نظر از جالب بودن کار تشخیص لبه، دلیل مفید بودن این کار چیست؟
برای پاسخ به این پرسش، تصویر زیر از یک فرفره کاغذی و تصویر دیگری که در آن فقط لبههای تصویر مشخص هستند، ارائه شده است.
میتوان مشاهده کرد که تصویر اصلی در سمت چپ، رنگها و سایههای گوناگونی دارد؛ در حالی که تصویری که در آن فقط لبههای فرفره کاغذی نمایش داده شدهاند، سیاه و سفید است. اگر این پرسش طرح شود که کدام تصویر نیازمند فضای ذخیرهسازی بیشتری است، اغلب افراد تصویر اصلی را انتخاب خواهند کرد. این انتخاب، یک انتخاب کاملا معنادار است. با تشخیص لبههای یک تصویر، از بسیاری از جزئیات تصویر صرفنظر میشود. همین امر، موجب سبکتر شدن تصویر مربوط به لبهها (سیاه و سفید) میشود. بنابراین، تشخیص لبه به طور خاص هنگامی که کاربر تمایلی به نگهداری جزئیات پیچیده تصویر ندارد و صرفا شکل کلی موجود در تصویر برای اون حائز اهمیت است، مفید محسوب میشود.
روش انجام تشخیص لبه
پیش از پیادهسازی کد مربوط به تشخیص لبه در پایتون، ابتدا ریاضیات نهفته در پس انجام این کار مورد بررسی قرار میگیرد. انسانها در کار تشخیص لبههای یک تصویر عملکرد بسیار خوبی دارند، اما چطور میتوان به یک کامپیوتر یاد داد که کار مشابهی را انجام دهد؟
ابتدا، میتوان یک تصویر که در آن یک مربع سیاه در میان یک پس زمینه سفید قرار گرفته است، فرض کرد.
در این مثال، در نظر گرفته میشود که هر پیکسل مقداری بین ۰ (سیاه) و ۱ (سفید) دارد. بنابراین، در حال حاضر فقط با تصویر سیاه و سفید کار خواهد شد. نظریه کاملا مشابهی، روی تصاویر رنگی نیز قابل اعمال است. اکنون، فرض میشود که کاربر در تلاش است تا مشخص کند که آیا پیکسل مشخص شده با رنگ سبز، جزوی از این تصویر است یا خیر. انسانها به سادگی پاسخ این پرسش را میدانند و فورا پاسخ مثبت خواهند داد. اما چطور میتوان از پیکسلهای موجود در همسایگی استفاده کرد تا به کامپیوتر کمک شود که به نتیجهای مشابه آنچه انسان رسیده است، برسد. یک مربع کوچک ۳ × ۳ از پیکسلهای محلی که پیکسل سبز رنگ در وسط آن قرار دارد، در نظر گرفته میشود. این مربع، به رنگ قرمز نمایش داده شده است. سپس، فیلتری روی این مربع کوچک اعمال میشود.
فیلتری که اعمال میشود، در تصویر بالا نمایش داده شده است و در نگاه اول، کمی عجیب به نظر میرسد. اما در ادامه، عملکرد آن مورد بررسی قرار خواهد گرفت. در ادامه این مطلب، هر گاه گفته شود که «فیلتر روی مربع محلی کوچک متشکل از پیکسلها اعمال شود» بدین معنا است که هر پیکسل موجود در مربع محلی قرمز رنگ در هر پیکسل موجود در فیلتر به صورت «درایهای» (Element-Wise) ضرب میشود. بنابراین، پیکسل موجود در سمت چپ بالا در مربع قرمز، برابر با ۱ است. این در حالی است که پیکسل موجود در سمت چپ بالا در فیلتر، برابر با ۱- است؛ بنابراین، حاصل ضرب این دو با یکدیگر، برابر با ۱- است که میتوان آن را در بالا و سمت چپ مربع نتیجه، مشاهده کرد. سایر پیکسلهای موجود در مربع نتیجه نیز به همین ترتیب به دست آمدهاند.
گام بعدی، جمع کردن پیکسلهای موجود در مربع نتیجه است که خروجی ۴- را به دست میدهد. شایان توجه است که ۴- در واقع کوچکترین مقداری است که میتوان با اعمال این فیلتر به دست آورد (زیرا پیکسلها فقط میتوانند ۰ و ۱ باشند). بنابراین، پیکسل مورد پرسش، بخشی از لبه عمودی بالایی است. زیرا مقدار کمینه ۴- حاصل شده است.
میتوان مشاهده کرد که نتایج نسبتا مشابهی حاصل شده است، با این تفاوت که مجموع مقادیر نتیجه، برابر با ۴ است. ۴ بیشترین مقداری است که میتوان با اعمال این فیلتر به دست آورد. بنابراین، مشخص میشود که پیکسل در لبه عمودی پایینی قرار دارد؛ زیرا پس از اعمال فیلتر، بیشترین مقدار ۴ به دست آمده است. برای نگاشت مجدد این مقادیر به بازه ه و ۱، هر یک از ارقام با ۴ جمع و سپس بر ۸ تقسیم میشوند. بدین شکل، ۴- به ۰ (مشکی) و ۴ به ۱ (سفید) نگاشت میشود. بنابراین، با استفاده از این فیلتر که به آن «فیلتر عمودی سوبل» (Vertical Sobel Filter) گفته میشود، میتوان به سادگی لبههای عمودی موجود در تصویر را پیدا کرد.
برای لبههای افقی چه کاری میتوان انجام داد؟ به سادگی، ترانهاده فیلتر عمودی اعمال میشود و این فیلتر جدید برای شناسایی مرزهای افقی روی تصویر اعمال میشود. اکنون، اگر هدف تشخیص مرزهای افقی، مرزهای عمودی و مرزهایی است که در میان اینها قرار دارند، میتوان امتیازهای افقی و عمودی را به صورتی که در کد زیر آمده است محاسبه کرد.
پیادهسازی تشخیص لبه در پایتون
ابتدا، تنظیمات اولیه انجام میشود.
1%matplotlib inline
2
3import numpy as np
4import matplotlib.pyplot as plt
5
6#define the vertical filter
7vertical_filter = [[-1,-2,-1], [0,0,0], [1,2,1]]
8
9#define the horizontal filter
10horizontal_filter = [[-1,0,1], [-2,0,2], [-1,0,1]]
11
12#read in the pinwheel image
13img = plt.imread('pinwheel.jpg')
14
15#get the dimensions of the image
16n,m,d = img.shape
17
18#initialize the edges image
19edges_img = img.copy()
در کد موجود، میتوان «pinwheel.jpg» (اسم تصویر مربوط به فرفره) را با هر تصویر جالب دیگری که کاربر تمایل به پیدا کردن مرزهای آن دارد، جا به جا کرد. همچنین، باید اطمینان حاصل کرد که این تصویر در پوشهای مشابه با پوشه کاری جاری قرار دارد. در ادامه، خود کد مربوط به تشخیص لبه (Edge Detection) ارائه شده است.
1%matplotlib inline
2
3import numpy as np
4import matplotlib.pyplot as plt
5
6#define the vertical filter
7vertical_filter = [[-1,-2,-1], [0,0,0], [1,2,1]]
8
9#define the horizontal filter
10horizontal_filter = [[-1,0,1], [-2,0,2], [-1,0,1]]
11
12#read in the pinwheel image
13img = plt.imread('pinwheel.jpg')
14
15#get the dimensions of the image
16n,m,d = img.shape
17
18#initialize the edges image
19edges_img = img.copy()
20
21#loop over all pixels in the image
22for row in range(3, n-2):
23 for col in range(3, m-2):
24
25 #create little local 3x3 box
26 local_pixels = img[row-1:row+2, col-1:col+2, 0]
27
28 #apply the vertical filter
29 vertical_transformed_pixels = vertical_filter*local_pixels
30 #remap the vertical score
31 vertical_score = vertical_transformed_pixels.sum()/4
32
33 #apply the horizontal filter
34 horizontal_transformed_pixels = horizontal_filter*local_pixels
35 #remap the horizontal score
36 horizontal_score = horizontal_transformed_pixels.sum()/4
37
38 #combine the horizontal and vertical scores into a total edge score
39 edge_score = (vertical_score**2 + horizontal_score**2)**.5
40
41 #insert this edge score into the edges image
42 edges_img[row, col] = [edge_score]*3
برخی از نکاتی که باید به آنها توجه داشت، در ادامه بیان شدهاند.
- با توجه به اینکه نمیتوان به طور کامل یک مربع محلی ۳ × ۳ را روی پیکسلهای حاشیه ساخت، یک حاشیه کوچک اطراف تصویر وجود خواهد داشت.
- با توجه به آنکه تشخیص روی مرزهای افقی و عمودی انجام میشود، امتیاز سطرها فقط تقسیم بر ۴ میشود (به جای آنکه ۴ واحد به آن اضافه و سپس، کل عدد بر ۸ تقسیم شود). این تغییر بزرگی نیست، اما میتواند لبههای تصویر را بهتر مشخص کند.
- ترکیب امتیازهای افقی و عمودی ممکن است موجب شود که امتیاز لبه نهایی خارج از طیف ۰ و ۱ باشد، بنابراین، کار با نرمالسازی مجدد امتیازها پایان پیدا میکند.
- کد بالا روی یک تصویر پیچیدهتر نیز اعمال شده است که در ادامه، میتوان این تصویر و نسخه تشخیص لبه داده شده از آن را مشاهده کرد.
تصویری که در آن، لبهها تشخیص داده شدهاند را میتوان در ادامه مشاهده کرد.
اگر نوشته بالا برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای دادهکاوی و یادگیری ماشین
- آموزش دادهکاوی در متلب
- مجموعه آموزشهای هوش مصنوعی
- تشخیص لبخند در چهره — راهنمای کاربردی
- آموزش یادگیری ماشین با مثالهای کاربردی ــ بخش چهارم
- بازشناسی تصویر با Keras و شبکههای عصبی پیچشی — راهنمای کاربردی
- بازشناسی گفتار (Speech Recognition) با پایتون — از صفر تا صد
^^