这个问题涉及有些实践和经验丰富的过程。我有一个Mat二进制图像,它由黑色背景中的简单白色多边形组成。实际上,这些多边形代表报纸页面中的一篇文章。所以我想要的是在报纸页面内存储文章位置的详细信息。 One Mat图像中只有一个多边形。
是一个选择以下是我要存储的Mat的示例图像。
第一种选择似乎可行,但我不知道如何实施第二种方法。如果可能的话,我认为这将是最有效的,因为那样每篇文章只能保存很少的坐标。我可以实现一个复杂的过程来找到它的顶点,并在需要时使用这些坐标重绘Mat图像。但我希望opencv中有一个简单的过程来完成这项任务。
所以我想知道哪种方法更好,如果第二种方法更好,如何在opencv中使用c ++。我既不是opencv专家也不是c ++专家,所以一个合适的答案可以节省我很多时间,也节省了程序的效率。
答案 0 :(得分:1)
稍微偏离墙的方法......你可以很容易地将Mat保存为OpenCV中的图像 - 最好是PGM
或PNG
,因为它们是无损的。然后你可以将图像传递给像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)
这取决于多边形的通用性。如果多边形的边缘始终与x
和y
轴平行,那么您可以查看特定像素的8-neigborhood中的像素,如果有奇数个白色像素,则可以找到角。或者使用4邻域并测试偶数个白色像素。
答案 3 :(得分:1)
您可以使用{{3>},使用适当的轮廓近似方法。基本上,除了将存储所有点的NSSet
之外,其他每种方法都适用于此示例:CV_CHAIN_APPROX_NONE
,CV_CHAIN_APPROX_SIMPLE
和CV_CHAIN_APPROX_TC89_L1
。
您可以将这些点存储在数据库中。然后,您可以重新加载这些点,并使用findContours绘制原始图像。
这个简单的例子用近似方法显示检索到的轮廓点,以及如何用这些点重新绘制图像。
注意您的图像是别名(您可能在png之前将其保存在jpeg中),因此您需要删除别名,例如只保留值等于255的点。
CV_CHAIN_APPROX_TC89_KCOS
使用轮廓近似法的绿色顶点: