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

OpenCV?Python身份證信息識別過程詳解

 更新時間:2022年04月11日 08:20:11   作者:wFitting  
本篇文章使用OpenCV-Python和CnOcr來實現(xiàn)身份證信息識別的案例,本篇文章使用的Python版本為3.6,OpenCV-Python版本為3.4.1.15,如果是4.x版本的同學,可能會有一些Api操作不同,下面跟隨小編看下OpenCV?Python身份證信息識別過程

本篇文章使用OpenCV-Python和CnOcr來實現(xiàn)身份證信息識別的案例。想要識別身份證中的文本信息,總共分為三大步驟:一、通過預處理身份證區(qū)域檢測查找;二、身份證文本信息提?。蝗?、身份證文本信息識別。下面來看一下識別的具體過程CnOcr官網(wǎng)。識別過程視頻

前置環(huán)境

這里的環(huán)境需要安裝OpenCV-Python,Numpy和CnOcr。本篇文章使用的Python版本為3.6,OpenCV-Python版本為3.4.1.15,如果是4.x版本的同學,可能會有一些Api操作不同。這些依賴的安裝和介紹,我就不在這里贅述了,均是使用Pip進行安裝。

識別過程

首先,導入所需要的依賴cv2,numpy,cnocr并創(chuàng)建一個show圖像的函數(shù),方便后面使用:

import cv2
import numpy as np
from cnocr import CnOcr
def show(image, window_name):
    cv2.namedWindow(window_name, 0)
    cv2.imshow(window_name, image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
# 加載CnOcr的模型
ocr = CnOcr(model_name='densenet_lite_136-gru')

身份證區(qū)域查找

通過對加載圖像的灰度處理–>濾波處理–>二值處理–>邊緣檢測–>膨脹處理–>輪廓查找–>透視變換(校正)–>圖像旋轉–>固定圖像大小一系列處理之后,我們便可以清晰的裁剪出身份證的具體區(qū)域。

原始圖像

使用OpenCV的imread方法讀取本地圖片。

image = cv2.imread('card.png')
show(image, "image")

在這里插入圖片描述

灰度處理

將三通道BGR圖像轉化為灰度圖像,因為一下OpenCV操作都是需要基于灰度圖像進行的。

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
show(gray, "gray")

在這里插入圖片描述

中值濾波

使用濾波處理,也就是模糊處理,這樣可以減少一些不需要的噪點。

blur = cv2.medianBlur(gray, 7)
show(blur, "blur")

在這里插入圖片描述

二值處理

二值處理,非黑即白。這里通過cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU,使用OpenCV的大津法二值化,對圖像進行處理,經(jīng)過處理后的圖像,更加清晰的分辨出了背景和身份證的區(qū)域。

threshold = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
show(threshold, "threshold")

在這里插入圖片描述

邊緣檢測

使用OpenCV中最常用的邊緣檢測方法,Canny,檢測出圖像中的邊緣。

canny = cv2.Canny(threshold, 100, 150)
show(canny, "canny")

在這里插入圖片描述

邊緣膨脹

為了使上一步邊緣檢測的邊緣更加連貫,使用膨脹處理,對白色的邊緣膨脹,即邊緣線條變得更加粗一些。

kernel = np.ones((3, 3), np.uint8)
dilate = cv2.dilate(canny, kernel, iterations=5)
show(dilate, "dilate")

在這里插入圖片描述

輪廓檢測

使用findContours對邊緣膨脹過的圖片進行輪廓檢測,可以清晰的看到背景部分還是有很多噪點的,所需要識別的身份證部分也被輪廓圈了起來。

binary, contours, hierarchy = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
image_copy = image.copy()
res = cv2.drawContours(image_copy, contours, -1, (255, 0, 0), 20)
show(res, "res")

在這里插入圖片描述

輪廓排序

經(jīng)過對輪廓的面積排序,我們可以準確的提取出身份證的輪廓。

contours = sorted(contours, key=cv2.contourArea, reverse=True)[0]
image_copy = image.copy()
res = cv2.drawContours(image_copy, contours, -1, (255, 0, 0), 20)
show(res, "contours")

在這里插入圖片描述

透視變換

通過對輪廓近似提取出輪廓的四個頂點,并按順序進行排序,之后通過warpPerspective對所選圖像區(qū)域進行透視變換,也就是對所選的圖像進行校正處理。

epsilon = 0.02 * cv2.arcLength(contours, True)
approx = cv2.approxPolyDP(contours, epsilon, True)
n = []
for x, y in zip(approx[:, 0, 0], approx[:, 0, 1]):
    n.append((x, y))
n = sorted(n)
sort_point = []
n_point1 = n[:2]
n_point1.sort(key=lambda x: x[1])
sort_point.extend(n_point1)
n_point2 = n[2:4]
n_point2.sort(key=lambda x: x[1])
n_point2.reverse()
sort_point.extend(n_point2)
p1 = np.array(sort_point, dtype=np.float32)
h = sort_point[1][1] - sort_point[0][1]
w = sort_point[2][0] - sort_point[1][0]
pts2 = np.array([[0, 0], [0, h], [w, h], [w, 0]], dtype=np.float32)

# 生成變換矩陣
M = cv2.getPerspectiveTransform(p1, pts2)
# 進行透視變換
dst = cv2.warpPerspective(image, M, (w, h))
# print(dst.shape)
show(dst, "dst")

在這里插入圖片描述

固定圖像大小

將圖像變正,通過對圖像的寬高進行判斷,如果寬<高,就將圖像旋轉90°。并將圖像resize到指定大小。方便之后對圖像進行處理。

if w < h:
    dst = np.rot90(dst)
resize = cv2.resize(dst, (1084, 669), interpolation=cv2.INTER_AREA)
show(resize, "resize")

在這里插入圖片描述

檢測身份證文本位置

經(jīng)過灰度,二值濾波和開閉運算后,將圖像中的文本區(qū)域主鍵顯現(xiàn)出來。

temp_image = resize.copy()
gray = cv2.cvtColor(resize, cv2.COLOR_BGR2GRAY)
show(gray, "gray")
threshold = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
show(threshold, "threshold")
blur = cv2.medianBlur(threshold, 5)
show(blur, "blur")
kernel = np.ones((3, 3), np.uint8)
morph_open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel)
show(morph_open, "morph_open")

