آموزش کامل پیرامون تحلیل مولفههای متصل و تابع Connected Components در OpenCV
در علوم کامپیوتر و به ویژه در نظریه گرافها، Connected Components یا اجزای متصل به گروههایی از رئوس در یک گراف گفته میشود که به یکدیگر از طریق یالها متصل هستند. به عبارت دیگر، هر جفت راس در یک جزء متصل به طور مستقیم یا غیرمستقیم از طریق مسیرهایی به هم مرتبط هستند و هیچ راسی خارج از این جزء وجود ندارد که به یکی از این رئوس متصل باشد. در پردازش تصویر، این مفهوم به شناسایی نواحی متصل از پیکسلها در تصاویر باینری اطلاق میشود که در آن پیکسلهای مجاور با ویژگیهای مشابه (مانند رنگ یا شدت نور) به عنوان یک ناحیه متصل در نظر گرفته میشوند. Connected Components برای کاربردهایی مانند تشخیص اشیا، تحلیل تصویر و جداسازی نواحی مختلف به کار میرود.
در فیلم زیر مفهوم تئوری این الگوریتم و کاربرد آن در پردازش تصویر و بینایی کامپیوتر بیان شده است.
این ویدیو بخشی از آموزش پردازش تصویر و بینایی ماشین با OpenCV است.
تحلیل مولفههای متصل در OpenCV
یکی از عملیاتهای اساسی در پردازش تصویر، تشخیص و جداسازی نواحی متصل در تصویر است. Connected Components به بخشهایی از تصویر اشاره دارد که به هم متصل بوده و میتوان آنها را به عنوان یک ناحیه یا گروه تشخیص داد. این مفهوم برای کاربردهای مختلفی از جمله تشخیص اشیا، استخراج ویژگیها و تحلیل تصویر بسیار مفید است.
در OpenCV، دو تابع پرکاربرد برای تشخیص نواحی متصل وجود دارد، تابع connectedComponents
و تابع connectedComponentsWithStats
است. این تابع علاوه بر شناسایی بخشهای متصل در تصویر، آمار و اطلاعات مفیدی از هر بخش ارائه میدهد. در ویدیوی زیر تابع connectedComponents و اثر تعداد همسایه آموزش داده شده است.
تابع connectedComponentsWithStats چیست؟
تابع connectedComponentsWithStats در OpenCV برای یافتن و برچسبگذاری نواحی متصل (connected components) در تصاویر باینری استفاده میشود. این تابع نواحی متصل را شناسایی کرده و سپس هر ناحیه را با یک برچسب مجزا مشخص میکند. علاوه بر این، این تابع اطلاعات آماری مانند اندازه و مختصات هر ناحیه را فراهم میکند.
ساختار و سینتکس تابع
تابع connectedComponentsWithStats
به صورت زیر تعریف میشود:
retval, labels, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity, ltype)
پارامترها:
- image: تصویر ورودی. این تصویر باید باینری (سیاه و سفید) باشد، به طوری که پیکسلهای غیرصفر به عنوان بخشهای متصل شناسایی شوند.
- connectivity: مقدار اتصال بین پیکسلها را مشخص میکند. این پارامتر میتواند مقدار 4 یا 8 باشد. اتصال 4 فقط پیکسلهایی که به صورت عمودی یا افقی به هم وصل شدهاند را در نظر میگیرد، در حالی که اتصال 8 شامل اتصالات مورب نیز میشود.
- ltype: نوع دادهای برچسبها. معمولاً
cv2.CV_32S
برای این پارامتر استفاده میشود.
مقادیر خروجی:
- retval: تعداد نواحی متصل شناسایی شده (از جمله پسزمینه).
- labels: تصویری که در آن هر پیکسل به یکی از نواحی متصل شناسایی شده تخصیص داده شده است. هر ناحیه با یک عدد برچسب یکتا نشان داده میشود.
- stats: یک ماتریس حاوی اطلاعات آماری هر ناحیه. هر سطر این ماتریس به یکی از نواحی متصل اختصاص دارد و ستونهای آن به ترتیب شامل اطلاعات زیر هستند:
- x: مختصات x بالای مستطیلی که ناحیه متصل را محصور کرده است.
- y: مختصات y بالای مستطیل.
- width: عرض مستطیل محصور کننده.
- height: ارتفاع مستطیل.
- area: مساحت ناحیه متصل.
- centroids: مرکز هر ناحیه متصل که شامل مختصات x و y است.
کاربردها
تشخیص و جداسازی نواحی متصل در تصاویر باینری در بسیاری از کاربردهای پردازش تصویر مفید است. برخی از این کاربردها عبارتند از:
- تشخیص اشیا: شناسایی و ردیابی اشیا در تصاویر.
- تقسیمبندی تصویر: جداسازی بخشهای مختلف تصویر برای تحلیلهای بیشتر.
- استخراج ویژگیها: یافتن ویژگیهای هندسی و آماری هر بخش متصل.
نمونه کد 1
import matplotlib.pyplot as plt import numpy as np import cv2 img = cv2.imread("images/shapes.png", 0) _, img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) num_labels, labels = cv2.connectedComponents(img) # Map component labels to hue val, 0-179 is the hue range in OpenCV label_hue = np.uint8(179*labels/np.max(labels)) blank = np.ones_like(img) * 255 labeled_img = cv2.merge([label_hue, blank, blank]) # Converting cvt to BGR labeled_img = cv2.cvtColor(labeled_img, cv2.COLOR_HSV2BGR) # set bg label to black labeled_img[label_hue==0] = 0 plt.figure(figsize=[10,8]) plt.subplot(121);plt.imshow(img, cmap='gray');plt.title("Original"); plt.subplot(122);plt.imshow(labeled_img, cmap='gray');plt.title("labeled image");
منبع کد: https://github.com/Alireza-Akhavan/class.vision/blob/master/25-Connected_components.ipynb
کد ارائه شده برای شناسایی و برچسبگذاری نواحی متصل در یک تصویر باینری به کار میرود و نتایج را به صورت تصویری نمایش میدهد. در این کد:
- تصویر ورودی به صورت خاکستری خوانده میشود و به تصویر باینری تبدیل میشود.
- نواحی متصل در تصویر شناسایی شده و برچسبگذاری میشوند.
- برچسبها به مقادیر رنگی تبدیل میشوند تا هر ناحیه متصل با رنگ متفاوتی نمایش داده شود.
- تصویر نهایی با رنگهای مختلف برای نواحی متصل ایجاد شده و پسزمینه سیاه میشود.
- در نهایت، تصویر اصلی و تصویر برچسبگذاری شده در کنار هم با استفاده از Matplotlib نمایش داده میشوند.
این کد به شما امکان میدهد تا نواحی متصل در تصویر را به راحتی شناسایی و تحلیل کنید. در نهایت خروجی کد به ازای این تصویر، تصویر زیر خواهد بود:
نمونه کد 2
این کد برای مقایسه دو نوع اتصال نواحی متصل (4-اتصال و 8-اتصال) در یک تصویر باینری استفاده میشود
import matplotlib.pyplot as plt import numpy as np import cv2 img = cv2.imread("images/small-connected-test.png", 0) _, img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) _, labels_with_4_connectivity = cv2.connectedComponents(img, connectivity=4) _, labels_with_8_connectivity = cv2.connectedComponents(img, connectivity=8) label_hue4 = np.uint8(179*labels_with_4_connectivity/np.max(labels_with_4_connectivity)) label_hue8 = np.uint8(179*labels_with_8_connectivity/np.max(labels_with_8_connectivity)) blank = np.ones_like(img) * 255 labeled_img4 = cv2.merge([label_hue4, blank, blank]) labeled_img8 = cv2.merge([label_hue8, blank, blank]) # Converting cvt to BGR labeled_img4 = cv2.cvtColor(labeled_img4, cv2.COLOR_HSV2BGR) labeled_img8 = cv2.cvtColor(labeled_img8, cv2.COLOR_HSV2BGR) # set bg label to black labeled_img4[label_hue4==0] = 0 labeled_img8[label_hue8==0] = 0 plt.figure(figsize=[10,8]) plt.subplot(131);plt.imshow(img, cmap='gray');plt.title("Original"); plt.subplot(132);plt.imshow(labeled_img4, cmap='gray');plt.title("labeled image with 4 connectivity"); plt.subplot(133);plt.imshow(labeled_img8, cmap='gray');plt.title("labeled image with 8 connectivity");
منبع کد: https://github.com/Alireza-Akhavan/class.vision/blob/master/25-Connected_components.ipynb
مراحل انجام شده در این کد به شرح زیر است:
- خواندن تصویر: تصویر ورودی به صورت خاکستری (Grayscale) خوانده میشود.
- آستانهگذاری (Thresholding): تصویر به باینری تبدیل میشود، به طوری که پیکسلهایی که مقدار آنها بیشتر از 127 است سفید (255) و بقیه سیاه (0) میشوند.
- شناسایی نواحی متصل:
- یکبار با استفاده از 4-اتصال: در این حالت فقط پیکسلهایی که به صورت افقی یا عمودی به هم متصل هستند به عنوان یک ناحیه در نظر گرفته میشوند.
- یکبار با استفاده از 8-اتصال: در این حالت پیکسلهایی که به صورت افقی، عمودی یا مورب به هم متصل هستند به عنوان یک ناحیه متصل در نظر گرفته میشوند.
- تبدیل برچسبها به مقادیر رنگی: برای نمایش نواحی مختلف متصل، برچسبهای هر ناحیه به مقادیر رنگی (Hue) در فضای رنگ HSV تبدیل میشوند.
- ترکیب تصاویر: تصویر برچسبگذاری شده (Hue) با یک تصویر سفید (Saturation و Value) ترکیب شده و سپس به فضای رنگی BGR تبدیل میشود تا قابل نمایش باشد.
- تنظیم پسزمینه: پسزمینه (نواحی با برچسب 0) به رنگ سیاه تنظیم میشود.
- نمایش تصاویر: تصویر اصلی، تصویر برچسبگذاری شده با 4-اتصال و تصویر برچسبگذاری شده با 8-اتصال در کنار هم به وسیله
matplotlib
نمایش داده میشوند.
این کد به شما امکان درک 8 یا 4 همسایه در این الگوریتم را میدهد. در نهایت خروجی کد به ازای این تصویر، تصویر زیر خواهد بود:
هدف:
این کد به شما نشان میدهد که چگونه انتخاب نوع اتصال (4 یا 8) میتواند بر روی شناسایی نواحی متصل در تصویر تأثیر بگذارد.
نمونه کد 3
این تتصویر را در نظر بگیرید:
آدرس تصویر: https://github.com/Alireza-Akhavan/SRU-deep-1402/blob/master/images/persian-digits.jpg?raw=true
اگر بخواهیم این اعداد را به کمک الگوریتمهای هوش مصنوعی نظیر یادگیری ماشین و دیپ لرنینگ تشخیص بدهیم، گام اول استخراج نواحی هر عدد است، کد زیر در راستای این هدف، ناحیه هر عدد روی کاغذ را استحراج میکند:
import cv2 import numpy as np # Read the input image (make sure it's a binary image) image = cv2.imread('images/persian-digits.jpg', cv2.IMREAD_GRAYSCALE) # Apply thresholding to create a binary image _, binary_image = cv2.threshold(image, 128, 255, cv2.THRESH_BINARY) binary_image = 255-binary_image # Use connectedComponentsWithStats to obtain labels and bounding boxes num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image, connectivity=8) # Iterate through each connected component for label in range(1, num_labels): # Get the bounding box of the current connected component x, y, w, h = stats[label][:4] # Crop the connected component using the bounding box connected_component = image[y:y+h, x:x+w] # Display or save the cropped connected component cv2.imshow(f'Cropped Component {label}', connected_component) cv2.waitKey(0) cv2.destroyAllWindows()
منبع کد: https://github.com/Alireza-Akhavan/SRU-deep-1402/blob/master/Connected_components.ipynb
این کد برای پردازش و تحلیل تصویر باینری طراحی شده و به شما امکان میدهد نواحی متصل را شناسایی و برش دهید. مراحل کلی کد به شرح زیر است:
- خواندن تصویر: تصویر ورودی به صورت خاکستری (Grayscale) خوانده میشود. این تصویر باید باینری باشد، به این معنی که پیکسلها یا سفید (255) یا سیاه (0) هستند.
- تبدیل به تصویر باینری: با استفاده از آستانهگذاری، تصویر به صورت باینری تبدیل میشود. سپس، تصویر باینری معکوس میشود تا نواحی مورد نظر (اشیاء) به رنگ سفید و پسزمینه به رنگ سیاه درآید.
- شناسایی نواحی متصل: تابع connectedComponentsWithStats برای شناسایی و برچسبگذاری نواحی متصل در تصویر باینری استفاده میشود. این تابع همچنین اطلاعات آماری مانند مختصات و ابعاد هر ناحیه را ارائه میدهد.
- برش نواحی متصل: برای هر ناحیه متصل، از روی اطلاعات آماری (مستطیل محصور کننده) آن ناحیه را برش میدهیم.
- نمایش نواحی برشخورده: نواحی برشخورده به صورت جداگانه نمایش داده میشود. هر ناحیه با یک پنجره جداگانه به نمایش در میآید.
این کد به شما امکان میدهد تا نواحی متصل در تصویر را شناسایی کنید و هر کدام را به صورت مجزا بررسی و تحلیل کنید.
دیدگاهتان را بنویسید