2017-08-18 00:34:00 weixin_34212762 阅读数 1442
  • 微信公众平台深度开发v2.0第3季——二维码、模板消息

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    10261 人正在学习 去看看 翟东平

基于OpenCV实现二维码发现与定位

在如今流行扫描的年代,应用程序实现二维码扫描检测与识别已经是应用程序的标配、特别是在移动端、如果你的应用程序不能自动发现检测二维码,自动定位二维码你都不好意思跟别人打招呼,二维码识别与解析基于ZXing包即可。难点就在于如何从画面中快速而准确的找到二维码区域,寻找到二维码三个匹配模式点。

一:二维码的结构与基本原理

标准的二维码结构如下:
这里写图片描述
特别要关注的是图中三个黑色正方形区域,它们就是用来定位一个二维码的最重要的三个区域,我们二维码扫描与检测首先要做的就是要发现这三个区域,如果找到这个三个区域,我们就成功的发现一个二维码了,就可以对它定位与识别了。二维码其它各个部分的说明如下:
这里写图片描述

三个角上的正方形区域从左到右,从上到下黑白比例为1:1:3:1:1。
这里写图片描述
不管角度如何变化,这个是最显著的特征,通过这个特征我们就可以实现二维码扫描检测与定位。

二:算法各部与输出

1. 首先把输入图像转换为灰度图像
这里写图片描述

2. 通过OTSU转换为二值图像
这里写图片描述

3. 对二值图像使用轮廓发现得到轮廓
这里写图片描述

4. 根据二维码三个区域的特征,对轮廓进行面积与比例过滤得到最终结果显示如下:
这里写图片描述

三:程序运行演示与代码实现

下面的图片左侧为原图、右侧为二维码定位结果
这里写图片描述

这里写图片描述

这里写图片描述

程序各个步骤完整源代码如下

#include <opencv2/opencv.hpp>
#include <math.h>
#include <iostream>

using namespace cv;
using namespace std;

void scanAndDetectQRCode(Mat & image, int index);
bool isXCorner(Mat &image);
bool isYCorner(Mat &image);
Mat transformCorner(Mat &image, RotatedRect &rect);
int main(int argc, char** argv) {
    /*for (int i = 1; i < 25; i++) {
        Mat qrcode_image = imread(format("D:/gloomyfish/qrcode/%d.jpg", i));
        scanAndDetectQRCode(qrcode_image, i);
    }
    return 0;
    */
    Mat src = imread("D:/gloomyfish/qrcode_99.jpg");
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    Mat gray, binary;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    imwrite("D:/gloomyfish/outimage/qrcode_gray.jpg", gray);

    threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
    imwrite("D:/gloomyfish/outimage/qrcode_binary.jpg", binary);

    // detect rectangle now
    vector<vector<Point>> contours;
    vector<Vec4i> hireachy;
    Moments monents;
    findContours(binary.clone(), contours, hireachy, RETR_LIST, CHAIN_APPROX_SIMPLE, Point());
    Mat result = Mat::zeros(src.size(), CV_8UC3);
    for (size_t t = 0; t < contours.size(); t++) {
        double area = contourArea(contours[t]);
        if (area < 100) continue;
        RotatedRect rect = minAreaRect(contours[t]);
        // 根据矩形特征进行几何分析
        float w = rect.size.width;
        float h = rect.size.height;
        float rate = min(w, h) / max(w, h);
        if (rate > 0.85 && w < src.cols/4 && h<src.rows/4) {
            printf("angle : %.2f\n", rect.angle);
            Mat qr_roi = transformCorner(src, rect);
            if (isXCorner(qr_roi) && isYCorner(qr_roi)) {
                drawContours(src, contours, static_cast<int>(t), Scalar(0, 0, 255), 2, 8);
                imwrite(format("D:/gloomyfish/outimage/contour_%d.jpg", static_cast<int>(t)), qr_roi);
                drawContours(result, contours, static_cast<int>(t), Scalar(255, 0, 0), 2, 8);
            }
        }
    }
    imshow("result", src);
    imwrite("D:/gloomyfish/outimage/qrcode_patters.jpg", src);
    waitKey(0);
    return 0;
}

欢迎继续关注本博客,加入OpenCV学习群

