وبلاگ رسانگار
با ما حرفه ای باشید

سرور مجازی NVMe

OpenCV Thresholding در پایتون با cv2.threshold()

0 60
زمان لازم برای مطالعه: 5 دقیقه


معرفی

Thresholding یک تکنیک ساده و کارآمد برای انجام تقسیم بندی اولیه در یک تصویر و باینریزه کردن آن (تبدیل آن به یک تصویر باینری) است که در آن پیکسل ها یا 0 یا 1 (یا 255 اگر از اعداد صحیح برای نشان دادن آنها استفاده می کنید).

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

if pixel_value > threshold:
    pixel_value = MAX
else:
    pixel_value = 0

این ضروری است process به عنوان شناخته شده است آستانه باینری. اکنون – راه های مختلفی وجود دارد که می توانید این ایده کلی را تغییر دهید، از جمله معکوس کردن عملیات (تغییر کردن > با a امضا کنید < علامت)، تنظیم pixel_value به threshold به جای حداکثر مقدار/0 (معروف به کوتاه کردن)، حفظ مقدار pixel_value خودش اگر بالاتر از threshold یا اگر زیر آن باشد threshold.

همه اینها به راحتی در OpenCV پیاده سازی شده اند:

  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV

… به ترتیب. این‌ها روش‌های نسبتاً ساده‌ای هستند، زیرا نسبتاً ساده هستند، زمینه را در تصاویر در نظر نمی‌گیرند، اطلاعاتی در مورد اشکال رایج دارند و غیره. برای این ویژگی‌ها – ما باید از نظر محاسباتی بسیار گران‌تر و قدرتمندتر استفاده کنیم تکنیک.

اکنون، حتی با روش های “ساده لوحانه” – مقداری برای یافتن آستانه های خوب، می توان اکتشافی را به کار برد، که شامل روش Otsu و روش مثلث می شود:

  • cv2.THRESH_OTSU
  • cv2.THRESH_TRIANGLE

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

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

آستانه گذاری ساده با OpenCV

آستانه گذاری در OpenCV پایتون API از طریق انجام می شود cv2.threshold() روش – که یک تصویر (آرایه NumPy، نشان داده شده با اعداد صحیح)، آستانه، حداکثر مقدار و روش آستانه را می پذیرد (چگونه threshold و maximum_value استفاده می شود):

img = cv2.imread('objects.jpg')

img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)


blurred = cv2.GaussianBlur(img, (7, 7), 0)

ret, img_masked = cv2.threshold(blurred, 220, 255, cv2.THRESH_BINARY)

کد بازگشتی فقط آستانه اعمال شده است:

print(f"Threshold: {ret}") 

در اینجا، از آنجایی که آستانه است 220 و ما از آن استفاده کرده ایم THRESH_BINARY روش – هر مقدار پیکسل بالا 220 افزایش خواهد یافت 255، در حالی که هر پیکسل زیر است 220 به پایین خواهد آمد 0، ایجاد یک تصویر سیاه و سفید، با یک “ماسک”، پوشش اشیاء پیش زمینه.

چرا 220؟ دانستن اینکه تصویر چگونه به نظر می رسد به شما امکان می دهد تا حدس هایی تقریبی در مورد آستانه ای که می توانید انتخاب کنید، انجام دهید. در عمل، به ندرت می خواهید یک آستانه دستی تنظیم کنید، و ما انتخاب آستانه خودکار را در یک لحظه پوشش خواهیم داد.

بیایید نتیجه را ترسیم کنیم! پنجره‌های OpenCV ممکن است کمی مشکل باشند، بنابراین تصویر اصلی، تصویر تار و نتایج را با استفاده از Matplotlib ترسیم می‌کنیم:

fig, ax = plt.subplots(1, 3, figsize=(12, 8))
ax(0).imshow(img)
ax(1).imshow(blurred)
ax(2).imshow(img_masked)

OpenCV Thresholding در پایتون با cv2.threshold()

روش های آستانه گذاری

همانطور که قبلا ذکر شد، روش‌های مختلفی وجود دارد که می‌توانید از مقدار آستانه و حداکثر در یک تابع استفاده کنید. در ابتدا نگاهی به آستانه باینری انداخته‌ایم. بیایید لیستی از روش ها ایجاد کنیم و آنها را یکی یکی اعمال کنیم و نتایج را ترسیم کنیم:

methods = (cv2.THRESH_BINARY, cv2.THRESH_BINARY_INV, cv2.THRESH_TRUNC, cv2.THRESH_TOZERO, cv2.THRESH_TOZERO_INV)
names = ('Binary Threshold', 'Inverse Binary Threshold', 'Truncated Threshold', 'To-Zero Threshold', 'Inverse To-Zero Threshold')

