问题:如果文字大小存在比较大的差异时,怎么办?
答:这里给出另外一种策略,不是使用投影直方图,而是使用膨胀以及寻找连通区域。进行分割。
1)对图像二值化
2)对二值化之后的图像进行膨胀操作(dilate)
3)在2)得到的结果上寻找联通区域的边界(findContours)。
4)利用3)得到的结果画出方框。
本文是对这里的文章的另一种实现。使用C++。
- 首先,读取图片
Mat img = imread(IMG_PATH);
if (img.empty())
{
cerr<<"can not read image"<<endl;
}
imshow("original image", img);
Mat img_erode = img.clone();
- 第一步:1)对图像二值化
- 第二步:2)对二值化之后的图像进行膨胀操作(dilate)
void step_1_erode(Mat& img){
cvtColor(img,img,CV_BGR2GRAY,1);
threshold(img,img,90,255,THRESH_OTSU);
img = 255 - img;
imshow("after otsu",img);
Mat ker = Mat::ones(3,7,CV_8U);
//Mat ker = getStructuringElement(MORPH_ELLIPSE,Size(3,3));
dilate(img,img,ker,Point(0,1));
imshow("after dilate",img);
}
腐蚀之后的结果:
问题:getStructuringElement是一个什么样的存在?
答:获取形态学滤波中使用的“结构元”
问题:dilate表示什么意思?
答:对图像进行“膨胀”操作
问题:是否有其他形态学算法?
答:有,比如腐蚀(erode),开(open),。。。
还有一个高大上的函数“morphologyEx”,只需要在其中选择参数就可以实现各种形态学操作。
- 第三步:3)在2)得到的结果上寻找联通区域的边界(findContours)。
- 第四步:4)利用3)得到的结果画出方框。
void step_2_find_conection(const Mat& original_img, Mat& img_erode){
// find contours of img
vector<vector<Point>> contours;
findContours(img_erode,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
Scalar color = Scalar(0,0,255);
// 在原图上画出边界
Mat img1 = original_img.clone();
drawContours(img1,contours,-1,color);
imshow("img with contours",img1);
// 在原图上画出,包括边界的最大矩形
Mat img2 = original_img.clone();
Rect ri;
vector<vector<Point>>::iterator itcon;
for (itcon = contours.begin(); itcon != contours.end(); itcon++)
{
ri = boundingRect(*itcon);
if (ri.height >10 && (ri.width * 1.0 / ri.height) > 0.2)
rectangle(img2,ri,color);
}
imshow("img with rectangle",img2);
// 如果有旋转的话,需要使用下面的方法画出旋转的方框
Mat img3 = original_img.clone();
vector<RotatedRect> minRect(contours.size());
for (int i = 0; i < contours.size(); i++){
minRect[i] = minAreaRect(Mat(contours[i]));
Point2f rect_points[4];
minRect[i].points(rect_points);
for (int j = 0; j < 4; j++)
line(img3,rect_points[j],rect_points[(j+1)%4],color,1,8);
}
imshow("img with rotated rectangle",img3);
}
找出的边界结果:
最后的方框结果:
问题:vector< vector> contours; 是什么鬼?好可怕
答:见这里。
问题:如果文字存在旋转,怎么办?比如下面这张图
答:在代码中有一段“// 如果有旋转的话,需要使用下面的方法画出旋转的方框”,这一段就是处理旋转的情况的。
对上图的处理结果如下:
放大招,整体代码如下:
// csdn_code.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#define IMG_PATH "..//figures//222_angle.jpg"
void step_1_erode(Mat& img){
cvtColor(img,img,CV_BGR2GRAY,1);
threshold(img,img,90,255,THRESH_OTSU);
img = 255 - img;
imshow("after otsu",img);
Mat ker = Mat::ones(3,7,CV_8U);
//Mat ker = getStructuringElement(MORPH_ELLIPSE,Size(3,3));
dilate(img,img,ker,Point(0,1));
imshow("after dilate",img);
}
void step_2_find_conection(const Mat& original_img, Mat& img_erode){
// find contours of img
vector<vector<Point>> contours;
findContours(img_erode,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
Scalar color = Scalar(0,0,255);
// 在原图上画出边界
Mat img1 = original_img.clone();
drawContours(img1,contours,-1,color);
imshow("img with contours",img1);
// 在原图上画出,包括边界的最大矩形
Mat img2 = original_img.clone();
Rect ri;
vector<vector<Point>>::iterator itcon;
for (itcon = contours.begin(); itcon != contours.end(); itcon++)
{
ri = boundingRect(*itcon);
if (ri.height >10 && (ri.width * 1.0 / ri.height) > 0.2)
rectangle(img2,ri,color);
}
imshow("img with rectangle",img2);
// 如果有旋转的话,需要使用下面的方法画出旋转的方框
Mat img3 = original_img.clone();
vector<RotatedRect> minRect(contours.size());
for (int i = 0; i < contours.size(); i++){
minRect[i] = minAreaRect(Mat(contours[i]));
Point2f rect_points[4];
minRect[i].points(rect_points);
for (int j = 0; j < 4; j++)
line(img3,rect_points[j],rect_points[(j+1)%4],color,1,8);
}
imshow("img with rotated rectangle",img3);
}
int main()
{
Mat img = imread(IMG_PATH);
if (img.empty())
{
cerr<<"can not read image"<<endl;
}
imshow("original image", img);
Mat img_erode = img.clone();
step_1_erode(img_erode);
step_2_find_conection(img,img_erode);
waitKey();
system("pause");
return 0;
}