2017-03-06 21:25:57 Z_hehe 阅读数 1662
  • 微信公众平台深度开发v2.0第3季——二维码、模板消息

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    10261 人正在学习 去看看 翟东平

最近在嵌入式设备上做QR码的识别(linux环境下),这里简单记录下用到的相关的库文件:

     zbar

     在进行移植的时候,因为zbar依赖libiconv库,有可能宿主机上有但是要移植的目标硬件上没有,就有可能会编译出错,所以需要先安装libiconv

          在iconv的官网上下载源码后解压

     ./configure --enable-static --enable-shared还有的选项自己可加

     make 

     make install

(export NM=nm)


     在zbar的官网下载源码后解压

      执行

./configure --prefix=/mulu/ --host=mips-linux --CC=mipsel-openwrt-linux-gcc --without-imagemagick 

–-disable-video –-without-qt –-without-gtk –-without-x --without python --enable-static --enable-static

还有许多可选的选项去增加和删除

make

make install

哦,还有,在编译zbar时要能找到前面编译的库文件,可以在./configure ... ...最后加上LDFLAGS='-L/mulu/'

CPPFLAGS='-I/mulu'


MagickWand的使用:zbar在读取图片时需要imagemagick,而里面关于C支持的库就是MagickWand,同时

编译出来后还要使用MagickCore。可不编译出Magick++,这是对C++语言支持的库。其它的选项可自己选择。

下载linux版本的源码,同上面的步骤,自己可加入第三方库区支持jpg(libjpeg),png等格式。

可能运行时要加上数学的库-lm


拷贝库文件时可使用软连接的形式,节省空间。


先mark到这里



2019-08-14 00:37:06 QQ1096693846 阅读数 95
  • 微信公众平台深度开发v2.0第3季——二维码、模板消息

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    10261 人正在学习 去看看 翟东平

使用ffmpeg对图片进行解码,zbar识别二维码。

我测试环境为: windows下32位, mingw与msvc编译器

ffmepg相关库下载地址: 

动态导入库和头文件:https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-20190813-8cd96e1-win32-shared.zip

动态运行库:https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-20190813-8cd96e1-win32-dev.zip

ZBar库(在安装时记得勾选Development Headers and Libraries选项,不然安安装目录下找不到头和库):http://sourceforge.net/projects/zbar/files/zbar/0.10/zbar-0.10-setup.exe/download

我以qt creator做个例子:

qmake配置

//添加对应库,下载的都是动态库来着,运行时记得让程序能找到对应动态库


INCLUDEPATH += C:/ffmpeg/include
LIBS += -L C:/ffmpeg/lib \
-lavcodec -lavformat -lavutil -lswscale

INCLUDEPATH += D:/ZBar/include
LIBS += D:/ZBar/lib/libzbar.dll.a

main.cpp 

#include "qrcode.h"

#include <iostream>
#include <vector>
#include <fstream>

int main()
try
{
    const std::string &filename = "d:/qrcode.png";
    std::vector<uint8_t> v;
    std::ifstream fin(filename.c_str(), std::ios::binary);
    if( !fin ) return 0;
    fin.seekg(0, std::ifstream::end);
    auto end = fin.tellg();
    fin.seekg(0, std::ifstream::beg);
    auto beg = fin.tellg();
    v.resize(end-beg);
    if( !fin.read( reinterpret_cast<char*>(&v[0]), v.size() ) )
        return 0;
    fin.close();

    QRCode code;//自己包装的类
    if( !code.load(&v[0], v.size()) )//内存流或者直接输入url
        std::cout << "failure : " << code.get_last_error() << std::endl;
    else
    {
       std::cout << std::endl;
       for( auto& x : code.get_result() )
       {
            std::cout << "result : " <<x << std::endl;
       }
       std::cout << std::endl;
    }

    std::cout << "endl" << std::endl;
    std::cin.get();
}
catch( const std::exception& e)
{
    std::cout << e.what() << std::endl;
}

qrcode.h 

#ifndef QRCODE_H
#define QRCODE_H

#include <string>
#include <vector>
#include <memory>
#include <functional>

class AVFormatContext;
class AVFrame;

