Skip to content

Commit

Permalink
Merge pull request #2084 from joto/switch-cimg-to-opencv
Browse files Browse the repository at this point in the history
Generalization: Switch from using CImg to OpenCV library.
  • Loading branch information
lonvia authored Sep 24, 2023
2 parents faf2097 + 845995c commit 374eca4
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 65 deletions.
4 changes: 3 additions & 1 deletion .github/actions/ubuntu-prerequisites/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ runs:
- name: Install software
run: |
sudo apt-get install -yq --no-install-suggests --no-install-recommends \
cimg-dev \
libboost-filesystem-dev \
libboost-system-dev \
libbz2-dev \
libexpat1-dev \
libopencv-core-dev \
libopencv-imgcodecs-dev \
libopencv-imgproc-dev \
libpotrace-dev \
libpq-dev \
libproj-dev \
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/win-install/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ runs:
boost-property-tree:x64-windows \
boost-system:x64-windows \
bzip2:x64-windows \
cimg:x64-windows \
expat:x64-windows \
libpq:x64-windows \
lua:x64-windows \
nlohmann-json:x64-windows \
opencv:x64-windows \
proj4:x64-windows \
zlib:x64-windows
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

- name: Install prerequisites
run: |
brew install lua boost postgis pandoc cimg potrace nlohmann-json
brew install boost lua nlohmann-json opencv pandoc postgis potrace
pip3 install psycopg2 behave osmium
pg_ctl -D /usr/local/var/postgres init
pg_ctl -D /usr/local/var/postgres start
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/test-install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ jobs:
sudo apt-get purge -yq postgresql*
sudo apt-get update -qq
sudo apt-get install -yq --no-install-suggests --no-install-recommends \
cimg-dev \
libboost-filesystem-dev \
libboost-system-dev \
libbz2-dev \
libexpat1-dev \
liblua${LUA_VERSION}-dev \
libluajit-5.1-dev \
libopencv-core-dev \
libopencv-imgcodecs-dev \
libopencv-imgproc-dev \
libpotrace-dev \
libpq-dev \
libproj-dev \
Expand Down
11 changes: 5 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ include_directories(SYSTEM ${NLOHMANN_INCLUDE_DIR})
find_path(POTRACE_INCLUDE_DIR potracelib.h)
find_library(POTRACE_LIBRARY NAMES potrace)

find_path(CIMG_INCLUDE_DIR CImg.h)
find_package(OpenCV OPTIONAL_COMPONENTS core imgcodecs imgproc)

############### Libraries are found now ########################

Expand Down Expand Up @@ -284,13 +284,12 @@ add_subdirectory(src)
add_executable(osm2pgsql src/osm2pgsql.cpp)
target_link_libraries(osm2pgsql osm2pgsql_lib ${LIBS})

