前言

最近正好遇到了一个图片的效期提取,正好当做一个小练习记录一下。

opencv 印章变得更红 opencv 提取印章_opencv

实现效果

opencv 印章变得更红 opencv 提取印章_cv_02

左边的大图是截取后的原图,右边是提取后的实际图,然后根据提取出来的再进行OCR识别,识别这块就不再说了,这里只是写一下怎么提取的图片。

#

实现思路

1

转灰度图、高斯模糊

2

Canny边缘提取

3

定义X轴较长的一个卷积进行膨胀操作

4

查找轮廓,找到符合条件的截取出来

01

预处理

读取图像,转为灰度图,然后高斯模糊。

opencv 印章变得更红 opencv 提取印章_cv_03

opencv 印章变得更红 opencv 提取印章_ocr_04

预处理后的图像

02

Canny边缘提取

opencv 印章变得更红 opencv 提取印章_ocr_05

这里测试后发现使用50,120的阈值效果不错

opencv 印章变得更红 opencv 提取印章_opencv_06

Canny后的效果

用Canny的边缘提取的效果是最好的,如果考虑图像二值化什么的,效果会差很多,下面是用二值化和自适应二值化后的效果,可以看到都很不理想。

opencv 印章变得更红 opencv 提取印章_opencv 印章变得更红_07

opencv 印章变得更红 opencv 提取印章_opencv_08

二值化的效果

opencv 印章变得更红 opencv 提取印章_ocr_09

opencv 印章变得更红 opencv 提取印章_opencv 印章变得更红_10

自适应二值化效果

上面可以看到,正常二值化效果最差,自适应二值化干扰项也很多,Canny边缘提取的效果最好。

03

膨胀操作

其实上图Canny提取后,里面直接就有一个正方形了,可以不需要这一步直接提取轮廓即可,不过再另一张图效果就没有那么好了,比如下面这个。

opencv 印章变得更红 opencv 提取印章_ocr_11

所以要对上面这个图做一个卷积为(30,5)的膨胀操作,尽量让其都连接起来。

opencv 印章变得更红 opencv 提取印章_opencv 印章变得更红_12

opencv 印章变得更红 opencv 提取印章_cv_13

膨胀后的效果

04

查找轮廓

opencv 印章变得更红 opencv 提取印章_opencv_14

将所有轮廓都查找出来,这里只查找最外侧轮廓就行,然后画出效果

opencv 印章变得更红 opencv 提取印章_cv_15

这一步只是看效果的,真正可以用不到,直接判断符合的轮廓提取即行

opencv 印章变得更红 opencv 提取印章_ocr_16

opencv 印章变得更红 opencv 提取印章_计算机视觉_17

完整代码

#pragma once
#include <iostream>
#include<opencv2/opencv.hpp>


using namespace std;
using namespace cv;


int main(int argc, char** argv) {
  Mat src = imread("E:/DCIM/testdate/pic1.png");


  imshow("src", src);


  Mat gray, dst;
  //转换灰度图
  cvtColor(src, gray, COLOR_BGR2GRAY);
  //高斯模糊
  GaussianBlur(gray, gray, Size(3, 3), 0.5, 0.5);


  imshow("gray", gray);




  //Canny边缘检测
  Canny(gray, dst, 50, 120);
  imshow("Canny", dst);


  Mat dst2;
  //使用膨胀操作,kernel定义的要长一点
  Mat kernel = getStructuringElement(MORPH_RECT, Size(30, 5));
  morphologyEx(dst, dst2, MORPH_DILATE, kernel);


  imshow("morph", dst2);


  //查找轮廓,只找最外侧轮廓
  vector<vector<Point>> contours;
  findContours(dst2, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);


  RNG rng(12345);
  Mat dstzero = Mat::zeros(dst2.size(), CV_8UC3);
  for (int i = 0; i < contours.size(); ++i) {
    //判断符合区域
    RotatedRect rRect = minAreaRect(contours[i]);
    Rect rect = rRect.boundingRect();


      Scalar color = Scalar(rng.uniform(0, 255), 
        rng.uniform(0, 255), rng.uniform(0, 255));
      rectangle(dstzero, rect, color);
  }
  imshow("zero", dstzero);


  for (int i = 0; i < contours.size(); ++i) {
    //判断符合区域
    RotatedRect rRect = minAreaRect(contours[i]);
    Rect rect = rRect.boundingRect();
    if (rect.width / rect.height < 2) {
      Mat cutmat = src(rect);
      imshow("dstzero"+i, cutmat);
    }
  }


  waitKey(0);
  return 0;
}

opencv 印章变得更红 opencv 提取印章_opencv_18

opencv 印章变得更红 opencv 提取印章_计算机视觉_19