برنامه نویسی

تشخیص و شمارش اشیا با OpenCV

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

اول از همه، بیایید کتابخانه هایمان را بارگذاری کنیم.

import cv2
import imutils
import numpy as np
import matplotlib.pyplot as plt
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من برای این کار عکسی با سکه انتخاب می کنم.

توضیحات تصویر

بیایید این تصویر را وارد کنیم.

image = cv2.imread("coins.jpg")
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

image_blur = cv2.medianBlur(image,25)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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


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

image_blur_gray = cv2.cvtColor(image_blur, cv2.COLOR_BGR2GRAY)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر مقدار پیکسل بزرگتر از مقدار آستانه باشد، یک مقدار (ممکن است سفید باشد) و در غیر این صورت مقدار دیگری (ممکن است سیاه باشد) به آن اختصاص داده می شود. تابع مورد استفاده cv2.threshold است. اولین آرگومان تصویر منبع است که باید یک تصویر در مقیاس خاکستری باشد. آرگومان دوم مقدار آستانه است که برای طبقه بندی مقادیر پیکسل استفاده می شود. آرگومان سوم maxVal است که اگر مقدار پیکسل بیشتر از (گاهی اوقات کمتر از) مقدار آستانه باشد، مقداری را نشان می دهد که باید داده شود.

image_res ,image_thresh = cv2.threshold(image_blur_gray,240,255,cv2.THRESH_BINARY_INV)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من روش “THRESH_BINARY_INV” را ترجیح می دهم زیرا می خواهم سکه ها در اینجا سفید و بقیه سیاه باشند. شما می توانید مقادیر مناسب را با توجه به تصویر خود انتخاب کنید.


حالا یک کرنل در اینجا ایجاد می کنیم. اندازه این هسته 3*3 خواهد بود.

kernel = np.ones((3,3),np.uint8)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس این را به صورت زیر روی عکس خود اعمال می کنیم.

opening = cv2.morphologyEx(image_thresh,cv2.MORPH_OPEN,kernel) 
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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


اکنون زمان آن است که با استفاده از distanceTransform مقدار هر پیکسل را با فاصله تا نزدیکترین پیکسل پس زمینه جایگزین کنیم. این کار را با استفاده از روش distanceTransform انجام خواهیم داد. وقتی این روش را اعمال می کنیم، نوع آرایه ما به float32 تبدیل می شود. بنابراین ما 2 مرحله دیگر را انجام می دهیم و آرایه خود را به نوع uint8 تبدیل می کنیم.

dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, last_image =  cv2.threshold(dist_transform, 0.3*dist_transform.max(),255,0)
last_image = np.uint8(last_image)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما 2 بلوک آخر کد را داریم. در این بخش، شمارش اشیا و ثبت موقعیت اشیا را پردازش می کنیم. ما از findContours برای تشخیص اشیا استفاده می کنیم. سپس آرایه خود را با روش grap_contours منظم می کنیم.

cnts = cv2.findContours(last_image.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نهایت تصویر خود را برمیگردانیم.

def display(img,count,cmap="gray"):
    f_image = cv2.imread("coins.jpg")
    f, axs = plt.subplots(1,2,figsize=(12,5))
    axs[0].imshow(f_image,cmap="gray")
    axs[1].imshow(img,cmap="gray")
    axs[1].set_title("Total Money Count = {}".format(count))

for (i, c) in enumerate(cnts):
    ((x, y), _) = cv2.minEnclosingCircle(c)
    cv2.putText(image, "#{}".format(i + 1), (int(x) - 45, int(y)+20),
        cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0), 5)
    cv2.drawContours(image, [c], -1, (0, 255, 0), 2)

display(image,len(cnts))
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توضیحات تصویر

سعی کردم تا حد امکان کوتاه و واضح بنویسم. برای اطلاعات دقیق تر، اسناد منبع را در زیر در این مقاله اضافه خواهم کرد. می توانید آنها را بخوانید و اطلاعات عمیق تری دریافت کنید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا