美文网首页工作生活
opencv-验证码识别

opencv-验证码识别

作者: Peakmain | 来源:发表于2019-07-04 18:01 被阅读0次

    首先定义两个工具类,mat和bitmap互转

    #include <jni.h>
    #include <string>
    #include <android/bitmap.h>
    #include <malloc.h>
    #include <opencv2/opencv.hpp>
    #include <iostream>
    #include <android/log.h>
    
    using namespace cv;
    #define TAG "JNI_TAG"
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
    
    /**
     * bitmap转成mat
     */
    
    Mat bitmap2Mat(JNIEnv *env, jobject bitmap) {
        // 1. 获取图片的宽高,以及格式信息
        AndroidBitmapInfo info;
        AndroidBitmap_getInfo(env, bitmap, &info);
        void *pixels;
        AndroidBitmap_lockPixels(env, bitmap, &pixels);
    
        Mat mat;
    
        if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
            LOGE("nMatToBitmap: CV_8UC4 -> RGBA_8888");
            mat = Mat(info.height, info.width, CV_8UC4, pixels);
        } else {
            LOGE("nMatToBitmap: CV_8UC2 -> RGBA_565");
            mat = Mat(info.height, info.width, CV_8UC2, pixels);
        }
    
        AndroidBitmap_unlockPixels(env, bitmap);
        return mat;
    }
    
    /**
     * mat转成bitmap
     */
    void mat2bitmap(JNIEnv *env, Mat src, jobject bitmap) {
        // 1. 获取图片的宽高,以及格式信息
        AndroidBitmapInfo info;
        AndroidBitmap_getInfo(env, bitmap, &info);
        void *pixels;
        AndroidBitmap_lockPixels(env, bitmap, &pixels);
    
        if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
            Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if (src.type() == CV_8UC1) {
                LOGE("nMatToBitmap: CV_8UC1 -> RGBA_8888");
                cvtColor(src, tmp, COLOR_GRAY2RGBA);
            } else if (src.type() == CV_8UC3) {
                LOGE("nMatToBitmap: CV_8UC3 -> RGBA_8888");
                cvtColor(src, tmp, COLOR_RGB2RGBA);
            } else if (src.type() == CV_8UC4) {
                LOGE("nMatToBitmap: CV_8UC4 -> RGBA_8888");
                src.copyTo(tmp);
            }
        } else {
            // info.format == ANDROID_BITMAP_FORMAT_RGB_565
            Mat tmp(info.height, info.width, CV_8UC2, pixels);
            if (src.type() == CV_8UC1) {
                LOGE("nMatToBitmap: CV_8UC1 -> RGB_565");
                cvtColor(src, tmp, COLOR_GRAY2BGR565);
            } else if (src.type() == CV_8UC3) {
                LOGE("nMatToBitmap: CV_8UC3 -> RGB_565");
                cvtColor(src, tmp, COLOR_RGB2BGR565);
            } else if (src.type() == CV_8UC4) {
                LOGE("nMatToBitmap: CV_8UC4 -> RGB_565");
                cvtColor(src, tmp, COLOR_RGBA2BGR565);
            }
        }
    
        AndroidBitmap_unlockPixels(env, bitmap);
    }
    

    形体学操作:morphologyEx

    腐蚀:取最小值
    膨胀:取最大值

    • CV_MOP_OPEN 开图像:先腐蚀后膨胀
      Mat src = bitmap2Mat(env, bitmap);
        Mat dest;
        Mat kernel ;
        kernel=getStructuringElement(MORPH_RECT,Size(15,15));
        //erode(src, dest, kernel);
        morphologyEx(src,dest,CV_MOP_OPEN,kernel);
        mat2bitmap(env, dest, bitmap);
    
    先腐蚀后膨胀
    • CV_MOP_CLOSE 闭图像:先膨胀后腐蚀
    morphologyEx(src,dest,CV_MOP_CLOSE,kernel);
    
    image.png
    • CV_MOP_GRADIENT 梯度:膨胀 - 腐蚀
    • CV_MOP_TOPHAT 顶帽:原图像- 开图像
        Mat kernel ;
        kernel=getStructuringElement(MORPH_RECT,Size(25,25));
        morphologyEx(src,dest,CV_MOP_TOPHAT,kernel);
    
    image.png

    开图像是,先腐蚀后膨胀,所以会得到讲小白色方块去掉的图,之后用原图像去减得到的图像,实际得到的就是小方块图像

    • CV_MOP_BLACKHAT 黑帽:闭图像 - 原图像
        Mat kernel ;
        kernel=getStructuringElement(MORPH_RECT,Size(25,25));
        morphologyEx(src,dest,CV_MOP_BLACKHAT,kernel);
    
    image.png

    首先闭图像会去先膨胀后腐蚀,就是将原来的图片中的黑点去填充为白色,再减去原图就剩下白色的圆圈

    过滤验证码的干扰

    往上随便找个验证码图,如下图,想除掉验证码干扰信息,怎么做


    code.png
    • 方法一、先闭图像后开图像
      Mat src = bitmap2Mat(env, bitmap);
        Mat dest;
        Mat final;
        Mat kernel,kernel1 ;
        kernel=getStructuringElement(MORPH_RECT,Size(3,3));
        morphologyEx(src,dest,CV_MOP_CLOSE,kernel);
        kernel1=getStructuringElement(MORPH_RECT,Size(5,5));
        morphologyEx(dest,final,CV_MOP_OPEN,kernel1);
        mat2bitmap(env, final, bitmap);
        return 1;
    
    image.png
    • 方法二:彩色变成黑白再处理
        Mat src = bitmap2Mat(env, bitmap);
        Mat gray;
       //二值化让彩色变成黑白
        cvtColor(src,gray,COLOR_BGR2GRAY);
        //二值化方法,自动阀值
        Mat binary;
        adaptiveThreshold(~gray,binary,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,15,0);
        Mat kernel ;
        kernel=getStructuringElement(MORPH_RECT,Size(3,3));
        Mat dest;
        morphologyEx(binary,dest,CV_MOP_OPEN,kernel);
        bitwise_not(dest,dest);//取反
        mat2bitmap(env, dest, bitmap);
    
    image.png

    提取水平和垂直线

    如下图,提取其中的水平后者垂直线


    ew.jpg
    • 提取水平线
        Mat src = bitmap2Mat(env, bitmap);
        Mat gray;
        //1.二值化让彩色变成黑白
        cvtColor(src, gray, COLOR_BGR2GRAY);
        //二值化方法,自动阀值
        Mat binary, dest;
        adaptiveThreshold(~gray, binary, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 7, 0);
        Mat kernel;
        kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
        //先大概去掉一些乱七八糟的点
        morphologyEx(binary, dest, CV_MOP_OPEN, kernel);
        //中间连接的时候有黑色的小方块,改为白色,膨胀
        kernel = getStructuringElement(MORPH_RECT, Size(7, 7));
        dilate(dest,dest,kernel);
        //腐蚀:最小值
        erode(dest,dest,kernel);
        //2.取水平线
        Mat level = getStructuringElement(MORPH_RECT, Size(src.cols/16, 1));
        //腐蚀,将不是水平线的变成黑色,所以取最小值
        erode(dest,dest,level);
        //膨胀,不然线变短了
        dilate(dest,dest,level);
        mat2bitmap(env, dest, bitmap);
    

    二极制后的结果图片


    二极制后的结果.png

    解决十字黑色问题后的图片


    解决十字黑色问题.png

    获取水平线的结果图片


    获取水平线.png
    • 取垂直线:修改第二步即可
        //3.取垂直线
        Mat level = getStructuringElement(MORPH_RECT, Size(1,src.cols/16));
        //腐蚀,将不是水平线的变成黑色,所以取最小值
        erode(dest,dest,level);
        //膨胀,不然线变短了
        dilate(dest,dest,level);
        mat2bitmap(env, dest, bitmap);
    

    结果


    image.png

    上采样:pyrUp和降采样pyrDown

    • 图片采样:也称取样,指把时间域或空间域的连续量转化成离散量的过程。也指把模拟音频转成数字音频的过程。在数字图像处理领域中,定义为图像空间坐标的数字化操作。可以理解为图片的分辨率、像素

    • 背景:图片单纯放大,比如一个像素放大几倍,会变成不清楚,对此opencv提供了采样来解决这问题

    • 上采样:也称为拉普拉斯。采用内插值方法,即在原有图像像素的基础上在像素点之间采用合适的插值算法插入新的元素。
      pyrUp:预计算值

        Mat src = bitmap2Mat(env, bitmap);
        Mat dest;
        pyrUp(src,dest,Size(src.cols*2,src.rows*2));
        mat2bitmap(env, dest, bitmap);
    
    • 降采样:1.对图像进行高斯模糊 2.再过滤左右临近点
        Mat src = bitmap2Mat(env, bitmap);
        Mat dest;
        pyrDown(src,dest,Size(src.cols/2,src.rows/2));
        mat2bitmap(env, dest, bitmap);
    

    相关文章

      网友评论

        本文标题:opencv-验证码识别

        本文链接:https://www.haomeiwen.com/subject/qjokhctx.html