نظرة عامة على طرق تجزئة الصور في مكتبة صور scikit

العتبة


هذه هي أسهل طريقة لفصل الكائنات عن الخلفية عن طريق تحديد وحدات بكسل أعلى أو أسفل عتبة معينة. يكون هذا مفيدًا عادة عندما نذهب إلى تقسيم الكائنات حسب خلفيتها. يمكنك قراءة المزيد عن العتبة هنا .

ربما يتفق الأشخاص المطلعون على فيلم Terminator على أنه كان أعظم فيلم خيال علمي في تلك الحقبة. في الفيلم ، قدم جيمس كاميرون مفهومًا مثيرًا للاهتمام عن المؤثرات البصرية ، والذي سمح للمشاهدين بالاختباء خلف أعين سايبورغ تُسمى المنهي. أصبح هذا التأثير يُعرف باسم "رؤية المنهي" (رؤية المنهي الإنجليزية). بمعنى أنه فصل الصور الظلية للناس عن الخلفية. قد يبدو هذا غير مناسب تمامًا بعد ذلك ، ولكن تجزئة الصور جزء مهم من العديد من تقنيات معالجة الصور اليوم.

تجزئة الصورة


هناك عدد من المكتبات المكتوبة لتحليل الصور. في هذه المقالة ، سوف نناقش بالتفصيل scikit-image ، مكتبة معالجة الصور بيثون ، بالتفصيل.

Scikit الصورة


الصورة

Scikit-image هي مكتبة بيثون لمعالجة الصور.

التثبيت


تم تثبيت scikit-image على النحو التالي:

pip install -U scikit-image(Linux and OSX) pip install scikit-image(Windows) # For Conda-based distributions conda install scikit-image 



نظرة عامة على صورة بايثون


قبل أن ننتقل إلى الجوانب الفنية لتجزئة الصور ، من المهم أن نتعرف قليلاً على النظام البيئي لصور Scikit وكيفية معالجتها للصور.

استيراد GrayScale صورة من مكتبة skimage


تحتوي وحدة بيانات المقياس على العديد من الأمثلة المدمجة لمجموعات البيانات ، والتي يتم تخزينها عادة بتنسيق jpeg أو png.

 from skimage import data import numpy as np import matplotlib.pyplot as plt image = data.binary_blobs() plt.imshow(image, cmap='gray') 

استيراد صورة ملونة من مكتبة المقشود


 from skimage import data import numpy as np import matplotlib.pyplot as plt image = data.astronaut() plt.imshow(image) 



استيراد صورة من مصدر خارجي


 # The I/O module is used for importing the image from skimage import data import numpy as np import matplotlib.pyplot as plt from skimage import io image = io.imread('skimage_logo.png') plt.imshow(image); 



قم بتنزيل صور متعددة


 images = io.ImageCollection('../images/*.png:../images/*.jpg') print('Type:', type(images)) images.files Out[]: Type: <class 'skimage.io.collection.ImageCollection'> 

حفظ الصور


 #Saving file as 'logo.png' io.imsave('logo.png', logo) 

تجزئة الصورة


الآن بعد أن أصبح لدينا فكرة عن صورة scikit ، فإننا نعرض النظر في تفاصيل تجزئة الصورة. تجزئة الصورة هي عملية تقسيم صورة رقمية إلى عدة قطاعات من أجل تبسيط و / أو تغيير تمثيل الصورة إلى شيء أكثر جدوى وأسهل في التحليل.

في هذه المقالة ، سننظر في خوارزميات النماذج التي يتم تدريسها مع كل من المعلم (الخاضع للإشراف) وبدون معلم (غير خاضع للإشراف).


تتوفر بعض خوارزميات التجزئة في مكتبة صور scikit.

الفصل مع المعلم: يتم استخدام بعض المعرفة الأولية ، ربما من مدخلات بشرية ، لتوجيه الخوارزمية.

