存储包含简单多边形的二进制图像的详细信息

时间:2015-11-11 08:24:16

标签: c++ opencv image-processing coordinates store

这个问题涉及有些实践和经验丰富的过程。我有一个Mat二进制图像,它由黑色背景中的简单白色多边形组成。实际上,这些多边形代表报纸页面中的一篇文章。所以我想要的是在报纸页面内存储文章位置的详细信息。 One Mat图像中只有一个多边形。

是一个选择
  1. 使用纯OpenCV调用将Mat存储到.xml或.yml文件中(How to write a Float Mat to a file in OpenCV:已接受答案)
  2. 找到有顶点的多边形坐标,并将这些坐标只存储到数据库中
  3. 以下是我要存储的Mat的示例图像。

    enter image description here

    第一种选择似乎可行,但我不知道如何实施第二种方法。如果可能的话,我认为这将是最有效的,因为那样每篇文章只能保存很少的坐标。我可以实现一个复杂的过程来找到它的顶点,并在需要时使用这些坐标重绘Mat图像。但我希望opencv中有一个简单的过程来完成这项任务。

    所以我想知道哪种方法更好,如果第二种方法更好,如何在opencv中使用c ++。我既不是opencv专家也不是c ++专家,所以一个合适的答案可以节省我很多时间,也节省了程序的效率。

4 个答案:

答案 0 :(得分:1)

稍微偏离墙的方法......你可以很容易地将Mat保存为OpenCV中的图像 - 最好是PGMPNG,因为它们是无损的。然后你可以将图像传递给像potrace这样的矢量跟踪器程序,并让它以SVG格式告诉你大纲并将其存储在你的数据库中。

因此,potrace喜欢PGM个文件,因此您可以将大纲保存为PGM在OpenCV中,也可以保存为PNG,然后使用ImageMagick将其转换为potrace PGM并将其传递给convert OpenCVImage.png pgm:- | potrace - -b svg -o file.svg ,如下所示:

svg

将为您提供如下<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="3486.000000pt" height="4747.000000pt" viewBox="0 0 3486.000000 4747.000000" preserveAspectRatio="xMidYMid meet"> <metadata> Created by potrace 1.13, written by Peter Selinger 2001-2015 </metadata> <g transform="translate(0.000000,4747.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none"> <path d="M0 23735 l0 -23735 17430 0 17430 0 0 23735 0 23735 -17430 0 -17430 0 0 -23735z m20980 6560 l0 -3415 -399 0 c-293 0 -402 3 -407 12 -7 11 -68 11 -2391 -9 l-781 -6 -6 -6576 c-3 -3617 -9 -6840 -12 -7163 l-6 -588 -1939 0 -1939 0 0 10580 0 10580 3940 0 3940 0 0 -3415z"/> </g> </svg> 文件:

convert outline.svg outline.png

顺便说一句,您可以在网络浏览器中查看。

您可以随时调用图像并使用ImageMagick或其他工具在命令行中重新创建它,如下所示:

PNG

我会注意到你的整个convert YourBigInefficientOutline.png NiceImageMagickOutlineOf6kB.png 实际上只有32kB而存储空间相当便宜,因此生成矢量化图像以节省空间似乎不值得。事实上,如果你使用像ImageMagick这样的合适工具并将你的图像转换为单个PNG,那么它可以归结为6,150个字节,这非常小......

convert YourBig.png -resize 700x900 MySmall.png

而且,如果你能把大小缩小到原来的1/5,这仍然可能足以找到报纸上的文章,你可以这样做:

for

的重量仅为1,825字节。

答案 1 :(得分:1)

cv::Mat inputImage = cv::imread("input.png", CV_LOAD_IMAGE_GRAYSCALE);

// find non-zero point coordinates
cv::Mat nonZeroCoordinates;
cv::findNonZero(inputImage, nonZeroCoordinates);

然后您可以将nonZeroCoordinates矩阵保存到您要使用的文件中。

如果要使用这些坐标创建相同的图像,可以这样做:

std::vector<std::vector<cv::Point> > points;
points.push_back(nonZeroCoordinates);

cv::Mat output = cv::Mat::zeros(inputImage.size(), CV_8UC1);
cv::fillPoly(output, points, cv::Scalar(255));

希望它有所帮助!

答案 2 :(得分:1)

这取决于多边形的通用性。如果多边形的边缘始终与xy轴平行,那么您可以查看特定像素的8-neigborhood中的像素,如果有奇数个白色像素,则可以找到角。或者使用4邻域并测试偶数个白色像素。

答案 3 :(得分:1)

您可以使用{{3>},使用适当的轮廓近似方法。基本上,除了将存储所有点的NSSet之外,其他每种方法都适用于此示例:CV_CHAIN_APPROX_NONECV_CHAIN_APPROX_SIMPLECV_CHAIN_APPROX_TC89_L1

您可以将这些点存储在数据库中。然后,您可以重新加载这些点,并使用findContours绘制原始图像。

这个简单的例子用近似方法显示检索到的轮廓点,以及如何用这些点重新绘制图像。

注意您的图像是别名(您可能在png之前将其保存在jpeg中),因此您需要删除别名,例如只保留值等于255的点。

CV_CHAIN_APPROX_TC89_KCOS

使用轮廓近似法的绿色顶点:

fillPoly