使用 opencv 检测图像中的文本 [英] detect text in images with opencv

查看:64
本文介绍了使用 opencv 检测图像中的文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要检测图片中的文字..

这里有一些在大多数情况下都有效的代码..但不是全部..见附加的输入/输出图像

代码

#include "string";#include fstream"#include "/var/bin/opencv/include/opencv2/opencv.hpp";使用命名空间标准;使用命名空间 cv;无效检测文本(字符串输入){垫大 = imread(输入);垫 RGB;//下采样并使用它进行处理pyrDown(大,RGB);垫子小;cvtColor(rgb,小,CV_BGR2GRAY);//形态梯度垫毕业;Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));形态Ex(小,毕业,MORPH_GRADIENT,morphKernel);//二值化垫体重;阈值(毕业,体重,0.0,255.0,THRESH_BINARY | THRESH_OTSU);//连接水平方向的区域垫子连接;morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));形态Ex(bw,连接,MORPH_CLOSE,morphKernel);//找到轮廓Mat mask = Mat::zeros(bw.size(), CV_8UC1);矢量<矢量<点>>轮廓;向量等级制度;findContours(连接,轮廓,层次结构,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE,点(0,0));//过滤轮廓for(int idx = 0; idx >= 0; idx = 层级[idx][0]){矩形矩形 = boundingRect(contours[idx]);Mat maskROI(mask, rect);maskROI = 标量(0, 0, 0);//填充轮廓drawContours(掩码、轮廓、idx、标量(255、255、255)、CV_FILLED);//填充区域中非零像素的比例double r = (double)countNonZero(maskROI)/(rect.width * rect.height);//如果包含文本,则假设至少填充了该区域的 45%如果 (r > 0.45 &&(rect.height > 8 && rect.width > 8)//限制区域大小//这两个条件本身并不是很健壮.最好使用一些东西//像水平投影中的重要峰值的数量作为第三个条件){矩形(RGB,矩形,标量(0、255、0)、2);}}imwrite(字符串(test_text_contours.jpg"),rgb);}int main(int argc, char* argv[]){检测文本(字符串(input.jpg"));}

输入

输出

更新