class QRCode
{
    using FreeVector = std::vector<std::function<void(void)>>;//存放一些清理工作
public:
    bool load( const std::string& url );
    bool load( uint8_t const *buf, size_t bytes );//加载内存数据
    std::vector<std::string> get_result()const{ return zbar_result;}
    std::string get_last_error() const{ return errorMsg;}

    QRCode();
    ~QRCode(){ if(errorBuf) delete []errorBuf;}
private:
    bool decode( std::shared_ptr<FreeVector> freeVector, AVFormatContext* pFmtCtx );
    bool getCodeByZBar(std::shared_ptr<FreeVector> freeVector, AVFrame* pic);
    std::string errorMsg;
    char *errorBuf;
    std::vector<std::string> zbar_result;
};

#endif // QRCODE_H

qrcode.cpp 

#include "qrcode.h"

#include <iostream>
#include <functional>
#include <assert.h>
#include <zbar.h>
#include <fstream>
extern "C"
{
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
}

using MemStream = std::tuple<uint8_t const*,size_t>; //tuple存储内存流信息


QRCode::QRCode():errorMsg(),errorBuf(nullptr)
{
    errorBuf = new char[AV_ERROR_MAX_STRING_SIZE];
    assert(errorBuf != nullptr);
}

//AVIOContext从内存流中读数据要用的回调
static int read_pkt( void *opaque, uint8_t *buf, int bytes )
{
    MemStream& data = *reinterpret_cast<MemStream*>(opaque);
    size_t &st_len = std::get<1>(data);
    uint8_t const*&st_buf = std::get<0>(data);
    bytes = static_cast<size_t>(bytes) <= st_len ? bytes : st_len;
    if( bytes == 0 ) return AVERROR_EOF;
    std::copy(st_buf, st_buf+bytes, buf);
    st_len -= bytes;
    return bytes;
}

bool QRCode::load( uint8_t const *buf, size_t bytes )
{
    zbar_result.clear();
    std::shared_ptr<FreeVector> freeVector( new FreeVector, [](FreeVector* v){
        for( auto& x : *v)
        {
            x();
        }
        delete v;
    });
    MemStream *pData = new MemStream (buf, bytes);
    freeVector->emplace_back([=](){
        std::cout << "free pData" << std::endl;delete pData;
    });

    constexpr size_t avio_ctx_buffer_size = 1024*1024*8; //8M
    uint8_t *avio_ctx_buf = static_cast<uint8_t*>( av_malloc(avio_ctx_buffer_size) );
    if(avio_ctx_buf == nullptr )
    {
        errorMsg = std::string()+__FILE__+" "+std::to_string(__LINE__)+", avio_ctx_buf==nullptr";
        return false;
    }

    AVIOContext *p_avio_ctx = avio_alloc_context
            ( avio_ctx_buf, avio_ctx_buffer_size, 0, pData, &read_pkt, nullptr,nullptr);
    if( p_avio_ctx == nullptr )
    {
        av_free(avio_ctx_buf);
        errorMsg = std::string()+__FILE__+" "+std::to_string(__LINE__)+", p_avio_ctx==nullptr";
        return false;
    }
    freeVector->emplace_back([p_avio_ctx]()mutable{
        std::cout << "free avio_ctx_buf" << std::endl;
        if( p_avio_ctx )
            av_free(p_avio_ctx->buffer);
        std::cout << "free p_avio_ctx" << std::endl;
        avio_context_free(&p_avio_ctx);
    });

    AVFormatContext *pFmtCtx = avformat_alloc_context();
    if( pFmtCtx == nullptr )
    {
        errorMsg = std::string()+__FILE__+" "+std::to_string(__LINE__)+", pFmtCtx==nullptr";
        return false;
    }
    pFmtCtx->pb = p_avio_ctx;

    int ret = avformat_open_input(&pFmtCtx, nullptr, nullptr, nullptr );
    if( 0 > ret )
    {
        av_make_error_string(errorBuf, AV_ERROR_MAX_STRING_SIZE, ret);
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" "+errorBuf;
        return false;
    }
    freeVector->emplace_back([=]()mutable{
        std::cout << "free pFmtCtx" << std::endl;
        avformat_close_input(&pFmtCtx);
    });
    return decode(freeVector, pFmtCtx);
}