تجزئة دون معلم: المعرفة المسبقة ليست مطلوبة. تحاول هذه الخوارزميات تقسيم الصور تلقائيًا إلى مناطق مهمة. لا يزال بإمكان المستخدم تكوين معلمات معينة للحصول على النتائج المرجوة.

دعنا نجرب ذلك على صورة تعليميّة مصحوبة بمجموعة بيانات scikit-image محددة مسبقًا.

استيراد منتظم


 import numpy as np import matplotlib.pyplot as plt import skimage.data as data import skimage.segmentation as seg import skimage.filters as filters import skimage.draw as draw import skimage.color as color 

ميزة التصوير بسيطة

 def image_show(image, nrows=1, ncols=1, cmap='gray'): fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(14, 14)) ax.imshow(image, cmap='gray') ax.axis('off') return fig, ax 

الصورة


 text = data.page() image_show(text) 



هذه الصورة أغمق قليلاً ، لكن ربما لا يزال بإمكاننا اختيار قيمة ستمنحنا تجزئة معقولة دون أي خوارزميات معقدة. الآن ، لمساعدتنا في اختيار هذه القيمة ، سنستخدم رسم بياني.

في هذه الحالة ، يعرض الرسم البياني عدد البكسل في الصورة بكثافة مختلفة موجودة في هذه الصورة. ببساطة ، الرسم البياني هو رسم بياني يعرض فيه المحور X جميع القيم الموجودة في الصورة ، ويظهر المحور Y تردد هذه القيم.

 fig, ax = plt.subplots(1, 1) ax.hist(text.ravel(), bins=32, range=[0, 256]) ax.set_xlim(0, 256); 



تبين أن مثالنا هو صورة ذات 8 بت ، لذلك لدينا 256 قيمة ممكنة على طول المحور X. يوضح الرسم البياني أن هناك تركيز للبكسلات الساطعة إلى حد ما (0: أسود ، 255: أبيض). هذا على الأرجح خلفية نصية فاتحة للغاية ، لكن البقية ضبابية بعض الشيء. سيكون رسم بياني تجزيئي مثالي ثنائي النطاق حتى نتمكن من تحديد رقم في المنتصف مباشرةً. الآن دعونا نحاول إنشاء بعض الصور المقسمة استنادًا إلى قيمة حدية بسيطة.

العتبة التي تسيطر عليها


ونظرًا لأننا نختار قيمة الحد ، فإننا نسميها قيمة الحد المتحكم فيها.

 text_segmented = text > (value concluded from histogram ie 50,70,120 ) image_show(text_segmented); 


اليسار: النص> 50 | منتصف: النص> 70 | اليمين: النص> 120

لم نحصل على نتائج مثالية ، لأن الظل على اليسار يخلق مشاكل. دعونا نحاول مع العتبة غير المراقب الآن.

العتبة غير المنضبط


عتبة غير متحكم بها تحتوي Scikit-image على عدد من طرق تحديد العتبة التلقائية التي لا تتطلب إدخالًا عند اختيار الحد الأمثل. فيما يلي بعض الطرق: otsu، li، local.

 text_threshold = filters.threshold_ # Hit tab with the cursor after the underscore to get all the methods. image_show(text < text_threshold); 


اليسار أوتسو || الحق: لي

في حالة المحلية ، نحتاج أيضًا إلى تحديد block_size. يساعد الإزاحة في ضبط الصورة للحصول على نتائج أفضل.

 text_threshold = filters.threshold_local(text,block_size=51, offset=10) image_show(text > text_threshold); 



هذه الطريقة تعطي تأثير جيد. إلى حد كبير ، يمكن للمرء أن يتخلص من المناطق الصاخبة.

تجزئة مع خوارزمية لنموذج مع المعلم


تعد Thresholding عملية تجزئة بسيطة للغاية ، ولن تعمل بشكل صحيح على صورة عالية التباين ، والتي سنحتاج إلى أدوات أكثر تطوراً.

في هذا القسم ، سنستخدم مثالًا متوفرًا مجانًا ونحاول تقسيم الجزء الرئيسي باستخدام طرق مع المعلم.

 # import the image from skimage import io image = io.imread('girl.jpg') plt.imshow(image); 