/** 编译* # g++ txtbin.cpp -o txtbin `pkg-config opencv --cflags --libs`** 获取opencv版本* # pkg-config --modversion opencv**  跑步* # ./txtbin input.jpg output.png*/#include 字符串"#include fstream"#include "/var/bin/opencv/include/opencv2/opencv.hpp";//#include "/usr/include/opencv2/opencv.hpp";#include "/usr/include/boost/tuple/tuple.hpp";使用命名空间标准;使用命名空间 cv;使用命名空间提升;void CalcBlockMeanVariance(Mat& Img, Mat& Res, float blockSide=21, float contrast=0.01){/** blockSide:为图像中较大的字体设置更大,反之亦然*对比度:设置较小的对比度较低的图像*/垫我;img.convertTo(I, CV_32FC1);Res = Mat::zeros(Img.rows/blockSide, Img.cols/blockSide, CV_32FC1);Mat inpaintmask;垫子补丁;垫小图像;标量 m, s;for(int i = 0; i  对比度){Res.at(i/blockSide, j/blockSide) = m[0];}别的{Res.at(i/blockSide,j/blockSide)=0;}}}调整大小(我,smallImg,Res.size());阈值(Res, inpaintmask, 0.02, 1.0, THRESH_BINARY);垫子修复;smallImg.convertTo(smallImg, CV_8UC1, 255);inpaintmask.convertTo(inpaintmask, CV_8UC1);inpaint(smallImg, inpaintmask, inpainted, 5, INPAINT_TELEA);调整大小(修复,Res,Img.size());Res.convertTo(Res, CV_32FC1, 1.0/255.0);}元组检测文本框(字符串输入,Mat& res,bool draw_contours=false){垫大 = imread(输入);bool test_output = false;整数顶部 = large.rows,底部 = 0,左 = large.cols,右 = 0;整数rect_bottom,rect_right;垫 RGB;//下采样并使用它进行处理pyrDown(大,RGB);pyrDown(rgb, rgb);垫子小;cvtColor(rgb,小,CV_BGR2GRAY);//形态梯度垫毕业;Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));形态Ex(小,毕业,MORPH_GRADIENT,morphKernel);//二值化垫体重;阈值(毕业,体重,0.0,255.0,THRESH_BINARY | THRESH_OTSU);//连接水平方向的区域垫子连接;morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));形态Ex(bw,连接,MORPH_CLOSE,morphKernel);//找到轮廓Mat mask = Mat::zeros(bw.size(), CV_8UC1);矢量<矢量<点>>轮廓;向量等级制度;findContours(连接,轮廓,层次结构,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE,点(0,0));标量颜色 = 标量(0, 255, 0);标量 color2 = 标量(0, 0, 255);整数厚度 = 2;//过滤轮廓for(int idx = 0; idx >= 0; idx = 层级[idx][0]){矩形矩形 = boundingRect(contours[idx]);Mat maskROI(mask, rect);maskROI = 标量(0, 0, 0);//填充轮廓drawContours(掩码、轮廓、idx、标量(255、255、255)、CV_FILLED);//填充区域中非零像素的比例double r = (double)countNonZero(maskROI)/(rect.width * rect.height);//如果包含文本,则假设至少填充了该区域的 25%如果 (r > 0.25 &&(rect.height > 8 && rect.width > 8)//限制区域大小//这两个条件本身并不是很健壮.最好使用一些东西//像水平投影中的重要峰值的数量作为第三个条件){如果(绘制轮廓){矩形(res,矩形(rect.x * 4,rect.y * 4,rect.width * 4,rect.height * 4),颜色,厚度);}如果(测试输出){矩形(rgb,矩形,颜色,厚度);}如果(rect.y <顶部){顶部 = rect.y;}rect_bottom = rect.y + rect.height;如果(rect_bottom > 底部){底部 = rect_bottom;}if(rect.x < left){左 = rect.x;}rect_right = rect.x + rect.width;如果(rect_right > right){右 = rect_right;}}}如果(绘制轮廓){矩形(res,点(左* 4,上* 4),点(右* 4,下* 4),颜色2,厚度);}如果(测试输出){矩形(rgb,点(左,上),点(右,下),颜色2,厚度);imwrite(字符串(test_text_contours.jpg"),rgb);}return make_tuple(left * 4, top * 4, (right - left) * 4, (bottom - top) * 4);}int main(int argc, char* argv[]){字符串输入;字符串输出 = "output.png";整数宽度 = 0,高度 = 0,块边 = 9;布尔值作物=假,画=假;浮动边距 = 0;cout<<"OpenCV 版本:"<<CV_VERSION <<结束;//如果缺少参数则返回错误如果(argc <3){cerr<<"\n用法:txtbin 输入 [选项] 输出\n\n";选项:\n""\t-w <数字>-- 设置最大宽度(保持纵横比)\n""\t-h <数字>-- 设置最大高度(保持纵横比)\n""\t-c -- 裁剪文本内容轮廓\n";"\t-m <number>-- 添加边距(以 % 为单位的数字)\n""\t-b <数字>-- 设置块边\n""\t-d -- 绘制文本内容轮廓(调试)\n";<<结束;返回 1;}//解析参数for(int i = 1; i < argc; i++){如果(我== 1){input = string(argv[i]);//如果输入文件无效则返回错误ifstream 流(input.c_str());if(!stream.good()){cerr<<错误:输入文件无效!"<<结束;返回 1;}}else if(string(argv[i]) == "-w"){宽度 = atoi(argv[++i]);}else if(string(argv[i]) == "-h"){高度 = atoi(argv[++i]);}else if(string(argv[i]) == "-c"){作物 = 真;}else if(string(argv[i]) == "-m"){margin = atoi(argv[++i]);}else if(string(argv[i]) == "-b"){blockside = atoi(argv[++i]);}else if(string(argv[i]) == "-d"){画=真;}否则如果(我 == argc - 1){output = string(argv[i]);}}Mat Img = imread(输入,CV_LOAD_IMAGE_GRAYSCALE);垫子;Img.convertTo(Img, CV_32FC1, 1.0/255.0);CalcBlockMeanVariance(Img, res, blockside);res = 1.0 - res;res = Img + res;阈值(res, res, 0.85, 1, THRESH_BINARY);整数txt_x,txt_y,txt_width,txt_height;如果(裁剪 || 绘制){领带(txt_x,txt_y,txt_width,txt_height)=detect_text_box(输入,res,绘制);}如果(作物){//res = res(Rect(txt_x, txt_y, txt_width, txt_height)).clone();res = res(Rect(txt_x, txt_y, txt_width, txt_height));}如果(保证金){int border = res.cols * margin/100;copyMakeBorder(res, res, border, border, border, border, BORDER_CONSTANT, Scalar(255, 255, 255));}漂浮width_input = res.cols,height_input = res.rows;布尔调整大小 = 假;//缩小图像如果(宽度> 0&&&&&& width_input>宽度){浮动比例 = width_input/宽度;width_input/= 比例;height_input/= 比例;调整大小 = 真;}如果(高度> 0&&& height_input>高度){浮动比例 = height_input/高度;width_input/= 比例;height_input/= 比例;调整大小 = 真;}如果(调整大小){调整大小(res,res,大小(圆形(宽度输入),圆形(高度输入)));}imwrite(输出,res * 255);返回0;}

