zoukankan      html  css  js  c++  java
  • 【OpenCV】一种基于阈值的图片中的文字分割

    在今年泰迪杯A题电商中图片的文字识别这道题中,我们先用了一种很笨的办法来分割字符。
    首先对图片进行灰度化,然后二值化,这里的二值化要选择一个合适的阈值。然后我们进行轮廓的提取,计算轮廓最小矩形的面积,若面积过大,则认为这个是背景图片,若面积过小,则认为是噪点。这种方法有一个弊端,就是文字有大有小,大的文字也有可能会被当成背景,小的标点也可能会被当成噪点。

    代码如下:
    实现了读入一张图片,进行灰度化,二值化,分割字符,输出字符.jpg到指定位置,以及输出字符最小矩形的坐标。

     const string imagename = "1.jpg";    //此处需要填写绝对地址,我测试时使用相对地址出错。
        //读入图像
        Mat img = imread(imagename);
        //如果读入图像失败
        if (img.empty())
        {
            return -1;
        }
    
        int Hmin = 0, Hmax = 156;
        int AreaMin = 15, AreaMax = 135;
        int Area = 200;
        //创建窗口 
        cv::namedWindow("thresh");
        cv::createTrackbar("Hmin", "thresh", &Hmin, 255, NULL); cv::createTrackbar("Hmax", "thresh", &Hmax, 255, NULL);
        cv::createTrackbar("AreaMin", "thresh", &AreaMin, 200, NULL);
         cv::createTrackbar("AreaMax", "thresh", &AreaMax, 200, NULL);
        cv::createTrackbar("Area", "thresh", &Area, 4000, NULL);
        for (;;){
            int _Hmin = Hmin, _Hmax = Hmax;
            int _AreaMin = AreaMin, _AreaMax = AreaMax;
            Mat HSV, thresh, GRAY,gray,src;
            //vector<Mat> channels;
            cvtColor(img, GRAY, CV_BGR2GRAY);
            //cvtColor(img, HSV, CV_BGR2HSV);
            //CV_BGR2GRAY转为灰度  CV_BGR2HSV转为HSV  CV_BGR2YUV转为YUV CV_BGR2YCrCb转为YCrCb
            //split(HSV, channels);
            // channels[2]=0;
            inRange(GRAY,
                cv::Scalar(MIN(_Hmin, _Hmax), MIN(0, 255), MIN(0, 255)),
                cv::Scalar(MAX(_Hmin, _Hmax), MAX(0, 255), MAX(0, 255)),     //scalar 中 (b,g,r,0) 即bgr 而非 rgb
                thresh);//color   
            gray = GRAY;
            thresh = 255 - thresh;
            //cvShowImage("ThresholdImg", GRAY);
    
            dilate(thresh, thresh, NULL, cv::Point(-1, -1), 30);
            erode(thresh, thresh, NULL, cv::Point(-1, -1), 30);
    
            cv::imshow("thres", thresh);
            cv::waitKey(1);
            vector<cv::vector<cv::Point> > contours;
            vector<cv::Vec4i> hierarchy;
            // 找出图像中的最大轮廓
            findContours(thresh, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
            // 定义一个 Rect 矢量来存放轮廓。因为轮廓的外形多数时候是不规则的。所以用一个矩形来代替 不规则的轮廓会在各种方面都方便很多。
            //printf("轮廓个数:%d", contours.size());
            cv::vector<cv::vector<cv::Point> > contours_poly(contours.size());
            cv::vector<cv::Rect> boundRect(contours.size());
    
            cv::vector<cv::Point2f>center(contours.size());
            cv::vector<float>radius(contours.size());
            int maxArea = 0;
            int index = 0;
            int minArea = 50;
            int ci = 0;
            for (unsigned int i = 0; i<contours.size(); i++)
                // 用一个 for 循环语句查看计算机找到的全部轮廓
            {
                int area = contourArea(contours[i]);// 计算当前轮廓的包含面积
                if (area> maxArea) // 找出包含面积最大的轮廓
                {
                    maxArea = area;
                    index = i;
                }
    
                if (area<_AreaMax&&area>_AreaMin)
                {
                    ci++;
                    approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true);
                    // approxPolyDP() 用来找出轮廓的近似多边形。用于简化轮廓的复杂度,加速计算过程。
    
                    boundRect[i] = cv::boundingRect(cv::Mat(contours_poly[i]));
                    //BoundingRect() 是一个用来找出轮廓最小包围矩形函数。
                    //最小包围矩形的意思就是用 4 条边从 上下左右四个方向把轮廓紧紧夹在中间。这 4 条边构成的矩形就是最小包围矩形。
    
                    //drawContours(img, contours, i, CV_RGB(255, 255, 255), 1, 8, hierarchy, 0, cv::Point()); // 画出物体的轮廓
    
                    rectangle(GRAY, boundRect[i].tl(), boundRect[i].br(), CV_RGB(255, 0, 0), 2, 8, 0); // 画出物体的最小包围矩形
                    // 矩形的自然就是 boundRect() 算出的轮廓。
                    //printf("左上角x坐标:%d左上角y坐标:%d ", boundRect[i].tl().x, boundRect[i].tl().y);
                    //printf("右下角x坐标:%d右下角y坐标:%d ", boundRect[i].br().x,boundRect[i].br().y);
                    printf("PA%dPA %d %d %d %d
    ",i,boundRect[i].tl().x, boundRect[i].br().y, boundRect[i].br().x, boundRect[i].tl().y);
                    //printf("左下角x坐标:%d左下角y坐标:%d 右上角x坐标:%d右上角y坐标:%d ", boundRect[i].tl().x, boundRect[i].br().y, boundRect[i].br().x, boundRect[i].tl().y);
                    Mat imgROI = img(Rect(boundRect[i].tl().x, boundRect[i].tl().y, std::abs(boundRect[i].br().x - boundRect[i].tl().x), std::abs(boundRect[i].br().y - boundRect[i].tl().y)));
                    CString _file;
                    _file.Format("./test/%d.jpg", i+1);
                    std::string path = _file;
                    imwrite(path, imgROI);
                }
    
            }
    
            //printf("字数:%d", ci);
            //imshow("HSV", HSV);
    
            imshow("GRAY", GRAY);
            //创建窗口
            //显示图像
        //  namedWindow("SRC", 1);
            imshow("img", img);
            CString _file;
            _file.Format("gray.jpg");
            std::string path = _file;
            imwrite(path, GRAY);
        //  imshow("it", thresh);
            //等待按键,按键盘任意键返回
            waitKey(0);
        }
  • 相关阅读:
    SSH 错误解决案例1:Read from socket failed: Connection reset by peer
    vmware已经全面支持open-vm-tools
    RHEL7.1 安装openstack juno 一个BUG
    web快速开发框架 WebBuilder 8.7发布
    2019年如何选择合适的快速开发平台和框架
    快速开发平台 WebBuilder 8.6发布
    快速开发平台比较
    快速开发平台 WebBuilder 8.4 发布
    快速开发平台 WebBuilder 8 发布
    快速开发平台WebBuilder中ExtJS表格的增删改查
  • 原文地址:https://www.cnblogs.com/wolfray/p/5547265.html
Copyright © 2011-2022 走看看