欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Python OpenCV數(shù)字識別案例

 更新時間:2021年05月21日 11:01:27   作者:華為云開發(fā)者社區(qū)  
信用卡識別的案例用到了圖像處理的一些基本操作,對剛上手CV的人來說還是比較友好的。

前言

實踐是檢驗真理的唯一標(biāo)準(zhǔn)。

因為覺得一板一眼地學(xué)習(xí)OpenCV太過枯燥,于是在網(wǎng)上找了一個以項目為導(dǎo)向的教程學(xué)習(xí)。話不多說,動手做起來。

一、案例介紹

提供信用卡上的數(shù)字模板:

要求:識別出信用卡上的數(shù)字,并將其直接打印在原圖片上。雖然看起來很蠢,但既然可以將數(shù)字打印在圖片上,說明已經(jīng)成功識別數(shù)字,因此也可以將其轉(zhuǎn)換為數(shù)字文本保存。車牌號識別等項目的思路與此案例類似。

示例:

原圖

處理后的圖

二、步驟

大致分為如下幾個步驟:

1.模板讀入

2.模板預(yù)處理,將模板數(shù)字分開,并排序

3.輸入圖像預(yù)處理,將圖像中的數(shù)字部分提取出來

4.將數(shù)字與模板數(shù)字進行匹配,匹配率最高的即為對應(yīng)數(shù)字。

1、模板讀入,以及一些包的導(dǎo)入,函數(shù)定義等

import cv2 as cv
import numpy as np
import myutils
def cv_show(name, img):        # 自定義的展示函數(shù)
    cv.imshow(name, img)
    cv.waitKey(0)
# 讀入模板圖
n = 'text'
img = cv.imread("images/ocr_a_reference.png")
# cv_show(n, template)        # 自定義的展示函數(shù),方便顯示圖片

2、模板預(yù)處理,將模板數(shù)字分開,并排序

模板的預(yù)處理順序:灰度圖,二值化,再進行輪廓檢測。需要注意的是openCV檢測輪廓時是檢測白色邊框,因此要將模板圖的數(shù)字二值化變?yōu)榘咨?/p>

# 模板轉(zhuǎn)換為灰度圖
ref = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# cv_show(n, ref)

# 轉(zhuǎn)換為二值圖,把數(shù)字部分變?yōu)榘咨?
ref = cv.threshold(ref, 10, 255, cv.THRESH_BINARY_INV)[1]  # 騷寫法,函數(shù)多個返回值為元組,這里取第二個返回值
cv_show(n, ref)

# 對模板進行輪廓檢測,得到輪廓信息
refCnts, hierarchy = cv.findContours(ref.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
cv.drawContours(img, refCnts, -1, (0, 0, 255), 2)  # 第一個參數(shù)為目標(biāo)圖像
# cv_show(n, img)

紅色部分即為檢測出的輪廓。

接下來進行輪廓排序,因為檢測出的輪廓是無序的,因此要按照輪廓的左上角點的x坐標(biāo)來排序。輪廓排序后按順序放入字典,則字典中的鍵值對是正確匹配的,如‘0'對應(yīng)輪廓0 ,‘1'對應(yīng)輪廓1。

# 輪廓排序
refCnts = myutils.sort_contours(refCnts)[0]
digits = {}

# 單個輪廓提取到字典中
for (i, c) in enumerate(refCnts):
    (x, y, w, h) = cv.boundingRect(c)
    roi = ref[y:y + h, x:x + w]  # 在模板中復(fù)制出輪廓
    roi = cv.resize(roi, (57, 88))  # 改成相同大小的輪廓
    digits[i] = roi  # 此時字典鍵對應(yīng)的輪廓即為對應(yīng)數(shù)字。如鍵‘1'對應(yīng)輪廓‘1'

至此,模板圖處理完畢。

3、輸入圖像預(yù)處理,將圖像中的數(shù)字部分提取出來

在此步驟中需要將信用卡上的每個數(shù)字提取出來,并與上一步得到的模板一一匹配。首先初始化卷積核,方便之后tophat操作以及閉運算操作使用。

# 初始化卷積核
rectKernel = cv.getStructuringElement(cv.MORPH_RECT, (9, 3))
sqKernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))

接下來讀入圖片,調(diào)整圖片大小,轉(zhuǎn)換為灰度圖。

# 待分析圖片讀入,預(yù)處理
card_image = cv.imread("images/credit_card_01.png")
# cv_show('a', card_image)
card_image = myutils.resize(card_image, width=300)    # 更改圖片大小
gray = cv.cvtColor(card_image, cv.COLOR_BGR2GRAY)
# cv_show('gray', gray)

