图像中二维码的检测和定位

简介: 图像中二维码的检测和定位

二维码



二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。


image.png

QR-Code-Overview.jpeg


定位图案


  • Position Detection Pattern是定位图案,用于标记二维码的矩形大小。这三个定位图案有白边叫Separators for Postion Detection Patterns。之所以三个而不是四个意思就是三个就可以标识一个矩形了。
  • Timing Patterns也是用于定位的。原因是二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了。
  • Alignment Patterns 只有Version 2以上(包括Version2)的二维码需要这个东东,同样是为了定位用的。


通过查找定位图案,可以实现二维码扫描的检测和定位。


检测和定位的步骤



先对图片进行灰度处理:

image = image.getImage().convert2Gray().getProcessor();
ByteProcessor src = ((ByteProcessor)image);


再对图像做二值化处理:

Threshold t = new Threshold();
t.process(src, Threshold.THRESH_OTSU, Threshold.METHOD_THRESH_BINARY_INV, 20);


然后是对y、x方向进行形态学上的开操作

MorphOpen mOpen = new MorphOpen();
        byte[] data = new byte[width*height];
        System.arraycopy(src.getGray(), 0, data, 0, data.length);
        ByteProcessor copy = new ByteProcessor(data, width, height);
        mOpen.process(src, new Size(n1, n2)); // Y方向开操作
        src.getImage().resetBitmap();
        mOpen.process(copy, new Size(n2, n1)); // X方向开操作
        CV4JImage cv4JImage = new CV4JImage(width,height);
        ((ByteProcessor)cv4JImage.getProcessor()).putGray(copy.getGray());


所谓开操作是指先腐蚀后膨胀的操作。在之前的文章二值图像分析:案例实战(文本分离+硬币计数)曾经介绍过开操作的用途。

import com.cv4j.core.datamodel.ByteProcessor;
import com.cv4j.core.datamodel.Size;
public class MorphOpen {
    /**
     * in order to remove litter noise block, erode + dilate operator
     *
     * @param binary
     * @param structureElement
     */
    public void process(ByteProcessor binary, Size structureElement) {
        FastErode erode = new FastErode();
        FastDilate dilate = new FastDilate();
        erode.process(binary, structureElement, 1);
        dilate.process(binary, structureElement, 1);
    }
}


接下来是标记联通区域,找到二维码的三个特征区域,也就是定位图案。

// 联通组件查找连接区域
        ConnectedAreaLabel ccal = new ConnectedAreaLabel();
        ccal.setFilterNoise(true);
        List<Rect> rectList = new ArrayList<>();
        int[] labelMask = new int[width*height];
        ccal.process(src, labelMask, rectList, true);
        float w = 0;
        float h = 0;
        float rate = 0;
        List<Rect> qrRects = new ArrayList<>();
        for(Rect roi : rectList) {
            if (roi == null) continue;
            if((roi.width > width/4 || roi .width < 10) || (roi.height < 10 || roi.height > height/4))
                continue;
            if((roi.x < 10 || roi.x > width -10)|| (roi.y < 10 || roi.y > height-10))
                continue;
            w = roi.width;
            h = roi.height;
            rate = (float)Math.abs(w / h  - 1.0);
            if(rate < 0.05 && isRect(roi, labelMask, width, height,true)) {
                qrRects.add(roi);
            }
        }


最后,通过定位图案能够找到二维码所在的区域,如果找不到会返回空的矩形。否则返回一个Rect,它表示找到的二维码所在图像中的区域。


我们可以对该区域进行标识,下面是算法的具体使用,找到图像中的二维码之后,用红色的边框框起来。

CV4JImage cv4JImage = new CV4JImage(bitmap);
        QRCodeScanner qrCodeScanner = new QRCodeScanner();
        Rect rect = qrCodeScanner.findQRCodeBounding(cv4JImage.getProcessor(),1,6);
        Bitmap bm = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        Canvas canvas = new Canvas(bm);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth((float) 10.0);
        paint.setStyle(Paint.Style.STROKE);
        android.graphics.Rect androidRect = new android.graphics.Rect(rect.x-20,rect.y-20,rect.br().x+20,rect.br().y+20);
        canvas.drawRect(androidRect,paint);
        image.setImageBitmap(bm);


image.png

定位图片中的二维码区域.png


image.png

定位有创意的二维码.png


image.png

截图微信的二维码.png


对于iPhone截屏之后的图片,该图片尺寸是1242 × 2208。在没有对图片做任何缩放处理的情况下,使用该算法进行定位二维码的区域也是ok的。


image.png

大图中的二维码.png


当然,对于大图如果适当地降采样处理或者缩放的话,算法速度会更快。


写在最后



彩色二维码和小程序的圆形二维码目前能够检测吗?


暂时不能。因为图像在二值化之后,彩色的部分像素点会变成白色的像素点,导致二维码轮廓不完整,最终导致无法实现二值分析。我们会在完成模版匹配的功能之后,继续优化算法完善该功能,加上检测彩色和圆形二维码的能力。


算法的源码位于cv4jQRCodeScanner中,该算法不能识别二维码的字符串,只能找到二维码的区域,如果需要识别二维码还是需要使用Google Zxing。


总结



cv4jgloomyfish和我一起开发的图像处理库,纯java实现,目前还处于早期的版本。

文章中的算法是对二值图像分析的综合运用,使用它再结合Google的ZXing能够提高二维码的识别率。当然,由于它是pure java实现的,稍作改动能够用它来判断出某张图片中是否包含有二维码。

相关文章
|
7月前
|
算法
请教视觉智能平台:同图检测到底是同一张图不同内容做检测是否相同?
请教视觉智能平台:同图检测到底是同一张图不同内容做检测是否相同?
85 0
|
固态存储 计算机视觉 异构计算
一起来学MediaPipe(一)人脸及五官定位检测
一起来学MediaPipe(一)人脸及五官定位检测
3354 0
一起来学MediaPipe(一)人脸及五官定位检测
|
4月前
|
存储 机器人 测试技术
AprilTags二维码的检测与应用
AprilTags二维码的检测与应用
428 0
|
5月前
人脸关键点检测
【7月更文挑战第31天】人脸关键点检测。
37 3
|
7月前
|
机器学习/深度学习 API Android开发
视觉智能平台常见问题之判断摄像头抓拍到包含人脸的照片如何解决
视觉智能平台是利用机器学习和图像处理技术,提供图像识别、视频分析等智能视觉服务的平台;本合集针对该平台在使用中遇到的常见问题进行了收集和解答,以帮助开发者和企业用户在整合和部署视觉智能解决方案时,能够更快地定位问题并找到有效的解决策略。
|
7月前
|
存储 数据挖掘
[Halcon&识别] 二维码识别
[Halcon&识别] 二维码识别
287 0
|
机器学习/深度学习 计算机视觉
定位和读取图像中的多个条形码
定位和读取图像中的多个条形码。
375 0
定位和读取图像中的多个条形码
|
计算机视觉
hyperlpr车牌检测使用报错解决方案
hyperlpr车牌检测使用报错解决方案
167 0
|
算法 编译器
使用matlab机器视觉工具箱实现人脸特征的检测和定位,识别并标注眉毛,眼睛,鼻子,嘴巴
使用matlab机器视觉工具箱实现人脸特征的检测和定位,识别并标注眉毛,眼睛,鼻子,嘴巴
383 0
使用matlab机器视觉工具箱实现人脸特征的检测和定位,识别并标注眉毛,眼睛,鼻子,嘴巴
|
机器学习/深度学习 传感器 文字识别
【图像检测】基于计算机实现交通标志图像检测提取附matlab代码和报告
【图像检测】基于计算机实现交通标志图像检测提取附matlab代码和报告