فائزه ثقفی
فائزه ثقفی
خواندن ۴ دقیقه·۳ سال پیش

ماشین لرنینگ #1 : مقایسه دو تصویر

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

این مقایسه چند تا مرحله داره: اول بیایم عکسا رو از کاربر بگیریم. بعد سایز و فرمت و shape اشون رو مقایسه کنیم. بعد سایز رو تغییر بدیم و دو تا تصویر رو عین هم کنیم. بعد بیایم عکسها رو سیاه و سفید کنیم. بعد بیایم similarity index یا میزان شباهت رو پیدا کنیم. بعد threshold ، بعد contour و grab رو دربیاریم. بعد دور اون contour ها یه مستطیل بکشیم و مشخصشون کنیم. بعد تفاوتها رو رسم کنیم. بعد با توجه به همه اینا یه امتیاز شباهت بدیم که دو تا عکس چقدر به هم شبیهن و اون عکس دومیه فیکه یا نه؟ حالا دونه دونه توضیح میدم.

اول چیکار میکنیم؟ میایم لایبرری هایی که نیاز داریم رو ادد میکنیم:

from skimage.metrics import structural_similarity
import imutils
import cv2
from PIL import Image
import requests

متد structural_similarity از ماژول skimage.metrics برای پردازش تصویر استفاده میشه. میاد اون similarity index رو محاسبه میکنه که در واقع شباهتهای ساختاری و مهم دو تا تصویره. imutils یه مجموعه ای از متدهاس که میاد کارای اصلی و اساسی پردازش تصویر رو برامون انجام میده مثل resize و rotate و اینا. cv2 هم که همون openCV عه . البته جمع وجورش. برای کامپیوتر ویژن. باز PIL هم یه کتابخونه پردازش تصویر توی پایتونه. request هم که برای دانلوده.

!mkdir pan_card_tampering
!mkdir pan_card_tampering/image

با این دو تا دستور هم میایم دو تا فولدر توی هم میسازیم که وقتی تصویرا رو دانلود کردیم بره توی اینجا.

original = Image.open(requests.get('https:// ... ', stream=True).raw)
tampered = Image.open(requests.get('https://...', stream=True).raw)

این دو تا دستور هم میان از یه آدرس دو تا عکس دانلود میکنن و میریزن توی دو تا متغیر. که خب از request برای دانلود و از Image برای خوندن دو تا عکس و ریختنشون توی متغیرها استفاده کردیم. اولیش اون اصلیه اس. دومیش هم اونیه که میخوایم فیک بودنش رو حساب کنیم. حالا آدرسش مهم نبود. چون طولانی میشد پاکش کردم. کد اصلی رو آخرش میذارم.

اول عکسا رو ببینیم چه شکلین. همینطوری اسمش رو بنویسم تصویر رو نمایش میده :

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

حالا کار شروع میشه. اول میایم سایز و فرمت دو تا تصویر رو میبینیم :

print(&quotOriginal image format : &quot,original.format)
print(&quotTampered image format : &quot,tampered.format)
print(&quotOriginal image size : &quot,original.size)
print(&quotTampered image size : &quot,tampered.size)

الان غیر از اینکه تصویرها هم اندازه نیستن، تصویر اصلی خیلیم بزرگه. بخاطر همین میایم ریسایز میکنیم. بعد هم توی دو تا متغیرها میریزیم. هم اینکه توی اون دو تا فولدری که ساختیم ذخیره اشون میکنیم.

original = original.resize((250, 160))
original.save('pan_card_tampering/image/original.png')
tampered = tampered.resize((250,160))
tampered.save('pan_card_tampering/image/tampered.png')

با استفاده از اون cv2 عکسا رو میخونیم، میریزیم توی همین دو تا متغیر که بعدا لازمشون داریم. این متد imread میاد عکسا رو به صورت ماتریس ذخیره می کنه.

original = cv2.imread('pan_card_tampering/image/original.png')
tampered = cv2.imread('pan_card_tampering/image/tampered.png')

