opencv-验证码识别

首先定义两个工具类,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);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容