OpenMV扫码识别

简介: OpenMV扫码识别

条形码识别详解

条形码识别示例

# 条形码识别例程
#
# 这个例子展示了使用OpenMV Cam M7来检测条形码是多么容易。条形码检测不适用于M4相机。
import sensor, image, time, math
sensor.reset()                         # 重置感光元件,重置摄像机
sensor.set_pixformat(sensor.GRAYSCALE) # 设置为灰度图模式,速率会快一些。
sensor.set_framesize(sensor.VGA)       # 高分辨率!
#因为我们的条形码一般都是一个长的矩形,一般要设置窗口大小,小和窄一点。一般窗口设置为640X80.意思是只显示条形码的这一部分。这样能够提高检测速度
sensor.set_windowing((640, 80))       # V Res的80 ==更少的工作(40为2倍的速度)。
sensor.skip_frames(time = 2000)        # 跳过n张照片,在更改设置后,跳过一些帧,等待感光元件变稳定。
sensor.set_auto_gain(False)            # 自动增益必须关闭此功能,以防止图像冲洗…
sensor.set_auto_whitebal(False)        # 白平衡必须关闭此功能,以防止图像冲洗…
clock = time.clock()
# 条形码检测可以在OpenMV Cam的OV7725相机模块的640x480分辨率下运行。
# 条码检测也将在RGB565模式下工作,但分辨率较低。 也就是说,
# 条形码检测需要更高的分辨率才能正常工作,因此应始终以640x480的灰度运行。
def barcode_name(code):   #返回条形码所属类型
    if(code.type() == image.EAN2):
        return "EAN2"
    if(code.type() == image.EAN5):
        return "EAN5"
    if(code.type() == image.EAN8):
        return "EAN8"
    if(code.type() == image.UPCE):
        return "UPCE"
    if(code.type() == image.ISBN10):
        return "ISBN10"
    if(code.type() == image.UPCA):
        return "UPCA"
    if(code.type() == image.EAN13):
        return "EAN13"
    if(code.type() == image.ISBN13):
        return "ISBN13"
    if(code.type() == image.I25):
        return "I25"
    if(code.type() == image.DATABAR):
        return "DATABAR"
    if(code.type() == image.DATABAR_EXP):
        return "DATABAR_EXP"
    if(code.type() == image.CODABAR):
        return "CODABAR"
    if(code.type() == image.CODE39):
        return "CODE39"
    if(code.type() == image.PDF417):
        return "PDF417"
    if(code.type() == image.CODE93):
        return "CODE93"
    if(code.type() == image.CODE128):
        return "CODE128"
while(True):
    clock.tick()
    img = sensor.snapshot()              # 截取感光元件中的一张图片
    codes = img.find_barcodes()          # 条形码检测函数
    for code in codes:                   # 对于返回的列表中的条形码
        img.draw_rectangle(code.rect())  # 将返回的条形码框选
# 打印条形码信息  条形码类型;返回条形码的有效载荷的字符串;返回以弧度计的条形码的旋度(浮点数),此处再转换成角度;返回条形码在图像中被检测到的次数(int);图片帧率
        print_args = (barcode_name(code), code.payload(), (180 * code.rotation()) / math.pi, code.quality(), clock.fps())
        # 将print_args打印出来,\表示转义字符,目的是打印出“
        print("Barcode %s, Payload \"%s\", rotation %f (degrees), quality %d, FPS %f" % print_args)
        message = code.payload()          # 仅打印条形码信息
        print(message)
    if not codes:
        print("FPS %f" % clock.fps())     # 打印帧率


固定代码部分

此处基本为固定代码,只有一处需要讲解。由于条形码识别只需要黑白两色,所以采用灰度图,因此我们可以采用VGA更高的分辨率。


set_windowing()函数讲解

该函数设置识别条形码识别窗口,因为为了条形码为长条形。所以如果为正方形,会有很大一部分为无效信息,可以通过设置识别窗口来提高识别效率。


传入值为roi,我们可以设置矩形区域的其实xy坐标,长宽值。如果我们只输入长宽两个值。此时图形将会居中。因为按照绝大多数人的习惯而言,都是居中看图像,所以我们只需要输入长宽两个值。星瞳官方建议是设置为(640, 80)。但是由于我所识别的条形码在这个框内无法完全识别,所以我个人是设置的(340, 160)