bool QRCode::load( const std::string& url )
{
    zbar_result.clear();
    std::shared_ptr<FreeVector> freeVector( new FreeVector, [](FreeVector* v){
        for( auto& x : *v)
        {
            x();
        }
        delete v;
    });
    AVFormatContext *pFmtCtx = nullptr;
    int ret = avformat_open_input(&pFmtCtx, url.c_str(), nullptr, nullptr );
    if( 0 > ret )
    {
        av_make_error_string(errorBuf, AV_ERROR_MAX_STRING_SIZE, ret);
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" "+errorBuf;
        return false;
    }
    freeVector->emplace_back([=]()mutable{
        std::cout << "free pFmtCtx" << std::endl;
        avformat_close_input(&pFmtCtx);
    });
    return decode(freeVector, pFmtCtx);
}

bool QRCode::decode( std::shared_ptr<FreeVector> freeVector, AVFormatContext* pFmtCtx )
{
    if( 0 > avformat_find_stream_info(pFmtCtx, nullptr) )
    {
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" avformat_find_stream_info";
        return false;
    }
    int video_stream_idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -1,-1,nullptr, 0);
    if( video_stream_idx < 0 )
    {
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" can't not find steam";
        return false;
    }

    AVStream *st = pFmtCtx->streams[video_stream_idx];

    AVCodec *p_codec = avcodec_find_decoder( st->codecpar->codec_id );

    if( p_codec == nullptr )
    {
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" can't not find decoder";
        return false;
    }

    AVCodecContext *p_codec_ctx = avcodec_alloc_context3(p_codec);
    if( p_codec_ctx == nullptr )
    {
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" alloc codec ctx failure";
        return false;
    }
    freeVector->emplace_back([=]()mutable{
        std::cout << "free p_codec_ctx" << std::endl;
        avcodec_free_context(&p_codec_ctx);
    });
    if( 0 > avcodec_parameters_to_context(p_codec_ctx, st->codecpar) )
    {
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" avcodec_parameters_to_context";
        return false;
    }

    if( 0 > avcodec_open2(p_codec_ctx, p_codec, nullptr ) )
    {
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" open codec failure";
        return false;
    }

    bool isNeedSws = p_codec_ctx->pix_fmt != AV_PIX_FMT_GRAY8 ? true:false;

    SwsContext *sws_ctx = nullptr;

    AVFrame *dst_frame = nullptr;
    if( isNeedSws )
    {
        dst_frame = av_frame_alloc();
        if( dst_frame == nullptr )
        {
            errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+"alloc dst_frame failure";
            return false;
        }
        freeVector->emplace_back([=]()mutable{
            std::cout << "free dst_frame" << std::endl;
           av_frame_free(&dst_frame);
        });
        dst_frame->width = p_codec_ctx->width;
        dst_frame->height = p_codec_ctx->height;
        dst_frame->format = AV_PIX_FMT_GRAY8;

        if( 0 > av_frame_get_buffer( dst_frame, 1 ) )
        {
            errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+"av_frame_get_buffer failure";
            return false;
        }

        sws_ctx = sws_getContext(p_codec_ctx->width, p_codec_ctx->height, p_codec_ctx->pix_fmt,
                                             p_codec_ctx->width, p_codec_ctx->height, static_cast<AVPixelFormat>(dst_frame->format),
                                             SWS_BILINEAR, nullptr,nullptr, nullptr);
        if( sws_ctx == nullptr )
        {
            errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+"sws_getContext failure";
            return false;
        }
        freeVector->emplace_back([=](){
            std::cout << "free sws_ctx" << std::endl;
            sws_freeContext(sws_ctx);
        });
    }

    AVPacket pkt;
    av_init_packet( &pkt );

    AVFrame *p_frame = av_frame_alloc();
    if( p_frame == nullptr )
    {
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+"alloc p_frame failure";
        return false;
    }
    freeVector->emplace_back([=]()mutable{
        std::cout << "free p_frame" << std::endl;
       av_frame_free(&p_frame);
    });

    int ret;

    while( 0 <= (ret = av_read_frame(pFmtCtx, &pkt) ) )
    {
        std::shared_ptr<AVPacket> guard( &pkt, [](AVPacket *p_pkt){
            av_packet_unref( p_pkt );
        });//保证while每次循环后unref pkt

        ret = avcodec_send_packet(p_codec_ctx, &pkt);
        if( ret < 0 )
        {
            errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+" send_packet failure";
            return false;
        }

        while( ret >= 0 )
        {
            ret = avcodec_receive_frame(p_codec_ctx, p_frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            {
                break;
            }
            if( ret < 0 )
            {
                errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+"receive_frame failure";
                return false;
            }

            AVFrame *pic = p_frame;
            if( isNeedSws )
            {
                sws_scale(sws_ctx, p_frame->data, p_frame->linesize, 0, p_codec_ctx->height, dst_frame->data, dst_frame->linesize);
                pic = dst_frame;
            }
            return this->getCodeByZBar( freeVector, pic );
        }
    }

    if( ret < 0 && ret != AVERROR_EOF )
    {
        errorMsg =std::string()+ __FILE__+" "+std::to_string(__LINE__)+"read_frame failure";
        return false;
    }

    return true;
}