def thresh(img_path, method, index):
    img = cv2.imread(img_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    blurred = cv2.GaussianBlur(img, (7, 7), 0)
    ret, img_masked = cv2.threshold(blurred, 220, 255, method)

    fig, ax = plt.subplots(1, 3, figsize=(12, 4))
    fig.suptitle(names(index), fontsize=18)
    ax(0).imshow(img)
    ax(1).imshow(blurred)
    ax(2).imshow(img_masked)
    plt.tight_layout()

for index, method in enumerate(methods):
    thresh('coins.jpeg', method, index)

THRESH_BINARY و THRESH_BINARY_INV معکوس یکدیگر هستند و یک تصویر را باینری می کنند 0 و 255، اختصاص دادن آنها به پس زمینه و پیش زمینه و بالعکس.

THRESH_TRUNCدوتایی می کند“تصویر بین threshold و 255.

THRESH_TOZERO و THRESH_TOZERO_INV دوتایی کردن بین 0 و مقدار پیکسل فعلی (src(x, y)). بیایید نگاهی به تصاویر به دست آمده بیندازیم:

OpenCV Thresholding در پایتون با cv2.threshold()
OpenCV Thresholding در پایتون با cv2.threshold()
OpenCV Thresholding در پایتون با cv2.threshold()
OpenCV Thresholding در پایتون با cv2.threshold()
OpenCV Thresholding در پایتون با cv2.threshold()

این روش‌ها به اندازه کافی شهودی هستند – اما، چگونه می‌توانیم یک مقدار آستانه خوب را خودکار کنیم، و اصلاً مقدار «آستانه خوب» به چه معناست؟ اکثر نتایج تا کنون دارای ماسک های غیر ایده آل بودند، با علامت ها و لکه هایی در آنها. این به دلیل تفاوت در سطوح بازتابنده سکه ها اتفاق می افتد – به دلیل تفاوت در روش انعکاس نور برجستگی ها، رنگ آنها یکنواخت نیست.

ما می‌توانیم تا حدی با یافتن آستانه جهانی بهتر با آن مبارزه کنیم.

آستانه گذاری خودکار/بهینه شده با OpenCV

OpenCV از دو روش موثر جستجوی آستانه جهانی – روش Otsu و روش Triangle استفاده می کند.

روش Otsu فرض می کند که کار می کند روی دوحالته تصاویر. تصاویر دو حالته تصاویری هستند که هیستوگرام رنگی آنها فقط شامل دو پیک است (یعنی فقط دو مقدار پیکسل مجزا دارند). با توجه به اینکه قله ها هر کدام متعلق به کلاسی مانند “پس زمینه” و “پیش زمینه” هستند – آستانه ایده آل درست در وسط آنها قرار دارد.

OpenCV Thresholding در پایتون با cv2.threshold()
اعتبار تصویر: https://scipy-lectures.org/

می‌توانید برخی از تصاویر را با تاری‌های گاوسی دووجهی‌تر کنید، اما نه همه.

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

OpenCV Thresholding در پایتون با cv2.threshold()

هیچ رقابتی بین آنها وجود ندارد – هر کدام کار می کنند روی انواع مختلفی از تصاویر، بنابراین بهتر است آنها را امتحان کنید و ببینید کدامیک نتیجه بهتری را نشان می دهد. هر دوی اینها یک تصویر در مقیاس خاکستری را فرض می کنند، بنابراین باید تصویر ورودی را از طریق خاکستری به خاکستری تبدیل کنیم. cv2.cvtColor():

img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (7, 7), 0)

ret, mask1 = cv2.threshold(blurred, 0, 255, cv2.THRESH_OTSU)
ret, mask2 = cv2.threshold(blurred, 0, 255, cv2.THRESH_TRIANGLE)

masked = cv2.bitwise_and(img, img, mask=mask1)

بیایید تصویر را با هر دو روش اجرا کنیم و نتایج را تجسم کنیم:

methods = (cv2.THRESH_OTSU, cv2.THRESH_TRIANGLE)
names = ('Otsu Method', 'Triangle Method')

def thresh(img_path, method, index):
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (7, 7), 0)

    ret, img_masked = cv2.threshold(blurred, 0, 255, method)
    print(f"Threshold: {ret}")

    fig, ax = plt.subplots(1, 3, figsize=(12, 5))
    fig.suptitle(names(index), fontsize=18)
    ax(0).imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    ax(1).imshow(cv2.cvtColor(gray, cv2.COLOR_BGR2RGB))
    ax(2).imshow(cv2.cvtColor(img_masked, cv2.COLOR_BGR2RGB))

for index, method in enumerate(methods):
    thresh('coins.jpeg', method, index)

OpenCV Thresholding در پایتون با cv2.threshold()
OpenCV Thresholding در پایتون با cv2.threshold()

در اینجا، روش مثلث از روش Otsu بهتر عمل می کند، زیرا تصویر دو حالته نیست:

import numpy as np

img = cv2.imread('coins.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (7, 7), 0)

histogram_gray, bin_edges_gray = np.histogram(gray, bins=256, range=(0, 255))
histogram_blurred, bin_edges_blurred = np.histogram(blurred, bins=256, range=(0, 255))

fig, ax = plt.subplots(1, 2, figsize=(12, 4))

ax(0).plot(bin_edges_gray(0:-1), histogram_gray)
ax(1).plot(bin_edges_blurred(0:-1), histogram_blurred)

OpenCV Thresholding در پایتون با cv2.threshold()

با این حال، واضح است که چگونه روش مثلث توانسته با تصویر کار کند و نتیجه رضایت‌بخش‌تری ایجاد کند.

محدودیت های OpenCV Thresholding

آستانه گذاری با OpenCV ساده، آسان و کارآمد است. با این حال، نسبتاً محدود است. به محض معرفی عناصر رنگارنگ، پس‌زمینه‌های غیریکنواخت و تغییر شرایط نوری – آستانه جهانی به عنوان یک مفهوم بسیار سفت و سخت می‌شود.

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

نتیجه

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

برای روی-the-fly، آستانه ساده، می توانید از OpenCV استفاده کنید. برای تقسیم بندی دقیق و در سطح تولید، باید از شبکه های عصبی استفاده کنید.

(برچسب‌ها به ترجمه)# python



منتشر شده در 1403-01-03 10:09:06

امتیاز شما به این مطلب
دیدگاه شما در خصوص مطلب چیست ؟

آدرس ایمیل شما منتشر نخواهد شد.

لطفا دیدگاه خود را با احترام به دیدگاه های دیگران و با توجه به محتوای مطلب درج کنید