sensor.reset()                         # 重置感光元件,重置摄像机
sensor.set_pixformat(sensor.GRAYSCALE) # 设置为灰度图模式,速率会快一些。
sensor.set_framesize(sensor.VGA)       # 高分辨率!
#因为我们的条形码一般都是一个长的矩形,一般要设置窗口大小,小和窄一点。一般窗口设置为640X80.意思是只显示条形码的这一部分。这样能够提高检测速度
sensor.set_windowing((640, 80))       # V Res的80 ==更少的工作(40为2倍的速度)。
sensor.skip_frames(time = 2000)        # 跳过n张照片,在更改设置后,跳过一些帧,等待感光元件变稳定。
sensor.set_auto_gain(False)            # 自动增益必须关闭此功能,以防止图像冲洗…
sensor.set_auto_whitebal(False)        # 白平衡必须关闭此功能,以防止图像冲洗…
clock = time.clock()


自定义函数详解

此函数就只有一个作用,用于识别我们所识别的条形码的类型,在死循环中将会使用。

def barcode_name(code):   #返回条形码所属类型
    if(code.type() == image.EAN2):
        return "EAN2"
    if(code.type() == image.EAN5):
        return "EAN5"
    if(code.type() == image.EAN8):
        return "EAN8"
    if(code.type() == image.UPCE):
        return "UPCE"
    if(code.type() == image.ISBN10):
        return "ISBN10"
    if(code.type() == image.UPCA):
        return "UPCA"
    if(code.type() == image.EAN13):
        return "EAN13"
    if(code.type() == image.ISBN13):
        return "ISBN13"
    if(code.type() == image.I25):
        return "I25"
    if(code.type() == image.DATABAR):
        return "DATABAR"
    if(code.type() == image.DATABAR_EXP):
        return "DATABAR_EXP"
    if(code.type() == image.CODABAR):
        return "CODABAR"
    if(code.type() == image.CODE39):
        return "CODE39"
    if(code.type() == image.PDF417):
        return "PDF417"
    if(code.type() == image.CODE93):
        return "CODE93"
    if(code.type() == image.CODE128):
        return "CODE128"


死循环详解

sensor.snapshot()函数详解

img = sensor.snapshot(),截取感光元件中的照片,将截取的图片存入辅助帧缓冲存储区,返回参数image对象。这个时候,img这个变量就是image,可以理解为等价。


image.find_barcodes()详解

因为上面img与image同类,所以img.find_barcodes()=image.find_barcodes() 可以理解为等价。

此函数可以识别条形码,并且返还一个image.barcode(这个下面再说),并且可以传入一个roi的元组。roi就算感兴趣区,可以设置读取条形码的区域。(x, y, w, h)表示识别的左上角xy坐标,感兴趣区的长宽。如果不传入参数,默认识别窗口全部区域。因为我们已经设置了窗口大小,所以不设置感兴趣区。注:个人不建议设置感兴趣区,否则会出现,明明条形码已经出现在图像中了,但是因为感兴趣区的存在,无法识别。


注:如果无法识别,但是没有传入感兴趣区。可能是摄像头聚焦问题。可以烧录示例,进行一次调焦。



image.barcode对象讲解

首先,我们第一个是barcode.corners(),就算条形码的四个角落xy坐标。我们目前没有使用。

第二个,barcode.rect()。他返回的值给后面的for...in...中img.draw_rectangle()用于绘制识别到的条形码框框。为什么是他来绘制条形码框框呢?我们可以查看img.draw_rectangle()函数解释,需要传入的是(x, y, w, h)的值,而不是四个角落的xy数值。所以是img.draw_rectangle(code.rect()) 而不是img.draw_rectangle(code.corners()) 。


这个时候可能会有人问了,为什么是code.corners()?不是barcode.corners()吗?这个是因为img.find_barcodes()返回了一个image.barcode的对象,这个对象给了codes,而在for...in...中,codes又把自己给等价为code了。所以此处是code.corners(),与barcode.corners()等价。


第三个和之后的就不一样了。他的值是可以通过索引获取,这就表明,他可以被print打印出来。