bool QRCode::getCodeByZBar(std::shared_ptr<FreeVector>, AVFrame* pic)
{
    int size = av_image_get_buffer_size( static_cast<AVPixelFormat>(pic->format), pic->width, pic->height, 1 );
    zbar::Image image(pic->width, pic->height, "Y800"
                            , pic->data[0], size);
    zbar::ImageScanner scan;
    scan.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
    scan.scan(image);
    for (zbar::SymbolIterator symbol = scan.get_results().symbol_begin();
                            symbol != image.symbol_end();++symbol)
     {
           zbar_result.emplace_back( symbol->get_data() );
     }
    if( zbar_result.empty() )
    {
        errorMsg = "zbar can't not parse, picture may be not a qrcode";
        return false;
    }
     // clean up
     image.set_data(NULL, 0);
     return true;
}

 

2017-06-17 18:08:57 Ashimar_a 阅读数 1778
  • 微信公众平台深度开发v2.0第3季——二维码、模板消息

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    10261 人正在学习 去看看 翟东平

整理了一个关于二维码扫描,生成二维码(带logo、换颜色),长按识别二维码的内容的Demo。效果如图:

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

github 下载地址

2019-12-24 12:10:22 qq_39071739 阅读数 94
  • 微信公众平台深度开发v2.0第3季——二维码、模板消息

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    10261 人正在学习 去看看 翟东平

Opencv:二维码检测与识别Python实现

一、内容

二维码检测与识别

OpenCV在对象检测模块中QRCodeDetector有两个相关API分别实现二维码检测与二维码解析

检测
QRCodeDetector::detect(
InputArray img,
OutputArray points
)const
img 输入图像,灰度或者彩色图像
points 得到的二维码四个点的坐标信息

解析
QRCodeDetector::decode(
InputArray img,
InputArray points,
OutputArray straight_qrcode = noArray()
)
img 输入图像,灰度或者彩色图像
points 二维码ROI最小外接矩形顶点坐标
qrcode 输出的是二维码区域ROI图像信息
返回的二维码utf-8字符串

上述两个API功能,可以通过一个API调用实现,该API如下:
QRCodeDetector::detectAndDecode(
InputArray img,
OutputArray points = noArray(),
OutputArray straight_qrcode = noArray()
)

二、代码

import cv2 as cv
import numpy as np

# 读取图像
src = cv.imread("D:/vsprojects/images/er.jpg")
cv.imshow("image", src)
# 灰度转换
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 检测
qrcoder = cv.QRCodeDetector()
# 解码
codeinfo, points, straight_qrcode = qrcoder.detectAndDecode(gray)
print(points)
result = np.copy(src)
# 描绘轮廓
cv.drawContours(result, [np.int32(points)], 0, (0, 0, 255), 2)
print("qrcode : %s" % codeinfo)
# 添加文字
cv.putText(result, "qrcode:" + str(codeinfo), (0, 20), cv.FONT_HERSHEY_SIMPLEX, .5, (255, 0, 0), 1);
cv.imshow("result", result)

cv.waitKey(0)
cv.destroyAllWindows()

三、结果

1.原始图片

在这里插入图片描述

2.结果图片

在这里插入图片描述
在这里插入图片描述

没有更多推荐了,返回首页