基于轮廓提取的矫正算法

标签(空格分隔): 计算机图形学 数字图像处理


背景

支付宝和微信对数字货币的推广起到了积极的作用,大多数现代人都不怎么用手点钞了,取而代之的是数字货币。随着数字货币的发展,终有一天纸币将会退出历史舞台。那一天一定会有很多人想将那个年代的钞票一张张拍下来留念。
将一张百元大钞拍下来,手抖拍得又歪又斜,怎么办呢?那么多张钞票要微调处理,不可能每次都使用PS,那样工作量会很太。利用图像矫正技术可以解决这个问题,首先要弄明白几个技术原理点。

图像矫正技术知识储备

  1. 目标识别(匹配、最佳统计分类器、神经网络)
  2. 轮廓检测与提取(矩形区域裁剪、灰度化、二值化、ROI)
  3. 霍夫变换(Hough),在本次实验中并没有使用上,因为钞票图像有明显的边缘轮廓,而Hough主要用在没有明显边缘轮廓的图像当中,例如文本处理。

目标识别

轮廓检测指在包含目标和背景的数字图像中,忽略背景和目标内部的纹理以及噪声干扰的影响,采用一定的技术和方法来实现目标轮廓提取的过程。它是目标检测、形状分析、目标识别和目标跟踪等技术的重要基础。来自百科的解释。
若钞票的背景图像比较复杂,在检测过程中肯定会受到噪声干扰的。这一步将会利用深度学习强大的学习能力解决这个目标轮廓区域检测的难题,这样效率会更高。这里涉及到一个重要点,通过设定指定的阀值就能判断目标区域的倾斜识别,让程序变得更智能,无需人工介入来判断。由于本文篇幅有限,感兴趣的同学自行找相关资料参考学习。

轮廓检测与提取

目标识别系统检测出钞票之后会在目标区域周围标注边界框,就可以获取边界框的坐标信息L(p_1,p_2,p_3,p_4),p_n = p(x,y),n∈1..4 ,然后根据L坐标信息的范围取相反方向,在相反方向区域内对图像背景填充黑色再进行图像灰度化、二值化、检测钞票的轮廓、寻找钞票轮廓边界矩阵、获得角度a、a不断旋转矫正,最后将已水平的图像区域抠取出来另存为一张新图像。

实现过程

1、目标识别

目标识别系统检测到钞票得到边界框的坐标信息是L(p_1,p_2,p_3,p_4)

image_1d5mm0hu63ok4f9r238h51ptfq.png-555.7kB
image_1d5mm0hu63ok4f9r238h51ptfq.png-555.7kB

image_1d5nov6li1unv1n322cn19c4ear1k.png-546.7kB
image_1d5nov6li1unv1n322cn19c4ear1k.png-546.7kB

问题的重点是网络模型怎样检测出钞票四个角的边缘特征,而不是只检测到红色的外边框。如果这一步解决了,后面问题将迎刃而解,此问题先暂时缓一下。
假设网络模型可以给出以下坐标参数
x_1 = 1011,y_1 = 750

x_2 = 2031,y_2 = 3300

x_3 = 2031,y_3 = 3300

x_4 = 2856,y_4 = 2352

2、感兴趣区域ROI,将不规则区域填充黑色

Mat mask = Mat::zeros(src.size(),CV_8UC1);
    Mat dst;
    vector<vector<Point2i>> contours;
    vector<Point2i> points;
    points.push_back(Point2i(x1, y1));
    points.push_back(Point2i(x2, y2));
    points.push_back(Point2i(x3, y3));
    points.push_back(Point2i(x4, y4));
    contours.push_back(points);
    drawContours(mask, contours, 0, Scalar::all(255), -1);
    src.copyTo(dst, mask);
    imwrite("images/result_process.jpg", dst);

将钞票的背景图像区域填充黑色


image_1d5ofb6r847dgiqqe113st1g4d33.png-154.2kB
image_1d5ofb6r847dgiqqe113st1g4d33.png-154.2kB

