当前位置: 首页 > 编程日记 > 正文

基于开源TiRG的文本检测与提取实现

在 http://funkybee.narod.ru/  中作者给出了文本检测和提取的实现,仅有一个.hpp文件,为了在windows上编译通过,这里简单进行了改动,改动后的code如下:

#include <math.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <set>namespace trg {
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
typedef unsigned char UC;
//---------------------------------------------------------------------------------------------
const char d8[8][2] = {{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1}};
//---------------------------------------------------------------------------------------------
struct Rgb {UC r, g, b;};
struct Rect {int x1, y1, x2, y2;};
struct Dot {int x, y;};
int w;
int h;
//---------------------------------------------------------------------------------------------
std::vector<std::vector<UC> > lum;
std::vector<std::vector<UC> > cyx;
std::vector<std::vector<char> > nei;
std::vector<std::vector<short> > b;
std::vector<Rect> res;
//---------------------------------------------------------------------------------------------
const int dw = 24;
const int dh = 24;
const int h_min = 6;
const int h_max = 66;
const int ns_min = 2;
const double pl_min = 0.5;
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------void print_b(const char* path) {freopen(path, "wt", stdout);for (int y = 0; y < h; ++y) {for (int x = 0; x < w; ++x)printf("%c", (b[y][x] ? (char)(b[y][x] + 48) : ' '));putchar('\n');}
}//---------------------------------------------------------------------------------------------void calc_lums(const std::vector<std::vector<Rgb> > &raw) {lum.assign(h, std::vector<UC>(w));cyx.assign(h, std::vector<UC>(w));int x, y;int zh = h / 1;int zw = w / 3;int y1 = 0;int y2 = y1 + zh;while (y1 < h) {int x1 = 0;int x2 = x1 + zw;while (x1 < w) {int sm = 0;for (y = y1; y < std::min(y2, h); ++y) {for (x = x1; x < std::min(x2, w); ++x) {Rgb px = raw[y][x];// ITU-R 601-2 luma transform:lum[y][x] = (UC)(px.r * 0.299 + px.g * 0.587 + px.b * 0.114);sm += lum[y][x];}}double sr = sm * 1.0 / (std::min(y2, h) - y1) / (std::min(x2, w) - x1);double cc = 0;for (y = y1; y < std::min(y2, h); ++y)for (x = x1; x < std::min(x2, w); ++x)cc += fabs(sr - lum[y][x]);cc = cc / (std::min(y2, h) - y1) / (std::min(x2, w) - x1);for (y = y1; y < std::min(y2, h); ++y)for (x = x1; x < std::min(x2, w); ++x)cyx[y][x] = (UC)std::max(35.0, cc);x1 = x2;x2 = x1 + zw;}y1 = y2;y2 = y1 + zh;}
}//---------------------------------------------------------------------------------------------void count_neis() {nei.clear();nei.resize(h);for (int i = 0; i < h; ++i) nei[i].resize(w, 0);std::set<char> t, t1, t2;t1.insert(6); t1.insert(7); t1.insert(0);t2.insert(7); t2.insert(0); t2.insert(1);for (int i = 1; i < h - 1; ++i) {for (int j = 1; j < w - 1; ++j) {char y = 0;t.clear();for (size_t k = 0; k < 8; ++k) {if (abs((int)lum[i][j] - lum[i + d8[k][0]][j + d8[k][1]]) > cyx[i][j]) {++y;t.insert(k);}}if (y == 3) {if (*(t.begin()) + (y - 1) == *(--t.end()) || t == t1 || t == t2)nei[i][j] = y;elsenei[i][j] = -y;}elsenei[i][j] = y;}}
}//---------------------------------------------------------------------------------------------int stroke_calc(int p1, int q1) {int p2 = std::min(h - 1, p1 + dh);int q2 = std::min(w - 1, q1 + dw);int nm = (p2 - p1) * (q2 - q1);double u = 0.0;std::vector<int> x(10);for (int i = p1; i < p2; ++i) {int fl = 0;for (int j = q1; j < q2; ++j) {if (nei[i][j] >= 0) ++x[nei[i][j]];if (nei[i][j] == 0) ++fl;}if (fl == q2 - q1) u += 1.0;}for (int k = 0; k < 7; ++k)if (x[k] == 0) return 0;if (nm > (x[3] + x[6]) * 20)return 0;int cnt1 = x[3] * 16 + x[6] * 16;int cnt2 = x[0];x[9] = int(cnt1 * cnt2 * 1.0 / nm);x[9] = int(x[9] * (1 + u / (p2 - p1)) * (1 + u / (p2 - p1)));if (x[9] < 600 || x[9] > 3000) x[9] = 0;return x[9];
}//---------------------------------------------------------------------------------------------void build_b() {int ww = w / dw;int hh = h / dh;b.assign(h + 1, std::vector<short>(w + 3));for (int dy = 0; dy <= dh / 2; dy += dh / 2) {std::vector<std::vector<int> > m(hh + 1, std::vector<int>(ww + 3));for (int i = 1 + dy; i < h; i += dh)for (int j = 1; j < w; j += dw)m[(i - 1 - dy) / dh][(j - 1) / dw] = stroke_calc(i, j);for (int i = 0; i < hh + 1; ++i) {for (int j = 0; j < ww; ++j) {if (m[i][j] != 0 && m[i][j + 1] != 0 && m[i][j + 2] != 0 &&m[i][j] + m[i][j + 1] + m[i][j + 2] > 3 * 800) {m[i][ww + 2] = 1;break;}}}for (int i = 0; i < hh + 1; ++i) {if (m[i][ww + 2] == 0)continue;for (int j = 0; j < ww + 1; ++j) {if (m[i][j] != 0) {int h1 = i * dh + 1 + dy;int h2 = h1 + dh;h2 = std::min(h - 1, h2);int w1 = j * dw + 1;int w2 = w1 + dw;w2 = std::min(w - 1, w2);for (int p = h1; p < h2; ++p) {b[p][w + 2] = 1;for (int q = w1; q < w2; ++q)if (nei[p][q] != 0) b[p][q] = 1;}}}}}//print_b("C:/b1.txt");//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@for (int i = 0; i < h; ++i) {if (b[i][w + 2] == 0) continue;int j = 0;int ss = 0;while (j < w) {if (b[i][j] && b[i][j + 1] && b[i][j + 2]) {int js = j;int sm = 0;int gap = 0;while (j < w && gap < 30) {if (b[i][j]) {gap = 0;++sm;}else++gap;++j;}if (sm > 20 && sm > (j - js - gap) * 0.4) {ss += j - js - gap;for (int k = js; k < j - gap; ++k)b[i][k] += 2;}++j;}else ++j;}if (ss < 40) b[i].assign(w + 3, 0);else b[i][w + 2] = 1;}//print_b("C:/b2.txt");//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@int cnt = 0;for (int i = 0; i < h + 1; ++i) {if (b[i][w + 2] == 0) {if (cnt > 0 && cnt < 8) {for (int ii = i - cnt; ii < i; ++ii) {b[ii].assign(w + 3, 0);}}cnt = 0;}else ++cnt;}//print_b("C:/b3.txt");//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
}//---------------------------------------------------------------------------------------------void get_res() {res.clear();for (int i = 0; i < h; ++i) {for (int j = 0; j < w; ++j) {if (b[i][j] > 1) {int cnt = 1;int x1 = w;int x2 = 0;int y1 = h;int y2 = 0;b[i][j] *= -1;Dot dt;std::vector<Dot> v, ww;dt.x = j;dt.y = i;v.push_back(dt);while (!v.empty()) {ww.clear();for (size_t z = 0; z < v.size(); ++z) {Dot vv = v[z];for (size_t k = 0; k < 8; ++k) {int yy = vv.y + d8[k][0];int xx = vv.x + d8[k][1];if (xx < 0 || xx >= w || yy < 0 || yy >= h)continue;if (b[yy][xx] > 1) {b[yy][xx] *= -1;dt.x = xx;dt.y = yy;ww.push_back(dt);x1 = std::min(x1, xx);x2 = std::max(x2, xx);y1 = std::min(y1, yy);y2 = std::max(y2, yy);}}}v.swap(ww);cnt += (int)v.size();}int dx = x2 - x1 + 1;int dy = y2 - y1 + 1;double pl = cnt * 1.0 / dx / dy;if (pl > pl_min && dy > h_min && dy < h_max && dx > dy * ns_min) {Rect r = {x1, y1, x2, y2};res.push_back(r);}}}}
}//---------------------------------------------------------------------------------------------std::vector<Rect> get_textlike_regions(const std::vector<std::vector<Rgb> > &raw) {res.clear();if (raw.empty()) return res;w = raw[0].size();h = raw.size();calc_lums(raw);count_neis();build_b();get_res();return res;
}//---------------------------------------------------------------------------------------------} // End of namespace trg; 