我们之后会通过print打印出来。以下为识别到条形码之后串行终端(位于左下角)的内容。


首先在自定义函数barcode_name()中传入code。然后我们可以看自定义函数中是code.type(),因为我们说了现在code和barcode等价,code.type()就是barcode.type(),我们看官方定义(在网页中按ctrl+f可搜索barcode.type())可以知道barcode.type()是返回条形码的类型,所以,我们第一个打印出来的是条形码类型。


以此类推,我们打印条形码里面的信息,条形码的旋转角度值(barcode.rotation()返回的是弧度制,弧度值就是Π这种。而此处转换成了角度值,180°就是,360°就是2Π),条形码在图像中被检测到的次数,帧率。


因为只有条形码的内容是有用的,我们可以只写下面messgae这两行。


        print_args = (barcode_name(code), code.payload(), (180 * code.rotation()) / math.pi, code.quality(), clock.fps())
        # 将print_args打印出来,\表示转义字符,目的是打印出“
        print("Barcode %s, Payload \"%s\", rotation %f (degrees), quality %d, FPS %f" % print_args)
        message = code.payload()          # 仅打印条形码信息
        print(message)

最后就算打印帧率

print("FPS %f" % clock.fps())     # 打印帧率


二维码识别详解

二维码检测示例

# 二维码例程
#
# 这个例子展示了OpenMV Cam使用镜头校正来检测QR码的功能(请参阅qrcodes_with_lens_corr.py脚本以获得更高的性能)。
import sensor, image, time
sensor.reset()                        # 重置感光元件,重置摄像机
sensor.set_pixformat(sensor.RGB565)   # 设置颜色格式为RGB565,彩色,每个像素16bit
sensor.set_framesize(sensor.QVGA)     # 图像大小为QVGA
sensor.skip_frames(time = 2000)       # 跳过n张照片,在更改设置后,跳过一些帧,等待感光元件变稳定。
sensor.set_auto_gain(False)           # 必须关闭此功能,以防止图像冲洗…
clock = time.clock()
while(True):
    clock.tick() 
    img = sensor.snapshot()  # 截取感光元件中的一张图片
    #采用软件畸变矫正,因为OpenMV标配自带的镜头是2.8mm聚焦的鱼眼镜头,会存在桶形畸变,也就是鱼眼效果,会影响识别二维码
    #畸变矫正运算量比较大,可能会影响帧率。对帧率有要求,可购买无畸变镜头,就无需软件畸变矫正
    img.lens_corr(1.8) # 1.8的强度参数对于2.8mm镜头来说是不错的。
    for code in img.find_qrcodes():     # 进行二维码检测
        img.draw_rectangle(code.rect(), color = (255, 0, 0))
        print(code)                     # 打印二维码内容
    print(clock.fps())                  # 打印帧率


image.lens_corr()详解

此处就算进行畸变矫正,如果因为我们购买的OpenMV的默认镜头是带鱼眼效果的,所以需要进行畸变矫正(注意:此处运算量大,不建议长时间使用OpenMV不然会发烫很严重)。因为我们这里没有指定是传入的zoom,x_corr,y_corr的值,所以按照顺序,传入的1.8是给strength。我们可以调节这个值,来查看即便矫正的效果,建议从1.8开始尝试。zoom就是进行图像缩放,比如10X10的图像,为0.5,就算5X5的图像。建议为默认值,只需要调节strength就行了。


image.find_qrcodes()函数讲解

作用就是对二维码的识别,可以传入感兴趣区(识别区域)。然后返回一个image.qrcode的对象。这个对象里面又二维码的信息。

image.qrcode对象讲解

image.qrcode的内部可以自己看官方文档理解。如下为打印的数据,这个时候有人可能会有疑惑,为什么打印的第一个数据是X的值,而不是qrcode.corners()的值呢?因为我们看官方文档可知,qrcode.corners()和qrcode.rect()是不能通过索引获取,所以没有打印出来。而qrcode.x()是索引0,也就是第一个打印出来的值。


img.draw_rectangle()函数讲解

此处的image.draw_rectangle ()就是在识别到二维码之后,在二维码画一个红色的框框。因为image.draw_rectangle ()需要传输的是x, y, w, h。所以此处传入的是code.rect()而不是qrcode.corners()。后面这个是设置矩形框为红色。


