2
* gdal_image.cpp -- Load GIS data into OpenCV Containers using the Geospatial Data Abstraction Library
6
#include "opencv2/core/core.hpp"
7
#include "opencv2/imgproc/imgproc.hpp"
8
#include "opencv2/highgui/highgui.hpp"
10
// C++ Standard Libraries
18
// define the corner points
19
// Note that GDAL library can natively determine this
20
cv::Point2d tl( -122.441017, 37.815664 );
21
cv::Point2d tr( -122.370919, 37.815311 );
22
cv::Point2d bl( -122.441533, 37.747167 );
23
cv::Point2d br( -122.3715, 37.746814 );
25
// determine dem corners
26
cv::Point2d dem_bl( -122.0, 38);
27
cv::Point2d dem_tr( -123.0, 37);
29
// range of the heat map colors
30
std::vector<std::pair<cv::Vec3b,double> > color_range;
33
// List of all function prototypes
34
cv::Point2d lerp( const cv::Point2d&, const cv::Point2d&, const double& );
36
cv::Vec3b get_dem_color( const double& );
38
cv::Point2d world2dem( const cv::Point2d&, const cv::Size&);
40
cv::Point2d pixel2world( const int&, const int&, const cv::Size& );
42
void add_color( cv::Vec3b& pix, const uchar& b, const uchar& g, const uchar& r );
47
* Linear Interpolation
50
* t - Ratio from Point 1 to Point 2
52
cv::Point2d lerp( cv::Point2d const& p1, cv::Point2d const& p2, const double& t ){
53
return cv::Point2d( ((1-t)*p1.x) + (t*p2.x),
54
((1-t)*p1.y) + (t*p2.y));
60
template <typename DATATYPE, int N>
61
cv::Vec<DATATYPE,N> lerp( cv::Vec<DATATYPE,N> const& minColor,
62
cv::Vec<DATATYPE,N> const& maxColor,
65
cv::Vec<DATATYPE,N> output;
66
for( int i=0; i<N; i++ ){
67
output[i] = (uchar)(((1-t)*minColor[i]) + (t * maxColor[i]));
73
* Compute the dem color
75
cv::Vec3b get_dem_color( const double& elevation ){
77
// if the elevation is below the minimum, return the minimum
78
if( elevation < color_range[0].second ){
79
return color_range[0].first;
81
// if the elevation is above the maximum, return the maximum
82
if( elevation > color_range.back().second ){
83
return color_range.back().first;
86
// otherwise, find the proper starting index
89
for( int x=0; x<(int)(color_range.size()-1); x++ ){
91
// if the current elevation is below the next item, then use the current
92
// two colors as our range
93
if( elevation < color_range[x+1].second ){
95
t = (color_range[x+1].second - elevation)/
96
(color_range[x+1].second - color_range[x].second);
102
// interpolate the color
103
return lerp( color_range[idx].first, color_range[idx+1].first, t);
107
* Given a pixel coordinate and the size of the input image, compute the pixel location
110
cv::Point2d world2dem( cv::Point2d const& coordinate, const cv::Size& dem_size ){
113
// relate this to the dem points
114
// ASSUMING THAT DEM DATA IS ORTHORECTIFIED
115
double demRatioX = ((dem_tr.x - coordinate.x)/(dem_tr.x - dem_bl.x));
116
double demRatioY = 1-((dem_tr.y - coordinate.y)/(dem_tr.y - dem_bl.y));
119
output.x = demRatioX * dem_size.width;
120
output.y = demRatioY * dem_size.height;
126
* Convert a pixel coordinate to world coordinates
128
cv::Point2d pixel2world( const int& x, const int& y, const cv::Size& size ){
130
// compute the ratio of the pixel location to its dimension
131
double rx = (double)x / size.width;
132
double ry = (double)y / size.height;
134
// compute LERP of each coordinate
135
cv::Point2d rightSide = lerp(tr, br, ry);
136
cv::Point2d leftSide = lerp(tl, bl, ry);
138
// compute the actual Lat/Lon coordinate of the interpolated coordinate
139
return lerp( leftSide, rightSide, rx );
143
* Add color to a specific pixel color value
145
void add_color( cv::Vec3b& pix, const uchar& b, const uchar& g, const uchar& r ){
147
if( pix[0] + b < 255 && pix[0] + b >= 0 ){ pix[0] += b; }
148
if( pix[1] + g < 255 && pix[1] + g >= 0 ){ pix[1] += g; }
149
if( pix[2] + r < 255 && pix[2] + r >= 0 ){ pix[2] += r; }
156
int main( int argc, char* argv[] ){
159
* Check input arguments
162
cout << "usage: " << argv[0] << " <image> <dem>" << endl;
166
// load the image (note that we don't have the projection information. You will
167
// need to load that yourself or use the full GDAL driver. The values are pre-defined
168
// at the top of this file
169
cv::Mat image = cv::imread(argv[1], cv::IMREAD_LOAD_GDAL | cv::IMREAD_COLOR );
171
// load the dem model
172
cv::Mat dem = cv::imread(argv[2], cv::IMREAD_LOAD_GDAL | cv::IMREAD_ANYDEPTH );
174
// create our output products
175
cv::Mat output_dem( image.size(), CV_8UC3 );
176
cv::Mat output_dem_flood( image.size(), CV_8UC3 );
178
// for sanity sake, make sure GDAL Loads it as a signed short
179
if( dem.type() != CV_16SC1 ){ throw std::runtime_error("DEM image type must be CV_16SC1"); }
181
// define the color range to create our output DEM heat map
182
// Pair format ( Color, elevation ); Push from low to high
183
// Note: This would be perfect for a configuration file, but is here for a working demo.
184
color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 188, 154, 46), -1));
185
color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 110, 220, 110), 0.25));
186
color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 150, 250, 230), 20));
187
color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 160, 220, 200), 75));
188
color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 220, 190, 170), 100));
189
color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 250, 180, 140), 200));
191
// define a minimum elevation
192
double minElevation = -10;
194
// iterate over each pixel in the image, computing the dem point
195
for( int y=0; y<image.rows; y++ ){
196
for( int x=0; x<image.cols; x++ ){
198
// convert the pixel coordinate to lat/lon coordinates
199
cv::Point2d coordinate = pixel2world( x, y, image.size() );
201
// compute the dem image pixel coordinate from lat/lon
202
cv::Point2d dem_coordinate = world2dem( coordinate, dem.size() );
204
// extract the elevation
206
if( dem_coordinate.x >= 0 && dem_coordinate.y >= 0 &&
207
dem_coordinate.x < dem.cols && dem_coordinate.y < dem.rows ){
208
dz = dem.at<short>(dem_coordinate);
213
// write the pixel value to the file
214
output_dem_flood.at<cv::Vec3b>(y,x) = image.at<cv::Vec3b>(y,x);
216
// compute the color for the heat map output
217
cv::Vec3b actualColor = get_dem_color(dz);
218
output_dem.at<cv::Vec3b>(y,x) = actualColor;
220
// show effect of a 10 meter increase in ocean levels
222
add_color( output_dem_flood.at<cv::Vec3b>(y,x), 90, 0, 0 );
224
// show effect of a 50 meter increase in ocean levels
226
add_color( output_dem_flood.at<cv::Vec3b>(y,x), 0, 90, 0 );
228
// show effect of a 100 meter increase in ocean levels
230
add_color( output_dem_flood.at<cv::Vec3b>(y,x), 0, 0, 90 );
235
// print our heat map
236
cv::imwrite( "heat-map.jpg" , output_dem );
238
// print the flooding effect image
239
cv::imwrite( "flooded.jpg", output_dem_flood);