试图找到一种在OpenCV / BOOST中记录图形数据的方法



首先:我正在使用OpenCV C++进行图像处理。在C++程序中加载一个垫子图像后,我使用 GNUPLOT 绘制了图像的图形。

现在,要求是记录垫图像的图形数据。

为此,我通过包含所有 BOOST 库创建了一个 BOOST C++ Logger。BOOST也是一个很好的测试和记录数据的库,但是,它的日志的问题在于它只能记录文本消息。如果我错了,请纠正我。

以下是我在OpenCV中使用GNUPlot绘制图形的代码:

try
{
Gnuplot g1("lines"); 
std::vector<double> rowVector;
std::vector<double> rowVectorExp;
for (int i = 0; i < 50; i++)  
{
rowVector.push_back((double)i); 
rowVectorExp.push_back((double)exp((float)i/10.0));
}
cout << "*** user-defined lists of doubles" << endl;
g1 << "set term png";
g1 << "set output "test.png"";
//type of plot pattern
g1.set_grid().set_style("lines"); 
g1.plot_xy(rowVector, rowVectorExp, "user-defined points 2d");
waitKey(0);
}
catch (GnuplotException ge)
{
cout << ge.what() << endl;
}
cout << endl << "*** end of gnuplot example" << endl;

这是我的提升日志代码

namespace logging = boost::log;
void PlainGetEdgeVector::init()
{
logging::add_file_log("sample%3N.log");
}
BOOST_LOG_TRIVIAL(info) << "This is my first Log line";

好消息是,我的BOOST记录器成功记录了短信。如果它也可以记录我的图形数据,那就太好了。

有什么建议吗?如果有人知道如何使用 BOOST 实现相同的内容,我将不胜感激,或者如果有任何替代方案,也很高兴知道这一点。

问题的解决方案在很大程度上取决于数据的性质,您希望如何使用记录的数据。

1. 重新考虑将二进制数据转换为文本

出于调试目的,将二进制数据转换为文本通常更方便。即使有大量数据,这种方法也很有用,因为用于文本处理的工具通常比处理任意二进制数据的工具要多得多。例如,您可以将应用程序不同运行中的两个日志与传统的合并/比较工具进行比较,以查看差异。文本日志也更容易使用grepawk等工具进行过滤,这些工具随时可用,而不是您可能需要为其编写解析器的二进制数据。

有许多方法可以将二进制数据转换为文本。最直接的方法是使用dump操纵器,它将有效地生成原始二进制数据的文本视图。它也适合图形数据,因为它的数量往往相对较大,并且通常很容易在文本表示中进行比较(例如,当颜色样本适合字节时)。

std::vector< std::uint8_t > image;
// Outputs hex dump of the image
BOOST_LOG_TRIVIAL(info) << logging::dump(image.data(), image.size());

输出二进制数据的更结构化方法是使用其他库,例如来自 Boost.Range 的库iterator_range库。如果您的图形数据由比原始字节更复杂的内容组成,这可能很有用。

std::vector< double > image;
// Outputs all elements of the image vector
BOOST_LOG_TRIVIAL(info) << boost::make_iterator_range(image);

您还可以编写自己的操纵器,该操纵器将按照您想要的方式格式化数据,例如按行拆分输出。

2. 对于二进制数据,请使用属性和自定义接收器后端

如果您打算通过更专业的软件(如图像查看器或编辑器)处理记录的数据,则可能需要以二进制形式保存数据。这可以使用 Boost.Log 完成,但这需要更多的努力,因为库提供的接收器是面向文本的,您无法按原样将二进制数据保存到文本文件中。您必须编写一个接收器后端,该后端将以所需的格式写入二进制数据(例如,如果您打算使用图像编辑器,则可能需要以该编辑器支持的格式写入文件)。这里有一个教程,它显示了你必须实现的接口和一个示例实现。重要的一点是后端的consume功能,它将接收包含数据的日志记录视图。

typedef boost::iterator_range< const double* > image_data;
BOOST_LOG_ATTRIBUTE_KEYWORD(a_image, "Image", image_data)
class image_writer_backend :
public sinks::basic_sink_backend< sinks::synchronized_feeding >
{
public:
void consume(logging::record_view const& rec)
{
// Extract the image data from the log record
if (auto image = rec[a_image])
{
image_data const& im = image.get();
// Write the image data to a file
}
}
};

若要将映像二进制数据传递到接收器,需要将其作为属性附加到日志记录。有多种方法可以执行此操作,但假设您不打算根据映像筛选日志记录,最简单的方法是使用add_value操纵器。

std::vector< double > image;
BOOST_LOG_TRIVIAL(info) << logging::add_value(a_image, image) << "Catch my image";

警告:为了避免复制潜在的大型图像数据,我们将传递轻量级iterator_range作为属性值。这仅适用于同步日志记录,因为在处理日志记录时,image向量需要保持活动状态。对于异步日志记录,您必须按值传递图像或使用引用计数。

如果确实要对图像数据应用筛选器,则可以使用作用域属性或将属性添加到记录器。

请注意,通过添加用于写入二进制数据的新接收器,不排除使用其他接收器写入文本日志,以便文本接收器可以处理"捕获我的图像"消息。通过使用其他属性(如日志记录计数器),可以将日志记录关联到不同接收器生成的不同文件中。

最新更新