解决方案

您的detect_text 代码与我在

代码:

void detect_text(字符串输入){垫大 = imread(输入);垫 RGB;//下采样并使用它进行处理pyrDown(大,RGB);pyrDown(rgb, rgb);垫子小;cvtColor(rgb,小,CV_BGR2GRAY);//形态梯度垫毕业;Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));形态Ex(小,毕业,MORPH_GRADIENT,morphKernel);//二值化垫体重;阈值(毕业,体重,0.0,255.0,THRESH_BINARY | THRESH_OTSU);//连接水平方向的区域垫子连接;morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));形态Ex(bw,连接,MORPH_CLOSE,morphKernel);//找到轮廓Mat mask = Mat::zeros(bw.size(), CV_8UC1);矢量<矢量<点>>轮廓;向量等级制度;findContours(连接,轮廓,层次结构,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE,点(0,0));//过滤轮廓for(int idx = 0; idx >= 0; idx = 层级[idx][0]){矩形矩形 = boundingRect(contours[idx]);Mat maskROI(mask, rect);maskROI = 标量(0, 0, 0);//填充轮廓drawContours(掩码、轮廓、idx、标量(255、255、255)、CV_FILLED);RotatedRect rrect = minAreaRect(contours[idx]);double r = (double)countNonZero(maskROI)/(rrect.size.width * rrect.size.height);标量颜色;整数厚度 = 1;//如果包含文本,则假设至少填充了该区域的 25%如果 (r > 0.25 &&(rrect.size.height > 8 && rrect.size.width > 8)//限制区域大小//这两个条件本身并不是很健壮.最好使用一些东西//像水平投影中的重要峰值的数量作为第三个条件){厚度 = 2;颜色 = 标量 (0, 255, 0);}别的{厚度 = 1;颜色 = 标量 (0, 0, 255);}Point2f pts[4];rrect.points(pts);for (int i = 0; i <4; i++){line(rgb, Point((int)pts[i].x, (int)pts[i].y), Point((int)pts[(i+1)%4].x,(int)pts[(i+1)%4].y),颜色,厚度);}}imwrite("cont.jpg", rgb);}

I need to detect text in images..

Have some code here which works in most cases.. But not in all.. See attached input/output image

code

#include "string"
#include "fstream"
#include "/var/bin/opencv/include/opencv2/opencv.hpp"

using namespace std;
using namespace cv;

void detect_text(string input){
    Mat large = imread(input);
    
    Mat rgb;
    // downsample and use it for processing
    pyrDown(large, rgb);
    Mat small;
    cvtColor(rgb, small, CV_BGR2GRAY);
    // morphological gradient
    Mat grad;
    Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    morphologyEx(small, grad, MORPH_GRADIENT, morphKernel);
    // binarize
    Mat bw;
    threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);
    // connect horizontally oriented regions
    Mat connected;
    morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));
    morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
    // find contours
    Mat mask = Mat::zeros(bw.size(), CV_8UC1);
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
    // filter contours
    for(int idx = 0; idx >= 0; idx = hierarchy[idx][0]){
        Rect rect = boundingRect(contours[idx]);
        Mat maskROI(mask, rect);
        maskROI = Scalar(0, 0, 0);
        // fill the contour
        drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);
        // ratio of non-zero pixels in the filled region
        double r = (double)countNonZero(maskROI) / (rect.width * rect.height);
        
        // assume at least 45% of the area is filled if it contains text
        if (r > 0.45 && 
        (rect.height > 8 && rect.width > 8) // constraints on region size
        // these two conditions alone are not very robust. better to use something 
        //like the number of significant peaks in a horizontal projection as a third condition
        ){
            rectangle(rgb, rect, Scalar(0, 255, 0), 2);
        }
    }
    
    imwrite(string("test_text_contours.jpg"), rgb);
}

int main(int argc, char* argv[]){
    detect_text(string("input.jpg"));
}

input

output

update

/*
 *  Compile
 *  # g++ txtbin.cpp -o txtbin `pkg-config opencv --cflags --libs`
 *
 *  Get opencv version
 *  # pkg-config --modversion opencv
 *
 *  Run
 *  # ./txtbin input.jpg output.png
 */

#include "string"
#include "fstream"
#include "/var/bin/opencv/include/opencv2/opencv.hpp"
//#include "/usr/include/opencv2/opencv.hpp"
#include "/usr/include/boost/tuple/tuple.hpp"

using namespace std;
using namespace cv;
using namespace boost;

void CalcBlockMeanVariance(Mat& Img, Mat& Res, float blockSide=21, float contrast=0.01){
    /*
     *  blockSide: set greater for larger fonts in image and vice versa
     *  contrast: set smaller for lower contrast image
     */
    
    Mat I;
    Img.convertTo(I, CV_32FC1);
    Res = Mat::zeros(Img.rows / blockSide, Img.cols / blockSide, CV_32FC1);
    Mat inpaintmask;
    Mat patch;
    Mat smallImg;
    Scalar m, s;
    
    for(int i = 0; i < Img.rows - blockSide; i += blockSide){
        for(int j = 0; j < Img.cols - blockSide; j += blockSide){
            patch = I(Range(i, i + blockSide + 1), Range(j, j + blockSide + 1));
            meanStdDev(patch, m, s);
            
            if(s[0] > contrast){
                Res.at<float>(i / blockSide, j / blockSide) = m[0];
            }
            else{
                Res.at<float>(i / blockSide, j / blockSide) = 0;
            }
        }
    }
    
    resize(I, smallImg, Res.size());
    
    threshold(Res, inpaintmask, 0.02, 1.0, THRESH_BINARY);
    
    Mat inpainted;
    smallImg.convertTo(smallImg, CV_8UC1, 255);
    
    inpaintmask.convertTo(inpaintmask, CV_8UC1);
    inpaint(smallImg, inpaintmask, inpainted, 5, INPAINT_TELEA);
    
    resize(inpainted, Res, Img.size());
    Res.convertTo(Res, CV_32FC1, 1.0 / 255.0);
}

tuple<int, int, int, int> detect_text_box(string input, Mat& res, bool draw_contours=false){
    Mat large = imread(input);
    
    bool test_output = false;
    
    int
        top = large.rows,
        bottom = 0,
        left = large.cols,
        right = 0;
    
    int
        rect_bottom,
        rect_right;
    
    Mat rgb;
    // downsample and use it for processing
    pyrDown(large, rgb);
    pyrDown(rgb, rgb);
    Mat small;
    cvtColor(rgb, small, CV_BGR2GRAY);
    // morphological gradient
    Mat grad;
    Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    morphologyEx(small, grad, MORPH_GRADIENT, morphKernel);
    // binarize
    Mat bw;
    threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);
    // connect horizontally oriented regions
    Mat connected;
    morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));
    morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
    // find contours
    Mat mask = Mat::zeros(bw.size(), CV_8UC1);
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
    
    Scalar color = Scalar(0, 255, 0);
    Scalar color2 = Scalar(0, 0, 255);
    int thickness = 2;
    
    // filter contours
    for(int idx = 0; idx >= 0; idx = hierarchy[idx][0]){
        Rect rect = boundingRect(contours[idx]);
        Mat maskROI(mask, rect);
        maskROI = Scalar(0, 0, 0);
        // fill the contour
        drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);
        // ratio of non-zero pixels in the filled region
        double r = (double)countNonZero(maskROI) / (rect.width * rect.height);
        
        // assume at least 25% of the area is filled if it contains text
        if (r > 0.25 && 
        (rect.height > 8 && rect.width > 8) // constraints on region size
        // these two conditions alone are not very robust. better to use something 
        //like the number of significant peaks in a horizontal projection as a third condition
        ){
            if(draw_contours){
                rectangle(res, Rect(rect.x * 4, rect.y * 4, rect.width * 4, rect.height * 4), color, thickness);
            }
            
            if(test_output){
                rectangle(rgb, rect, color, thickness);
            }
            
            if(rect.y < top){
                top = rect.y;
            }
            rect_bottom = rect.y + rect.height;
            if(rect_bottom > bottom){
                bottom = rect_bottom;
            }
            if(rect.x < left){
                left = rect.x;
            }
            rect_right = rect.x + rect.width;
            if(rect_right > right){
                right = rect_right;
            }
        }
    }
    
    if(draw_contours){
        rectangle(res, Point(left * 4, top * 4), Point(right * 4, bottom * 4), color2, thickness);
    }
    
    if(test_output){
        rectangle(rgb, Point(left, top), Point(right, bottom), color2, thickness);
        imwrite(string("test_text_contours.jpg"), rgb);
    }
    
    return make_tuple(left * 4, top * 4, (right - left) * 4, (bottom - top) * 4);
}

int main(int argc, char* argv[]){
    string input;
    string output = "output.png";
    
    int
        width = 0,
        height = 0,
        blockside = 9;
    
    bool
        crop = false,
        draw = false;
    
    float margin = 0;
    
    cout << "OpenCV version: " << CV_VERSION << endl;
    
    //  Return error if arguments are missing
    if(argc < 3){
        cerr << "\nUsage: txtbin input [options] output\n\n"
            "Options:\n"
            "\t-w <number>          -- set max width (keeps aspect ratio)\n"
            "\t-h <number>          -- set max height (keeps aspect ratio)\n"
            "\t-c                   -- crop text content contour\n"
            "\t-m <number>          -- add margins (number in %)\n"
            "\t-b <number>          -- set blockside\n"
            "\t-d                   -- draw text content contours (debugging)\n" << endl;
        return 1;
    }
    
    //  Parse arguments
    for(int i = 1; i < argc; i++){
        if(i == 1){
            input = string(argv[i]);
            
            //  Return error if input file is invalid
            ifstream stream(input.c_str());
            if(!stream.good()){
                cerr << "Error: Input file is invalid!" << endl;
                return 1;
            }
        }
        else if(string(argv[i]) == "-w"){
            width = atoi(argv[++i]);
        }
        else if(string(argv[i]) == "-h"){
            height = atoi(argv[++i]);
        }
        else if(string(argv[i]) == "-c"){
            crop = true;
        }
        else if(string(argv[i]) == "-m"){
            margin = atoi(argv[++i]);
        }
        else if(string(argv[i]) == "-b"){
            blockside = atoi(argv[++i]);
        }
        else if(string(argv[i]) == "-d"){
            draw = true;
        }
        else if(i == argc - 1){
            output = string(argv[i]);
        }
    }
    
    Mat Img = imread(input, CV_LOAD_IMAGE_GRAYSCALE);
    Mat res;
    Img.convertTo(Img, CV_32FC1, 1.0 / 255.0);
    CalcBlockMeanVariance(Img, res, blockside);
    res = 1.0 - res;
    res = Img + res;
    threshold(res, res, 0.85, 1, THRESH_BINARY);
    
    int
        txt_x,
        txt_y,
        txt_width,
        txt_height;
    
    if(crop || draw){
        tie(txt_x, txt_y, txt_width, txt_height) = detect_text_box(input, res, draw);
    }
    
    if(crop){
        //res = res(Rect(txt_x, txt_y, txt_width, txt_height)).clone();
        res = res(Rect(txt_x, txt_y, txt_width, txt_height));
    }
    
    if(margin){
        int border = res.cols * margin / 100;
        copyMakeBorder(res, res, border, border, border, border, BORDER_CONSTANT, Scalar(255, 255, 255));
    }
    
    float
        width_input = res.cols,
        height_input = res.rows;
    
    bool resized = false;
    
    //  Downscale image
    if(width > 0 && width_input > width){
        float scale = width_input / width;
        width_input /= scale;
        height_input /= scale;
        resized = true;
    }
    if(height > 0 && height_input > height){
        float scale = height_input / height;
        width_input /= scale;
        height_input /= scale;
        resized = true;
    }
    if(resized){
        resize(res, res, Size(round(width_input), round(height_input)));
    }
    
    imwrite(output, res * 255);
    
    return 0;
}