在這里插入圖片描述

極度膨脹

給定一個比較大的卷積盒,進行膨脹處理,使白色的區(qū)域加深加大。更加顯現(xiàn)出文本的區(qū)域。

kernel = np.ones((7, 7), np.uint8)
dilate = cv2.dilate(morph_open, kernel, iterations=6)
show(dilate, "dilate")

在這里插入圖片描述

輪廓查找文本區(qū)域

使用輪廓查找,將白色塊狀區(qū)域查找出來。

binary, contours, hierarchy = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
resize_copy = resize.copy()
res = cv2.drawContours(resize_copy, contours, -1, (255, 0, 0), 2)
show(res, "res")

在這里插入圖片描述

篩選出文本區(qū)域

經(jīng)過上一步輪廓檢測,我們發(fā)現(xiàn),選中的輪廓中有一些噪點,通過對圖像的觀察,使用近似輪廓,然后用以下邏輯篩選出文本區(qū)域。并定義文本描述信息,將文本區(qū)域位置信息加入到指定集合中。到這一步,可以清晰的看到,所需要的文本區(qū)域統(tǒng)統(tǒng)都被提取了出來。

labels = ['姓名', '性別', '民族', '出生年', '出生月', '出生日', '住址', '公民身份證號碼']
positions = []
data_areas = {}
resize_copy = resize.copy()
for contour in contours:
    epsilon = 0.002 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon, True)
    x, y, w, h = cv2.boundingRect(approx)
    if h > 50 and x < 670:
        res = cv2.rectangle(resize_copy, (x, y), (x + w, y + h), (0, 255, 0), 2)
        area = gray[y:(y + h), x:(x + w)]
        blur = cv2.medianBlur(area, 3)
        data_area = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
        positions.append((x, y))
        data_areas['{}-{}'.format(x, y)] = data_area

show(res, "res")

在這里插入圖片描述

對文本區(qū)域進行排序

發(fā)現(xiàn)文本的區(qū)域是由下到上的順序,并且x軸從左到右的的區(qū)域是無序的,所以使用以下邏輯,對文本區(qū)域進行排序

positions.sort(key=lambda p: p[1])
result = []
index = 0
while index < len(positions) - 1:
    if positions[index + 1][1] - positions[index][1] < 10:
        temp_list = [positions[index + 1], positions[index]]
        for i in range(index + 1, len(positions)):
            if positions[i + 1][1] - positions[i][1] < 10:
                temp_list.append(positions[i + 1])
            else:
                break
        temp_list.sort(key=lambda p: p[0])
        positions[index:(index + len(temp_list))] = temp_list
        index = index + len(temp_list) - 1
    else:
        index += 1

