如何读取和解码印度 Aadhaar 卡图像上的安全二维码

How to read & decode Secure QR code on Indian Aadhaar Card image

我正在尝试从 Aadhar 卡(印度)的图像中提取完整的 Aadhar 号码(12 位数字)

我可以用二维码识别地区。要提取信息 - 我一直在研究 python 库,这些库读取和解码印度 Aadhaar 卡上的安全二维码。 这两个库似乎对这个用例特别有用:

  1. pyaadhaar
  2. aadhaar-py

我无法在 Aadhaar 卡上使用它们解码安全二维码。 Information on Secure QR code is available here. 请推荐可能的解决方案或一些其他方法来完成此任务

这是我使用这些库解码安全二维码的代码。 Python版本:3.8

from pyaadhaar.utils import Qr_img_to_text, isSecureQr
from pyaadhaar.deocde import AadhaarSecureQr
from pyaadhaar.deocde import AadhaarOldQr

qrData = Qr_img_to_text(sys.argv[1])
print(qrData)

if len(qrData) == 0:
    print(" No QR Code Detected !!")
else:
    isSecureQR = (isSecureQr(qrData[0]))
    if isSecureQR:
        print("Secure QR code")
        try:
            obj  = AadhaarSecureQr(qrData[0])
        except:
            print("Try aadhaar-py library")
            from aadhaar.qr import AadhaarSecureQR
            integer_scanned_from_qr = 123456
            # secure_qr = AadhaarSecureQR(integer_scanned_from_qr)
            secure_qr = AadhaarSecureQR(int(qrData[0]))
            decoded_secure_qr_data = secure_qr.extract_data()
            print(decoded_secure_qr_data)

以下是我在使用这些库时遇到的问题:

  1. pyaadhaar:安全二维码解码代码,尝试将 base10 字符串转换为字节但失败。 注意:对于 Aadhaar 卡的旧 QR 码格式,pyaadhaar 库运行良好,此问题仅发生在安全 QR 码上。下面的堆栈跟踪:

    File "/home/piyush/libs/py38/lib/python3.8/site-packages/pyaadhaar/deocde.py", line 23, in __init__
    bytes_array = base10encodedstring.to_bytes(5000, 'big').lstrip(b'\x00')
    

    AttributeError: 'str' object has no attribute 'to_bytes'

  2. aadhaar-py:安全 QR 解码失败,因为它无法验证从 QR 码收到的整数。下面的堆栈跟踪:

    Traceback (most recent call last): File "/home/piyush/libs/py38/lib/python3.8/site-packages/aadhaar/qr.py", line 55, in init self.decompressed_byte_array = zlib.decompress(self.byte_array, wbits=16+zlib.MAX_WBITS) zlib.error: Error -3 while decompressing data: incorrect header check During handling of the above exception, another exception occurred:

    Traceback (most recent call last): File "aadhaarQRCode.py", line 52, in secure_qr = AadhaarSecureQR(integer_scanned_from_qr) File "/home/piyush/libs/py38/lib/python3.8/site-packages/aadhaar/qr.py", line 57, in init raise MalformedIntegerReceived('Decompression failed, please send a valid integer received from QR code') aadhaar.exceptions.MalformedIntegerReceived: Decompression failed, please send a valid integer received from QR code

对于需要在实际解码之前提取干净的 QR 码 ROI 的任何人,这里有一种使用阈值、形态学操作和轮廓过滤来提取 QR 码的简单方法。

  1. 获取二进制图像。 Load image, grayscale, Gaussian blur, Otsu's threshold

  2. 连接各个 QR 轮廓。 使用 cv2.getStructuringElement() then perform morphological operationscv2.MORPH_CLOSE 创建矩形结构内核。

  3. 二维码过滤。 Find contours 并使用 contour approximation, contour area, and aspect ratio.

    进行过滤

这是图像处理管道

加载图像,灰度,高斯模糊,然后Otsu的阈值得到二值图像

现在我们创建一个矩形内核并变形接近以将 QR 码组合成一个轮廓

我们使用轮廓区域、轮廓近似和纵横比为 QR 码找到轮廓和过滤器。检测到的二维码以绿色突出显示

提取的投资回报率

代码