然后進行tophat操作,tophat可以突出圖片中明亮的區(qū)域,過濾掉較暗的部分:

tophat = cv.morphologyEx(gray, cv.MORPH_TOPHAT, rectKernel)
# cv_show('tophat', tophat)

再通過sobel算子檢測邊緣,進行一次閉操作,二值化,再進行一次閉操作,填補空洞。

# x方向的Sobel算子
gradX = cv.Sobel(tophat, cv.CV_32F, 1, 0, ksize=3) 

gradX = np.absolute(gradX)  # absolute: 計算絕對值
min_Val, max_val = np.min(gradX), np.max(gradX)
gradX = (255 * (gradX - min_Val) / (max_val - min_Val))
gradX = gradX.astype("uint8")

# 通過閉操作(先膨脹,再腐蝕)將數(shù)字連在一起.  將本是4個數(shù)字的4個框膨脹成1個框,就腐蝕不掉了
gradX = cv.morphologyEx(gradX, cv.MORPH_CLOSE, rectKernel)
# cv_show('close1', gradX)

# 二值化
thresh = cv.threshold(gradX, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]

# 閉操作,填補空洞
thresh = cv.morphologyEx(thresh, cv.MORPH_CLOSE, sqKernel)
# cv_show('close2', thresh)

之后就可以查找輪廓了。

threshCnts = cv.findContours(thresh.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]
card_copy = card_image.copy()
cv.drawContours(card_copy, threshCnts, -1, (0, 0, 255), 2)
cv_show('Input_Contours', card_copy)

4、模板匹配

將模板數(shù)字和待識別的圖片都處理好后,就可以進行匹配了。

locs = []  # 存符合條件的輪廓
for i, c in enumerate(threshCnts):
    # 計算矩形
    x, y, w, h = cv.boundingRect(c)

    ar = w / float(h)
    # 選擇合適的區(qū)域,根據(jù)實際任務(wù)來,這里的基本都是四個數(shù)字一組
    if 2.5 < ar < 4.0:
        if (40 < w < 55) and (10 < h < 20):
            # 符合的留下來
            locs.append((x, y, w, h))

# 將符合的輪廓從左到右排序
locs = sorted(locs, key=lambda x: x[0])

接下來,遍歷每一個大輪廓,每個大輪廓中有四個數(shù)字,對應(yīng)四個小輪廓。將小輪廓與模板匹配。

output = []  # 存正確的數(shù)字
for (i, (gx, gy, gw, gh)) in enumerate(locs):  # 遍歷每一組大輪廓(包含4個數(shù)字)
    groupOutput = []

    # 根據(jù)坐標(biāo)提取每一個組(4個值)
    group = gray[gy - 5:gy + gh + 5, gx - 5:gx + gw + 5]  # 往外擴一點
    # cv_show('group_' + str(i), group)
    # 預(yù)處理
    group = cv.threshold(group, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]  # 二值化的group
    # cv_show('group_'+str(i),group)
    # 計算每一組的輪廓 這樣就分成4個小輪廓了
    digitCnts = cv.findContours(group.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]
    # 排序
    digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0]

# 計算并匹配每一組中的每一個數(shù)值
    for c in digitCnts:  # c表示每個小輪廓的終點坐標(biāo)
        z = 0
        # 找到當(dāng)前數(shù)值的輪廓,resize成合適的的大小
        (x, y, w, h) = cv.boundingRect(c)  # 外接矩形
        roi = group[y:y + h, x:x + w]  # 在原圖中取出小輪廓覆蓋區(qū)域,即數(shù)字
        roi = cv.resize(roi, (57, 88))
        # cv_show("roi_"+str(z),roi)

        # 計算匹配得分: 0得分多少,1得分多少...
        scores = []  # 單次循環(huán)中,scores存的是一個數(shù)值 匹配 10個模板數(shù)值的最大得分

        # 在模板中計算每一個得分
        # digits的digit正好是數(shù)值0,1,...,9;digitROI是每個數(shù)值的特征表示
        for (digit, digitROI) in digits.items():
            # 進行模板匹配, res是結(jié)果矩陣
            res = cv.matchTemplate(roi, digitROI, cv.TM_CCOEFF)  # 此時roi是X digitROI是0 依次是1,2.. 匹配10次,看模板最高得分多少
            Max_score = cv.minMaxLoc(res)[1]  # 返回4個,取第二個最大值Maxscore
            scores.append(Max_score)  # 10個最大值
        # print("scores:",scores)
        # 得到最合適的數(shù)字
        groupOutput.append(str(np.argmax(scores)))  # 返回的是輸入列表中最大值的位置
        z = z + 1
