Ail*_*lho 3 c++ image-processing boost-graph geotiff
我想加载一个tiff图像(带有浮点值的像素的GEOTIFF),如boost C++中的图形(我是C++中的新手).我的目标是使用从源A到目标B的双向Dijkstra来获得更高的性能.
Boost:GIL load tiif images:
std::string filename( "raster_clip.tif" );
rgb8_image_t img;
read_image( filename, img, tiff_tag() );
Run Code Online (Sandbox Code Playgroud)
但是如何转换为Boost图?我正在阅读文档并查找示例,但我还没有实现它.
我发现的类似问题和例子:
http://www.geeksforgeeks.org/shortest-path-for-directed-acyclic-graphs/
我目前正在使用scikit-image库并使用skimage.graph.route_through_array函数在python中加载带数组的图形.我用GDAL通过在该示例@ustroetz的建议以获得由负载图像的阵列这里:
raster = gdal.Open("raster.tiff")
band = raster.GetRasterBand(1)
array = band.ReadAsArray()
Run Code Online (Sandbox Code Playgroud)
好的,请阅读PNG:
我已经裁剪了空白边框,因为它反正不一致
using Img = boost::gil::rgb8_image_t; // gray8_image_t;
using Px = Img::value_type;
Img img;
//boost::gil::png_read_image("graph.png", img);
boost::gil::png_read_and_convert_image("graph.png", img);
auto vw = view(img);
Run Code Online (Sandbox Code Playgroud)
接下来,确保我们知道尺寸以及如何解决每个单元格的中心像素:
double constexpr cell_w = 30.409;
double constexpr cell_h = 30.375;
auto pixel_sample = [=](boost::array<size_t, 2> xy) -> auto& {
return vw((xy[0]+.5)*cell_w, (xy[1]+.5)*cell_h);
};
auto const w= static_cast<size_t>(img.dimensions()[0] / cell_w);
auto const h= static_cast<size_t>(img.dimensions()[1] / cell_h);
Run Code Online (Sandbox Code Playgroud)
现在让我们来制作图表.对于此任务,网格图似乎是有序的.它应该是w×h而不是在边缘处缠绕(如果它应该,false改为true):
using Graph = boost::grid_graph<2>;
Graph graph({{w,h}}, false);
Run Code Online (Sandbox Code Playgroud)
我们想在每个边缘附加重量.我们可以使用预先确定尺寸的老式外部地图:
std::vector<double> weight_v(num_edges(graph));
auto weights = boost::make_safe_iterator_property_map(weight_v.begin(), weight_v.size(), get(boost::edge_index, graph));
Run Code Online (Sandbox Code Playgroud)
或者,我们可以使用动态分配和增长的属性映射:
auto weights = boost::make_vector_property_map<float>(get(boost::edge_index, graph));
Run Code Online (Sandbox Code Playgroud)
作为奖励,这是使用关联属性映射的等效方法:
std::map<Graph::edge_descriptor, double> weight_m;
auto weights = boost::make_assoc_property_map(weight_m);
Run Code Online (Sandbox Code Playgroud)
这些都是兼容的,您可以选择.
我们只是迭代所有边缘,从色差中设置成本:
BGL_FORALL_EDGES(e, graph, Graph) {
auto& from = pixel_sample(e.first);
auto& to = pixel_sample(e.second);
// compare RED channels only
auto cost = std::abs(from[0] - to[0]);
put(weights, e, cost);
}
Run Code Online (Sandbox Code Playgroud)
注意考虑将权重标准化为例如
[0.0, 1.0)使用源图像的实际位深度
让我们创建一个验证TIF,这样我们就可以真正看到样本在图像中的位置:
{
BGL_FORALL_VERTICES(v, graph, Graph) {
pixel_sample(v) = Px(255, 0, 123); // mark the center pixels so we can verify the sampling
}
boost::gil::tiff_write_view("/tmp/verification.tif", const_view(img));
}
Run Code Online (Sandbox Code Playgroud)
最终verification.tif结束(注意每个单元格的中心像素):
我们将它写入Graphviz文件:
{
auto calc_color = [&](size_t v) {
std::ostringstream oss;
oss << std::hex << std::noshowbase << std::setfill('0');
auto const& from = pixel_sample(vertex(v, graph));
oss << "#" << std::setw(2) << static_cast<int>(from[0])
<< std::setw(2) << static_cast<int>(from[1])
<< std::setw(2) << static_cast<int>(from[2]);
return oss.str();
};
write_dot_file(graph, weights, calc_color);
}
Run Code Online (Sandbox Code Playgroud)
这将计算相同样本像素的颜色,并使用一些特定于Graphviz的魔术来写入文件:
template <typename Graph, typename Weights, typename ColorFunction>
void write_dot_file(Graph const& graph, Weights const& weights, ColorFunction calc_color) {
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, graph));
dp.property("fillcolor", boost::make_transform_value_property_map(calc_color, get(boost::vertex_index, graph)));
dp.property("style", boost::make_static_property_map<typename Graph::vertex_descriptor>(std::string("filled")));
std::ofstream ofs("grid.dot");
auto vpw = boost::dynamic_vertex_properties_writer { dp, "node_id" };
auto epw = boost::make_label_writer(weights);
auto gpw = boost::make_graph_attributes_writer(
std::map<std::string, std::string> { },
std::map<std::string, std::string> { {"shape", "rect"} },
std::map<std::string, std::string> { }
);
boost::write_graphviz(ofs, graph, vpw, epw, gpw);
}
Run Code Online (Sandbox Code Playgroud)
这导致像这样的grid.dot文件.
接下来,让我们使用neato以下布局:
neato -T png grid.dot -o grid.png
Run Code Online (Sandbox Code Playgroud)
#include <boost/gil/extension/io/png_dynamic_io.hpp>
#include <boost/gil/extension/io/tiff_dynamic_io.hpp>
#include <boost/graph/grid_graph.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/graphviz.hpp>
#include <iostream>
template <typename Graph, typename Weights, typename ColorFunction>
void write_dot_file(Graph const& graph, Weights const& weights, ColorFunction);
int main() try {
using Img = boost::gil::rgb8_image_t; // gray8_image_t;
using Px = Img::value_type;
Img img;
//boost::gil::png_read_image("/home/sehe/graph.png", img);
boost::gil::png_read_and_convert_image("/home/sehe/graph.png", img);
auto vw = view(img);
double constexpr cell_w = 30.409;
double constexpr cell_h = 30.375;
auto pixel_sample = [=](boost::array<size_t, 2> xy) -> auto& {
return vw((xy[0]+.5)*cell_w, (xy[1]+.5)*cell_h);
};
auto const w= static_cast<size_t>(img.dimensions()[0] / cell_w);
auto const h= static_cast<size_t>(img.dimensions()[1] / cell_h);
using Graph = boost::grid_graph<2>;
Graph graph({{w,h}}, false);
#if 0 // dynamic weight map
auto weights = boost::make_vector_property_map<float>(get(boost::edge_index, graph));
std::cout << "Edges: " << (weights.storage_end() - weights.storage_begin()) << "\n";
#elif 1 // fixed vector weight map
std::vector<double> weight_v(num_edges(graph));
auto weights = boost::make_safe_iterator_property_map(weight_v.begin(), weight_v.size(), get(boost::edge_index, graph));
#else // associative weight map
std::map<Graph::edge_descriptor, double> weight_m;
auto weights = boost::make_assoc_property_map(weight_m);
#endif
auto debug_vertex = [] (auto& v) -> auto& { return std::cout << "{" << v[0] << "," << v[1] << "}"; };
auto debug_edge = [&](auto& e) -> auto& { debug_vertex(e.first) << " -> "; return debug_vertex(e.second); };
BGL_FORALL_EDGES(e, graph, Graph) {
//debug_edge(e) << "\n";
auto& from = pixel_sample(e.first);
auto& to = pixel_sample(e.second);
// compare RED channels only
auto cost = std::abs(from[0] - to[0]);
put(weights, e, cost);
}
{
auto calc_color = [&](size_t v) {
std::ostringstream oss;
oss << std::hex << std::noshowbase << std::setfill('0');
auto const& from = pixel_sample(vertex(v, graph));
oss << "#" << std::setw(2) << static_cast<int>(from[0])
<< std::setw(2) << static_cast<int>(from[1])
<< std::setw(2) << static_cast<int>(from[2]);
return oss.str();
};
write_dot_file(graph, weights, calc_color);
}
{
BGL_FORALL_VERTICES(v, graph, Graph) {
pixel_sample(v) = Px(255, 0, 123); // mark the center pixels so we can verify the sampling
}
boost::gil::tiff_write_view("/tmp/verification.tif", const_view(img));
}
} catch(std::exception const& e) {
std::cout << "Exception occured: " << e.what() << "\n";
}
template <typename Graph, typename Weights, typename ColorFunction>
void write_dot_file(Graph const& graph, Weights const& weights, ColorFunction calc_color) {
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, graph));
dp.property("fillcolor", boost::make_transform_value_property_map(calc_color, get(boost::vertex_index, graph)));
dp.property("style", boost::make_static_property_map<typename Graph::vertex_descriptor>(std::string("filled")));
std::ofstream ofs("grid.dot");
auto vpw = boost::dynamic_vertex_properties_writer { dp, "node_id" };
auto epw = boost::make_label_writer(weights);
auto gpw = boost::make_graph_attributes_writer(
std::map<std::string, std::string> { },
std::map<std::string, std::string> { {"shape", "rect"} },
std::map<std::string, std::string> { }
);
boost::write_graphviz(ofs, graph, vpw, epw, gpw);
}
Run Code Online (Sandbox Code Playgroud)