import cv2
import numpy as np

# Load imgae, grayscale, Gaussian blur, Otsu's threshold
image = cv2.imread('1.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Morph close
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=1)

# Find contours and filter for QR code using contour area, approximation, and aspect ratio
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.04 * peri, True)
    x,y,w,h = cv2.boundingRect(approx)
    area = cv2.contourArea(c)
    ar = w / float(h)
    if len(approx) == 4 and area > 1000 and (ar > .85 and ar < 1.3):
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)
        ROI = original[y:y+h, x:x+w]
        # cv2.imwrite('ROI.png', ROI)

# Display
cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('image', image)
cv2.imshow('ROI', ROI)

# Save images
# cv2.imwrite('thresh.png', thresh)
# cv2.imwrite('close.png', close)
# cv2.imwrite('image.png', image)
# cv2.imwrite('ROI.png', ROI)
cv2.waitKey()     

我想我已经确定了两个问题:

  • 发布的示例图片质量不够好。
  • 张贴的样本只是一个例子,不是真正的“安全二维码”,只是一个例子(isSecureQR returns false)。

将输入的大小调整为 2 倍允许读取 QR 码:

正在读取、调整大小并另存为新图像:

import cv2    

image_file_name = 'image.png';

img = cv2.imread(image_file_name, cv2.IMREAD_GRAYSCALE)  # Read image as grayscale.
img2 = cv2.resize(img, (img.shape[1]*2, img.shape[0]*2), interpolation=cv2.INTER_LANCZOS4)  # Resize by x2 using LANCZOS4 interpolation method.

cv2.imwrite('image2.png', img2)

完整代码示例:

import cv2
from pyaadhaar.utils import Qr_img_to_text, isSecureQr
from pyaadhaar.deocde import AadhaarSecureQr
from pyaadhaar.deocde import AadhaarOldQr

image_file_name = 'image.png';

img = cv2.imread(image_file_name, cv2.IMREAD_GRAYSCALE)  # Read image as grayscale.
img2 = cv2.resize(img, (img.shape[1]*2, img.shape[0]*2), interpolation=cv2.INTER_LANCZOS4)  # Resize by x2 using LANCZOS4 interpolation method.

cv2.imwrite('image2.png', img2)

#qrData = Qr_img_to_text(image_file_name)
qrData = Qr_img_to_text('image2.png')

print(qrData[0])

if len(qrData) == 0:
    print(" No QR Code Detected !!")
else:
    isSecureQR = (isSecureQr(qrData[0]))

输出:

BEGIN:VCARD
VERSION:2.1
N:John Doe
TEL;HOME;VOICE:555-555-5555
TEL;WORK;VOICE:666-666-6666
EMAIL:email@example.com
ORG:TEC-IT
URL:http://www.example.com
END:VCARD

如您所见,信息是可读的。


我不知道错误消息的原因。
我正在使用 Python 3.6 和 Windows 10,没有错误。


更新:

我想我找到了一个很好的 QR 样本 here:

您可以使用以下步骤来读取和解码二维码:

  • 读取图像并转换为灰度:

     img = cv2.imread('QR-code.png')
     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
  • 使用pyzbar解码QR图像:

     from pyzbar.pyzbar import decode
    
     code = decode(gray)
     qrData = code[0].data
    

输出为:

