c++


How to load a TIFF image like a graph in C++ BOOST


I want do load a tiff image (GEOTIFF with pixels with float values) like graph in boost C++ (i'm a newbie in C++). My goal is use the bidirectional Dijkstra from source A to target B to get more performance.
Boost:GIL load tiif images:
std::string filename( "raster_clip.tif" );
rgb8_image_t img;
read_image( filename, img, tiff_tag() );
But how convert to Boost graph? I am reading the documentation and looking for examples but I have not yet been able to implement it.
Similar questions and examples that i found:
Shortest path graph algorithm help Boost;
http://www.geeksforgeeks.org/shortest-path-for-directed-acyclic-graphs/
I am currently using the scikit-image library and use skimage.graph.route_through_array function to load graph with array in python. I use GDAL to get an array by load image as suggested by #ustroetz in this example Here:
raster = gdal.Open("raster.tiff")
band = raster.GetRasterBand(1)
array = band.ReadAsArray()
Example of TIFF (was converted to PNG after upload) is:
Ok, so read the PNG:
I've cropped the whitespace border since it wasn't consistent anyways
Reading And Sampling The Image
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);
Next up, make sure we know the dimensions and how to address the center pixels for each cell:
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);
Constructing The Graph
Now let's make the graph. For this task a grid-graph seems in order. It should be w×h and not wrap around at the edges (if it should, change false to true):
using Graph = boost::grid_graph<2>;
Graph graph({{w,h}}, false);
We want to attach weights at each edge. We can either use an old-fashioned external property map that's sized up-front:
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));
Alternatively, we can use a dynamically allocating and growing property-map:
auto weights = boost::make_vector_property_map<float>(get(boost::edge_index, graph));
As a bonus, here's the equivalent approach using an associative property-map:
std::map<Graph::edge_descriptor, double> weight_m;
auto weights = boost::make_assoc_property_map(weight_m);
Each of these are drop-in compatible and the choice is yours.
Filling The Graph
We simply iterate all edges, setting the cost from the colour difference:
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);
}
Note Consider normalizing weight to e.g. [0.0, 1.0) using the actual bit-depth of the source image
Let's create a verification TIF so we can actually see where the samples were taken in the image:
{
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));
}
The verification.tif ends up like (note the center pixel for each cell):
Bonus: Visualize The Grid Graph
Let's write it to a Graphviz file:
{
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);
}
This calculates the color from the same sample pixel and uses some Graphviz-specific magic to write to a file:
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);
}
Which results in a grid.dot file like this.
Next, let's layout using neato:
neato -T png grid.dot -o grid.png
And the result is:
FULL CODE LISTING
#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);
}

Related Links

ioService.post(boost::bind(&myFunction, this, attr1, attri2) does not post the work
Propagating onPositionChanged events to background items in QtQuick 1.1
Constexpr vs macros
Why clang is not able to instantiate nested variadic template with defaulted integer_sequence?
forward declaration of classes, splitting variables and functions [duplicate]
How to use templates to avoid global variables in a multi file program in C++? [duplicate]
CMake find_library nvEncodeAPI.dll
trying to distinguish between different kinds of rvalues - literals and non-literals
C++ Error C2678 binary '<': no operator found which takes a left-hand operand of type 'const State' [duplicate]
Fade library Delaunay Triangulation site neighbors
Declare abstract class in c++
Compiler error of clang++ 8.0 — Segmentation fault — on Mac OSX Sierra 10.12.3
SIFT orientations in OpenCV implementation
How to detect thread entry/spawn point in LLVM pass?
Insert array pointer to a 2 dimension vector in C++
How to simulate user input in c++? [duplicate]

Categories

HOME
machine-learning
menu
logic
arduino
sitecore8
screensaver
iframe
sql-server-2005
sendmail
autodesk-forge
etcd
unity5
64bit
asp.net-web-api2
jaxb
formula
worksheet-function
translate
strongloop
dynamics-ax-2012
junit4
amazon-route53
postgresql-9.0
atlassian-sourcetree
qtspim
boost-python
pywavelets
git-clone
hp-quality-center
nestedscrollview
nsdate
lightgallery
hana-cloud-platform
each
data-storage
xfs
predict
devexpress-wpf
retrieve-and-rank
clisp
rt
ctags
javac
graylog
jquery-events
same-origin-policy
nosuchelementexception
google-keep
scodec
rpy2
nslog
ch
turtle-rdf
markov-models
pxe
ratchet
anthill
orchardcms-1.9
couchbase-sync-gateway
rgraph
sparklines
8085
msbuildcommunitytasks
fluid-layout
cordova-chrome-app
certificatestore
soundex
puphpet
setlocale
file-attributes
editplus
jekyll-extensions
teamsite
runscope
dav
ios-provisioning
kif-framework
svggraph
mashup
updatemodel
usermode
iron
complete.ly
android-3.0-honeycomb
fold
rs485
jquery-ui-selectable
jsonexception
ruby-on-rails-plugins
readelf
getprocaddress
.lrc
mobile-phones
testdriven.net
endl
iphone-3gs
vtl
viewexpiredexception
httpverbs
visual-programming
vmwaretasks
astoria

Resources

Encrypt Message



code
soft
python
ios
c
html
jquery
cloud
mobile