第三十八章 image码识别实验
在上一章节中,介绍了image模块中图像对比方法给的使用,本章将继续介绍image模块中码识别方法的使用。通过本章的学习,读者将学习到image模块中码识别的使用。
本章分为如下几个小节:
38.1 image模块码识别方法介绍
38.2 硬件设计
38.3 程序设计
38.4 运行验证
38.1 image模块码识别方法介绍
image模块为Image对象提供了find_barcodes()方法,用于识别图像中的条形码,find_barcodes()方法如下所示:
image.find_barcodes(roi)
find_barcodes()方法用于识别图像中的条形码,并会返回一个image.barcode对象列表,由于条形码的特殊性,条形码是一维图像,所以只需在一个方向上有较高的分辨率,而在另一个方向上秩序较低的分辨率。
roi指的是对Image对象感兴趣的区域,若未指定,即为图像矩形。
find_barcode()方法会返回一个image.barcode对象列表。
find_barcode()方法的使用示例如下所示:
import image
img = image.Image(size=(320, 240))
barcodes = img.find_barcode()
if barcodes:
print("%s" % (barcodes[0].payload))
image模块为Image对象提供了find_datamatrices()方法,用于识别图像中的DM码,find_datamatrices()方法如下所示:
image.find_datamatrices(roi, effort=200)
find_datamatrices()方法用于识别图像中的DM码,并返回一个image.datamatrix对象列表,该方法要求被识别图像中的DM码需要比较平展。
roi指的是对Image对象感兴趣的区域,若未指定,即为图像矩形。
effort指的是用于控制查找DM码匹配的时间,默认为200,这应该适用于大部分的使用场景,需要注意的是,当该参数配置为160以下,可能无法进行任何的DM码识别,并且当该参数可配置的最大值为240。
find_datamatrices()方法会返回一个image.datamatrix对象列表。
find_datamatrices()方法的使用示例如下所示:
import image
img = image.Image(size=(320, 240))
datamatrices = img.find_datamatrices()
if datamatrices:
print("%s" % (datamatrices[0].payload))
image模块为Image对象提供了find_qrcodes()方法,用于识别图像中的二维码,并返回一个image.rqcode对象列表,find_rqcodes()方法如下所示:
image.find_rqcodes(roi)
find_rqcodes()方法用于识别图像中的二维码,并返回一个image.rqcode对象列表,该方法要求被识别图像中的二维码需要比较平展。
roi指的是对Image对象感兴趣的区域,若未指定,即为图像矩形。
find_rqcodes()方法会返回一个image.rqcode对象列表。
find_rqcodes()方法的使用示例如下所示:
import image
img = image.Image(size=(320, 240))
rqcodes = img.find_rqcodes()
if rqcodes:
print("%s" % (rqcodes[0].payload))
image模块为Image对象提供了find_apriltags()方法,用于识别图像中的AprilTag码,并返回一个image.apriltag对象列表,find_apriltags()方法如下所示:
image.find_apriltags(roi, families=image.TAG36H11, fx, fy, cx, cy)
find_apriltags()方法用于识别图像中的AprilTag码,与二维码相比,AprilTag码可在更远距离、较差光线和更扭曲的图像环境下被检测并识别,AprilTag码可以应对所有种类的图像失真问题,而二维码不能,但是AprilTag码只能作为数字ID编码的载体。
roi指的是对Image对象感兴趣的区域,若未指定,即为图像矩形。
families指的是要解码的标签家族的位掩码,可以用逻辑或来同时指定解码多种标签家族,必须是image模块中定义号的标签家族常量,如下表所示:
fx和fy指的是以像素为单位的相机X和Y方向的焦距。
cx和cy指的是图像的中心X和Y坐标,即image.width() // 2和image.height() //2,而不是roi.width() // 2和roi.height() // 2。
find_airiltags()方法会返回一个image.apriltag对象列表。
find_airiltags()方法的使用示例如下所示:
import image
img = image.Image(size=(320, 240))
apriltags = img.find_apriltags(families=image.TAG36H11)
if apriltags:
print("%d" % (apriltags[0].id))
38.2 硬件设计
38.2.1 例程功能
1. 获取摄像头输出的图像,并使用image模块对图像进行码识别,并在图像上绘制识别到的内容,然后将图像显示在LCD上。
2. 当KEY0按键被按下后,切换image模块识别图像中不同种类的码。
38.2.2 硬件资源
本章实验内容,主要讲解image模块的使用,无需关注硬件资源。
38.2.3 原理图
本章实验内容,主要讲解image模块的使用,无需关注原理图。
38.3 程序设计
38.3.1 image模块图像码识别方法介绍
有关image模块图像码识别方法的介绍,请见第38.1小节《image模块图像码识别方法介绍》。
38.3.2 程序流程图
38.3.3 main.py代码
main.py中的脚本代码如下所示:
from board import board_info
from fpioa_manager import fm
from maix import GPIO
import time
import lcd
import sensor
import image
import math
import gc
lcd.init()
sensor.reset()
sensor.set_framesize(sensor.QVGA)
sensor.set_pixformat(sensor.RGB565)
sensor.set_hmirror(False)
type = 0
type_dict = {
0: "Normal",
1: "Barcode",
2: "DataMatrices",
3: "QRCode",
4: "AprilTag"
}
fm.register(board_info.KEY0, fm.fpioa.GPIOHS0)
key0 = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)
def key_irq_handler(key):
global key0
global type
time.sleep_ms(20)
if key is key0 and key.value() == 0:
type = type + 1
if type == len(type_dict):
type = 0
key0.irq(key_irq_handler, GPIO.IRQ_FALLING, GPIO.WAKEUP_NOT_SUPPORT, 7)
while True:
img= sensor.snapshot()
if type == 0:
pass
elif type == 1:
# 条形码识别
roi = (img.width() // 2 - 120, img.height() // 2 - 80, 240, 160)
gray = img.copy(roi).to_grayscale()
img.draw_rectangle(roi, color=(0, 255, 0))
barcodes = gray.find_barcodes((0, 0, gray.width(), gray.height()))
if barcodes:
img.draw_string(10, 30, barcodes[0].payload(), color=(255, 0, 0), scale=1.6)
elif type == 2:
# DM码识别
roi = (img.width() // 2 - 100, img.height() // 2 - 100, 200, 200)
gray = img.copy(roi).to_grayscale()
img.draw_rectangle(roi, color=(0, 255, 0))
datamatrices = gray.find_datamatrices((0, 0, gray.width(), gray.height()))
if datamatrices:
img.draw_string(10, 30, datamatrices[0].payload(), color=(255, 0, 0), scale=1.6)
elif type == 3:
# 二维码识别
roi = (img.width() // 2 - 100, img.height() // 2 - 100, 200, 200)
gray = img.copy(roi).to_grayscale()
img.draw_rectangle(roi, color=(0, 255, 0))
qrcodes = gray.find_qrcodes((0, 0, gray.width(), gray.height()))
if qrcodes:
img.draw_string(10, 30, qrcodes[0].payload(), color=(255, 0, 0), scale=1.6)
elif type == 4:
# AprilTag识别
roi = (img.width() // 2 - 100, img.height() // 2 - 100, 200, 200)
gray = img.copy(roi).to_grayscale()
img.draw_rectangle(roi, color=(0, 255, 0))
apriltags = gray.find_apriltags((0, 0, gray.width(), gray.height()), families=image.TAG36H11)
if apriltags:
def shot_degrees(axis, y, rotation):
degrees = (180 * rotation) / math.pi
img.draw_string(10, y, "{:s}:{:.0f}".format(axis, degrees), color=(255, 0, 0), scale=1.6)
img.draw_string(10, 30, "ID:{:d}".format(apriltags[0].id()), color=(255, 0, 0), scale=1.6)
shot_degrees("X", 50, apriltags[0].x_rotation())
shot_degrees("Y", 70, apriltags[0].y_rotation())
shot_degrees("Z", 90, apriltags[0].z_rotation())
else:
type = 0
img.draw_string(10, 10, type_dict[type], color=(255, 0, 0), scale=1.6)
lcd.display(img)
gc.collect()
可以看到一开始是先初始化了LCD、摄像头和中断按键,并且按下中断按键可以切换不同的码识别方法类识别图像中不同种类的码。
接着在一个循环中不断地获取摄像头输出的图像,因为获取到的图像就是Image对象,因此可以直接调用image模块为Image对象提供的各种方法,然后就是对图像中的码进行检测和识别,并在LCD上绘制识别到码的信息,最后在LCD显示图像。
38.4 运行验证
将DNK210开发板连接CanMV IDE,点击CanMV IDE上的“开始(运行脚本)”按钮后,便能看到LCD上显示了摄像头输出的图像,并能看一个绿色的识别框,但将对应的码移入识别框后,能够看到LCD的左上角显示了识别到的结果,按下KEY0按键还能够切换识别码的种类,以识别不同种类的码,如下图所示: