صورت مسئله – یک تولید کننده ، در محل کارخانه خود با مشکلات مختلف امنیتی مواجه شده است. با ارزیابی دقیق کارخانه ، متوجه می شویم که از روش های استاندارد برای کنترل تردد و نظارت استفاده نمی شود. آن ها همچنین تعداد زیادی نیروی انسانی جهت حافظت و نظارت استخدام کرده اند که با وجود حضور آن ها ، امکان نظارت دقیق و ۲۴ ساعته بر کل محوطه کارخانه نیست.
در طول روز افراد زیادی به محوطه کارخانه وارد و خارج می شوند که اکثر این تردد ها از طریق خودرو ها و وسایل نقلیه صورت می گیرد.
اکنون می خواهیم راهکاری ارائه دهیم تا بتوان به طور کامل و تمام وقت بر روی خودرو های در حال تردد در محوطه این کارخانه نظارت داشته باشیم و اطلاعات کامل تردد خودرو ها را ثبت کنیم. راهکار مناسب برای این کار، پلاک خوان است. می خواهیم هر نگهبان بتواند از طریق تلفن همراه خود ، تصویری از خودرو گرفته و شماره پلاک آن در سیستم ثبت شود.
فهرست مطالب
- ابزارها و کتابخانه های مورد نیاز
- مراحل اجرا پروژه
- گام اول: یک پروژه Flask در PyCharm ایجاد کنید
- گام دوم : برای سهولت تقسیم بندی کاراکتر ها ابتدا با پردازش تصویر شروع می کنیم
- گام سوم: بخش بندی اعداد و حروف پلاک
- گام چهارم : ایجاد یک مدل یادگیری ماشین و آموزش آن برای شناسایی کاراکتر ها
- گام پنجم : مدل را آموزش دهید
- گام ششم : مدل را ذخیره کنید
- روشی برای تشخیص پلاک های ایرانی
- گام هفتم : استقرار مدل با استفاده از Flask
با ما همراه باشید تا در این آموزش، یک برنامه پلاک خوان برای تشخیص پلاک خودرو های در حال تردد پیاده سازی کنیم.
ابزارها و کتابخانه های مورد نیاز
- پایتون – از پایتون ۳٫۸ برای ساخت مدل های یادگیری ماشین استفاده شده است.
- IDE یا محیط توسعه – PyCharm و Jupyter Notebook
- NumPy و Pandas – ابزار Numpy یک بسته الحاقی برای انجام محاسبات عددی با پایتون است که جایگزین NumArray و Numeric شده است. از آرایه های چند بعدی ( جداول ) و ماتریس ها پشتیبانی می کند.
Pandas با تبدیل فایل های داده ی CSV ، JSON و TSV یا پایگاه داده SQL به یک فریم داده، یک شی پایتون مانند یک Excel یا یک جدول SPSS با سطر ها و ستون ها تجزیه و تحلیل را ساده می کند.
- Matplotlib – برای تجسم سازی استفاده می شود
- Scikit-learn – این ابزار یک کتابخانه متن باز یادگیری ماشین Python است که در بر روی SciPy (پایتون علمی) ، NumPy و matplotlib ساخته شده است و تعدادی الگوریتم بهینه برای یادگیری نظارت شده و بدون نظارت فراهم می کند.
- Keras – Keras یک کتابخانه یادگیری عمیق پایتون است که می تواند بر روی Theano و TensorFlow اجرا شود. این کتابخانه می تواند روی GPU و CPU اجرا شود و از هر دو شبکه رابط و کانولوشن و همچنین ترکیب آن ها پشتیبانی کند.
- Flask – از فلاسک ۱٫۱٫۲ برای استقرار مدل استفاده می شود
مراحل اجرا پروژه
منبع ورودی – همانطور که گفته شد، تصویر پلاک خودرو باید توسط نیروهای حفاظتی با استفاده از برنامه نصب شده روی تلفن همراه ثبت شود.
تجزیه و تحلیل و پردازش تصویر پلاک خودرو – با استفاده از توابع grayscale ، threshold ، erode ، dilate و contour detection در OpenCV و با تنظیم برخی پارامتر ها ، به راحتی می توانیم اطلاعات کافی برای تشخیص دادن پلاک در تصویر را بدست بیاوریم تا تصمیم بگیریم اطلاعات بدست آمده برای تشخیص شماره پلاک مناسب است یا نه. اگر تصویر بسیار مخدوش باشد یا تار افتاده باشد، ممکن است برخی ارقام پلاک قابل تشخیص نباشند. پس به همین دلیل بهتر است عکس مجددی گرفته شود و با بررسی عکس جدید، مجدد این پروسه را تکرار کنیم تا عکسی واضح و قابل پردازش بدست آید. همچنین قبل از انتقال تصویر به فرآیند بعدی باید مطمئن شویم که تصویر بیش از حد نویز ندارد.
بخش بندی کارکتر های پلاک – اگر همه مراحل ذکر شده به درستی انجام شود، تصویر برای استخراج کاراکتر های پلاک آماده است. برای این کار با threshold ، erode ، dilate و blur روی تصویر تا حد امکان نویز تصویر را کم می کنیم تا خروجی تقریبا بدون نویز حاصل شود. سپس مجدداً از contour detection استفاده می کنیم و با تنظیم پارامتر های آن، حروف و ارقام پلاک را جداسازی می کنیم.
تشخیص کارکتر ها ( OCR ) – اکنون که همه کارکتر ها را به طور تفکیک شده داریم، باید کاراکتر ها را یکی یکی به مدل آموزش دیده خود منتقل کنیم تا همه ی ارقام و حروف شماره پلاک ما پیش بینی شود. ما از Keras برای ساخت مدل Convolutional Neural Network جهت انجام این کار استفاده خواهیم کرد.
استقرار مدل – استقرار مدل با استفاده از چارچوب Flask انجام خواهد شد.
گام اول: یک پروژه Flask در PyCharm ایجاد کنید
۱-در بخش New project ، موارد زیر را انجام دهید:
نوع پروژه را از نوع Flask مشخص کنید.
محل ذخیره پروژه را مشخص کنید.
۲- سپس ، Python Interpreter را باز کرده و با کلیک روی دکمه رادیویی مربوطه ، new environment یا previously configured interpreter را انتخاب کنید.
استفاده از New Environment : اگر این گزینه انتخاب شده است، ابزاری که برای ایجاد یک محیط مجازی می خواهید استفاده کنید را انتخاب کنید. برای این کار، روی لیست کلیک کنید و Virtual env یا Pipenv یا Conda را انتخاب کنید.
در مرحله بعدی، مکان و مفسر اصلی را برای محیط مجازی جدید مشخص کنید. در صورت لزوم ، روی گزینه Inherit global-packages و Make available for all projects کلیک کنید.
هنگام پیکربندی مفسر اصلی ، باید مسیر اجرایی Python را مشخص کنید. اگر PyCharm هیچ پایتونی را بر روی دستگاه شما تشخیص ندهد، دو گزینه فراهم می کند: بارگیری آخرین نسخه های پایتون از python.org یا تعیین مسیری برای اجرای پایتون (در صورت نصب غیر استاندارد).
۳-روی More Settings کلیک کنید و موارد زیر را مشخص کنید:
از لیست Template language ، زبان مورد استفاده را انتخاب کنید.
در قسمت پوشه Templates ، فهرست مورد نظر را برای ذخیره الگو ها و محل بارگیری آن ها تعیین کنید. می توانید نام پوشه ای را که هنوز وجود ندارد تعیین کنید. در این حالت ، دایرکتوری ایجاد می شود.
۴- روی Create کلیک کنید.
PyCharm یک برنامه ایجاد می کند و ساختار دایرکتوری خاصی را ایجاد کرده که می توانید آن را در پنجره ابزار Project پیدا کنید. علاوه بر این، PyCharm یک ریز اسکریپت پایتون با نام app.py ایجاد می کند، که همراه مثال ساده ی “Hello, World!” است.
اکنون می توانید فایل ها را طبق نیاز خود در پروژه اضافه کنید. قبل از اجرای پروژه، مدل خود را برای تشخیص شماره پلاک آماده می کنیم.
گام دوم : برای سهولت تقسیم بندی کاراکتر ها ابتدا با پردازش تصویر شروع می کنیم
def segment_characters(image) : # Preprocess cropped license plate image img_lp = cv2.resize(image, (333, 75)) img_gray_lp = cv2.cvtColor(img_lp, cv2.COLOR_BGR2GRAY) _, img_binary_lp = cv2.threshold(img_gray_lp, 200, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) img_binary_lp = cv2.erode(img_binary_lp, (3,3)) img_binary_lp = cv2.dilate(img_binary_lp, (3,3)) LP_WIDTH = img_binary_lp.shape[0] LP_HEIGHT = img_binary_lp.shape[1] # Make borders white img_binary_lp[0:3,:] = 255 img_binary_lp[:,0:3] = 255 img_binary_lp[72:75,:] = 255 img_binary_lp[:,330:333] = 255 # Estimations of character contours sizes of cropped license plates dimensions = [LP_WIDTH/6, LP_WIDTH/2, LP_HEIGHT/10, ۲*LP_HEIGHT/3] plt.imshow(img_binary_lp, cmap='gray') plt.show() cv2.imwrite('contour.jpg',img_binary_lp) # Get contours within cropped license plate char_list = find_contours(dimensions, img_binary_lp) return char_list
توابع مورد استفاده برای پردازش تصویر عبارتند از :
۱- تابع cv2.resize() – اندازه تصویر را در ابعادی تغییر می دهد به طوری که همه کاراکتر ها مشخص و واضح به نظر برسند.
۲- تابع cv2.cvtColor() – تصاویر را از یک فضای رنگی به فضای دیگر تبدیل می کند، مانند BGR Grey ، BGR HSV و غیره
برای تبدیل تصاویر از فضای رنگی BGR HSV از فلگ cv2.COLOR_BGR2GRAY استفاده کنید.
به طور مشابه برای BGR HSV ، ما از فلگ cv2.COLOR_BGR2HSV استفاده می کنیم.
۳- تابع cv2.erode() و cv2.dilate() – تبدیلات ریخت شناسی برخی از عملیات ساده بر اساس شکل تصویر است. به طور معمول بر روی تصاویر باینری انجام می شود. به دو ورودی احتیاج دارد ، یکی تصویر اصلی ماست ، دیگری عنصر یا هسته ساختاردهنده است که ماهیت کار را تعیین می کند. دو عملگر اصلی ریخت شناسی Erosion و Dilation هستند.
Erosion – ایده اصلی فرآیند Erosion مانند فرسایش خاک است، مرزهای جسم پیش زمینه را از بین می برد (همیشه سعی کنید پیش زمینه به رنگ سفید باشد). این فرآیند چه کاری انجام می دهد؟ کرنل از درون تصویر عبور می کند (مانند کانولوشن ۲ بعدی). یک پیکسل در تصویر اصلی (۱ یا ۰) فقط زمانی ۱ در نظر گرفته می شود که تمام پیکسل های زیر کرنل ۱ باشد، در غیر این صورت فرسایش می یابد (۰ می شود).
Dilation – Dilation نقطه ی مقابل Erosion است. در اینجا ، یک عنصر پیکسل “۱” است اگر حداقل یک پیکسل در زیر کزنل “۱” باشد. بنابراین منطقه سفید را در تصویر افزایش می دهد و یا اندازه جسم پیش زمینه را افزایش می دهد. به طور معمول، در مواردی مانند حذف نویز های تصویر، پس از Erosion از Dilation استفاده می شود. زیرا Erosion ، نویز های سفید را از بین می برد، اما باعث کوچک تر شدن جسم ما نیز می شود. بنابراین آن را بزرگتر می کنیم. از آنجا که نویز های تصویر از بین رفته است آن ها بر نمی گردند، اما محیط شی ما افزایش می یابد. همچنین این فرآیند در اتصال بخش های شکسته یک جسم مفید است.
۴- مرحله بعدی اکنون سفید کردن مرز های تصویر است. این کار برای حذف پیکسل های خارج از فریم تصویر است.
۵-در مرحله بعد ، لیستی از ابعاد را تعریف می کنیم که شامل ۴ مقدار است که با آن ها ابعاد کاراکتر ها را برای فیلتر کردن کاراکتر های مورد نیاز مقایسه می کنیم.
۶-از طریق فرایندهای فوق ، ما تصویر خود را به یک تصویر باینری پردازش شده تقلیل داده ایم و آماده دریافت این تصویر برای استخراج کاراکتر ها هستیم.
گام سوم: بخش بندی اعداد و حروف پلاک
def find_contours(dimensions, img) : # Find all contours in the image cntrs, _ = cv2.findContours(img.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # Retrieve potential dimensions lower_width = dimensions[0] upper_width = dimensions[1] lower_height = dimensions[2] upper_height = dimensions[3] # Check largest 5 or 15 contours for license plate or character respectively cntrs = sorted(cntrs, key=cv2.contourArea, reverse=True)[:15] ii = cv2.imread('contour.jpg') iii = cv2.imread('contour.jpg') cv2.drawContours(iii, cntrs, -1, (0,255,0), 3) plt.imshow(iii, cmap='gray') plt.show() x_cntr_list = [] target_contours = [] img_res = [] for cntr in cntrs : #detects contour in binary image and returns the coordinates of rectangle enclosing it intX, intY, intWidth, intHeight = cv2.boundingRect(cntr) #checking the dimensions of the contour to filter out the characters by contour's size if intWidth > lower_width and intWidth < upper_width and intHeight > lower_height and intHeight < upper_height : x_cntr_list.append(intX) #stores the x coordinate of the character's contour, to used later for indexing the contours char_copy = np.zeros((44,24)) #extracting each character using the enclosing rectangle's coordinates. char = img[intY:intY+intHeight, intX:intX+intWidth] char = cv2.resize(char, (20, 40)) cv2.rectangle(ii, (intX,intY), (intWidth+intX, intY+intHeight), (50,21,200), 2) plt.imshow(ii, cmap='gray') # Make result formatted for classification: invert colors char = cv2.subtract(255, char) # Resize the image to 24x44 with black border char_copy[2:42, 2:22] = char char_copy[0:2, :] = 0 char_copy[:, 0:2] = 0 char_copy[42:44, :] = 0 char_copy[:, 22:24] = 0 img_res.append(char_copy) #List that stores the character's binary image (unsorted) #Return characters on ascending order with respect to the x-coordinate (most-left character first) plt.show() #arbitrary function that stores sorted list of character indeces indices = sorted(range(len(x_cntr_list)), key=lambda k: x_cntr_list[k]) img_res_copy = [] for idx in indices: img_res_copy.append(img_res[idx])# stores character images according to their index img_res = np.array(img_res_copy) return img_res
۱- ()cv.findContours و ()cv.drawContours – کانتور ها را می توان به طور ساده به عنوان یک منحنی تعریف کرد که به تمام نقاط پیوسته (در امتداد مرز) به هم متصل هم رنگ و هم وزن را در بر می گیرد. کانتور ها ابزاری مفید برای تجزیه و تحلیل شکل و تشخیص و شناسایی اشیا هستند.
برای دقت بهتر، از تصاویر باینری استفاده کنید. بنابراین قبل از پیدا کردن خطوط، آستانه یا لبه تصویر را مشخص کنید.
از OpenCV 3.2 به بعد تابع findContours() دیگر تصویر اصلی را اصلاح نمی کند.
در OpenCV یافتن خطوط مانند یافتن جسم سفید از پس زمینه سیاه است. بنابراین به یاد داشته باشید ، شیئی که باید پیدا شود باید سفید و زمینه باید سیاه باشد.
برای ترسیم خطوط از تابع cv.drawContours استفاده می شود. همچنین این تابع می تواند برای ترسیم هر شکلی به شرط داشتن نقاط مرزی آن استفاده شود.
۲- بعد از پیدا کردن تمام خطوط، آن ها را یک به یک در نظر می گیریم و بعد مستطیل محدود مربوطه را محاسبه می کنیم. اکنون مستطیل محاطی را در نظر بگیرید کوچکترین مستطیل ممکن است که حاوی شمارنده است.
۳- از آنجا که ابعاد این مستطیل های مرزی را داریم، تنها کاری که باید انجام دهیم این است پارامتر ها را تنظیم کنیم و مستطیل مورد نظر حاوی کاراکتر های مورد نیاز را فیلتر کنیم. برای این منظور، ما با مقایسه ابعادی بر اساس پذیرش مستطیل هایی که دارای عرضی بین ۰ تا { طول تصویر تقسیم بر تعداد کاراکتر ها } و طولی بین { عرض تصویر تقسیم بر ۲ } و { ۴ برابر عرض تصویر تقسیم بر ۵ } هستند، انجام می دهیم. اگر همه چیز خوب کار کند، همه کاراکتر ها به عنوان تصاویر باینری استخراج می شوند.
گام چهارم : ایجاد یک مدل یادگیری ماشین و آموزش آن برای شناسایی کاراکتر ها
۱- داده ها آماده و مرتب هستند، اکنون وقت آن است که یک شبکه عصبی ایجاد کنیم که به اندازه کافی هوشمند باشد تا کاراکتر ها را پس از آموزش تشخیص دهد.
model = Sequential() model.add(Conv2D(32, (24,24), input_shape=(28, 28, 3), activation='relu', padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.4)) model.add(Flatten()) model.add(Dense(128, activation='relu')) model.add(Dense(36, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer=optimizers.Adam(lr=0.00001), metrics=['accuracy']) model.summary()
۲- برای ساده نگه داشتن مدل، ما با ایجاد یک شی ترتیبی محور شروع می کنیم.
۳- لایه اول یک لایه کانولوشن با ۳۲ فیلتر خروجی، یک پنجره کانولوشن با اندازه ۵*۵ و Relu به عنوان تابع فعال سازی خواهد بود.
۴- سپس، ما یک لایه max-pooling با اندازه پنجره ۲*۲ اضافه خواهیم کرد.
۵-Max pooling یک فرآیند گسسته سازی مبتنی بر نمونه است. هدف این است که نمایشی از ورودی (تصویر ، ماتریس خروجی لایه پنهان و غیره) را نمونه برداری کنید، از ابعاد آن بکاهید و اجازه دهید فرضیه هایی در مورد ویژگی های موجود در مناطق زیر مجموعه ایجاد شود.
۶- اکنون، برای مراقبت از بیش برازش ( Overfit ) ، اندکی نرخ کاهش ( dropout rate ) را اضافه خواهیم کرد.
۷-Dropout یک ابر پارامتر تنظیم کننده است که برای جلوگیری از بیش برازش بیش از حد شبکه های عصبی معرفی شده است. Dropout تکنیکی است که در طی آموزش، نورون های تصادفی انتخاب شده نادیده گرفته می شوند. آن ها به طور تصادفی از بین می روند. ما نرخ کاهش را ۰٫۴ را انتخاب کرده ایم ، به این معنی که ۶۰٪ گره حفظ خواهد شد.
۸- اکنون وقت آن است که داده های گره را مسطح کنیم ، بنابراین برای آن یک لایه مسطح اضافه می کنیم. لایه مسطح داده ها را از لایه قبلی می گیرد و آن ها را در یک بعد واحد نشان می دهد.
۹- در نهایت، ما ۲ لایه متراکم اضافه خواهیم کرد ، یکی با بعد فضای خروجی ۱۲۸ ، تابع فعال سازی = relu و دیگری ، لایه نهایی ما با ۳۶ خروجی برای طبقه بندی ۲۶ حروف الفبا (AZ) + 10 رقم ( ۰–۹) و تابع فعال سازی = softmax .
گام پنجم : مدل را آموزش دهید
۱-داده هایی که ما استفاده خواهیم کرد شامل تصاویر حروف الفبا (A-Z) و ارقام (۰–۹) با اندازه ۲۸×۲۸ است ، همچنین داده ها متعادل هستند بنابراین در اینجا نیازی به انجام هر نوع تنظیم داده ای نخواهیم داشت.
۲-ما از کلاس ImageDataGenerator موجود در Keras استفاده خواهیم کرد تا داده های بیشتری را با استفاده از تکنیک های افزایش تصویر مانند تغییر عرض، تغییر ارتفاع ایجاد کنیم.
۳-اکنون وقت آن است که مدل خود را آموزش دهیم!
ما از تابع categorical_crossentropy به عنوان تابع ضرر، از تابع Adam به عنوان تابع بهینه سازی و تابع Accuracy به عنوان ماتریس خطای خود استفاده خواهیم کرد.
from tensorflow.keras.preprocessing.image import ImageDataGenerator train_datagen = ImageDataGenerator(rescale=1./255, width_shift_range=0.1, height_shift_range=0.1) train_generator = train_datagen.flow_from_directory( 'data/data/train', batch_size=1, target_size=(28,28), class_mode='categorical') validation_generator = train_datagen.flow_from_directory( 'data/data/val', # this is the target directory target_size=(28,28), # all images will be resized to 28x28 batch_size=1, class_mode='categorical')
گام ششم : مدل را ذخیره کنید
۱- در یادگیری ماشین، هنگام کار با کتابخانه یادگیری scikit ، ما برای پیش بینی داده های جدید یا مقایسه مدل ها با مدل های دیگر، باید مدل های آموزش دیده را در یک پرونده ذخیره کنیم و آن ها را بازیابی کنیم.
۲- ذخیره کردن داده ها Serialization نامیده می شود ، در حالی که بازیابی داده ها Deserialization نامیده می شود.
۳- روش های مختلفی برای دستیابی به این هدف وجود دارد، با استفاده از pickle و joblib یا فرمتKeras H5 . ما از فرمت Keras H5 استفاده خواهیم کرد و این فرمت یک گزینه کم وزن برای TensorFlow’s SavedModel است.
model.save(“anpr_model.h5”)
۴- با فراخوانی save(‘my_model.h5’) فایل my_model.h5 به عنوان H5 ایجاد می شود که می تواند برای پیش بینی داده های جدید استفاده شود.
روشی برای تشخیص پلاک های ایرانی
همانطور که در این پروژه دیدیم، با روش گفته شده می توان پلاک هایی که شامل حروف و اعداد انگلیسی هستند را تشخیص داد. اما برای پلاک های ایرانی این روش جوابگو نیست. پلاک های استاندارد ایران شامل ۷ رقم عدد فارسی به همراه یک حرف الفبا یا علامت هستند.
برای تشخیص اعداد و حروف پلاک های فارسی باید شبکه ای با صد ها هزار تصویر از پلاک های مختلف تهیه کرد تا بتوان دقت مناسبی در پلاک خوانی بدست آورد. این کار برای اکثر علاقه مندان و توسعه دهندگان ایران، قابل انجام و بهینه نیست و علاوه بر وقت زیادی که نیاز است بر روی جمع آوری دیتاست صرف شود، برای تشخیص چارچوب پلاک های ایرانی هم باید شبکه به نحوه ی خاصی آماده شود.
کتابخانه تشخیص پلاک ایرانی ساتپا ، روشی مناسب برای پیاده سازی برنامه های پلاک خوان فارسی است. ساتپا در زبان C++ نوشته شده و به همین دلیل از سرعت بالایی در پلاک خوانی برخوردار است. از کتابخانه ساتپا می توان در زبان های مختلفی استفاده کرد و به راحتی با دادن تصویر یا ویدیو دوربین پلاک خوان به این کتابخانه، پلاک خودرو های موجود در تصویر به شما برگردانده می شود.
همچنین این کتابخانه از پشتیبانی فنی بسیار مناسبی برخوردار است. پشتیبانی ساتپا شما را در تمامی مراحل اجرا پروژه راهنمایی می کنند و همچنین می توانید از مستندات کتابخانه تشخیص پلاک ساتپا نیز برای اجرا پروژه خود استفاده کنید.
گام هفتم : استقرار مدل با استفاده از Flask
۱- ابتدا کلاس Flask را وارد خواهیم کرد. نمونه ای از این کلاس برنامه WSGI ما خواهد بود.
۲-بعد نمونه ای از این کلاس را ایجاد می کنیم. اولین آرگومان نام ماژول یا بسته برنامه است. اگر از یک ماژول استفاده می کنید (مانند این مثال) ، باید از __name__ استفاده کنید زیرا بسته به اینکه به عنوان برنامه شروع شده یا به عنوان ماژول وارد شده باشد، نامش متفاوت خواهد بود (“__main__ اصلی” در مقابل نام واقعی وارد کردن). این مورد لازم است تا Flask بداند کجا به دنبال الگو ها، فایل های ثابت و غیره باشد. برای اطلاعات بیشتر، نگاهی به اسناد و مدارک فلاسک بیندازید.
۳- سپس با استفاده از decorator مسیر ()route به Flask می گوییم چه لینک URL ای باید تابع ما را فعال کند.
۴- به این تابع نامی داده می شود که برای تولید URL برای آن عملکرد خاص نیز استفاده می شود و پیامی را که می خواهیم در مرورگر کاربر نمایش دهیم برمی گرداند.
from flask import Flask, render_template, send_from_directory, request, abort from keras.models import load_model import numpy as np import cv2 import os from werkzeug.utils import secure_filename UPLOAD_FOLDER = 'static/images' app = Flask(__name__) @app.route("/") @app.route("/index") def index(): return render_template('index.html')
۵- قسمت بعدی ساختن یک API است که تصویر را از طریق GUI دریافت می کند و شماره پلاک را بر اساس مدل ما برمی گرداند. بدین منظور با افزودن خط زیر در پرونده app.py به پروژه خود، مدل را به شکل شی پایتون سریال سازی کردیم (فایل anpr_model.h5 را در پروژه خود ذخیره کنید).
model = load_model('anpr_model.h5')
۶- توابعی ایجاد کنید که پردازش تصویر، تقسیم بندی و در نهایت پیش بینی را روی تصویر انتخاب شده با استفاده از مدل ذخیره شده انجام دهد.
@app.route('/segment_and_predict', methods=['GET', 'POST']) def segment_and_predict(): # Preprocess cropped license plate image if request.method == 'POST': uploaded_file = request.files['image'] original_image = uploaded_file.filename print('original_image', original_image) if not uploaded_file: return render_template('index.html', label="No file") if uploaded_file.filename != '': filename = secure_filename(uploaded_file.filename) file_ext = os.path.splitext(filename)[1] # if file_ext not in app.config['UPLOAD_EXTENSIONS']: # abort(400) uploaded_file.save(os.path.join(app.config['UPLOAD_PATH'], filename)) image = cv2.imread("static/images/"+uploaded_file.filename, cv2.IMREAD_COLOR) img_lp = cv2.resize(image, (333, 75)) img_gray_lp = cv2.cvtColor(img_lp, cv2.COLOR_BGR2GRAY) _, img_binary_lp = cv2.threshold(img_gray_lp, 200, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) img_binary_lp = cv2.erode(img_binary_lp, (3,3)) img_binary_lp = cv2.dilate(img_binary_lp, (3,3)) LP_WIDTH = img_binary_lp.shape[0] LP_HEIGHT = img_binary_lp.shape[1] # Make borders white img_binary_lp[0:3,:] = 255 img_binary_lp[:,0:3] = 255 img_binary_lp[72:75,:] = 255 img_binary_lp[:,330:333] = 255 # Estimations of character contours sizes of cropped license plates dimensions = [LP_WIDTH/6, LP_WIDTH/2, LP_HEIGHT/10, ۲*LP_HEIGHT/3] cv2.imwrite('contour.jpg',img_binary_lp) # Get contours within cropped license plate char_list = find_contours(dimensions, img_binary_lp) dic = {} characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' for i, c in enumerate(characters): dic[i] = c output = [] for i, ch in enumerate(char_list): # iterating over the characters img_ = cv2.resize(ch, (28, 28)) img = fix_dimension(img_) img = img.reshape(1, 28, 28, 3) y_ = model.predict_classes(img)[0] # predicting the class character = dic[y_] # output.append(character) plate_number = ''.join(output) return render_template('results.html', prediction=plate_number)
۷- پروژه را برای مشاهده نتایج اجرا کنید.
امیدواریم این آموزش برای شما مفید بوده باشد.
سلام، ممنون بابت مطلب آموزنده تون
سوالی که داشتم اینه که برای پیدا کردن موقعیت پلاک های ایرانی و همچنین تشخیص حروف و ارقامشون از چه شبکه عصبی استفاده کنیم تا دقت و سرعت خوبی داشته باشه؟
سلام
همونطور که توی مطلب ذکر کردیم میتونید از کتابخانه تشخیص پلاک ایرانی ساتپا استفاده کنید.
بله مطلب رو خوندم، همچین پروژه ای به صورت دانشجویی برامون تعریف شده و این که خودمون باید شبکه رو آموزش بدیم نه این که از کتابخونه آماده استفاده کنیم، برای همین پرسیدم
از روش هایی که توی این آموزش و آموزش های قبلی توضیح دادیم میتونید استفاده کنید ولی باید ارقام و حروف پلاک های فارسی رو به شبکه ترین کنید