Skip to content

Commit 374eca4

Browse files
authored
Merge pull request #2084 from joto/switch-cimg-to-opencv
Generalization: Switch from using CImg to OpenCV library.
2 parents faf2097 + 845995c commit 374eca4

File tree

9 files changed

+83
-65
lines changed

9 files changed

+83
-65
lines changed

.github/actions/ubuntu-prerequisites/action.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ runs:
1616
- name: Install software
1717
run: |
1818
sudo apt-get install -yq --no-install-suggests --no-install-recommends \
19-
cimg-dev \
2019
libboost-filesystem-dev \
2120
libboost-system-dev \
2221
libbz2-dev \
2322
libexpat1-dev \
23+
libopencv-core-dev \
24+
libopencv-imgcodecs-dev \
25+
libopencv-imgproc-dev \
2426
libpotrace-dev \
2527
libpq-dev \
2628
libproj-dev \

.github/actions/win-install/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ runs:
1212
boost-property-tree:x64-windows \
1313
boost-system:x64-windows \
1414
bzip2:x64-windows \
15-
cimg:x64-windows \
1615
expat:x64-windows \
1716
libpq:x64-windows \
1817
lua:x64-windows \
1918
nlohmann-json:x64-windows \
19+
opencv:x64-windows \
2020
proj4:x64-windows \
2121
zlib:x64-windows
2222
shell: bash

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121

2222
- name: Install prerequisites
2323
run: |
24-
brew install lua boost postgis pandoc cimg potrace nlohmann-json
24+
brew install boost lua nlohmann-json opencv pandoc postgis potrace
2525
pip3 install psycopg2 behave osmium
2626
pg_ctl -D /usr/local/var/postgres init
2727
pg_ctl -D /usr/local/var/postgres start

.github/workflows/test-install.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ jobs:
3838
sudo apt-get purge -yq postgresql*
3939
sudo apt-get update -qq
4040
sudo apt-get install -yq --no-install-suggests --no-install-recommends \
41-
cimg-dev \
4241
libboost-filesystem-dev \
4342
libboost-system-dev \
4443
libbz2-dev \
4544
libexpat1-dev \
4645
liblua${LUA_VERSION}-dev \
4746
libluajit-5.1-dev \
47+
libopencv-core-dev \
48+
libopencv-imgcodecs-dev \
49+
libopencv-imgproc-dev \
4850
libpotrace-dev \
4951
libpq-dev \
5052
libproj-dev \

CMakeLists.txt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ include_directories(SYSTEM ${NLOHMANN_INCLUDE_DIR})
211211
find_path(POTRACE_INCLUDE_DIR potracelib.h)
212212
find_library(POTRACE_LIBRARY NAMES potrace)
213213

214-
find_path(CIMG_INCLUDE_DIR CImg.h)
214+
find_package(OpenCV OPTIONAL_COMPONENTS core imgcodecs imgproc)
215215

216216
############### Libraries are found now ########################
217217

@@ -284,13 +284,12 @@ add_subdirectory(src)
284284
add_executable(osm2pgsql src/osm2pgsql.cpp)
285285
target_link_libraries(osm2pgsql osm2pgsql_lib ${LIBS})
286286

