检测纸张边缘并裁剪
Detecting Paper Edge and Crop it
我正在使用 C# 编写一个程序来检测纸张边缘并从图像中裁剪出纸张的方形边缘。
下面是我要裁剪的图片。论文将始终出现在页面底部。
我已经阅读了这些链接,但我仍然不知道该怎么做。
OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection
编辑:我正在为这个 OCR 项目使用 EMGU
- 决定纸张颜色
- 确定增量以允许颜色变化
- 确定沿底部的点进行垂直测试
- 向上进行垂直测试,收集颜色停止出现的最小 y
- 至少做 10-20 次这样的测试
结果 y 应该比你想要保留的多 1。如果图像太亮,您可能需要插入一个限制以避免裁剪所有内容。要么优化算法,要么将这样的图片标记为例外人工处理!
要裁剪,请使用 DrawImage
重载源和目标矩形!
这里还有一些提示:
要找到纸张颜色,您可以从左下边缘沿对角线向右向上移动,直到找到 Color.GetBrightness
> 0.8 的像素;然后进一步移动 2 个像素以清除任何抗锯齿像素。
合理的增量取决于您的图像;从 10%
开始
使用底部随机游走;当你完成后,可以在第一遍中找到的最小值附近添加一个额外的遍。
垂直测试可以使用 GetPixel
来获取颜色,如果速度太慢,您可能需要查看 LockBits
。但是先搞定搜索算法,再考虑优化!
如果您 运行 遇到代码问题,请扩展您的问题!
您还可以:
- 将您的图像转换为灰度图像
- 按像素强度应用
ThresholdBinary
求等高线。
要查看有关查找轮廓的示例,您可以查看 this post.
FundContours
方法不关心轮廓大小。在找到轮廓之前唯一要做的就是通过对图像进行二值化来强调它们(我们在步骤 2 中这样做)。
有关更多信息,请参阅 OpenCV 文档:findContours, example.
根据边界框的大小和位置找到合适的轮廓。
(在这一步中,我们遍历所有在轮廓上找到的东西,并尝试找出哪一个是纸张的轮廓sheet,使用已知的纸张尺寸,它们的比例和相对位置 - 图片的左下角)。
使用纸张 sheet 的边界框裁剪图像。
Image<Gray, byte> grayImage = new Image<Gray, byte>(colorImage);
Image<Bgr, byte> color = new Image<Bgr, byte>(colorImage);
grayImage = grayImage.ThresholdBinary(new Gray(thresholdValue), new Gray(255));
using (MemStorage store = new MemStorage())
for (Contour<Point> contours= grayImage.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_NONE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE, store); contours != null; contours = contours.HNext)
{
Rectangle r = CvInvoke.cvBoundingRect(contours, 1);
// filter contours by position and size of the box
}
// crop the image using found bounding box
更新:我添加了更多细节。
我正在使用 C# 编写一个程序来检测纸张边缘并从图像中裁剪出纸张的方形边缘。
下面是我要裁剪的图片。论文将始终出现在页面底部。
我已经阅读了这些链接,但我仍然不知道该怎么做。
OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection
编辑:我正在为这个 OCR 项目使用 EMGU
- 决定纸张颜色
- 确定增量以允许颜色变化
- 确定沿底部的点进行垂直测试
- 向上进行垂直测试,收集颜色停止出现的最小 y
- 至少做 10-20 次这样的测试
结果 y 应该比你想要保留的多 1。如果图像太亮,您可能需要插入一个限制以避免裁剪所有内容。要么优化算法,要么将这样的图片标记为例外人工处理!
要裁剪,请使用 DrawImage
重载源和目标矩形!
这里还有一些提示:
要找到纸张颜色,您可以从左下边缘沿对角线向右向上移动,直到找到
Color.GetBrightness
> 0.8 的像素;然后进一步移动 2 个像素以清除任何抗锯齿像素。合理的增量取决于您的图像;从 10%
开始
使用底部随机游走;当你完成后,可以在第一遍中找到的最小值附近添加一个额外的遍。
垂直测试可以使用
GetPixel
来获取颜色,如果速度太慢,您可能需要查看LockBits
。但是先搞定搜索算法,再考虑优化!
如果您 运行 遇到代码问题,请扩展您的问题!
您还可以:
- 将您的图像转换为灰度图像
- 按像素强度应用
ThresholdBinary
求等高线。
要查看有关查找轮廓的示例,您可以查看 this post.
FundContours
方法不关心轮廓大小。在找到轮廓之前唯一要做的就是通过对图像进行二值化来强调它们(我们在步骤 2 中这样做)。
有关更多信息,请参阅 OpenCV 文档:findContours, example.根据边界框的大小和位置找到合适的轮廓。
(在这一步中,我们遍历所有在轮廓上找到的东西,并尝试找出哪一个是纸张的轮廓sheet,使用已知的纸张尺寸,它们的比例和相对位置 - 图片的左下角)。使用纸张 sheet 的边界框裁剪图像。
Image<Gray, byte> grayImage = new Image<Gray, byte>(colorImage); Image<Bgr, byte> color = new Image<Bgr, byte>(colorImage); grayImage = grayImage.ThresholdBinary(new Gray(thresholdValue), new Gray(255)); using (MemStorage store = new MemStorage()) for (Contour<Point> contours= grayImage.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_NONE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE, store); contours != null; contours = contours.HNext) { Rectangle r = CvInvoke.cvBoundingRect(contours, 1); // filter contours by position and size of the box } // crop the image using found bounding box
更新:我添加了更多细节。