这是我的第一个openCV程序,如果我对某些基本的计算机视觉概念一无所知,请原谅。
更新:由于sturkmen
的回答,请查看底部的新代码/新问题我正在研究"数字化"一大堆图像,如附加的图像,作为一个项目。所有图像都来自同一来源。最终目标是将提取的文本块传递给tesseract,即OCR库。
(源代码在底部) 我将解释我目前的方法,然后陈述我的问题。
我目前的做法如下:
应用反向二进制阈值
扩张图像并找到轮廓
从每个轮廓创建boundingRect
,然后过滤最小和最大尺寸
这已经确定
我希望的最终结果是每列有一个boundingRect
。因此,对于提供的图片,其中有七个。
所以,问题在于列表的“迷你”部分"在图像中没有被可靠地拾取(最好的例子是最右边一列中没有boundingRect
的那个)。
我可以想到两种可能的解决方案(以便不是开放式/意见型问题),但如果你知道更好的解决方案,请分享它!
1)组合作为垂直邻居的boundingRect
来捕获列。包含可能的边缘情况。
2)在找到轮廓之前,找到另一种操作图像的方法。从我的研究来看,游程长度平滑算法看起来很有希望吗?
所以我的问题是,哪种方法最好?我忽略了一个更好的解决方案吗?我在这个部门缺乏经验,所以没有任何建议太小。
感谢阅读!
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
Mat image = imread(path_to_file);
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
Mat fin;
double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
//size impacts dilation
Mat kernel = getStructuringElement(MORPH_CROSS, Size(2, 4));
Mat dilated;
dilate(fin, dilated, kernel, Point(-1,-1), 6);
imwrite("testbw.png",dilated);
Mat hierarchy;
vector<vector<Point> >contours;
findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
//potentially sort by x
for (const auto& c : contours)
{
// x y
//columns 850 x 5400
Rect r = boundingRect(c);
if (r.height > 3000 || r.width > 875)
continue;
if (r.height < 100 || r.width < 500)
continue;
rectangle(image, r, Scalar(255, 0, 255), 2); //made thicker
}
imwrite("test.png", image);
waitKey(0);
return 0;
}
原始图片:
更新了代码
int main(int argc, char* argv[])
{
Mat image = imread(path_to_file);
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
Mat fin;
double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
Mat kernel = getStructuringElement(MORPH_CROSS, Size(2, 4));
Mat dilated;
dilate(fin, dilated, kernel, Point(-1,-1), 6);
vector<Vec4i> hierarchy;
vector<vector<Point> >contours;
findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
vector<Rect> rects;
Rect big_rect = Rect(image.cols/2,image.rows/2,1,1);
for (const auto& c : contours)
{
// x y
//columns 850 x 5400
Rect r = boundingRect(c);
if (r.height > 5500 || r.width > 875)
continue;
if (r.height < 300 || r.width < 500)
continue;
big_rect = big_rect | r; // here we will find bounding box of all Rects
rects.push_back( r ); // stores rects
}
for ( size_t i = 0; i < rects.size(); i++ )
{
// sets y and height of all rects
//cout << rects[i].x << endl;
rects[i].y = big_rect.y;
rects[i].height = big_rect.height;
}
//groupRectangles(rects, 1); DIDN'T WORK
for ( size_t i = 0; i < rects.size(); i++ )
{
rectangle(image, rects[i], Scalar(255, 0, 255), 2);
}
imshow("test", image);
新结果:
新问题:每列周围有很多boundingRect
个(您可能无法通过查看图片来判断)。这是一个问题,因为我想制作每列的子图像,例如Mat ROI = image(rects[i])
会比所需的7张图像渲染得更多。
新问题:如何将每列的多个矩形合并为一个?我见过openCV&#39; groupRectangles
,但它无法正常工作。
答案 0 :(得分:1)
只是为了显示我尝试更改代码的方法,如下所示。
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
Mat image = imread(argv[1]);
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
Mat fin;
double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
//size impacts dilation
Mat kernel = getStructuringElement(MORPH_CROSS, Size(2, 4));
Mat dilated;
dilate(fin, dilated, kernel, Point(-1,-1), 1);
imwrite("testbw.png",dilated);
Mat hierarchy;
vector<vector<Point> >contours;
findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
vector<Rect> rects;
Rect big_rect = Rect(image.cols/2,image.rows/2,1,1);
//potentially sort by x
for (const auto& c : contours)
{
// x y
//columns 850 x 5400
Rect r = boundingRect(c);
if (r.height > 3000 || r.width > 875)
continue;
if (r.height < 10 || r.width < 10) // changed for test small image
continue;
big_rect = big_rect | r; // here we will find bounding box of all Rects
rects.push_back( r ); // stores rects
}
for ( size_t i = 0; i < rects.size(); i++ )
{
// sets y and height of all rects
rects[i].y = big_rect.y;
rects[i].height = big_rect.height;
}
for ( size_t i = 0; i < rects.size(); i++ )
{
rectangle(image, rects[i], Scalar(255, 0, 255), 2);
}
imshow("result", image);
waitKey(0);
return 0;
}
我知道它是不完整的,但我希望你能理解方法,并通过过滤rects来找到所需的七个rect来完成它,或者我将很快完成代码。
编辑:代码可能有点脏,但vector<Rect> final_rects
只包含您需要的内容。
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace cv;
using namespace std;
struct sorter_func
{
bool operator ()( Rect a, Rect b )
{
return a.x < b.x;
}
};
int main(int argc, char* argv[])
{
Mat image = imread(argv[1]);
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
Mat fin;
double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
//size impacts dilation
Mat kernel = getStructuringElement(MORPH_CROSS, Size(2, 4));
Mat dilated;
dilate(fin, dilated, kernel, Point(-1,-1), 1);
imwrite("testbw.png",dilated);
Mat hierarchy;
vector<vector<Point> >contours;
findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
vector<Rect> rects;
Rect big_rect = Rect(image.cols/2,image.rows/2,1,1);
//potentially sort by x
for (const auto& c : contours)
{
// x y
//columns 850 x 5400
Rect r = boundingRect(c);
if (r.height > 3000 || r.width > 875)
continue;
if (r.height < 10 || r.width < 10) // changed for test small image
continue;
big_rect = big_rect | r; // here we will find bounding box of all Rects
rects.push_back( r ); // stores rects
}
for ( size_t i = 0; i < rects.size(); i++ )
{
// sets y and height of all rects
rects[i].y = big_rect.y;
rects[i].height = big_rect.height;
}
std::sort(rects.begin(), rects.end(), sorter_func());
for ( size_t i = 1; i < rects.size(); i++ )
{
Rect big_rect = rects[i-1] | rects[i];
if( big_rect.width < rects[i-1].width + rects[i].width )
{
rects[i-1] = Rect();
rects[i] = big_rect;
}
}
vector<Rect> final_rects;
for ( size_t i = 1; i < rects.size(); i++ )
{
if( rects[i].width > 0 )
{
rectangle(image, rects[i], Scalar(rand()&255,rand()&255,rand()&255), 2);
final_rects.push_back( rects[i] );
cerr << final_rects.size() << endl;
}
}
imshow("result", image);
waitKey(0);
return 0;
}