287-
if (${POTRACE_LIBRARY} STREQUAL "POTRACE_LIBRARY-NOTFOUND" OR ${CIMG_INCLUDE_DIR} STREQUAL "CIMG_INCLUDE_DIR-NOTFOUND")
288-
message(STATUS "Did not find cimg and/or potrace library. Not building osm2pgsql-gen.")
287+
if (${POTRACE_LIBRARY} STREQUAL "POTRACE_LIBRARY-NOTFOUND" OR NOT OPENCV_CORE_FOUND)
288+
message(STATUS "Did not find opencv and/or potrace library. Not building osm2pgsql-gen.")
289289
else()
290290
if (WITH_LUA)
291-
message(STATUS "Found cimg and potrace library. Building osm2pgsql-gen.")
291+
message(STATUS "Found opencv and potrace library. Building osm2pgsql-gen.")
292292
set(BUILD_GEN 1)
293-
include_directories(SYSTEM ${CIMG_INCLUDE_DIR})
294293
include_directories(SYSTEM ${POTRACE_INCLUDE_DIR})
295294
add_executable(osm2pgsql-gen src/gen/osm2pgsql-gen.cpp
296295
src/gen/canvas.cpp
@@ -305,7 +304,7 @@ else()
305304
src/gen/params.cpp
306305
src/gen/raster.cpp
307306
src/gen/tracer.cpp)
308-
target_link_libraries(osm2pgsql-gen osm2pgsql_lib ${LIBS} ${POTRACE_LIBRARY})
307+
target_link_libraries(osm2pgsql-gen osm2pgsql_lib ${LIBS} ${POTRACE_LIBRARY} ${OpenCV_LIBS})
309308
else()
310309
message(STATUS "No Lua. Not building osm2pgsql-gen.")
311310
endif()

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Required libraries are
5050
* [Boost libraries](https://www.boost.org/), including geometry, system and
5151
filesystem
5252
* [nlohmann/json](https://json.nlohmann.me/)
53-
* [CImg](https://cimg.eu/) (Optional, for generalization only)
53+
* [OpenCV](https://opencv.org/) (Optional, for generalization only)
5454
* [potrace](https://potrace.sourceforge.net/) (Optional, for generalization only)
5555
* [PostgreSQL](https://www.postgresql.org/) client libraries
5656
* [Lua](https://www.lua.org/) (Optional, used for Lua tag transforms
@@ -83,7 +83,8 @@ On a Debian or Ubuntu system, this can be done with:
8383

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

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

@@ -101,7 +102,7 @@ dependencies with:
101102

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

src/gen/canvas.cpp

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,48 +8,66 @@
88
*/
99

1010
#include "canvas.hpp"
11+
1112
#include "raster.hpp"
1213

13-
cimg_library::CImg<int> canvas_t::create_pointlist(geom::point_list_t const &pl,
14-
tile_t const &tile) const
14+
#include <opencv2/imgcodecs.hpp>
15+
#include <opencv2/imgproc.hpp>
16+
17+
void canvas_t::open_close(unsigned int buffer_size)
1518
{
16-
cimg_library::CImg<int> points{static_cast<unsigned int>(pl.size()), 2};
19+
auto const kernel1 = cv::getStructuringElement(
20+
cv::MORPH_RECT,
21+
cv::Size(static_cast<int>(buffer_size), static_cast<int>(buffer_size)));
22+
auto const kernel2 = cv::getStructuringElement(
23+
cv::MORPH_RECT, cv::Size(static_cast<int>(buffer_size * 2),
24+
static_cast<int>(buffer_size * 2)));
25+
26+
cv::erode(m_rast, m_rast, kernel1);
27+
cv::dilate(m_rast, m_rast, kernel2);
28+
cv::erode(m_rast, m_rast, kernel1);
29+
}
30+
31+
void canvas_t::create_pointlist(std::vector<cv::Point> *out,
32+
geom::point_list_t const &pl,
33+
tile_t const &tile) const
34+
{
35+
out->reserve(pl.size());
1736

18-
int n = 0;
1937
for (auto const point : pl) {
2038
auto const tp = tile.to_tile_coords(point, m_extent);
21-
points(n, 0) = static_cast<int>(static_cast<double>(m_buffer) + tp.x());
22-
points(n, 1) =
23-
static_cast<int>(static_cast<double>(m_buffer + m_extent) - tp.y());
24-
++n;
39+
auto const x = static_cast<double>(m_buffer) + tp.x();
40+
auto const y = static_cast<double>(m_buffer + m_extent) - tp.y();
41+
out->emplace_back(x, y);
2542
}
26-
27-
return points;
2843
}
2944

3045
std::size_t canvas_t::draw_polygon(geom::polygon_t const &polygon,
3146
tile_t const &tile)
3247
{
33-
if (polygon.inners().empty()) {
34-
m_rast.draw_polygon(create_pointlist(polygon.outer(), tile), &White);
35-
return polygon.outer().size();
36-
}
37-
3848
std::size_t num_points = polygon.outer().size();
39-
m_temp.draw_polygon(create_pointlist(polygon.outer(), tile), &White);
49+
50+
std::vector<std::vector<cv::Point>> poly_data;
51+
poly_data.resize(polygon.inners().size() + 1);
52+
53+
create_pointlist(poly_data.data(), polygon.outer(), tile);
54+
std::size_t n = 1;
4055
for (auto const &inner : polygon.inners()) {
4156
num_points += inner.size();
42-
m_temp.draw_polygon(create_pointlist(inner, tile), &Black);
57+
create_pointlist(&poly_data[n], inner, tile);
58+
n++;
4359
}
44-
m_rast |= m_temp;
60+
cv::fillPoly(m_rast, poly_data, cv::Scalar{255});
4561

4662
return num_points;
4763
}
4864

4965
std::size_t canvas_t::draw_linestring(geom::linestring_t const &linestring,
5066
tile_t const &tile)
5167
{
52-
m_rast.draw_line(create_pointlist(linestring, tile), &White);
68+
std::vector<cv::Point> line_data;
69+
create_pointlist(&line_data, linestring, tile);
70+
cv::polylines(m_rast, line_data, false, cv::Scalar{255});
5371
return linestring.size();
5472
}
5573

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

82100
void canvas_t::save(std::string const &filename) const
83101
{
84-
m_rast.save(filename.c_str());
102+
cv::imwrite(filename, m_rast);
85103
}
86104

87105
std::string canvas_t::to_wkb(tile_t const &tile, double margin) const
88106
{
89107
std::string wkb;
90-
wkb.reserve(61 + 2 + m_rast.size());
108+
wkb.reserve(61 + 2 + size() * size());
91109

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

108126
// rasterdata
109-
wkb.append(reinterpret_cast<char const *>(m_rast.data()), m_rast.size());
127+
wkb.append(reinterpret_cast<char const *>(begin()),
128+
reinterpret_cast<char const *>(end()));
110129

111-
assert(wkb.size() == 61 + 2 + m_rast.size());
130+
assert(wkb.size() == 61 + 2 + size() * size());
112131

113132
return wkb;
114133
}
115134

116-
void canvas_t::merge(canvas_t const &other) { m_rast |= other.m_rast; }
135+
void canvas_t::merge(canvas_t const &other)
136+
{
137+
cv::bitwise_or(m_rast, other.m_rast, m_rast);
138+
}
117139

118140
std::string to_hex(std::string const &in)
119141
{
120142
std::string result;
143+
result.reserve(in.size() * 2);
144+
121145
char const *const lookup_hex = "0123456789ABCDEF";
122146

123147
for (const auto c : in) {

src/gen/canvas.hpp

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,42 @@
1313
#include "geom.hpp"
1414
#include "tile.hpp"
1515

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

1918
#include <cstddef>
2019

2120
/**
22-
* This class wraps the image class from the CImg library.
21+
* This class wraps the image class from the OpenCV library.
2322
*/
2423
class canvas_t
2524
{
2625
public:
27-
static void info() { cimg_library::cimg::info(); }
28-
2926
/**
3027
* Create a new image canvas. It will be quadratic and have the width and
3128
* height extent + 2*buffer.
3229
*/
3330
canvas_t(std::size_t extent, std::size_t buffer)
34-
: m_extent(extent),
35-
m_buffer(buffer), m_rast{size(), size(), 1, 1, 0}, m_temp{size(), size(),
36-
1, 1, 0}
37-
{}
31+
: m_extent(extent), m_buffer(buffer), m_rast{static_cast<int>(size()),
32+
static_cast<int>(size()),
33+
CV_8UC1, cv::Scalar::all(0)}
34+
{
35+
}
3836

3937
unsigned int size() const noexcept
4038
{
4139
return static_cast<unsigned int>(m_extent + 2 * m_buffer);
4240
}
4341

44-
unsigned char const *begin() const noexcept { return m_rast.begin(); }
45-
unsigned char const *end() const noexcept { return m_rast.end(); }
46-
47-
std::size_t draw(geom::geometry_t const &geometry, tile_t const &tile);
42+
unsigned char const *begin() const noexcept { return m_rast.data; }
4843

49-
unsigned char operator()(int x, int y) const noexcept
44+
unsigned char const *end() const noexcept
5045
{
51-
return m_rast(x, y, 0, 0);
46+
return m_rast.data + (static_cast<size_t>(size() * size()));
5247
}
5348

54-
void open_close(unsigned int buffer_size)
55-
{
56-
m_rast.dilate(buffer_size).erode(buffer_size * 2).dilate(buffer_size);
57-
}
49+
std::size_t draw(geom::geometry_t const &geometry, tile_t const &tile);
50+
51+
void open_close(unsigned int buffer_size);
5852

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

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

6559
private:
66-
constexpr static unsigned char const Black = 0;
67-
constexpr static unsigned char const White = 255;
68-
69-
using image_type = cimg_library::CImg<unsigned char>;
60+
using image_type = cv::Mat;
7061

71-
cimg_library::CImg<int> create_pointlist(geom::point_list_t const &pl,
72-
tile_t const &tile) const;
62+
void create_pointlist(std::vector<cv::Point> *out,
63+
geom::point_list_t const &pl,
64+
tile_t const &tile) const;
7365

7466
std::size_t draw_polygon(geom::polygon_t const &polygon,
7567
tile_t const &tile);
@@ -80,7 +72,6 @@ class canvas_t
8072
std::size_t m_extent;
8173
std::size_t m_buffer;
8274
image_type m_rast;
83-
image_type m_temp;
8475
}; // class canvas_t
8576

8677
std::string to_hex(std::string const &in);

src/gen/osm2pgsql-gen.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,6 @@ int main(int argc, char *argv[])
710710
break;
711711
case 'V': // --version
712712
log_info("osm2pgsql-gen version {}", get_osm2pgsql_version());
713-
canvas_t::info();
714713
return 0;
715714
case 201: // --log-sql
716715
get_logger().enable_sql();

0 commit comments

Comments
 (0)