از اسناد مهم پشتیبان تهیه کنید و در این فرآیند کمی در مورد بینایی کامپیوتری بیاموزید.
ممکن است بخواهید یک سند را دیجیتالی کنید تا فضای فیزیکی ذخیره شود یا یک نسخه پشتیبان ذخیره کنید. در هر صورت، نوشتن برنامهای که بتواند عکسهای فایلهای کاغذی شما را به فرمت استاندارد تبدیل کند، کاری است که پایتون در آن برتری دارد.
با استفاده از ترکیبی از کتابخانه های مناسب، می توانید یک برنامه کوچک برای دیجیتالی کردن اسناد بسازید. برنامه شما تصویری از یک سند فیزیکی به عنوان ورودی می گیرد، چندین تکنیک پردازش تصویر را روی آن اعمال می کند و یک نسخه اسکن شده از ورودی را خروجی می دهد.
آماده کردن محیط
برای دنبال کردن این مقاله باید با اصول پایتون آشنا باشید. همچنین باید درک درستی از نحوه کار با کتابخانه NumPy Python داشته باشید.
هر IDE پایتون را باز کنید و دو فایل پایتون ایجاد کنید. یکی main.py و دیگری transform.py را نام ببرید. سپس دستور زیر را در ترمینال اجرا کنید تا کتابخانه های مورد نیاز نصب شوند.
pip install OpenCV-Python imutils scikit-image NumPy
شما از OpenCV-Python برای گرفتن ورودی تصویر و انجام برخی پردازش های تصویری استفاده خواهید کرد. Imutils برای تغییر اندازه تصاویر ورودی و خروجی. scikit-image برای اعمال آستانه بر روی تصویر. NumPy به شما کمک می کند تا با آرایه ها کار کنید.
منتظر بمانید تا نصب به پایان برسد و IDE اسکلت های پروژه را به روز کند. پس از تکمیل بهروزرسانی اسکلتها، آماده شروع کدنویسی هستید. کد منبع کامل در یک مخزن GitHub موجود است.
واردات کتابخانه های نصب شده
فایل main.py را باز کنید و کتابخانه هایی را که نصب کرده اید در محیط وارد کنید. این به شما امکان می دهد در صورت لزوم تماس بگیرید و از عملکردهای آنها استفاده کنید.
import cv2
import imutils
from skimage.filters import threshold_local
from transform import perspective_transform
خطای پرتاب شده در view_transform را نادیده بگیرید. هنگامی که کار بر روی فایل transform.py را تمام کردید ناپدید می شود.
گرفتن و تغییر اندازه ورودی
یک تصویر واضح از سندی که می خواهید اسکن کنید بگیرید. اطمینان حاصل کنید که چهار گوشه سند و محتوای آن قابل مشاهده است. تصویر را در همان پوشه ای که فایل های برنامه را ذخیره می کنید کپی کنید.
مسیر تصویر ورودی را به OpenCV منتقل کنید. یک کپی از تصویر اصلی تهیه کنید زیرا در طول تبدیل پرسپکتیو به آن نیاز دارید. ارتفاع تصویر اصلی را بر ارتفاعی که می خواهید اندازه آن را تغییر دهید تقسیم کنید. این نسبت تصویر را حفظ می کند. در نهایت تصویر تغییر اندازه را خروجی بگیرید.
# Passing the image path
original_img = cv2.imread('sample.jpg')
copy = original_img.copy()
# The resized height in hundreds
ratio = original_img.shape[0] / 500.0
img_resize = imutils.resize(original_img, height=500)
# Displaying output
cv2.imshow('Resized image', img_resize)
# Waiting for the user to press any key
cv2.waitKey(0)
خروجی کد بالا به صورت زیر است:
اکنون اندازه ارتفاع تصویر اصلی را به 500 پیکسل تغییر داده اید.
تبدیل تصویر تغییر سایز به Grayscale
تغییر اندازه تصویر RGB را به مقیاس خاکستری تبدیل کنید. اکثر کتابخانه های پردازش تصویر فقط با تصاویر در مقیاس خاکستری کار می کنند زیرا پردازش آنها آسان تر است.
gray_image = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY)
cv2.imshow('Grayed Image', gray_image)
cv2.waitKey(0)
به تفاوت بین تصویر اصلی و تصویر خاکستری توجه کنید.
میز رنگی سیاه و سفید شده است.
استفاده از ردیاب لبه
برای حذف نویز، یک فیلتر گاوسی تاری روی تصویر خاکستری اعمال کنید. سپس تابع OpenCV canny را برای تشخیص لبه های موجود در تصویر فراخوانی کنید.
blurred_image = cv2.GaussianBlur(gray_image, (5, 5), 0)
edged_img = cv2.Canny(blurred_image, 75, 200)
cv2.imshow('Image edges', edged_img)
cv2.waitKey(0)
لبه ها در خروجی قابل مشاهده است.
لبه هایی که با آنها کار خواهید کرد لبه های سند هستند.
پیدا کردن بزرگترین کانتور
خطوط موجود در تصویر لبه را تشخیص دهید. آنها را به ترتیب نزولی مرتب کنید و فقط پنج امتداد بزرگ را حفظ کنید. با حلقه زدن خطوط مرتب شده، بزرگ ترین کانتور را با چهار طرف تقریب بزنید.
cnts, _ = cv2.findContours(edged_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
doc = approx
break
کانتور با چهار طرف احتمالاً حاوی سند است.
دور چهار گوشه کانتور سند
گوشه های کانتور سند شناسایی شده را دور بزنید. این به شما کمک می کند تا تعیین کنید که آیا برنامه شما قادر به تشخیص سند در تصویر است یا خیر.
p = []
for d in doc:
tuple_point = tuple(d[0])
cv2.circle(img_resize, tuple_point, 3, (0, 0, 255), 4)
p.append(tuple_point)
cv2.imshow('Circled corner points', img_resize)
cv2.waitKey(0)
چرخش را روی تصویر RGB تغییر اندازه اعمال کنید.
پس از شناسایی سند، اکنون باید سند را از تصویر استخراج کنید.
استفاده از Warp Perspective برای دریافت تصویر مورد نظر
پرسپکتیو Warp یک تکنیک بینایی کامپیوتری برای تبدیل تصویر به منظور اصلاح اعوجاج است. این یک تصویر را به یک صفحه متفاوت تبدیل می کند و به شما امکان می دهد تصویر را از زاویه دیگری مشاهده کنید.
warped_image = perspective_transform(copy, doc.reshape(4, 2) * ratio)
warped_image = cv2.cvtColor(warped_image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Warped Image", imutils.resize(warped_image, height=650))
cv2.waitKey(0)
برای به دست آوردن یک تصویر تاب خورده، باید یک ماژول ساده ایجاد کنید که تبدیل پرسپکتیو را انجام دهد.
ماژول تحول
ماژول نقاط گوشه های سند را ترتیب می دهد. همچنین تصویر سند را به یک صفحه متفاوت تبدیل میکند و زاویه دوربین را به یک عکس بالای سر تغییر میدهد.
فایل transform.py را که قبلا ایجاد کردید باز کنید. کتابخانه های OpenCV و NumPy را وارد کنید.
import numpy as np
import cv2
این ماژول شامل دو تابع خواهد بود. تابعی ایجاد کنید که مختصات نقاط گوشه سند را ترتیب دهد. مختصات اول گوشه بالا سمت چپ، مختصات دوم گوشه بالا سمت راست، مختصات سوم گوشه پایین سمت راست و چهارمین مختصات گوشه پایین سمت چپ خواهد بود.
def order_points(pts):
# initializing the list of coordinates to be ordered
rect = np.zeros((4, 2), dtype = "float32")
s = pts.sum(axis = 1)
# top-left point will have the smallest sum
rect[0] = pts[np.argmin(s)]
# bottom-right point will have the largest sum
rect[2] = pts[np.argmax(s)]
'''computing the difference between the points, the
top-right point will have the smallest difference,
whereas the bottom-left will have the largest difference'''
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
# returns ordered coordinates
return rect
یک تابع دوم ایجاد کنید که مختصات گوشه تصویر جدید را محاسبه می کند و یک عکس از سر به دست می آورد. سپس ماتریس تبدیل پرسپکتیو را محاسبه کرده و تصویر تاب خورده را برمی گرداند.
def perspective_transform(image, pts):
# unpack the ordered coordinates individually
rect = order_points(pts)
(tl, tr, br, bl) = rect
'''compute the width of the new image, which will be the
maximum distance between bottom-right and bottom-left
x-coordinates or the top-right and top-left x-coordinates'''
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
maxWidth = max(int(widthA), int(widthB))
'''compute the height of the new image, which will be the
maximum distance between the top-left and bottom-left y-coordinates'''
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
maxHeight = max(int(heightA), int(heightB))
'''construct the set of destination points to obtain an overhead shot'''
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype = "float32")
# compute the perspective transform matrix
transform_matrix = cv2.getPerspectiveTransform(rect, dst)
# Apply the transform matrix
warped = cv2.warpPerspective(image, transform_matrix, (maxWidth, maxHeight))
# return the warped image
return warped
اکنون ماژول تبدیل را ایجاد کرده اید. خطای وارد کردن view_transform اکنون ناپدید خواهد شد.
توجه داشته باشید که تصویر نمایش داده شده دارای یک عکس بالای سر است.
اعمال آستانه تطبیقی و ذخیره خروجی اسکن شده
در فایل main.py، آستانه گاوسی را روی تصویر تاب خورده اعمال کنید. این به تصویر تاب خورده ظاهری اسکن شده می دهد. خروجی تصویر اسکن شده را در پوشه حاوی فایل های برنامه ذخیره کنید.
T = threshold_local(warped_image, 11, offset=10, method="gaussian")
warped = (warped_image > T).astype("uint8") * 255
cv2.imwrite('./'+'scan'+'.png',warped)
ذخیره اسکن در فرمت PNG کیفیت سند را حفظ می کند.
نمایش خروجی
خروجی تصویر سند اسکن شده:
cv2.imshow("Final Scanned image", imutils.resize(warped, height=650))
cv2.waitKey(0)
cv2.destroyAllWindows()
تصویر زیر خروجی برنامه را نشان می دهد، یک عکس سربار از سند اسکن شده.
چگونه در بینایی کامپیوتری پیشرفت کنیم
ایجاد یک اسکنر اسناد برخی از حوزه های اصلی بینایی کامپیوتر را پوشش می دهد که یک زمینه گسترده و پیچیده است. برای پیشرفت در بینایی کامپیوتر باید روی پروژه های جالب اما چالش برانگیز کار کنید.
همچنین باید در مورد نحوه استفاده از بینایی کامپیوتر با فناوری های فعلی بیشتر بخوانید. این شما را در جریان قرار میدهد و ایدههای جدیدی برای پروژهها به شما میدهد.