مرحله بعدی اینه که برای پردازش بهتر و همینطور ساده کردن ماتریس عکسا و سبک کردنش، بیایم چیکار کنیم؟ عکسا رو سیاه و سفید کنیم. اول اینکه با اینکار لبه های قسمتهای مختلف تصویر بهتر مشخص میشه. بعد هم اینکه یه عکس رنگی 3 تا مقدار rgb داره ولی یه عکس سیاه و سفید 1 دونه مقدار داره برای هر پیکسل.

گفتیم که میخوایم یه عدد در نظر بگیریم و به میزان شباهت دو تا تصویر امتیاز بدیم. این کار با استفاده از از متد structural_similarity انجام میشه که یه عدد SSIM برمیگردونه . این میزان شباهته . که خب هر چیم عددش کمتر باشه، میزان شباهت کمتره:

(score, diff) = structural_similarity(original_gray, tampered_gray, full=True)
print(&quotSSIM: {}&quot.format(score))

مال این دو تا تصویر که بالا نشون دادم زیاد نیست

SSIM: 0.3167879033273942

تازه از اینجا پردازش تصویر شروع میشه. اول میایم آستانه گذاری میکنیم یا همون threshold. تقریبا میشه گفت یه روش ساده سازی تصویره. میاد تصویر رو باینری میکنه. یعنی یه پیکسل یا سفیده و 1 مدارش ، یا سیاه و 0 . البته این ساده ترین تعریفشه.

یعنی اول اومدیم تصویر رو از حالت رنگی تبدیلش کردیم به gray-scale. این سیاه و سفید نیست. خاکستری طوره. یعنی هنوزم طیف رنگ داریم. یه جاهایی پر رنگتر از جاهای دیگه اس. سایه و این حرفا رو داریم. حالا میخوایم با threshold بیایم و کاملا تصویر رو سیاه و سفید کنیم.

یه مثال از آستانه گذاری. توضیح فارسی خوب پیدا نکردم. برید از ویکی پدیا بخونید
یه مثال از آستانه گذاری. توضیح فارسی خوب پیدا نکردم. برید از ویکی پدیا بخونید

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

اون خط سبزا
اون خط سبزا


حالا این دو تا کار پایه ای رو از کتابخانه cv2 که همون openCV هست بر میداریم:

thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

این دو تا متد این کارا رو برامون انجام میدن. یعنی اول آستانه گذاری و تبدیل عکس به عکس باینری. بعد هم چی؟ پیدا کردن خطوط که برای تشخیص اشیا در تصویر ضروریه. خروجی اش هم یه آرایه است.

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

for c in cnts:
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(original, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv2.rectangle(tampered, (x, y), (x + w, y + h), (0, 0, 255), 2)

حالا کارایی که کردیم رو نمایش میدیم

print('Original Format Image')
Image.fromarray(original)
خطوط یا contourهای تصویر اصلی
خطوط یا contourهای تصویر اصلی
print('Tampered Image')
Image.fromarray(tampered)
خطوط یا contourهای تصویری که میخوایم صحتش رو بسنجیم
خطوط یا contourهای تصویری که میخوایم صحتش رو بسنجیم
print('Different Image')
Image.fromarray(diff)
تفاوت دو تا عکس که با قسمتای سیاه نشون داده شدن
تفاوت دو تا عکس که با قسمتای سیاه نشون داده شدن


print('Threshold Image')
Image.fromarray(thresh)
تفاوت دو تا عکس که با threshold نشون داده شدن و قسمتای سفید هستن
تفاوت دو تا عکس که با threshold نشون داده شدن و قسمتای سفید هستن

خب این از قسمت اول. کدهاش رو هم میذارم اینجا

computer visionpythonmachin learning
برنامه نویس پایتون، عاشق کتاب، فیلم، روزنوشته و ... محمدحسین
شاید از این پست‌ها خوشتان بیاید