解决方案

Your detect_text code is very much similar to my text detection post here. If you have used that code, you will see that the input images in the original post are 1400 x 800. But your input images in this post and your previous post are usually four times as large. So, first you can try downsampling the input images twice. Also your text looks bit tilted, so you can try rotated rectangle instead of the upright rectangle. Then you can tune the parameters for your case. As I have mentioned in the code, the contour filtering criteria isn't very robust. After doing these changes to the code, I get a reasonable output as shown below. Note that I've highlighted the rotated rectangle of the detected text region in green.

Code:

void detect_text(string input){
    Mat large = imread(input);

    Mat rgb;
    // downsample and use it for processing
    pyrDown(large, rgb);
    pyrDown(rgb, rgb);
    Mat small;
    cvtColor(rgb, small, CV_BGR2GRAY);
    // morphological gradient
    Mat grad;
    Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    morphologyEx(small, grad, MORPH_GRADIENT, morphKernel);
    // binarize
    Mat bw;
    threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);
    // connect horizontally oriented regions
    Mat connected;
    morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));
    morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
    // find contours
    Mat mask = Mat::zeros(bw.size(), CV_8UC1);
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
    // filter contours
    for(int idx = 0; idx >= 0; idx = hierarchy[idx][0]){
        Rect rect = boundingRect(contours[idx]);
        Mat maskROI(mask, rect);
        maskROI = Scalar(0, 0, 0);
        // fill the contour
        drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);

        RotatedRect rrect = minAreaRect(contours[idx]);
        double r = (double)countNonZero(maskROI) / (rrect.size.width * rrect.size.height);

        Scalar color;
        int thickness = 1;
        // assume at least 25% of the area is filled if it contains text
        if (r > 0.25 && 
        (rrect.size.height > 8 && rrect.size.width > 8) // constraints on region size
        // these two conditions alone are not very robust. better to use something 
        //like the number of significant peaks in a horizontal projection as a third condition
        ){
            thickness = 2;
            color = Scalar(0, 255, 0);
        }
        else
        {
            thickness = 1;
            color = Scalar(0, 0, 255);
        }

        Point2f pts[4];
        rrect.points(pts);
        for (int i = 0; i < 4; i++)
        {
            line(rgb, Point((int)pts[i].x, (int)pts[i].y), Point((int)pts[(i+1)%4].x, (int)pts[(i+1)%4].y), color, thickness);
        }
    }

    imwrite("cont.jpg", rgb);
}

这篇关于使用 opencv 检测图像中的文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