if (${POTRACE_LIBRARY} STREQUAL "POTRACE_LIBRARY-NOTFOUND" OR ${CIMG_INCLUDE_DIR} STREQUAL "CIMG_INCLUDE_DIR-NOTFOUND")
message(STATUS "Did not find cimg and/or potrace library. Not building osm2pgsql-gen.")
if (${POTRACE_LIBRARY} STREQUAL "POTRACE_LIBRARY-NOTFOUND" OR NOT OPENCV_CORE_FOUND)
message(STATUS "Did not find opencv and/or potrace library. Not building osm2pgsql-gen.")
else()
if (WITH_LUA)
message(STATUS "Found cimg and potrace library. Building osm2pgsql-gen.")
message(STATUS "Found opencv and potrace library. Building osm2pgsql-gen.")
set(BUILD_GEN 1)
include_directories(SYSTEM ${CIMG_INCLUDE_DIR})
include_directories(SYSTEM ${POTRACE_INCLUDE_DIR})
add_executable(osm2pgsql-gen src/gen/osm2pgsql-gen.cpp
src/gen/canvas.cpp
Expand All @@ -305,7 +304,7 @@ else()
src/gen/params.cpp
src/gen/raster.cpp
src/gen/tracer.cpp)
target_link_libraries(osm2pgsql-gen osm2pgsql_lib ${LIBS} ${POTRACE_LIBRARY})
target_link_libraries(osm2pgsql-gen osm2pgsql_lib ${LIBS} ${POTRACE_LIBRARY} ${OpenCV_LIBS})
else()
message(STATUS "No Lua. Not building osm2pgsql-gen.")
endif()
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Required libraries are
* [Boost libraries](https://www.boost.org/), including geometry, system and
filesystem
* [nlohmann/json](https://json.nlohmann.me/)
* [CImg](https://cimg.eu/) (Optional, for generalization only)
* [OpenCV](https://opencv.org/) (Optional, for generalization only)
* [potrace](https://potrace.sourceforge.net/) (Optional, for generalization only)
* [PostgreSQL](https://www.postgresql.org/) client libraries
* [Lua](https://www.lua.org/) (Optional, used for Lua tag transforms
Expand Down Expand Up @@ -83,7 +83,8 @@ On a Debian or Ubuntu system, this can be done with:

```sh
sudo apt-get install make cmake g++ libboost-dev libboost-system-dev \
libboost-filesystem-dev libexpat1-dev zlib1g-dev libpotrace-dev cimg-dev \
libboost-filesystem-dev libexpat1-dev zlib1g-dev libpotrace-dev \
libopencv-core-dev libopencv-imgcodecs-dev libopencv-imgproc-dev \
libbz2-dev libpq-dev libproj-dev lua5.3 liblua5.3-dev pandoc \
nlohmann-json3-dev pyosmium
```
Expand All @@ -92,7 +93,7 @@ On a Fedora system, use

```sh
sudo dnf install cmake make gcc-c++ boost-devel expat-devel zlib-devel \
potrace-devel cimg-devel json-devel python3-osmium \
potrace-devel opencv-devel json-devel python3-osmium \
bzip2-devel postgresql-devel proj-devel proj-epsg lua-devel pandoc
```

Expand All @@ -101,7 +102,7 @@ dependencies with:

```sh
sudo yum install cmake make gcc-c++ boost-devel expat-devel zlib-devel \
potrace-devel cimg-devel json-devel python3-osmium \
potrace-devel opencv-devel json-devel python3-osmium \
bzip2-devel postgresql-devel proj-devel proj-epsg lua-devel pandoc
```

Expand Down
72 changes: 48 additions & 24 deletions src/gen/canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,66 @@
*/

#include "canvas.hpp"

#include "raster.hpp"

cimg_library::CImg<int> canvas_t::create_pointlist(geom::point_list_t const &pl,
tile_t const &tile) const
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>

void canvas_t::open_close(unsigned int buffer_size)
{
cimg_library::CImg<int> points{static_cast<unsigned int>(pl.size()), 2};
auto const kernel1 = cv::getStructuringElement(
cv::MORPH_RECT,
cv::Size(static_cast<int>(buffer_size), static_cast<int>(buffer_size)));
auto const kernel2 = cv::getStructuringElement(
cv::MORPH_RECT, cv::Size(static_cast<int>(buffer_size * 2),
static_cast<int>(buffer_size * 2)));

cv::erode(m_rast, m_rast, kernel1);
cv::dilate(m_rast, m_rast, kernel2);
cv::erode(m_rast, m_rast, kernel1);
}

void canvas_t::create_pointlist(std::vector<cv::Point> *out,
geom::point_list_t const &pl,
tile_t const &tile) const
{
out->reserve(pl.size());

int n = 0;
for (auto const point : pl) {
auto const tp = tile.to_tile_coords(point, m_extent);
points(n, 0) = static_cast<int>(static_cast<double>(m_buffer) + tp.x());
points(n, 1) =
static_cast<int>(static_cast<double>(m_buffer + m_extent) - tp.y());
++n;
auto const x = static_cast<double>(m_buffer) + tp.x();
auto const y = static_cast<double>(m_buffer + m_extent) - tp.y();
out->emplace_back(x, y);
}

return points;
}

std::size_t canvas_t::draw_polygon(geom::polygon_t const &polygon,
tile_t const &tile)
{
if (polygon.inners().empty()) {
m_rast.draw_polygon(create_pointlist(polygon.outer(), tile), &White);
return polygon.outer().size();
}

std::size_t num_points = polygon.outer().size();
m_temp.draw_polygon(create_pointlist(polygon.outer(), tile), &White);

std::vector<std::vector<cv::Point>> poly_data;
poly_data.resize(polygon.inners().size() + 1);

create_pointlist(poly_data.data(), polygon.outer(), tile);
std::size_t n = 1;
for (auto const &inner : polygon.inners()) {
num_points += inner.size();
m_temp.draw_polygon(create_pointlist(inner, tile), &Black);
create_pointlist(&poly_data[n], inner, tile);
n++;
}
m_rast |= m_temp;
cv::fillPoly(m_rast, poly_data, cv::Scalar{255});

return num_points;
}

std::size_t canvas_t::draw_linestring(geom::linestring_t const &linestring,
tile_t const &tile)
{
m_rast.draw_line(create_pointlist(linestring, tile), &White);
std::vector<cv::Point> line_data;
create_pointlist(&line_data, linestring, tile);
cv::polylines(m_rast, line_data, false, cv::Scalar{255});
return linestring.size();
}

Expand Down Expand Up @@ -81,13 +99,13 @@ std::size_t canvas_t::draw(geom::geometry_t const &geometry, tile_t const &tile)

void canvas_t::save(std::string const &filename) const
{
m_rast.save(filename.c_str());
cv::imwrite(filename, m_rast);
}

std::string canvas_t::to_wkb(tile_t const &tile, double margin) const
{
std::string wkb;
wkb.reserve(61 + 2 + m_rast.size());
wkb.reserve(61 + 2 + size() * size());

// header
wkb_raster_header header{};
Expand All @@ -106,18 +124,24 @@ std::string canvas_t::to_wkb(tile_t const &tile, double margin) const
add_raster_band(&wkb, band);

// rasterdata
wkb.append(reinterpret_cast<char const *>(m_rast.data()), m_rast.size());
wkb.append(reinterpret_cast<char const *>(begin()),
reinterpret_cast<char const *>(end()));

assert(wkb.size() == 61 + 2 + m_rast.size());
assert(wkb.size() == 61 + 2 + size() * size());

return wkb;
}

void canvas_t::merge(canvas_t const &other) { m_rast |= other.m_rast; }
void canvas_t::merge(canvas_t const &other)
{
cv::bitwise_or(m_rast, other.m_rast, m_rast);
}

std::string to_hex(std::string const &in)
{
std::string result;
result.reserve(in.size() * 2);

char const *const lookup_hex = "0123456789ABCDEF";

for (const auto c : in) {
Expand Down
43 changes: 17 additions & 26 deletions src/gen/canvas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,42 @@
#include "geom.hpp"
#include "tile.hpp"

#define cimg_display 0 // NOLINT(cppcoreguidelines-macro-usage)
#include "CImg.h"
#include <opencv2/core.hpp>

#include <cstddef>

/**
* This class wraps the image class from the CImg library.
* This class wraps the image class from the OpenCV library.
*/
class canvas_t
{
public:
static void info() { cimg_library::cimg::info(); }

/**
* Create a new image canvas. It will be quadratic and have the width and
* height extent + 2*buffer.
*/
canvas_t(std::size_t extent, std::size_t buffer)
: m_extent(extent),
m_buffer(buffer), m_rast{size(), size(), 1, 1, 0}, m_temp{size(), size(),
1, 1, 0}
{}
: m_extent(extent), m_buffer(buffer), m_rast{static_cast<int>(size()),
static_cast<int>(size()),
CV_8UC1, cv::Scalar::all(0)}
{
}

unsigned int size() const noexcept
{
return static_cast<unsigned int>(m_extent + 2 * m_buffer);
}

unsigned char const *begin() const noexcept { return m_rast.begin(); }
unsigned char const *end() const noexcept { return m_rast.end(); }

std::size_t draw(geom::geometry_t const &geometry, tile_t const &tile);
unsigned char const *begin() const noexcept { return m_rast.data; }

unsigned char operator()(int x, int y) const noexcept
unsigned char const *end() const noexcept
{
return m_rast(x, y, 0, 0);
return m_rast.data + (static_cast<size_t>(size() * size()));
}

void open_close(unsigned int buffer_size)
{
m_rast.dilate(buffer_size).erode(buffer_size * 2).dilate(buffer_size);
}
std::size_t draw(geom::geometry_t const &geometry, tile_t const &tile);

void open_close(unsigned int buffer_size);

void save(std::string const &filename) const;

Expand All @@ -63,13 +57,11 @@ class canvas_t
void merge(canvas_t const &other);

private:
constexpr static unsigned char const Black = 0;
constexpr static unsigned char const White = 255;

using image_type = cimg_library::CImg<unsigned char>;
using image_type = cv::Mat;

cimg_library::CImg<int> create_pointlist(geom::point_list_t const &pl,
tile_t const &tile) const;
void create_pointlist(std::vector<cv::Point> *out,
geom::point_list_t const &pl,
tile_t const &tile) const;

std::size_t draw_polygon(geom::polygon_t const &polygon,
tile_t const &tile);
Expand All @@ -80,7 +72,6 @@ class canvas_t
std::size_t m_extent;
std::size_t m_buffer;
image_type m_rast;
image_type m_temp;
}; // class canvas_t

std::string to_hex(std::string const &in);
Expand Down
1 change: 0 additions & 1 deletion src/gen/osm2pgsql-gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,6 @@ int main(int argc, char *argv[])
break;
case 'V': // --version
log_info("osm2pgsql-gen version {}", get_osm2pgsql_version());
canvas_t::info();
return 0;
case 201: // --log-sql
get_logger().enable_sql();
Expand Down

0 comments on commit 374eca4

Please sign in to comment.