opencv实践-OCR识别c++版
opencv
OpenCV: 开源计算机视觉库
项目地址:https://gitcode.com/gh_mirrors/opencv31/opencv
免费下载资源
·
1. OCR 简介
OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程;即,针对印刷体字符,采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,并通过识别软件将图像中的文字转换成文本格式,供文字处理软件进一步编辑加工的技术。如何除错或利用辅助信息提高识别正确率,是OCR最重要的课题,ICR(Intelligent Character Recognition)的名词也因此而产生。衡量一个OCR系统性能好坏的主要指标有:拒识率、误识率、识别速度、用户界面的友好性,产品的稳定性,易用性及可行性等。
2. 实现步骤
- 灰度化处理:
- 采用高斯滤波去噪
- 边缘检测
- 查找轮廓并排序:
- 绘制全部轮廓
- 多边形逼近
- 仿射变换
- 写入图片文件
- 扫描读取
- 写入本地
3. 代码实现
识别图片:
源码:
#include <opencv2/opencv.hpp>
#include <vector>
#include <map>
#include <string>
#include "tesseract/baseapi.h"
#include "leptonica\allheaders.h"
using namespace cv;
using namespace std;
void order_point(const std::vector<cv::Point>& inPots, std::vector<cv::Point>& outPots)
{
// 左上的坐标一定是x, y加起来最小的坐标.
// 右下的坐标一定是x, y加起来最大的坐标.
// 右上角的x, y相减的差值一定是最小的.
// 左下角的x, y相减的差值, 一定是最大.
// diff的作用是后一列减前一列得到的差值 y - x
int index = 0;
map<int, int> sum_dict;
map<int, int> diff_dict;
for (auto& p : inPots)
{
int sum = p.x + p.y;
int diff = p.y - p.x;
sum_dict.insert(std::make_pair(sum, index));
diff_dict.insert(std::make_pair(diff, index));
index++;
}
outPots[0] = inPots.at(sum_dict.begin()->second);
outPots[1] = inPots.at(diff_dict.begin()->second);
outPots[2] = inPots.at(sum_dict.rbegin()->second);
outPots[3] = inPots.at(diff_dict.rbegin()->second);
}
cv::Mat four_point_transform(const cv::Mat &image, const std::vector<cv::Point> &pts)
{
std::vector<cv::Point> rect(4);
order_point(pts, rect);
cv::Point lt, rt, rb, lb;
lt = rect.at(0);
rt = rect.at(1);
rb = rect.at(2);
lb = rect.at(3);
//空间中两点的距离,并且要取最大的距离确保全部文字都看得到
int widthA = sqrt(pow((rb.x - lb.x), 2) + pow((rb.y - lb.y), 2));
int widthB = sqrt(pow((rt.x - lt.x), 2) + pow((rt.y - lt.y), 2));
int max_width = max(widthA, widthB);
int heightA = sqrt(pow((rt.x - rb.x), 2) + pow((rt.y - rb.y), 2));
int heightB = sqrt(pow((lt.x - lb.x), 2) + pow((lt.y - lb.y), 2));
int max_height = max(heightA, heightB);
//计算变换矩阵
Point2f AffinePoints0[4] = { Point2f(lt.x, lt.y), Point2f(rt.x, rt.y), Point2f(rb.x, rb.y), Point2f(lb.x, lb.y) };
Point2f AffinePoints1[4] = { Point2f(0, 0), Point2f(max_width, 0), Point2f(max_width, max_height), Point2f(0, max_height) };
Mat Trans = cv::getPerspectiveTransform(AffinePoints0, AffinePoints1);
cv::Mat dst;
cv::warpPerspective(image, dst, Trans, Size(max_width, max_height), INTER_CUBIC);
return dst;
}
cv::Mat Image_Pretreatment(cv::Mat image)
{
// 计算比例.限定高度500
// 此时像素点都缩小了一定的比例,进行放射变换时要还原
float ratio = image.rows / 500.0;
// 拷贝一份
cv::Mat image_copy = image.clone();
// 修改尺寸
cv::resize(image_copy, image, cv::Size(image.cols / ratio, 500));
//cv::imshow("image", image);
// 图片预处理
// 灰度化处理
cv::Mat gray, Gaussian, edged;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
//cv::imshow("gray", gray);
// 高斯平滑
cv::GaussianBlur(gray, Gaussian, Size(5, 5), 0);
// cv_show('Gaussian', Gaussian)
// 边缘检测,寻找边界(为后续查找轮廓做准备)
cv::Canny(Gaussian, edged, 70, 200);
//cv::imshow("edged", edged);
// 查找轮廓
std::vector<std::vector<cv::Point>> cnts;
cv::findContours(edged, cnts, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
// 将轮廓按照面积降序排序
sort(cnts.begin(), cnts.end(), [&](std::vector<cv::Point> &v1, std::vector<cv::Point> &v2) {
return cv::contourArea(v1) > cv::contourArea(v2);
});
// 绘制所有轮廓
cv::Mat image_contours = image.clone();
cv::drawContours(image_contours, cnts, -1, (0, 0, 255), 1);
//cv::imshow("image_contours", image_contours);
image_contours.release();
vector<cv::Point> screen_cnt;
// 遍历轮廓找出最大的轮廓.
for (auto& c : cnts) {
// 计算轮廓周长
int perimeter = cv::arcLength(c, true);
// 多边形逼近,得到近似的轮廓
// 近似完后,只剩下四个顶点的角的坐标
vector<cv::Point> approx(c.size());
cv::approxPolyDP(c, approx, 0.02 * perimeter, true);
// 最大的轮廓
if (approx.size() == 4) {
// 接收approx
screen_cnt = approx;
break;
}
}
// 画出多边形逼近
cv::Mat image_screen_cnt = image.clone();
cv::drawContours(image_screen_cnt, std::vector< vector<cv::Point>>{screen_cnt}, -1, (0, 0, 255), 1);
//cv::imshow("image_screen_cnt", image_screen_cnt);
image_screen_cnt.release();
// 进行仿射变换,使图片变正
for (auto& scr_t : screen_cnt)
{
scr_t.x *= ratio;
scr_t.y *= ratio;
}
cv::Mat warped = four_point_transform(image_copy, screen_cnt);
//cv::imshow("warped", warped);
// 二值处理,先转成灰度图
cv::Mat warped_gray;
cv::cvtColor(warped, warped_gray, cv::COLOR_BGR2GRAY);
// 再二值化处理
cv::Mat ref;
cv::threshold(warped_gray, ref, 150, 255, cv::THRESH_BINARY);
//cv::namedWindow("ref", WINDOW_NORMAL);
//cv::imshow("ref", ref);
//cv::waitKey(0);
return ref;
}
int main()//ocr_demo()
{
// 读取图片
cv::Mat image = cv::imread("C:\\Users\\Administrator\\Desktop\\1.jpg");
// 返回透视变换的结果
cv::Mat ref = Image_Pretreatment(image);
// 把处理好的图片写入图片文件.
cv::imwrite("ref.jpg", ref);
char* outText;
// Open input image with leptonica library
Pix* img_pix = pixRead("ref.jpg");
api->SetImage(img_pix);
// Get OCR result
outText = api->GetUTF8Text();
printf("OCR output:\n%s", outText);
// Destroy used object and release memory
api->End();
delete api;
delete[] outText;
pixDestroy(&img_pix);
return 0;
}
4. 待完成
上述代码中的ocr识别部分,由于tesseract库一直没调通,因此没做验证,后期会补上。
本文参考:
https://blog.csdn.net/weixin_56197703/article/details/124309367
GitHub 加速计划 / opencv31 / opencv
77.34 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:28 天前 )
e1fec156
features2d: fixed out of bounds access in SIFT 6 天前
63087396 - 6 天前
更多推荐
已为社区贡献11条内容
所有评论(0)