پردازش تصویر در OpenCV
تبدیلهای هندسی تصاویر (Geometric Transformations of Images)
اهداف#
- یاد بگیرید چگونه تبدیلهای هندسی مختلف مانند انتقال (Translation)، دوران (Rotation)، تبدیل آفین (Affine Transformation) و غیره را بر روی تصاویر اعمال کنید.
- این توابع را خواهید دید: cv.getPerspectiveTransform
تبدیلها (Transformations)#
OpenCV دو تابع تبدیل cv.warpAffine و cv.warpPerspective را فراهم میکند که با آنها میتوانید انواع تبدیلها را انجام دهید. cv.warpAffine یک ماتریس تبدیل ۲x۳ میگیرد در حالی که cv.warpPerspective یک ماتریس تبدیل ۳x۳ به عنوان ورودی میگیرد.
مقیاسبندی (Scaling)#
مقیاسبندی همان تغییر اندازه تصویر است. OpenCV تابع cv.resize() را برای این منظور دارد. اندازه تصویر میتواند به صورت دستی مشخص شود، یا میتوانید ضریب مقیاس را تعیین کنید. روشهای درونیابی (Interpolation) مختلفی استفاده میشود. روشهای درونیابی ترجیحی cv.INTER_AREA برای کوچک کردن و cv.INTER_CUBIC (کند) و cv.INTER_LINEAR برای بزرگ کردن هستند. به طور پیشفرض، روش درونیابی cv.INTER_LINEAR برای تمام اهداف تغییر اندازه استفاده میشود. میتوانید با هر یک از روشهای زیر تصویر ورودی را تغییر اندازه دهید:
import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
res = cv.resize(img,None,fx=2, fy=2, interpolation = cv.INTER_CUBIC)
#OR
height, width = img.shape[:2]
res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)
انتقال (Translation)#
انتقال همان جابجایی موقعیت یک شیء است. اگر جابجایی در جهت (x,y) را بدانید و آن را بنامید، میتوانید ماتریس تبدیل را به صورت زیر بسازید:
میتوانید آن را به یک آرایه Numpy از نوع np.float32 تبدیل کرده و به تابع cv.warpAffine() ارسال کنید. مثال زیر را برای یک جابجایی به اندازه (100,50) ببینید:
import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "file could not be read, check with os.path.exists()"
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',dst)
cv.waitKey(0)
cv.destroyAllWindows()
هشدار
آرگومان سوم تابع cv.warpAffine() اندازه تصویر خروجی است که باید به شکل (width, height) باشد. به خاطر بسپارید که width = تعداد ستونها و height = تعداد سطرها است.
نتیجه را در زیر ببینید:

دوران (Rotation)#
دوران یک تصویر به اندازه زاویه با ماتریس تبدیل به شکل زیر حاصل میشود:
اما OpenCV دوران با مقیاس و مرکز دوران قابل تنظیم را فراهم میکند تا بتوانید در هر مکانی که ترجیح میدهید بچرخید. ماتریس تبدیل اصلاحشده به صورت زیر است:
که در آن:
برای پیدا کردن این ماتریس تبدیل، OpenCV تابع cv.getRotationMatrix2D را فراهم میکند. مثال زیر را که تصویر را ۹۰ درجه نسبت به مرکز بدون هیچ مقیاسبندی میچرخاند، ببینید:
img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "file could not be read, check with os.path.exists()"
rows,cols = img.shape
# cols-1 and rows-1 are the coordinate limits.
M = cv.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1)
dst = cv.warpAffine(img,M,(cols,rows))
نتیجه را ببینید:

تبدیل آفین (Affine Transformation)#
در تبدیل آفین، تمام خطوط موازی در تصویر اصلی در تصویر خروجی نیز موازی خواهند بود. برای پیدا کردن ماتریس تبدیل، به سه نقطه از تصویر ورودی و مکانهای متناظر آنها در تصویر خروجی نیاز داریم. سپس cv.getAffineTransform یک ماتریس ۲x۳ ایجاد میکند که باید به cv.warpAffine ارسال شود.
مثال زیر را ببینید و همچنین به نقاطی که انتخاب کردم (که با رنگ سبز مشخص شدهاند) توجه کنید:
img = cv.imread('drawing.png')
assert img is not None, "file could not be read, check with os.path.exists()"
rows,cols,ch = img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv.getAffineTransform(pts1,pts2)
dst = cv.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
نتیجه را ببینید:

تبدیل پرسپکتیو (Perspective Transformation)#
برای تبدیل پرسپکتیو، به یک ماتریس تبدیل ۳x۳ نیاز دارید. خطوط مستقیم حتی پس از تبدیل نیز مستقیم باقی میمانند. برای پیدا کردن این ماتریس تبدیل، به ۴ نقطه روی تصویر ورودی و نقاط متناظر در تصویر خروجی نیاز دارید. از این ۴ نقطه، ۳ تا از آنها نباید همخط باشند. سپس ماتریس تبدیل را میتوان با تابع cv.getPerspectiveTransform یافت. سپس cv.warpPerspective را با این ماتریس تبدیل ۳x۳ اعمال کنید.
کد زیر را ببینید:
img = cv.imread('sudoku.png')
assert img is not None, "file could not be read, check with os.path.exists()"
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv.getPerspectiveTransform(pts1,pts2)
dst = cv.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
نتیجه:

منابع اضافی#
- "Computer Vision: Algorithms and Applications"، Richard Szeliski