img.draw_rectangle(code.rect(), color = (255, 0, 0))


二维码补充理解

生成二维码

因为我们很多时候,需要的是对二维码的数据进行提取和使用。以下为我写的示例。我们利用网站产生一个信息为OpenMV的二维码。如下图


代码

如果识别到了内容为OpenMV的二维码,则在串行终端打印OK

如果识别到的是非OpenMV内容的二维码,串行终端打印“非目标二维码”。

如果没有二维码,就不打印东西。

# 二维码例程
#
# 这个例子展示了OpenMV Cam使用镜头校正来检测QR码的功能(请参阅qrcodes_with_lens_corr.py脚本以获得更高的性能)。
import sensor, image, time
sensor.reset()                       # 重置感光元件,重置摄像机
sensor.set_pixformat(sensor.RGB565)  # 设置颜色格式为RGB565,彩色,每个像素16bit
sensor.set_framesize(sensor.QVGA)    # 图像大小为QVGA
sensor.skip_frames(time = 2000)      # 跳过n张照片,在更改设置后,跳过一些帧,等待感光元件变稳定。
sensor.set_auto_gain(False)          # 必须关闭此功能,以防止图像冲洗…
clock = time.clock()
while(True):
    clock.tick()
    img = sensor.snapshot()          # 截取感光元件中的一张图片
    #采用软件畸变矫正,因为OpenMV标配自带的镜头是2.8mm聚焦的鱼眼镜头,会存在桶形畸变,也就是鱼眼效果,会影响识别二维码
    #畸变矫正运算量比较大,可能会影响帧率。对帧率有要求,可购买无畸变镜头,就无需软件畸变矫正
    img.lens_corr(1.8)               # 1.8的强度参数对于2.8mm镜头来说是不错的。
    for code in img.find_qrcodes():  # 进行二维码检测
        img.draw_rectangle(code.rect(), color = (255, 0, 0))
        #print(code)                  # 输出二维码内容
        message = code.payload()
        if message == 'OpenMV':
            print('ok',message)
        else:
            print('非目标二维码') #检测到非目标二维码打印
    #print(clock.fps())
目录
相关文章
|
编解码
LabVIEW条形码识别(实战篇—5)
LabVIEW条形码识别(实战篇—5)
LabVIEW条形码识别(实战篇—5)
|
4月前
|
存储 机器人 测试技术
AprilTags二维码的检测与应用
AprilTags二维码的检测与应用
423 0
|
5月前
|
存储 算法 计算机视觉
LabVIEW二维码生成与识别
LabVIEW二维码生成与识别
75 0
|
6月前
程序技术好文:通过二维码图片识别二维码内容方法
程序技术好文:通过二维码图片识别二维码内容方法
88 0
|
7月前
|
JSON 文字识别 数据可视化
印刷文字识别产品使用合集之有识别二维码并将识别二维码的内容通过接口返回的功能吗
印刷文字识别(Optical Character Recognition, OCR)技术能够将图片、扫描文档或 PDF 中的印刷文字转化为可编辑和可搜索的数据。这项技术广泛应用于多个领域,以提高工作效率、促进信息数字化。以下是一些印刷文字识别产品使用的典型场景合集。
|
7月前
|
小程序 JavaScript
微信小程序长按识别图片二维码功能
微信小程序长按识别图片二维码功能
456 0
|
移动开发 前端开发 JavaScript
纯web端实现二维码识别
最近公司的业务场景中有个生成二维码和识别二维码的需求。生成二维码之前有做过,选用的 qrcode.js这个前端库,操作比较简单。这里不再赘述。 刚开始看到二维识别这个需求觉得很简单,以为有相应的前端库直接用就行了。但当真正开始写功能时,发现二维识别会涉及到很多其他的功能。废话不再多说,还是来看看如何实现的吧。
|
7月前
|
小程序
微信小程序中长按识别二维码
微信小程序中长按识别二维码
208 0
|
7月前
|
存储 数据挖掘
[Halcon&识别] 二维码识别
[Halcon&识别] 二维码识别
286 0
防伪彩色二维码的设计制作
彩码指彩色二维码、一般使用QRcode类型,彩码的作用主要是防伪领域
138 0