قبل القيام بأي تجزئة للصور ، يوصى بإزالة الضوضاء منه باستخدام بعض المرشحات.

ومع ذلك ، في حالتنا ، لا تحتوي الصورة على ضوضاء كبيرة ، لذلك سوف نقبلها كما هي. الخطوة التالية هي تحويل الصورة إلى تدرج الرمادي باستخدام rgb2gray.

 image_gray = color.rgb2gray(image) image_show(image_gray); 



سوف نستخدم طريقتين للتقسيم تعملان على مبادئ مختلفة تمامًا.

تجزئة كفاف نشطة


يُطلق أيضًا على تجزئة المسار النشط ثعبان ويتم تهيئته باستخدام مسار محدد من قبل المستخدم أو خط حول منطقة مهمة ، ثم يتم ضغط هذا المسار ببطء وجذبه أو صده بواسطة الضوء والحواف.

على سبيل المثال لدينا صورة ، دعونا رسم دائرة حول رأس الإنسان لتهيئة الثعبان.

 def circle_points(resolution, center, radius): """ Generate points which define a circle on an image.Centre refers to the centre of the circle """ radians = np.linspace(0, 2*np.pi, resolution) c = center[1] + radius*np.cos(radians)#polar co-ordinates r = center[0] + radius*np.sin(radians) return np.array([c, r]).T # Exclude last point because a closed path should not have duplicate points points = circle_points(200, [80, 250], 80)[:-1] 

الحسابات أعلاه تحسب إحداثيات س و ص النقاط على محيط الدائرة. بما أننا قدمنا ​​قرارًا بقيمة 200 ، فسيتم حساب 200 نقطة من هذا القبيل.

 fig, ax = image_show(image) ax.plot(points[:, 0], points[:, 1], '--r', lw=3) 



تقوم الخوارزمية بعد ذلك بتقسيم وجه الشخص من بقية الصورة ، مع تركيب منحنى مغلق على حواف الوجه.



يمكننا تكوين معلمات تسمى alpha و beta. تؤدي قيم ألفا الأعلى إلى تقلص المنحنى بشكل أسرع ، في حين أن الإصدار التجريبي يجعل المنحنى أكثر سلاسة.

 snake = seg.active_contour(image_gray, points,alpha=0.06,beta=0.3) fig, ax = image_show(image) ax.plot(points[:, 0], points[:, 1], '--r', lw=3) ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3); 



تجزئة ووكر عشوائي


في هذه الطريقة ، يتم تنفيذ التجزئة باستخدام العلامات التفاعلية ، والتي تسمى العلامات. من خلال رسم كل بكسل على التسمية التي يتم احتساب أعلى الاحتمالات الخاصة بها ، يمكنك الحصول على تجزئة صورة عالية الجودة. يمكن العثور على مزيد من التفاصيل حول هذه الطريقة في هذا العمل.

بعد ذلك ، سوف نستخدم القيم السابقة مرة أخرى من مثالنا. كان بإمكاننا القيام بعمليات تهيئة مختلفة ، ولكن من أجل البساطة دعونا نتمسك بمبدأ الدوائر.

 image_labels = np.zeros(image_gray.shape, dtype=np.uint8) 

خوارزمية مرور عشوائي تقبل التسميات كمدخلات. وبالتالي ، سيكون لدينا دائرة كبيرة تغطي كامل وجه الشخص ، ودائرة أصغر أخرى بالقرب من منتصف الوجه.

 indices = draw.circle_perimeter(80, 250,20)#from here image_labels[indices] = 1 image_labels[points[:, 1].astype(np.int), points[:, 0].astype(np.int)] = 2 image_show(image_labels); 


الآن دعونا نستخدم Random Walker ونرى ما سيحدث.

 image_segmented = seg.random_walker(image_gray, image_labels) # Check our results fig, ax = image_show(image_gray) ax.imshow(image_segmented == 1, alpha=0.3); 



النتيجة ليست الأفضل ، بقيت حواف الوجه دون تحقيق. لتصحيح هذا الموقف ، يمكننا ضبط المعلمة مرور حتى نحصل على النتيجة المرجوة. بعد عدة محاولات ، قمنا بتعيين القيمة إلى 3000 ، والتي تعمل بشكل جيد للغاية.

 image_segmented = seg.random_walker(image_gray, image_labels, beta = 3000) # Check our results fig, ax = image_show(image_gray) ax.imshow(image_segmented == 1, alpha=0.3); 



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

تجزئة دون معلم


تجزئة دون معلم لا يتطلب معرفة مسبقة. ضع في اعتبارك صورة كبيرة جدًا بحيث يتعذر رؤية جميع وحدات البكسل مرة واحدة. وبالتالي ، في مثل هذه الحالات ، يمكن للتقسيم بدون معلم تقسيم الصورة إلى عدة مناطق فرعية ، لذا بدلاً من ملايين البكسل ، لديك عشرات أو مئات المناطق. دعونا نلقي نظرة على اثنين من هذه الخوارزميات:

التجميع الخطي البسيط البسيط


تستخدم الطريقة (التكتل الخطي البسيط الانجليزي أو SLIC) خوارزمية للتعلم الآلي تسمى K-Means. يستغرق كل قيم البكسل في الصورة ويحاول تقسيمها إلى عدد معين من النطاقات الفرعية. قراءة هذا العمل للحصول على معلومات مفصلة.

SLIC يعمل بألوان مختلفة ، لذلك سوف نستخدم الصورة الأصلية.

 image_slic = seg.slic(image,n_segments=155) 

كل ما نحتاج إلى القيام به هو ببساطة تحديد قيمة متوسطة لكل قطعة نجدها ، مما يجعلها تبدو كصورة.

 # label2rgb replaces each discrete label with the average interior color image_show(color.label2rgb(image_slic, image, kind='avg')); 



لقد قمنا بتقليل هذه الصورة من 512 * 512 = 262000 بكسل إلى 155 قطعة.

فيلزينزوالب


تستخدم هذه الطريقة أيضًا خوارزمية تعلم آلية تسمى تجميع الأشجار على الحد الأدنى الممتد. لا يخبرنا Felzenszwaib بالعدد الدقيق للمجموعات التي سيتم تقسيم الصورة إليها. سيولد العديد من المجموعات التي يراها مناسبة لذلك.

 image_felzenszwalb = seg.felzenszwalb(image) image_show(image_felzenszwalb); 



هناك العديد من المناطق في الصورة. دعونا نحسب عدد القطاعات الفريدة.

 np.unique(image_felzenszwalb).size 3368 

الآن ، دعونا نعيد تلوينها باستخدام متوسط ​​القيمة على القطعة ، كما فعلنا في خوارزمية SLIC.

 image_felzenszwalb_colored = color.label2rgb(image_felzenszwalb, image, kind='avg') image_show(image_felzenszwalb_colored); 

الآن نحصل على شرائح أقل. إذا أردنا شرائح أقل ، فيمكننا تغيير معلمة المقياس. هذا النهج يسمى أحيانا الإفراط في التجزئة.



هذا يشبه إلى حد كبير صورة مرسومة ، والتي هي في الأساس مجرد انخفاض في عدد الألوان. للجمع بينهما مرة أخرى (RAG).

الخاتمة


تجزئة الصور هي خطوة مهمة للغاية في معالجة الصور. هذا مجال نشط للبحث مع مجموعة متنوعة من التطبيقات ، تتراوح من رؤية الكمبيوتر إلى الصور الطبية وحركة المرور والمراقبة بالفيديو. يوفر Python مكتبة صور scikit قوية مع عدد كبير من خوارزميات معالجة الصور. وهي متوفرة مجانًا وبدون قيود ، والتي يدعمها مجتمع نشط. أوصي بأن تقرأ وثائقهم. يمكن الاطلاع على المقال الأصلي هنا .

Source: https://habr.com/ru/post/ar441006/


All Articles