識別文本

對文本區(qū)域使用CnOcr一一進行識別,最后將識別結果進行輸出。

positions.sort(key=lambda p: p[1])
result = []
index = 0
while index < len(positions) - 1:
    if positions[index + 1][1] - positions[index][1] < 10:
        temp_list = [positions[index + 1], positions[index]]
        for i in range(index + 1, len(positions)):
            if positions[i + 1][1] - positions[i][1] < 10:
                temp_list.append(positions[i + 1])
            else:
                break
        temp_list.sort(key=lambda p: p[0])
        positions[index:(index + len(temp_list))] = temp_list
        index = index + len(temp_list) - 1
    else:
        index += 1

在這里插入圖片描述

結語

通過以上的步驟,便成功的將身份證信息進行了提取,過程中的一些數(shù)字參數(shù),可能會在不同的場景中有些許的調整。
以下放上所有的代碼:

代碼

import cv2
import numpy as np
from cnocr import CnOcr

def show(image, window_name):
    cv2.namedWindow(window_name, 0)
    cv2.imshow(window_name, image)
    # 0任意鍵終止窗口
    cv2.waitKey(0)
    cv2.destroyAllWindows()


ocr = CnOcr(model_name='densenet_lite_136-gru')

image = cv2.imread('card.png')
show(image, "image")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
show(gray, "gray")
blur = cv2.medianBlur(gray, 7)
show(blur, "blur")
threshold = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
show(threshold, "threshold")
canny = cv2.Canny(threshold, 100, 150)
show(canny, "canny")
kernel = np.ones((3, 3), np.uint8)
dilate = cv2.dilate(canny, kernel, iterations=5)
show(dilate, "dilate")
binary, contours, hierarchy = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
image_copy = image.copy()
res = cv2.drawContours(image_copy, contours, -1, (255, 0, 0), 20)
show(res, "res")
contours = sorted(contours, key=cv2.contourArea, reverse=True)[0]
image_copy = image.copy()
res = cv2.drawContours(image_copy, contours, -1, (255, 0, 0), 20)
show(res, "contours")
epsilon = 0.02 * cv2.arcLength(contours, True)
approx = cv2.approxPolyDP(contours, epsilon, True)
n = []
for x, y in zip(approx[:, 0, 0], approx[:, 0, 1]):
    n.append((x, y))
n = sorted(n)
sort_point = []
n_point1 = n[:2]
n_point1.sort(key=lambda x: x[1])
sort_point.extend(n_point1)
n_point2 = n[2:4]
n_point2.sort(key=lambda x: x[1])
n_point2.reverse()
sort_point.extend(n_point2)
p1 = np.array(sort_point, dtype=np.float32)
h = sort_point[1][1] - sort_point[0][1]
w = sort_point[2][0] - sort_point[1][0]
pts2 = np.array([[0, 0], [0, h], [w, h], [w, 0]], dtype=np.float32)

M = cv2.getPerspectiveTransform(p1, pts2)
dst = cv2.warpPerspective(image, M, (w, h))
# print(dst.shape)
show(dst, "dst")
if w < h:
    dst = np.rot90(dst)
resize = cv2.resize(dst, (1084, 669), interpolation=cv2.INTER_AREA)
show(resize, "resize")
temp_image = resize.copy()
gray = cv2.cvtColor(resize, cv2.COLOR_BGR2GRAY)
show(gray, "gray")
threshold = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
show(threshold, "threshold")
blur = cv2.medianBlur(threshold, 5)
show(blur, "blur")
kernel = np.ones((3, 3), np.uint8)
morph_open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel)
show(morph_open, "morph_open")
kernel = np.ones((7, 7), np.uint8)
dilate = cv2.dilate(morph_open, kernel, iterations=6)
show(dilate, "dilate")
binary, contours, hierarchy = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
resize_copy = resize.copy()
res = cv2.drawContours(resize_copy, contours, -1, (255, 0, 0), 2)
show(res, "res")
labels = ['姓名', '性別', '民族', '出生年', '出生月', '出生日', '住址', '公民身份證號碼']
positions = []
data_areas = {}
resize_copy = resize.copy()
for contour in contours:
    epsilon = 0.002 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon, True)
    x, y, w, h = cv2.boundingRect(approx)
    if h > 50 and x < 670:
        res = cv2.rectangle(resize_copy, (x, y), (x + w, y + h), (0, 255, 0), 2)
        area = gray[y:(y + h), x:(x + w)]
        blur = cv2.medianBlur(area, 3)
        data_area = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
        positions.append((x, y))
        data_areas['{}-{}'.format(x, y)] = data_area

