تشخیص و توصیف ویژگی
تشخیص گوشه هریس (Harris Corner Detection)
هدف#
در این فصل،
- مفاهیم مربوط به آشکارساز گوشه هریس (Harris Corner Detection) را درک خواهیم کرد.
- توابع زیر را خواهیم دید: ()cv.cornerHarris، ()cv.cornerSubPix
تئوری#
در فصل گذشته دیدیم که گوشهها مناطقی در تصویر با تغییرات شدید شدت روشنایی در تمام جهات هستند. یکی از تلاشهای اولیه برای یافتن این گوشهها توسط کریس هریس و مایک استفنز (Chris Harris & Mike Stephens) در مقاله خود با عنوان A Combined Corner and Edge Detector در سال ۱۹۸۸ انجام شد، بنابراین اکنون به عنوان آشکارساز گوشه هریس شناخته میشود. او این ایده ساده را به شکل ریاضی درآورد. این روش اساساً اختلاف در شدت روشنایی را برای یک جابجایی در تمام جهات پیدا میکند که به صورت زیر بیان میشود:
تابع پنجره یا یک پنجره مستطیلی است یا یک پنجره گاوسی که به پیکسلهای زیرین وزن میدهد.
ما باید این تابع را برای تشخیص گوشه بیشینه کنیم؛ یعنی باید عبارت دوم را بیشینه کنیم. با اعمال بسط تیلور بر روی معادله فوق و استفاده از برخی مراحل ریاضی (لطفاً برای استخراج کامل به هر یک از کتابهای مرجع استاندارد مراجعه کنید)، معادله نهایی را به صورت زیر به دست میآوریم:
که در آن
در اینجا، و به ترتیب مشتقات تصویر در جهات x و y هستند (این موارد را میتوان به راحتی با استفاده از ()cv.Sobel پیدا کرد).
سپس بخش اصلی فرا میرسد. پس از این مرحله، آنها یک امتیاز (Score)، اساساً یک معادله، ایجاد کردند که تعیین میکند آیا یک پنجره میتواند حاوی یک گوشه باشد یا خیر:
که در آن
- و مقادیر ویژه (Eigenvalues) ماتریس هستند.
بنابراین بزرگی این مقادیر ویژه تعیین میکند که آیا یک ناحیه گوشه، لبه یا مسطح است:
- هنگامی که کوچک است، که زمانی رخ میدهد که و کوچک باشند، ناحیه مسطح است.
- هنگامی که است، که زمانی اتفاق میافتد که یا برعکس باشد، ناحیه لبه است.
- هنگامی که بزرگ است، که زمانی رخ میدهد که و بزرگ و باشند، ناحیه گوشه است.
این مفهوم را میتوان در تصویر زیبایی به شکل زیر نشان داد:

بنابراین نتیجه آشکارساز گوشه هریس یک تصویر در مقیاس خاکستری با این امتیازها است. آستانهگذاری برای یک امتیاز مناسب، گوشههای موجود در تصویر را در اختیار شما قرار میدهد. ما این کار را با یک تصویر ساده انجام خواهیم داد.
آشکارساز گوشه هریس در OpenCV#
کتابخانه OpenCV تابعی به نام ()cv.cornerHarris برای این منظور دارد. آرگومانهای آن عبارتند از:
- img - تصویر ورودی که باید در مقیاس خاکستری و از نوع float32 باشد.
- blockSize - اندازه همسایگی در نظر گرفتهشده برای تشخیص گوشه
- ksize - پارامتر دیافراگم مشتق سوبل استفادهشده
- k - پارامتر آزاد آشکارساز هریس در معادله
مثال زیر را ببینید:
import numpy as np
import cv2 as cv
filename = 'chessboard.png'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv.cornerHarris(gray,2,3,0.04)
#result is dilated for marking the corners, not important
dst = cv.dilate(dst,None)
# Threshold for an optimal value, it may vary depending on the image.
img[dst>0.01*dst.max()]=[0,0,255]
cv.imshow('dst',img)
if cv.waitKey(0) & 0xff == 27:
cv.destroyAllWindows()
در زیر سه نتیجه حاصل آمده است:

گوشه با دقت زیرپیکسلی (SubPixel Accuracy)#
گاهی اوقات، ممکن است نیاز داشته باشید گوشهها را با حداکثر دقت پیدا کنید. OpenCV تابعی به نام ()cv.cornerSubPix دارد که گوشههای شناساییشده را با دقت زیرپیکسلی بیش از پیش اصلاح میکند. مثال زیر را ببینید. طبق معمول، ابتدا باید گوشههای هریس را پیدا کنیم. سپس مراکز ثقل (Centroids) این گوشهها را ارسال میکنیم (ممکن است دستهای از پیکسلها در یک گوشه وجود داشته باشند که ما مرکز ثقل آنها را در نظر میگیریم) تا آنها را تصحیح کنیم. گوشههای هریس با پیکسلهای قرمز و گوشههای تصحیحشده با پیکسلهای سبز مشخص شدهاند. برای این تابع، باید معیاری تعیین کنیم که چه زمانی تکرار متوقف شود. ما آن را پس از تعداد مشخصی از تکرارها یا با دستیابی به دقتی معین متوقف میکنیم، هر کدام که زودتر رخ دهد. همچنین باید اندازه همسایگی که در آن به جستجوی گوشهها میپردازد را مشخص نماییم:
import numpy as np
import cv2 as cv
filename = 'chessboard2.jpg'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# find Harris corners
gray = np.float32(gray)
dst = cv.cornerHarris(gray,2,3,0.04)
dst = cv.dilate(dst,None)
ret, dst = cv.threshold(dst,0.01*dst.max(),255,0)
dst = np.uint8(dst)
# find centroids
ret, labels, stats, centroids = cv.connectedComponentsWithStats(dst)
# define the criteria to stop and refine the corners
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners = cv.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria)
# Now draw them
res = np.hstack((centroids,corners))
res = np.int0(res)
img[res[:,1],res[:,0]]=[0,0,255]
img[res[:,3],res[:,2]] = [0,255,0]
cv.imwrite('subpixel5.png',img)
در زیر نتیجه حاصل شده است، جایی که برخی از مکانهای مهم در پنجره بزرگنماییشده برای تجسم نشان داده شدهاند:
![]()