测试代码如下:

#include "funset.hpp"
#include <string>
#include <opencv2/opencv.hpp>
#include "trg.hpp"int test_TiRG()
{const std::string name{ "E:/GitCode/OCR_Test/test_data/tirg.jpg" };cv::Mat mat = cv::imread(name, 1);if (!mat.data || mat.channels() != 3) {fprintf(stderr, "read image fail: %s\n", name.c_str());return -1;}const int width{ mat.cols }, height{ mat.rows };std::vector<std::vector<trg::Rgb>> data(height, std::vector<trg::Rgb>(width));for (int y = 0; y < height; ++y) {for (int x = 0; x < width; ++x) {cv::Vec3b pixel = mat.at<cv::Vec3b>(cv::Point(x, y));trg::Rgb rgb = { pixel.val[2], pixel.val[1], pixel.val[0] };data[y][x] = rgb;}}std::vector<trg::Rect> rect = trg::get_textlike_regions(data);for (int i = 0; i < rect.size(); ++i) {cv::rectangle(mat, cv::Point(rect[i].x1, rect[i].y1), cv::Point(rect[i].x2, rect[i].y2), cv::Scalar(0, 255, 0));}cv::imwrite("E:/GitCode/OCR_Test/test_data/result_tirg.jpg", mat);return 0;
}