show(res, "res")

positions.sort(key=lambda p: p[1])
result = []
index = 0
while index < len(positions) - 1:
    if positions[index + 1][1] - positions[index][1] < 10:
        temp_list = [positions[index + 1], positions[index]]
        for i in range(index + 1, len(positions)):
            if positions[i + 1][1] - positions[i][1] < 10:
                temp_list.append(positions[i + 1])
            else:
                break
        temp_list.sort(key=lambda p: p[0])
        positions[index:(index + len(temp_list))] = temp_list
        index = index + len(temp_list) - 1
    else:
        index += 1
for index in range(len(positions)):
    position = positions[index]
    data_area = data_areas['{}-{}'.format(position[0], position[1])]
    ocr_data = ocr.ocr(data_area)
    ocr_result = ''.join([''.join(result[0]) for result in ocr_data]).replace(' ', '')
    # print('{}:{}'.format(labels[index], ocr_result))
    result.append('{}:{}'.format(labels[index], ocr_result))
    show(data_area, "data_area")

for item in result:
    print(item)
show(res, "res")

到此這篇關于OpenCV Python身份證信息識別的文章就介紹到這了,更多相關Python身份證信息識別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • python中not、and和or的優(yōu)先級與詳細用法介紹

    python中not、and和or的優(yōu)先級與詳細用法介紹

    這篇文章主要給大家介紹了python中not、and和or的優(yōu)先級與詳細用法介紹,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • Python使用sorted對字典的key或value排序

    Python使用sorted對字典的key或value排序

    這篇文章主要介紹了Python使用sorted對字典的key或value排序,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • jupyter notebook讀取/導出文件/圖片實例

    jupyter notebook讀取/導出文件/圖片實例

    這篇文章主要介紹了jupyter notebook讀取/導出文件/圖片實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • 對python numpy.array插入一行或一列的方法詳解

    對python numpy.array插入一行或一列的方法詳解

    今天小編就為大家分享一篇對python numpy.array插入一行或一列的方法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • Python人工智能之路 之PyAudio 實現(xiàn)錄音 自動化交互實現(xiàn)問答

    Python人工智能之路 之PyAudio 實現(xiàn)錄音 自動化交互實現(xiàn)問答

    關于音頻, PyAudio 這個庫, 可以實現(xiàn)開啟麥克風錄音, 可以播放音頻文件等等。文章介紹了如何使用Python第三方庫PyAudio進行麥克風錄音然后自動播放已經(jīng)合成的語音實現(xiàn)語音交互回答,需要的朋友可以參考下
    2019-08-08
  • python簡單實例訓練(21~30)

    python簡單實例訓練(21~30)

    上篇文章給大家介紹了python簡單實例訓練的1-10,這里繼續(xù)為大家介紹python的一些用法,希望大家每個例子都打出來測試一下
    2017-11-11
  • Python?Requests庫知識匯總

    Python?Requests庫知識匯總

    這篇文章主要介紹了Python?Requests庫學習總結,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • pytest通過assert進行斷言的實現(xiàn)

    pytest通過assert進行斷言的實現(xiàn)

    assert斷言是一種用于檢查代碼是否按預期工作的方法,在pytest中,assert斷言可以用于測試代碼的正確性,以確保代碼在運行時按照預期工作,本文就來介紹一下如何使用,感興趣的可以了解下
    2023-12-12
  • python打印經(jīng)典故事從前有座山的幾種寫法

    python打印經(jīng)典故事從前有座山的幾種寫法

    在定義了函數(shù)之后,就可以使用該函數(shù)了,下面這篇文章主要給大家介紹了關于python打印經(jīng)典故事從前有座山的幾種寫法,通過這個有意思的實例幫助大家學習python,需要的朋友可以參考下
    2022-05-05
  • 解決Keras的自定義lambda層去reshape張量時model保存出錯問題

    解決Keras的自定義lambda層去reshape張量時model保存出錯問題

    這篇文章主要介紹了解決Keras的自定義lambda層去reshape張量時model保存出錯問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07

最新評論