اسکن مدارک با استفاده از OpenCV و Python
در این پست قصد داریم با استفاده از OpenCV و Python، برنامه اسکنی شبیه به آنچه که در گوش های امروزی وجود دارد بنویسیم. در پست پیشین (تبدیل Perspective با استفاده از مختصات اولیه و نهایی ۴ نقطه از تصویر)، برنامه ای برای تبدیل حالت پرسپکتیو نوشته شد و از آن در این برنامه استفاده خواهیم کرد. در اینجا مختصات نقاط اولیه نیز به طور خودکار و با استفاده از تشخیص لبه و Contour بدست می آیند.
اسکن یک فایل از سه مرحله ساده تشکیل شده است:
- مرحله اول: تشخیص لبه ها
- مرحله دوم: استفاده از لبه ها برای پیدا کردن Contour ها
- مرحله سوم: اعمال تبدیل پرسپکتیو
مرحله اول: تشخیص لبه ها
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# import the necessary packages import cv2 import numpy as np import sys sys.path.append('/home/pi/myfunctions.py') from myfunctions import four_point_transform # load the image img=cv2.imread('document2.jpg') orig=img.copy() # convert the image to grayscale, blur it, and find edges # in the image gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) gray=cv2.GaussianBlur(gray,(5,5),0) edged=cv2.Canny(gray,75,200) # show the original image and the edge detected image print "STEP 1: Edge Detection" cv2.imwrite("Image.jpg", img) cv2.imwrite("Edged.jpg", edged) |
ابتدا پکیج های مورد نیاز را وارد می کنیم. numpy برای Numberical Processing و cv2 برای OpenCV هستند. تبدیل پرسپکتیو وارد می کنیم تا در مرحله آخر از آن استفاده نماییم.
حال تصویر مورد نظر را بارگذادی می کنیم. لازم است تا لبه های تصویر مشخص شوند. برای این کار باید تصویر رنگی (BGR) را با استفاده از دستور cv2.cvtColor به خاکستری (GRAY) تبدیل کنیم.
برای رفع نویزهای فرکانس بالا و افزایش دقت تشخیص لبه ها از فیلتر Gaussian استفاده کردیم.
در آخر با دستور Canny، لبه های شکل را مشخص می کنیم. شکل زیر نتیجه را تا به اینجا نشان می دهد.
تصویر سمت راست، تصویر اصلی است و پس از اعمال دستور Canny، تصویر سمت چپ حاصل می شود. مرحله اول به پایان رسید.
مرحله دوم: استفاده از لبه ها برای پیدار کردن Contour ها
همانطوری که در تصویر مرحله قبل مشخص است، لبه های زیادی پیدا شده است؛ ولی هدف ما فقط لبه های برگه اصلی است و نه لبه های دیگر. به عبارت دیگر باید به دنبال بزرگترین Contour بگردیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# find the contours in the edged image, keeping only the # largest ones, and initialize the screen contour (_,contours,_)=cv2.findContours(edged.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key = cv2.contourArea, reverse = True)[:5] # loop over the contours for c in contours: # approximate the contour peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * peri, True) # if our approximated contour has four points, then we # can assume that we have found our screen if len(approx) == 4: screenCnt = approx break # show the contour (outline) of the piece of paper print "STEP 2: Find contours of paper" cv2.drawContours(img, [screenCnt], -1, (0, 255, 0), 2) cv2.imwrite("Outline.jpg", img) |
توسط دستور cv2.finfContours، تمامی Contour های موجود در تصویر را پیدا می کنیم. سپس آنها را مرتب می کنیم.
فرض بر این است که هر بار فقط یک برگه را می خواهیم اسکن کنیم و برگه ها همگی مستطیل شکل (۴ گوشه) هستند.
اکنون محیط Contour های مشخص شده را پیدا کرده و برحسب آنها یک چند گوشه را با استفاده از دستور cv2.approxPolyDP مشخص می کنیم. حال اگر تعداد المان های هر یک از چند گوشه ها برابر ۴ باشد، بدین معناست که یک ۴ گوش پیدا کردیم.
در آخر با دستور drawContours، بزرگترین Contour را بر روی شکل مشخص می کنیم. شکل زیر نتیجه مرحله دوم را نشان می دهد.
مرحله دوم نیز به پایان رسید و اکنون نوبت به اعمال تبدیل پرسپکتیو می رسد.
مرحله سوم: اعمال تبدیل پرسپکتیو
در پست پیشین گفتیم که برای استفاده از تبدیل پرسپکتیو به مختصات اوله و نهایی ۴ نقطه از تصویر احتیاج داریم. مختصات نهایی را خودمان بدست آوردیم. در این برنامه، دو مرحله قبلی صرفاً جهت پیدا کردن مختصات اولیه آن ۴ نقطه انجام شد و مرحله سوم اصلی ترین مرحله است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# apply the four point transform to obtain a top-down # view of the original image warped = four_point_transform(orig, screenCnt.reshape(4, 2) ) # convert the warped image to grayscale, then threshold it # to give it that 'black and white' paper effect warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY) warped=cv2.adaptiveThreshold(warped,251,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2) # show the original and scanned images print "STEP 3: Apply perspective transform" cv2.imshow("Original", orig) warped=cv2.resize(warped,(img.shape[1],img.shape[0]),interpolation=cv2.INTER_AREA) cv2.imshow("Scanned",warped) cv2.imwrite("Scanned.jpg",warped) cv2.waitKey(0) |
تابع four_point_transform را فراخوانی می کنیم. با استفاده از بزرگترین Contour که در مرحله قبل پیدا کرده بودیم، مختصات نقاط اوله را در اختیار داریم.
پس از آن باید تصویر اصلی از حالت BGR به GRAY تبدیل کنیم. در قسمت بعدی با اعمال Adaptive Threshold، تصویر خاکستری را به حالت سیاه-سفید تبدیل می کنیم. و در آخر آن را نمایش می دهیم. شکل زیر تصویر اصلی و اسکن شده است.
تصویر سمت چپ، برگه اصلی و تصویر سمت راست، خروجی کد است. در لینک زیر می توانید کد را به همراه تصاویر دانلود نمایید.