原图及执行结果如下:


GitHub: https://github.com/fengbingchun/OCR_Test 

相关文章:

Kaggle Days首次落地中国,日本团队拿下冠军

2019 年 10 月 20 日&#xff0c; 为期两天的 Kaggle Days 中国活动在北京圆满结束。作为全球最知名的线下数据科学活动在中国的首次落地&#xff0c;Kaggle Days 获得了谷歌、Kaggle 以及 16 位来自美国、俄罗斯、捷克、日本以及中国的 Kaggle Grandmaster 以及 Master 的大力…

《WF编程》笔记目录

《WF编程》笔记目录

activity的四种加载模式

在android里&#xff0c;有4种activity的启动模式&#xff0c;分别为&#xff1a; standard, singleTop, singleTask和singleInstance, 其中standard和singleTop类似&#xff0c; singleTask和singleInstance类似&#xff0c; 用法如下&#xff1a; (1).standard和singleTop 这…

吴恩达老师深度学习视频课笔记:优化算法

优化算法能够帮助你快速训练模型。mini-batch梯度下降法&#xff1a;把训练集分割(split)为小一点的子训练集&#xff0c;这些子集被叫做mini-batch。batch梯度下降法指的是&#xff1a;同时处理整个训练集&#xff0c;只有处理完整个训练集才更新一次权值和偏置。并且预期每次…

程序员编程时戴耳机是在听什么?

1024程序员节&#xff0c;CSDN旗下的码书商店为程序员放个“价”&#xff0c;全场所有书籍8折&#xff0c;电子产品可以拥有大额优惠券&#xff0c;购买前可加文末客服微信领取优惠券哦。兰士顿耳机&#xff0c;原价199元&#xff0c;1024专属价159元&#xff0c;购买时候请输入…

Mac中MacPorts安装和使用

文章转载至http://www.zikercn.com/node/8 星期四, 06/07/2012 - 19:02 — 张慧敏 MacPorts简单介绍 MacPorts&#xff0c;以前叫做DarwinPorts&#xff0c;是一个软件包管理系统&#xff0c;用来简化Mac OS X和Darwin操作系统上软件的安装。它是一个用来简化自由软件/开放源码…

小白入门:我是如何学好机器学习的?

作者 | Jae Duk Seo译者 | Tianyu编辑 | 夕颜出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;在我看来&#xff0c;机器学习是一个计算机科学和数学知识相融合的研究领域。虽然这是个很有趣的领域&#xff0c;但它其实没有想象中那么难。我相信只要你有足够的动力、…

数据库服务器 之 PostgreSQL数据库的日常维护工作

来自&#xff1a;LinuxSir.Org摘要&#xff1a;为了保持所安装的 PostgreSQL 服务器平稳运行, 我们必须做一些日常性的维护工作。我们在这里讨论的这些工作都是经常重复的事情&#xff0c; 可以很容易地使用标准的 Unix 工具&#xff0c;比如cron 脚本来实现; 目录1. 综述&…