# 畫出來
    cv.rectangle(card_image, (gx - 5, gy - 5), (gx + gw + 5, gy + gh + 5), (0, 0, 255), 1)  # 左上角,右下角
# putText參數(shù):圖片,添加的文字,左上角坐標(biāo),字體,字體大小,顏色,字體粗細(xì)
    cv.putText(card_image, "".join(groupOutput), (gx, gy - 15), cv.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)

最后將其打印出來,任務(wù)就完成了。

cv.imshow("Output_image_"+str(i), card_image)
cv.waitKey(0)

總結(jié)

信用卡識別的案例用到了圖像處理的一些基本操作,對剛上手CV的人來說還是比較友好的。

以上就是詳解Python OpenCV數(shù)字識別案例的詳細(xì)內(nèi)容,更多關(guān)于Python OpenCV數(shù)字識別案例的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 聊聊自學(xué),那些讓你事半功倍的自學(xué)資源(干貨分享)

    聊聊自學(xué),那些讓你事半功倍的自學(xué)資源(干貨分享)

    B站是一個學(xué)習(xí)網(wǎng)站。一入B站深似海,從此游戲是路人。B站雖然視頻資源多,但是內(nèi)容也是五花八門、參差不齊,本文給大家收集了關(guān)于學(xué)習(xí)計算機編程的視頻,這里有我曾經(jīng)的入門視頻,也有跟朋友交流獲得的,特此篩選了下面這些視頻,分享給大家
    2021-04-04
  • Matlab使用fft畫出信號頻譜圖的方法

    Matlab使用fft畫出信號頻譜圖的方法

    這篇文章主要介紹了Matlab使用fft畫出信號頻譜圖的方法,本文通過實例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 淺談軟件工程師的自我修養(yǎng)

    淺談軟件工程師的自我修養(yǎng)

    在本文中,我們將探討軟件開發(fā)過程中關(guān)于角色、重構(gòu)和質(zhì)量的問題。軟件不僅成為了一個必需品,更成為了一個競爭優(yōu)勢。因為眾多公司圍繞軟件而競爭,軟件開發(fā)相關(guān)的事宜顯得越發(fā)重要。開發(fā)軟件的人—軟件工程師正顯得越發(fā)重要。
    2021-05-05
  • vant/vue實現(xiàn)小程序下拉刷新功能方法詳解

    vant/vue實現(xiàn)小程序下拉刷新功能方法詳解

    這篇文章主要介紹了vant/vue實現(xiàn)小程序下拉刷新功能方法詳解,需要的朋友可以參考下
    2022-12-12
  • 淺談架構(gòu)模式變遷之從分層架構(gòu)到微服務(wù)架構(gòu)

    淺談架構(gòu)模式變遷之從分層架構(gòu)到微服務(wù)架構(gòu)

    一般地,架構(gòu)模式大致可以分成兩類,單體架構(gòu)(monolithic architecture)和分布式架構(gòu)(distributed architecture)。
    2021-05-05
  • 漫談架構(gòu)之微服務(wù)

    漫談架構(gòu)之微服務(wù)

    微服務(wù)的架構(gòu)出現(xiàn)已經(jīng)很久很久了,微服務(wù)架構(gòu)就是一種將單個應(yīng)用程序轉(zhuǎn)換為一組小服務(wù)的方法,每個小服務(wù)都在自己的進程中運行,并使用輕量級的交互方式(如HTTP)進行通信
    2021-06-06
  • uniapp打包安卓App的兩種方式(云打包、本地打包)方法詳解

    uniapp打包安卓App的兩種方式(云打包、本地打包)方法詳解

    這篇文章主要介紹了uniapp打包安卓App的兩種方式(云打包、本地打包)方法詳解,需要的朋友可以參考下
    2022-12-12
  • 詳解靜態(tài)分析技術(shù)符號執(zhí)行

    詳解靜態(tài)分析技術(shù)符號執(zhí)行

    本文提綱絜領(lǐng)的介紹了符號執(zhí)行,讓大家明白這個技術(shù)的主要作用和面臨的挑戰(zhàn),領(lǐng)大家入坑。
    2021-05-05
  • vscode配置備份的操作代碼

    vscode配置備份的操作代碼

    這篇文章主要介紹了vscode配置備份的相關(guān)知識,本文通過實例代碼相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 匯編語言無效指令錯誤概述

    匯編語言無效指令錯誤概述

    此錯誤僅適用于奔騰 處理器、奔騰處理器與MMX技術(shù)、奔騰OverDrive處理器 和奔騰OverDrive處理器帶有MMX技術(shù)。 奔騰Pro處理器, 奔騰II處理器和i486及更早版本處理器不受影響
    2012-07-07

最新評論