qrData = b'2374971804270526477833002468783965837992554564899874087591661303561346432389832047870524302186901344489362368642972767716416349990805756094923115719687656090691368051627957878187788907419297818953295185555346288172578594637886352753543271000481717080003254556962148594350559820352806251787713278744047402230989238559317351232114240089849934148895256488140236015024800731753594740948640957680138566468247224859669467819596919398964809164399637893729212452791889199675715949918925838319591794702333094022248132120531152523331442741730158840977243402215102904932650832502847295644794421419704633765033761284508863534321317394686768650111457751139630853448637215423705157211510636160227953566227527799608082928846103264491539001327407775670834868948113753614112563650255058316849200536533335903554984254814901522086937767458409075617572843449110393213525925388131214952874629655799772119820372255291052673056372346072235458198199995637720424196884145247220163810790179386390283738429482893152518286247124911446073389185062482901364671389605727763080854673156754021728522287806275420847159574631844674460263574901590412679291518508010087116598357407343835408554094619585212373168435612645646129147973594416508676872819776522537778717985070402222824965034768103900739105784663244748432502180989441389718131079445941981681118258324511923246198334046020123727749408128519721102477302359413240175102907322619462289965085963377744024233678337951462006962521823224880199210318367946130004264196899778609815012001799773327514133268825910089483612283510244566484854597156100473055413090101948456959122378865704840756793122956663218517626099291311352417342899623681483097817511136427210593032393600010728324905512596767095096153856032112835755780472808814199620390836980020899858288860556611564167406292139646289142056168261133256777093245980048335918156712295254776487472431445495668303900536289283098315798552328294391152828182614909451410115516297083658174657554955228963550255866282688308751041517464999930825273776417639569977754844191402927594739069037851707477839207593911886893016618794870530622356073909077832279869798641545167528509966656120623184120128052588408742941658045827255866966100249857968956536613250770326334844204927432961924987891433020671754710428050564671868464658436926086493709176888821257183419013229795869757265111599482263223604228286513011751601176504567030118257385997460972803240338899836840030438830725520798480181575861397469056536579877274090338750406459700907704031830137890544492015701251066934352867527112361743047684237105216779177819594030160887368311805926405114938744235859610328064947158936962470654636736991567663705830950312548447653861922078087824048793236971354828540758657075837209006713701763902429652486225300535997260665898927924843608750347193892239342462507130025307878412116604096773706728162016134101751551184021079984480254041743057914746472840768175369369852937574401874295943063507273467384747124843744395375119899278823903202010381949145094804675442110869084589592876721655764753871572233276245590041302887094585204427900634246823674277680009401177473636685542700515621164233992970974893989913447733956146698563285998205950467321954304'

isSecureQR = (isSecureQr(qrData)) returns True.

  • 使用pyaadhaar解码qrData:

     secure_qr = AadhaarSecureQr(int(qrData))
     decoded_secure_qr_data = secure_qr.decodeddata()
    

完整代码示例:

import cv2
from pyzbar.pyzbar import decode
from pyaadhaar.utils import isSecureQr
from pyaadhaar.deocde import AadhaarSecureQr

img = cv2.imread('QR-code.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

code = decode(gray)
qrData = code[0].data

isSecureQR = (isSecureQr(qrData))

if isSecureQR:
    secure_qr = AadhaarSecureQr(int(qrData))
    decoded_secure_qr_data = secure_qr.decodeddata()
    print(decoded_secure_qr_data)

输出:

{'email_mobile_status': '3', 'referenceid': '269720190308114407437', 'name': 'Sumit Kumar', 'dob': '01-01-1984', 'gender': 'M', 'careof': 'C/O Ishwar Chand', 'district': 'East Delhi', 'landmark': '', 'house': 'B-31, 3rd Floor', 'location': '', 'pincode': '110051', 'postoffice': 'Krishna Nagar', 'state': 'Delhi', 'street': 'Radhey Shyam Park Extension', 'subdistrict': 'Gandhi Nagar', 'vtc': 'Krishna Nagar', 'adhaar_last_4_digit': '2697', 'adhaar_last_digit': '7', 'email': 'yes', 'mobile': 'yes'}


您的原始代码也适用于上图:

from pyaadhaar.utils import Qr_img_to_text, isSecureQr

qrData = Qr_img_to_text('QR-code.png')

isSecureQR = (isSecureQr(qrData[0]))

if isSecureQR:
    secure_qr = AadhaarSecureQr(int(qrData[0]))
    decoded_secure_qr_data = secure_qr.decodeddata()
    print(decoded_secure_qr_data)

感谢您提出问题。 我是 aadhaar-py 的作者,代码引发异常,因为无法解析传递给 lib 的数据。它必须是某种类型才能被解析。请参考以下 link 示例:https://uidai.gov.in/te/ecosystem-te/authentication-devices-documents-te/qr-code-reader-te.html

如果您扫描页面上的二维码并将收到的数据传递给库,您将收到提取的数据。 P.S.: 库已经用新的 API 进行了改进。一定要检查一下:) https://pypi.org/project/aadhaar-py/