吴恩达老师深度学习视频课笔记:超参数调试、Batch正则化和程序框架

Tuning process(调试处理)&#xff1a;神经网络的调整会涉及到许多不同超参数的设置。需要调试的重要超参数一般包括&#xff1a;学习率、momentum、mini-batch size、隐藏单元(hidden units)、层数、学习率衰减。一般对于你要解决的问题而言&#xff0c;你很难提前知道哪个参数…

AD上删除了Exchange容器,再重装时报'找不到企业组织容器

AD上删除了Exchange容器,再重装时报找不到企业组织容器。安装日志如下:[06/16/2014 04:58:15.0054] [0] **********************************************[06/16/2014 04:58:15.0054] [0] Starting Microsoft Exchange Server 2013 Service Pack 1 Setup[06/16/2014 04:58:15.0…

实战:基于OpenPose的卡通人物可视化 | CSDN博文精选

作者 | Wuzebiao2016来源 | CSDN博客前言去年打算用些现成的Pose做些展示&#xff0c;因为以前有在OpenPose做些识别等开发工作&#xff0c;所以这次我就简单在OpenPose上把骨架用动画填充上去&#xff0c;关于能够和人动作联系起来的动画&#xff0c;我找到了Unity提供的示例A…

基于Idea从零搭建一个最简单的vue项目

一、需要了解的基本知识 node.js Node.js是一个Javascript运行环境(runtime)&#xff0c;发布于2009年5月&#xff0c;由Ryan Dahl开发&#xff0c;实质是对Chrome V8引擎进行了封装。Node.js对一些特殊用例进行优化&#xff0c;提供替代的API&#xff0c;使得V8在非浏览器环境…

OpenCV中基于LBP算法的人脸检测测试代码

下面是OpenCV 3.3中基于CascadeClassifier类的LBP算法实现的人脸检测&#xff0c;从结果上看&#xff0c;不如其它开源库效果好&#xff0c;如libfacedetection&#xff0c;可参考 https://blog.csdn.net/fengbingchun/article/details/52964163 #include "funset.hpp&qu…

解决getOutputStream() has already been called for this response[java io流]

getOutputStream() has already been called for this response以上异常出现的原因和解决方法&#xff1a;jsp中出现此错误一般都是在jsp中使用了输出流&#xff08;如输出图片验证码&#xff0c;文件下载等&#xff09;&#xff0c;没有妥善处理好的原因。具体的原因&#xff…

吴恩达老师深度学习视频课笔记:构建机器学习项目(机器学习策略)(1)

机器学习策略(machine learning strategy)&#xff1a;分析机器学习问题的方法。正交化(orthogonalization)&#xff1a;要让一个监督机器学习系统很好的工作&#xff0c;一般要确保四件事情&#xff0c;如下图&#xff1a;(1)、首先&#xff0c;你通常必须确保至少系统在训练集…

内行的AI盛会——北京智源大会带你洞见未来!(含日程及限量优惠)

报名请点击「阅读原文」北京国家会议中心2019年10月31日-11月1日www.baai.ac.cn/2019使用优惠码「BAAICSDN」专享7折优惠学生票仅69元&#xff0c;数量有限&#xff0c;先到先得世界AI看中国&#xff0c;中国AI看北京&#xff08;长按上图或点击「阅读原文」注册参会&#xff0…

微软职位内部推荐-Sr. Dev Lead

微软近期Open的职位:JD如果你想试试这个职位&#xff0c;请跟我联系&#xff0c;我是微软的员工&#xff0c;可以做内部推荐。发你的中英文简历到我的邮箱&#xff1a;Nicholas.lu.mail(at)gmail.com转载于:https://www.cnblogs.com/DotNetNuke/p/3885283.html

吴恩达老师深度学习视频课笔记:构建机器学习项目(机器学习策略)(2)

进行误差分析&#xff1a;可进行人工统计或可同时并行评估几个想法。进行误差分析时&#xff0c;你应该找一组错误例子&#xff0c;可能在你的开发集里或者在你的测试集里&#xff0c;观察错误标记的例子&#xff0c;看看假阳性(false positives)和假阴性(false negatives)&…

3D机器人视觉在仓储物流和工业自动化领域的应用 | AI ProCon 2019

整理 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;随着深度学习和机器学习的发展&#xff0c;机器人已经走出实验室&#xff0c;越来越多地地应用于各行各业&#xff0c;其中&#xff0c;仓储物流和工业化领域就有许多适合机器人作业的场景环境。人眼的一大…

【转载】gdi+ 内存泄漏

【转载】http://issf.blog.163.com/blog/static/1941290822009111894413472/ 最近用GDI实现了几个自定义控件&#xff0c;但是发现存在内存泄露问题 BOOL CGdiplusBugDlg::OnEraseBkgnd(CDC* pDC) {Image* pImage Image::FromFile(L"E:\\bac.bmp");Graphics g(pDC-&…

ubuntu fctix

感觉ubuntu自在大ibus输入法用起来实在是灰常蛋痛啊&#xff0c;于是乎就换了fcitx输入法&#xff08;很多人推荐嘛&#xff09;在安装之前先说一下fcitx输入法吧。1.添加fcitx源(官方的源是旧版,不推荐使用)fcitx的ppa源&#xff0c;内含fcitx和fcitx-config,使用命令sudo ged…

深度学习中的优化简介

深度学习算法在许多情况下都涉及到优化。1. 学习和纯优化有什么不同在大多数机器学习问题中&#xff0c;我们关注某些性能度量P&#xff0c;其定义于测试集上并且可能是不可解的。因此&#xff0c;我们只是间接地优化P。我们系统通过降低代价函数J(θ)来提高P。这一点与纯优化不…

飞凌OK6410开发板移植u-boot官方最新版u-boot-2012.10.tar.bz2

Part0 准备知识 0.1 关键参数说明 0.1.1 开发板说明 OK6410是飞凌公司发布的一款开发板&#xff0c;当前有2个版本&#xff0c;OK6410-A和OK6410-B&#xff0c;我当前使用的是前者&#xff1b;前者也经历过升级&#xff0c;所以有128M ram的和较新的256内存的版本&#xff0c;n…

参数量110亿,附赠750GB数据集,Google提NLP预训练模型T5

整理 | Just&#xff0c;夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;近日&#xff0c;Google 在最新一篇共有 53 页的论文《Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer》中&#xff0c;提出了一个最新的预训练模型…

Linux之bash编程基本语法

在Linux运维工作中&#xff0c;我们为了提高工作效率通常会用bash编写脚本来完成某工作。今天就来为大家介绍bash的一些常见的基本语法。在讲解bash语法之前首先介绍一下bash。bash环境主要是由解释器来完成的。【解释器】&#xff1a;解释命令&#xff1a;词法分析、语法分析、…

深度学习中的卷积网络简介

卷积网络(convolutional network)也叫做卷积神经网络(convolutional neural network, CNN)&#xff0c;是一种专门用来处理具有类似网格结构的数据的神经网络。例如时间序列数据(可以认为是在时间轴上有规律地采样形成的一维网格)和图像数据(可以看作是二维的像素网格)。卷积网…

Windows下搭建PHP开发环境

PHP集成开发环境有很多&#xff0c;如XAMPP、AppServ......只要一键安装就把PHP环境给搭建好了。但这种安装方式不够灵活&#xff0c;软件的自由组合不方便&#xff0c;同时也不利于学习。所以我还是喜欢手工搭建PHP开发环境&#xff0c;需要哪个模块自己安装就行了&#xff0c…

大数据时代下的新生态、新洞察、新趋势 | 神策 2019 数据驱动大会

10 月 22 日&#xff0c;以“矩•变”为主题的神策 2019 数据驱动大会在北京维景国际大酒店顺利举行&#xff0c;来自全球大数据各大行业的领袖人物聚首北京&#xff0c;融合国际前沿技术与行业实践&#xff0c;深入探讨大数据时代下的新生态、新洞察、新趋势。 大会主题“矩•…

ckedit 文本编辑器

Ckeditor是一个功能非常强大的富文本编辑器&#xff0c;博客园有使用此编辑器&#xff0c;其功能完全可以与MS的Word媲美。 用起来也非常方便。下面是本人总结的安装步骤&#xff1a; 第一步&#xff0c;从http://ckeditor.com/download 下载ckeditor文件包 第二步&#xff0c;…

为什么我害怕数据结构学得好的程序员?

我害怕数据结构学得好的程序员&#xff0c;一跟他们讨论技术&#xff0c;我就感觉自己不是程序员&#xff0c;仅仅是在搬砖维持生活。我所拥有的编程技巧是什么&#xff1f;不就是每个程序员都会的&#xff0c;对数据库的增删改查吗&#xff1f;每一个初入职场的程序员都会。但…