3、轮廓检测与提取

    Mat gray, binImg;
    //灰度化
    cvtColor(dst,gray, COLOR_RGB2GRAY);
    imshow("灰度图", gray);
    //二值化
    threshold(gray, binImg, 100, 200, CV_THRESH_BINARY);
    imshow("二值化", binImg);
    contours.clear();
    vector<Rect> boundRect(contours.size());
    //注意第5个参数为CV_RETR_EXTERNAL,只检索外框
    findContours(binImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //找轮廓
    cout << contours.size() << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        //需要获取的坐标
        CvPoint2D32f rectpoint[4];
        CvBox2D rect =minAreaRect(Mat(contours[i]));
        
        cvBoxPoints(rect, rectpoint); //获取4个顶点坐标
        //与水平线的角度
        float angle = rect.angle;
        cout << angle << endl;
        
        int line1 = sqrt(pow(rectpoint[1].y - rectpoint[0].y,2)+pow(rectpoint[1].x - rectpoint[0].x,2));
        int line2 = sqrt(pow(rectpoint[3].y - rectpoint[0].y,2)+pow(rectpoint[3].x - rectpoint[0].x,2));
  
        //面积太小的直接过滤
        if (line1 * line2 < 600)
        {
            continue;
        }
        
        //为了让正方形横着放,所以旋转角度是不一样的。竖放的,给他加90度,翻过来
        if (line1 > line2)
        {
            angle = 90 + angle;
        }
        
        //新建一个感兴趣的区域图,大小跟原图一样大
        Mat RoiSrcImg(dst.rows, dst.cols, CV_8UC3); //注意这里必须选CV_8UC3
        RoiSrcImg.setTo(0); //颜色设置为黑色

        //对得到的轮廓填充一下
        drawContours(binImg, contours, -1, Scalar(255),CV_FILLED);
        
        //抠图到RoiSrcImg
        dst.copyTo(RoiSrcImg, binImg);
        
        
        //再显示一下看看,除了感兴趣的区域,其他部分都是黑色的了
        namedWindow("RoiSrcImg", 1);
        imshow("RoiSrcImg", RoiSrcImg);
        
        //创建一个旋转后的图像
        Mat RatationedImg(RoiSrcImg.rows, RoiSrcImg.cols, CV_8UC1);
        RatationedImg.setTo(0);
        //对RoiSrcImg进行旋转
        Point2f center = rect.center;  //中心点
        Mat M2 = getRotationMatrix2D(center, angle, 1);//计算旋转加缩放的变换矩阵
        warpAffine(RoiSrcImg, RatationedImg, M2, RoiSrcImg.size(),1, 0, Scalar(0));//仿射变换
        imshow("旋转之后", RatationedImg);
        imwrite("images/test_temp.jpg", RatationedImg); //将矫正后的图片保存下来
    }
    

角度调整之后的图片如下


image_1d5of9vk21sca1pkg1um01h2s1j432m.png-164.2kB
image_1d5of9vk21sca1pkg1um01h2s1j432m.png-164.2kB

对旋转后的图片进行ROI轮廓区域的提取

#if 1
    vector<vector<Point> > contours2;
    Mat raw = imread("images/test_temp.jpg");
    Mat SecondFindImg;
    cvtColor(raw, SecondFindImg, COLOR_BGR2GRAY);  //灰度化
    threshold(SecondFindImg, SecondFindImg, 80, 200, CV_THRESH_BINARY);
    findContours(SecondFindImg, contours2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    
    for (int j = 0; j < contours2.size(); j++)
    {
        //这时候其实就是一个长方形了,所以获取rect。
        Rect rect = boundingRect(Mat(contours2[j]));
        //面积太小的轮廓直接过滤,通过设置过滤面积大小,可以保证只拿到外框。
        if (rect.area() < 600)
        {
            continue;
        }
        Mat dstImg = raw(rect);
        imshow("dst", dstImg);
        imwrite("images/test_result.jpg", dstImg);
    }
#endif
}

最终结果如下,这个误差应该可以在接受的范围之内。


image_1d5of76991g6b1e2k19sf14kmbkd29.png-425kB
image_1d5of76991g6b1e2k19sf14kmbkd29.png-425kB

总结

算法名称基于轮廓提取的矫正算法,本次实验的算法是在Madcola的基础上优化大部分代码,并结合深度学习目标识别检测钞票图像的角点特征预测。由于时间紧迫,本文的算法和实验并不完美,还有很多值得改进的地方。

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