Opencv 如何在扫描文档中查找段落边界框坐标?

Opencv 如何在扫描文档中查找段落边界框坐标?,opencv,neural-network,statistics,imagemagick-convert,connected-components,Opencv,Neural Network,Statistics,Imagemagick Convert,Connected Components,我想在如下所示的文档扫描中获得包含任何文本的所有区域的坐标(质量降低;原始文件具有高分辨率): 我正在寻找类似于这些(GIMP'ed-up!)边界框的东西。对我来说,重要的是这些段落应该得到承认。但是,如果两个大块(左侧页面的顶部框,右侧页面的中心框)各有两个边界框,则可以: 获取这些边界框坐标的方法可以是通过某种API(脚本语言优于编译语言)或通过命令行命令,我不在乎。重要的是我得到的是坐标本身,而不仅仅是它们可见的图像的修改版本。原因是我需要计算每一个物体的面积大小,然后在最大物体的中心

我想在如下所示的文档扫描中获得包含任何文本的所有区域的坐标(质量降低;原始文件具有高分辨率):

我正在寻找类似于这些(GIMP'ed-up!)边界框的东西。对我来说,重要的是这些段落应该得到承认。但是,如果两个大块(左侧页面的顶部框,右侧页面的中心框)各有两个边界框,则可以:

获取这些边界框坐标的方法可以是通过某种API(脚本语言优于编译语言)或通过命令行命令,我不在乎。重要的是我得到的是坐标本身,而不仅仅是它们可见的图像的修改版本。原因是我需要计算每一个物体的面积大小,然后在最大物体的中心切出一块

我已经尝试过的,到目前为止没有成功:

  • ImageMagick-它不适合这样的任务
  • OpenCV-要么学习曲线太高,要么我的google foo太差
  • Tesseract——据我所知,这是一款一次性的OCR软件,由于历史原因,在尝试字符形状识别之前不会进行页面布局分析
  • OCRopus/OCRopy——应该能够做到,但我不知道如何告诉它我对段落感兴趣,而不是文字或字符
  • 克拉肯伊本奥克洛普斯-奥克洛普斯的叉子,有一些粗糙的边缘,仍在与之战斗
  • 使用统计学,尤其是图像二值化后的聚类算法(光学似乎是最适合此任务的算法)——我的数学和编码技能都不足以胜任

我在互联网上看到文档扫描图像被分割成包含文本、照片和其他元素的部分,因此这个问题似乎已经在学术上得到了解决。但是,如何获得好的效果呢?

在Imagemagick中,您可以对图像设置阈值以避免产生太多的噪声,然后对其进行模糊,然后再次设置阈值以使大面积的黑色区域连接起来。然后使用
-connected components
过滤出小区域,尤其是白色区域,然后找到黑色区域的边界框。(Unix bash语法)


这是创建的
tmp.png
图像。请注意,我已经丢弃了面积小于20像素的区域。根据需要进行调整。还可以根据需要调整模糊。您可以将其变大以获得更大的连接区域,也可以将其变小以更接近单个文本行。我在图像顶部刮去5个像素以去除斑点噪声,然后用5个像素的白色边框填充

这是边界框的列表

清单如下:

267x223+477+123
267x216+136+43
48x522+413+0
266x86+136+317
266x43+136+410
266x66+477+404
123x62+479+346
137x43+142+259
117x43+486+65
53x20+478+46
31x20+606+347
29x19+608+48
26x18+716+347
26x17+256+480
25x17+597+481
27x18+716+47
21x17+381+240
7x7+160+409
我们可以进一步绘制有关区域的方框:

boxes=""
bboxArr=(`convert image.png -threshold 95% \
-shave 5x5 -bordercolor white -border 5 \
-blur 0x2.5 -threshold 99% -type bilevel \
-define connected-components:verbose=true \
-define connected-components:area-threshold=20 \
-define connected-components:mean-color=true \
-connected-components 4 \
+write tmp.png null: | grep "gray(0)" | sed 's/^[ ]*//' | cut -d\  -f2`)
num="${#bboxArr[*]}"
for ((i=0; i<num; i++)); do
WxH=`echo "${bboxArr[$i]}" | cut -d+ -f1`
xo=`echo "${bboxArr[$i]}" | cut -d+ -f2`
yo=`echo "${bboxArr[$i]}" | cut -d+ -f3`
ww=`echo "$WxH" | cut -dx -f1`
hh=`echo "$WxH" | cut -dx -f2`
x1=$xo
y1=$yo
x2=$((xo+ww-1))
y2=$((yo+hh-1))
boxes="$boxes rectangle $x1,$y1 $x2,$y2"
done
convert image.png -fill none -strokewidth 2 -stroke red -draw "$boxes" -alpha off image_boxes.png
box=“”
bboxArr=(`convert image.png-阈值95%\
-剃须5x5-边框颜色白色-边框5\
-模糊0x2.5-阈值99%-类型二层\
-定义连接的组件:verbose=true\
-定义连接的组件:面积阈值=20\
-定义连接的组件:平均颜色=真\
-连接部件4\
+写入tmp.png null:| grep“gray(0)”| sed's/^[]*/'| cut-d \-f2`)
num=“${#bboxArr[*]}”

为了((i=0;iI不理解该问题。如果指定
convert image-crop WxH+X+Y+repage result
。那么您应该只获得指定的区域。任何外部边界都不重要。您是否裁剪了很大的区域。我以为您的问题是裁剪一个小区域以获得特定的单词。请澄清。问题i不是关于如何裁剪,而是关于如何决定裁剪什么。我有数百个,每一个都不同。很多图片的中心都有文本,但到目前为止还不是全部。那么如何找出适合裁剪的区域?@fmw42,你还不清楚我的问题吗?我很想修改它,让它更容易理解,但我不确定关于它可能是不清楚的…我没有一个好的解决方案为你避免任何大的边界效果,如你所显示的。如果你知道你想要的区域的大小,那么你可以创建一个模板,比如说5%的灰度低于白色,然后使用Imagemagick比较,以找到在更大的图像中的最佳匹配。但如果你不知道大小,你可以对于你想要的区域,那么我现在没有一个好的解决方案。我会考虑的。继续:但我仍然不明白你是如何决定要提取哪一段文本的。哇,这太令人印象深刻了,仅仅使用ImageMagick!这些小框根本没有问题,因为我正在计算框的面积大小,然后选择l最大的框。问题是左右页面之间的阴影也被检测到。我会稍微调整一下阈值,看看它是否能消失。如果不能,我必须首先丢弃任何比它宽得多的东西。如果可以,我想在接受答案之前等待一段时间,以便看看“理解”“阴影”和“文本”之间的区别是否也存在。只需测试这个盒子就可以扔出那个非常高的瘦盒子,也就是说,几乎是整个页面的高度和你认为合适的宽度都落在这两个页面图像的中间。一个小东西:为什么你遵循<代码> GRIP“Gray(0)”。
up with
tail-n+2
?这是否意味着要删除“对象(id:边界框质心区域平均颜色):”在某种程度上?另外,如果您感兴趣,这就是您的代码在不调整任何应用值的情况下对全分辨率图像所做的操作:……如果有人试图使用Tesseract进行OCR,这可能是一个很好的准备。没有进行太多实验。这就是我要做的:(剃须100x100,边框100,模糊0x7.5)。
boxes=""
bboxArr=(`convert image.png -threshold 95% \
-shave 5x5 -bordercolor white -border 5 \
-blur 0x2.5 -threshold 99% -type bilevel \
-define connected-components:verbose=true \
-define connected-components:area-threshold=20 \
-define connected-components:mean-color=true \
-connected-components 4 \
+write tmp.png null: | grep "gray(0)" | sed 's/^[ ]*//' | cut -d\  -f2`)
num="${#bboxArr[*]}"
for ((i=0; i<num; i++)); do
WxH=`echo "${bboxArr[$i]}" | cut -d+ -f1`
xo=`echo "${bboxArr[$i]}" | cut -d+ -f2`
yo=`echo "${bboxArr[$i]}" | cut -d+ -f3`
ww=`echo "$WxH" | cut -dx -f1`
hh=`echo "$WxH" | cut -dx -f2`
x1=$xo
y1=$yo
x2=$((xo+ww-1))
y2=$((yo+hh-1))
boxes="$boxes rectangle $x1,$y1 $x2,$y2"
done
convert image.png -fill none -strokewidth 2 -stroke red -draw "$boxes" -alpha off image_boxes.png