پروژه پلاک خوان در پایتون

صورت مسئله – یک تولید کننده ، در محل کارخانه خود با مشکلات مختلف امنیتی مواجه شده است. با ارزیابی دقیق کارخانه ، متوجه می شویم که از روش های استاندارد برای کنترل تردد و نظارت استفاده نمی شود. آن ها همچنین تعداد زیادی نیروی انسانی جهت حافظت و نظارت استخدام کرده اند که با وجود حضور آن ها ، امکان نظارت دقیق و ۲۴ ساعته بر کل محوطه کارخانه نیست.

در طول روز افراد زیادی به محوطه کارخانه وارد و خارج می شوند که اکثر این تردد ها از طریق خودرو ها و وسایل نقلیه صورت می گیرد.

اکنون می خواهیم راهکاری ارائه دهیم تا بتوان به طور کامل و تمام وقت بر روی خودرو های در حال تردد در محوطه این کارخانه نظارت داشته باشیم و اطلاعات کامل تردد خودرو ها را ثبت کنیم. راهکار مناسب برای این کار، پلاک خوان است. می خواهیم هر نگهبان بتواند از طریق تلفن همراه خود ، تصویری از خودرو گرفته و شماره پلاک آن در سیستم ثبت شود.

با ما همراه باشید تا در این آموزش، یک برنامه پلاک خوان برای تشخیص پلاک خودرو های در حال تردد پیاده سازی کنیم.

ابزارها و کتابخانه های مورد نیاز

  1. پایتون – از پایتون ۳٫۸ برای ساخت مدل های یادگیری ماشین استفاده شده است.
  2. IDE یا محیط توسعه – PyCharm و Jupyter Notebook
  3. NumPy و Pandas – ابزار Numpy یک بسته الحاقی برای انجام محاسبات عددی با پایتون است که جایگزین NumArray و Numeric شده است. از آرایه های چند بعدی ( جداول ) و ماتریس ها پشتیبانی می کند.

Pandas با تبدیل فایل های داده ی CSV ، JSON و TSV یا پایگاه داده SQL به یک فریم داده، یک شی پایتون مانند یک Excel یا یک جدول SPSS با سطر ها و ستون ها تجزیه و تحلیل را ساده می کند.

  1. Matplotlib – برای تجسم سازی استفاده می شود
  2. Scikit-learn – این ابزار یک کتابخانه متن باز یادگیری ماشین Python است که در بر روی SciPy (پایتون علمی) ، NumPy و matplotlib ساخته شده است و تعدادی الگوریتم بهینه برای یادگیری نظارت شده و بدون نظارت فراهم می کند.
  3. Keras – Keras یک کتابخانه یادگیری عمیق پایتون است که می تواند بر روی Theano و TensorFlow اجرا شود. این کتابخانه می تواند روی GPU و CPU اجرا شود و از هر دو شبکه رابط و کانولوشن و همچنین ترکیب آن ها پشتیبانی کند.
  4. 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 ، فهرست مورد نظر را برای ذخیره الگو ها و محل بارگیری آن ها تعیین کنید. می توانید نام پوشه ای را که هنوز وجود ندارد تعیین کنید. در این حالت ، دایرکتوری ایجاد می شود.

هوش مصنوعی 2

۴- روی 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 استفاده می شود. همچنین این تابع می تواند برای ترسیم هر شکلی به شرط داشتن نقاط مرزی آن استفاده شود.

هوش مصنوعی 3

۲- بعد از پیدا کردن تمام خطوط، آن ها را یک به یک در نظر می گیریم و بعد مستطیل محدود مربوطه را محاسبه می کنیم. اکنون مستطیل محاطی را در نظر بگیرید کوچکترین مستطیل ممکن است که حاوی شمارنده است.

هوش مصنوعی 4

۳- از آنجا که ابعاد این مستطیل های مرزی را داریم، تنها کاری که باید انجام دهیم این است پارامتر ها را تنظیم کنیم و مستطیل مورد نظر حاوی کاراکتر های مورد نیاز را فیلتر کنیم. برای این منظور، ما با مقایسه ابعادی بر اساس پذیرش مستطیل هایی که دارای عرضی بین ۰ تا { طول تصویر تقسیم بر تعداد کاراکتر ها } و طولی بین { عرض تصویر تقسیم بر ۲ }  و { ۴ برابر عرض تصویر تقسیم بر ۵ } هستند، انجام می دهیم. اگر همه چیز خوب کار کند، همه کاراکتر ها به عنوان تصاویر باینری استخراج می شوند.

پلاک خوان

گام چهارم : ایجاد یک مدل یادگیری ماشین و آموزش آن برای شناسایی کاراکتر ها

۱- داده ها آماده و مرتب هستند، اکنون وقت آن است که یک شبکه عصبی ایجاد کنیم که به اندازه کافی هوشمند باشد تا کاراکتر ها را پس از آموزش تشخیص دهد.

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 .

پلاک خوان 2

گام پنجم : مدل را آموزش دهید

۱-داده هایی که ما استفاده خواهیم کرد شامل تصاویر حروف الفبا (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)

۷- پروژه را برای مشاهده نتایج اجرا کنید.

امیدواریم این آموزش برای شما مفید بوده باشد.

بیشتر بخوانید

منبع medium.com

همچنین ببینید

فناوری تشخیص چهره و کاربردهای آن، تاریخچه تکنولوژی تشخیص چهره

فناوری تشخیص چهره و کاربردهای آن + تاریخچه

فناوری تشخیص چهره یک فناوری بیومتریک است که با استفاده از تجزیه و تحلیل الگوهایی …

4 نظر

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

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *