image.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifdef _MSC_VER
  9. #pragma warning(disable : 4244) // conversion from 'gil::image<V,Alloc>::coord_t' to 'int', possible loss of data (visual studio compiler doesn't realize that the two types are the same)
  10. #pragma warning(disable : 4503) // decorated name length exceeded, name was truncated
  11. #pragma warning(disable : 4701) // potentially uninitialized local variable 'result' used in boost/crc.hpp
  12. #endif
  13. #include <boost/gil.hpp>
  14. #include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
  15. #include <boost/core/ignore_unused.hpp>
  16. #include <boost/crc.hpp>
  17. #include <boost/mp11.hpp>
  18. #include <ios>
  19. #include <iostream>
  20. #include <fstream>
  21. #include <map>
  22. #include <stdexcept>
  23. #include <string>
  24. #include <type_traits>
  25. #include <vector>
  26. using namespace boost::gil;
  27. using namespace std;
  28. using namespace boost;
  29. extern rgb8c_planar_view_t sample_view;
  30. void error_if(bool condition);
  31. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  32. #pragma warning(push)
  33. #pragma warning(disable:4127) //conditional expression is constant
  34. #endif
  35. // When BOOST_GIL_GENERATE_REFERENCE_DATA is defined, the reference data is generated and saved.
  36. // When it is undefined, regression tests are checked against it
  37. //#define BOOST_GIL_GENERATE_REFERENCE_DATA
  38. ////////////////////////////////////////////////////
  39. ///
  40. /// Some algorithms to use in testing
  41. ///
  42. ////////////////////////////////////////////////////
  43. template <typename GrayView, typename R>
  44. void gray_image_hist(GrayView const& img_view, R& hist)
  45. {
  46. for (auto it = img_view.begin(); it != img_view.end(); ++it)
  47. ++hist[*it];
  48. // Alternatively, prefer the algorithm with lambda
  49. // for_each_pixel(img_view, [&hist](gray8_pixel_t const& pixel) {
  50. // ++hist[pixel];
  51. // });
  52. }
  53. template <typename V, typename R>
  54. void get_hist(const V& img_view, R& hist) {
  55. gray_image_hist(color_converted_view<gray8_pixel_t>(img_view), hist);
  56. }
  57. // testing custom color conversion
  58. template <typename C1, typename C2>
  59. struct my_color_converter_impl : public default_color_converter_impl<C1,C2> {};
  60. template <typename C1>
  61. struct my_color_converter_impl<C1,gray_t> {
  62. template <typename P1, typename P2>
  63. void operator()(const P1& src, P2& dst) const {
  64. default_color_converter_impl<C1,gray_t>()(src,dst);
  65. get_color(dst,gray_color_t())=channel_invert(get_color(dst,gray_color_t()));
  66. }
  67. };
  68. struct my_color_converter {
  69. template <typename SrcP,typename DstP>
  70. void operator()(const SrcP& src,DstP& dst) const {
  71. using src_cs_t = typename color_space_type<SrcP>::type;
  72. using dst_cs_t = typename color_space_type<DstP>::type;
  73. my_color_converter_impl<src_cs_t,dst_cs_t>()(src,dst);
  74. }
  75. };
  76. /// Models a Unary Function
  77. /// \tparam P models PixelValueConcept
  78. template <typename P>
  79. struct mandelbrot_fn
  80. {
  81. using point_t = boost::gil::point_t;
  82. using const_t = mandelbrot_fn<P>;
  83. using value_type = P;
  84. using reference = value_type;
  85. using const_reference = value_type;
  86. using argument_type = point_t;
  87. using result_type = reference;
  88. static constexpr bool is_mutable = false;
  89. value_type _in_color,_out_color;
  90. point_t _img_size;
  91. static const int MAX_ITER=100; // max number of iterations
  92. mandelbrot_fn() {}
  93. mandelbrot_fn(const point_t& sz, const value_type& in_color, const value_type& out_color) : _in_color(in_color), _out_color(out_color), _img_size(sz) {}
  94. result_type operator()(const point_t& p) const {
  95. // normalize the coords to (-2..1, -1.5..1.5)
  96. // (actually make y -1.0..2 so it is asymmetric, so we can verify some view factory methods)
  97. double t=get_num_iter(point<double>(p.x/(double)_img_size.x*3-2, p.y/(double)_img_size.y*3-1.0f));//1.5f));
  98. t=pow(t,0.2);
  99. value_type ret;
  100. for (int k=0; k<num_channels<P>::value; ++k)
  101. ret[k]=(typename channel_type<value_type>::type)(_in_color[k]*t + _out_color[k]*(1-t));
  102. return ret;
  103. }
  104. private:
  105. double get_num_iter(const point<double>& p) const {
  106. point<double> Z(0,0);
  107. for (int i=0; i<MAX_ITER; ++i) {
  108. Z = point<double>(Z.x*Z.x - Z.y*Z.y + p.x, 2*Z.x*Z.y + p.y);
  109. if (Z.x*Z.x + Z.y*Z.y > 4)
  110. return i/(double)MAX_ITER;
  111. }
  112. return 0;
  113. }
  114. };
  115. template <typename T>
  116. void x_gradient(const T& src, const gray8s_view_t& dst) {
  117. for (int y=0; y<src.height(); ++y) {
  118. typename T::x_iterator src_it = src.row_begin(y);
  119. gray8s_view_t::x_iterator dst_it = dst.row_begin(y);
  120. for (int x=1; x<src.width()-1; ++x)
  121. dst_it[x] = (src_it[x+1] - src_it[x-1]) / 2;
  122. }
  123. }
  124. // A quick test whether a view is homogeneous
  125. template <typename Pixel>
  126. struct pixel_is_homogeneous : public std::true_type {};
  127. template <typename P, typename C, typename L>
  128. struct pixel_is_homogeneous<packed_pixel<P,C,L> > : public std::false_type {};
  129. template <typename View>
  130. struct view_is_homogeneous : public pixel_is_homogeneous<typename View::value_type> {};
  131. ////////////////////////////////////////////////////
  132. ///
  133. /// Tests image view transformations and algorithms
  134. ///
  135. ////////////////////////////////////////////////////
  136. class image_test {
  137. public:
  138. virtual void initialize() {}
  139. virtual void finalize() {}
  140. virtual ~image_test() {}
  141. void run();
  142. protected:
  143. virtual void check_view_impl(const rgb8c_view_t& view, const string& name)=0;
  144. template <typename View>
  145. void check_view(const View& img_view, const string& name) {
  146. rgb8_image_t rgb_img(img_view.dimensions());
  147. copy_and_convert_pixels(img_view,view(rgb_img));
  148. check_view_impl(const_view(rgb_img), name);
  149. }
  150. private:
  151. template <typename Img> void basic_test(const string& prefix);
  152. template <typename View> void view_transformations_test(const View& img_view, const string& prefix);
  153. template <typename View> void homogeneous_view_transformations_test(const View& img_view, const string& prefix, std::true_type);
  154. template <typename View> void homogeneous_view_transformations_test(const View& img_view, const string& prefix, std::false_type)
  155. {
  156. boost::ignore_unused(img_view);
  157. boost::ignore_unused(prefix);
  158. }
  159. template <typename View> void histogram_test(const View& img_view, const string& prefix);
  160. void virtual_view_test();
  161. void packed_image_test();
  162. void dynamic_image_test();
  163. template <typename Img> void image_all_test(const string& prefix);
  164. };
  165. // testing image iterators, clone, fill, locators, color convert
  166. template <typename Img>
  167. void image_test::basic_test(const string& prefix) {
  168. using View = typename Img::view_t;
  169. // make a 20x20 image
  170. Img img(typename View::point_t(20,20));
  171. const View& img_view=view(img);
  172. // fill it with red
  173. rgb8_pixel_t red8(255,0,0), green8(0,255,0), blue8(0,0,255), white8(255,255,255);
  174. typename View::value_type red,green,blue,white;
  175. color_convert(red8,red);
  176. default_color_converter()(red8,red);
  177. red=color_convert_deref_fn<rgb8_ref_t,typename Img::view_t::value_type>()(red8);
  178. color_convert(green8,green);
  179. color_convert(blue8,blue);
  180. color_convert(white8,white);
  181. fill(img_view.begin(),img_view.end(),red);
  182. color_convert(red8,img_view[0]);
  183. // pointer to first pixel of second row
  184. typename View::reference rt=img_view.at(0,0)[img_view.width()];
  185. typename View::x_iterator ptr=&rt;
  186. typename View::reference rt2=*(img_view.at(0,0)+img_view.width());
  187. typename View::x_iterator ptr2=&rt2;
  188. error_if(ptr!=ptr2);
  189. error_if(img_view.x_at(0,0)+10!=10+img_view.x_at(0,0));
  190. // draw a blue line along the diagonal
  191. typename View::xy_locator loc=img_view.xy_at(0,img_view.height()-1);
  192. for (int y=0; y<img_view.height(); ++y) {
  193. *loc=blue;
  194. ++loc.x();
  195. loc.y()--;
  196. }
  197. // draw a green dotted line along the main diagonal with step of 3
  198. loc=img_view.xy_at(img_view.width()-1,img_view.height()-1);
  199. while (loc.x()>=img_view.x_at(0,0)) {
  200. *loc=green;
  201. loc-=typename View::point_t(3,3);
  202. }
  203. // Clone and make every red pixel white
  204. Img imgWhite(img);
  205. for (typename View::iterator it=view(imgWhite).end(); (it-1)!=view(imgWhite).begin(); --it) {
  206. if (*(it-1)==red)
  207. *(it-1)=white;
  208. }
  209. check_view(img_view,prefix+"red_x");
  210. check_view(view(imgWhite),prefix+"white_x");
  211. }
  212. template <typename View>
  213. void image_test::histogram_test(const View& img_view, const string& prefix) {
  214. // vector<int> histogram(255,0);
  215. // get_hist(cropped,histogram.begin());
  216. unsigned char histogram[256];
  217. fill(histogram,histogram+256,0);
  218. get_hist(img_view,histogram);
  219. gray8c_view_t hist_view=interleaved_view(256,1,(const gray8_pixel_t*)histogram,256);
  220. check_view(hist_view,prefix+"histogram");
  221. }
  222. template <typename View>
  223. void image_test::view_transformations_test(const View& img_view, const string& prefix) {
  224. check_view(img_view,prefix+"original");
  225. check_view(subimage_view(img_view, iround(img_view.dimensions()/4), iround(img_view.dimensions()/2)),prefix+"cropped");
  226. check_view(color_converted_view<gray8_pixel_t>(img_view),prefix+"gray8");
  227. check_view(color_converted_view<gray8_pixel_t>(img_view,my_color_converter()),prefix+"my_gray8");
  228. check_view(transposed_view(img_view),prefix+"transpose");
  229. check_view(rotated180_view(img_view),prefix+"rot180");
  230. check_view(rotated90cw_view(img_view),prefix+"90cw");
  231. check_view(rotated90ccw_view(img_view),prefix+"90ccw");
  232. check_view(flipped_up_down_view(img_view),prefix+"flipped_ud");
  233. check_view(flipped_left_right_view(img_view),prefix+"flipped_lr");
  234. check_view(subsampled_view(img_view,typename View::point_t(2,1)),prefix+"subsampled");
  235. check_view(kth_channel_view<0>(img_view),prefix+"0th_k_channel");
  236. homogeneous_view_transformations_test(img_view, prefix, view_is_homogeneous<View>());
  237. }
  238. template <typename View>
  239. void image_test::homogeneous_view_transformations_test(const View& img_view, const string& prefix, std::true_type) {
  240. check_view(nth_channel_view(img_view,0),prefix+"0th_n_channel");
  241. }
  242. void image_test::virtual_view_test()
  243. {
  244. using deref_t = mandelbrot_fn<rgb8_pixel_t>;
  245. using point_t = deref_t::point_t;
  246. using locator_t = virtual_2d_locator<deref_t, false>;
  247. using my_virt_view_t = image_view<locator_t>;
  248. boost::function_requires<PixelLocatorConcept<locator_t> >();
  249. gil_function_requires<StepIteratorConcept<locator_t::x_iterator> >();
  250. point_t dims(200,200);
  251. my_virt_view_t mandel(dims, locator_t(point_t(0,0), point_t(1,1), deref_t(dims, rgb8_pixel_t(255,0,255), rgb8_pixel_t(0,255,0))));
  252. gray8s_image_t img(dims);
  253. fill_pixels(view(img),0); // our x_gradient algorithm doesn't change the first & last column, so make sure they are 0
  254. x_gradient(color_converted_view<gray8_pixel_t>(mandel), view(img));
  255. check_view(color_converted_view<gray8_pixel_t>(const_view(img)), "mandelLuminosityGradient");
  256. view_transformations_test(mandel,"virtual_");
  257. histogram_test(mandel,"virtual_");
  258. }
  259. // Test alignment and packed images
  260. void image_test::packed_image_test()
  261. {
  262. using bgr131_image_t = bit_aligned_image3_type<1,3,1, bgr_layout_t>::type;
  263. using bgr131_pixel_t = bgr131_image_t::value_type;
  264. bgr131_pixel_t fill_val(1,3,1);
  265. bgr131_image_t bgr131_img(3,10);
  266. fill_pixels(view(bgr131_img), fill_val);
  267. bgr131_image_t bgr131a_img(3,10,1);
  268. copy_pixels(const_view(bgr131_img), view(bgr131a_img));
  269. bgr131_image_t bgr131b_img(3,10,4);
  270. copy_pixels(const_view(bgr131_img), view(bgr131b_img));
  271. error_if(bgr131_img!=bgr131a_img || bgr131a_img!=bgr131b_img);
  272. }
  273. void image_test::dynamic_image_test()
  274. {
  275. using any_image_t = any_image
  276. <
  277. mp11::mp_list
  278. <
  279. gray8_image_t,
  280. bgr8_image_t,
  281. argb8_image_t,
  282. rgb8_image_t,
  283. rgb8_planar_image_t
  284. >
  285. >;
  286. rgb8_planar_image_t img(sample_view.dimensions());
  287. copy_pixels(sample_view, view(img));
  288. any_image_t any_img=any_image_t(img);
  289. check_view(view(any_img), "dynamic_");
  290. check_view(flipped_left_right_view(view(any_img)), "dynamic_fliplr");
  291. check_view(flipped_up_down_view(view(any_img)), "dynamic_flipud");
  292. any_image_t::view_t subimageView=subimage_view(view(any_img),0,0,10,15);
  293. check_view(subimageView, "dynamic_subimage");
  294. check_view(subsampled_view(rotated180_view(view(any_img)), 2,1), "dynamic_subimage_subsampled180rot");
  295. }
  296. template <typename Img>
  297. void image_test::image_all_test(const string& prefix) {
  298. basic_test<Img>(prefix+"basic_");
  299. Img img;
  300. img.recreate(sample_view.dimensions());
  301. copy_and_convert_pixels(sample_view,view(img));
  302. view_transformations_test(view(img), prefix+"views_");
  303. histogram_test(const_view(img),prefix+"histogram_");
  304. }
  305. void image_test::run() {
  306. initialize();
  307. image_all_test<bgr8_image_t>("bgr8_");
  308. image_all_test<rgb8_image_t>("rgb8_");
  309. image_all_test<rgb8_planar_image_t>("planarrgb8_");
  310. image_all_test<gray8_image_t>("gray8_");
  311. using bgr121_ref_t = bit_aligned_pixel_reference
  312. <
  313. boost::uint8_t,
  314. mp11::mp_list_c<int, 1, 2, 1>,
  315. bgr_layout_t,
  316. true
  317. > const;
  318. using bgr121_image_t = image<bgr121_ref_t, false>;
  319. image_all_test<bgr121_image_t>("bgr121_");
  320. // TODO: Remove?
  321. view_transformations_test(subsampled_view(sample_view, point_t(1,2)), "subsampled_");
  322. view_transformations_test(color_converted_view<gray8_pixel_t>(sample_view),"color_converted_");
  323. virtual_view_test();
  324. packed_image_test();
  325. dynamic_image_test();
  326. finalize();
  327. }
  328. ////////////////////////////////////////////////////
  329. ///
  330. /// Performs or generates image tests using checksums
  331. ///
  332. ////////////////////////////////////////////////////
  333. class checksum_image_mgr : public image_test
  334. {
  335. protected:
  336. using crc_map_t = map<string, boost::crc_32_type::value_type>;
  337. crc_map_t _crc_map;
  338. };
  339. ////////////////////////////////////////////////////
  340. ///
  341. /// Performs image tests by comparing image pixel checksums against a reference
  342. ///
  343. ////////////////////////////////////////////////////
  344. class checksum_image_test : public checksum_image_mgr {
  345. public:
  346. checksum_image_test(const char* filename) : _filename(filename) {}
  347. private:
  348. const char* _filename;
  349. void initialize() override;
  350. void check_view_impl(const rgb8c_view_t& v, const string& name) override;
  351. };
  352. // Load the checksums from the reference file and create the start image
  353. void checksum_image_test::initialize() {
  354. boost::crc_32_type::value_type crc_result;
  355. fstream checksum_ref(_filename,ios::in);
  356. while (true) {
  357. string crc_name;
  358. checksum_ref >> crc_name >> std::hex >> crc_result;
  359. if(checksum_ref.fail()) break;
  360. if (!crc_name.empty() && crc_name[0] == '#')
  361. {
  362. crc_result = 0; // skip test case
  363. crc_name = crc_name.substr(1);
  364. }
  365. _crc_map[crc_name]=crc_result;
  366. }
  367. checksum_ref.close();
  368. }
  369. // Create a checksum for the given view and compare it with the reference checksum. Throw exception if different
  370. void checksum_image_test::check_view_impl(const rgb8c_view_t& img_view, const string& name) {
  371. boost::crc_32_type checksum_acumulator;
  372. checksum_acumulator.process_bytes(img_view.row_begin(0),img_view.size()*3);
  373. unsigned int const crc_expect = _crc_map[name];
  374. if (crc_expect == 0)
  375. {
  376. cerr << "Skipping checksum check for " << name << " (crc=0)" << endl;
  377. return;
  378. }
  379. boost::crc_32_type::value_type const crc = checksum_acumulator.checksum();
  380. if (crc==crc_expect) {
  381. cerr << "Checking checksum for " << name << " (crc=" << std::hex << crc << ")" << endl;
  382. }
  383. else {
  384. cerr << "Checksum error in " << name
  385. << " (crc=" << std::hex << crc << " != " << std::hex << crc_expect << ")" << endl;
  386. error_if(true);
  387. }
  388. }
  389. ////////////////////////////////////////////////////
  390. ///
  391. /// Generates a set of reference checksums to compare against
  392. ///
  393. ////////////////////////////////////////////////////
  394. class checksum_image_generate : public checksum_image_mgr {
  395. public:
  396. checksum_image_generate(const char* filename) : _filename(filename) {}
  397. private:
  398. const char* _filename;
  399. void check_view_impl(const rgb8c_view_t& img_view, const string& name) override;
  400. void finalize() override;
  401. };
  402. // Add the checksum of the given view to the map of checksums
  403. void checksum_image_generate::check_view_impl(const rgb8c_view_t& img_view, const string& name) {
  404. boost::crc_32_type result;
  405. result.process_bytes(img_view.row_begin(0),img_view.size()*3);
  406. cerr << "Generating checksum for " << name << endl;
  407. _crc_map[name] = result.checksum();
  408. }
  409. // Save the checksums into the reference file
  410. void checksum_image_generate::finalize() {
  411. fstream checksum_ref(_filename,ios::out);
  412. for (crc_map_t::const_iterator it=_crc_map.begin(); it!=_crc_map.end(); ++it) {
  413. checksum_ref << it->first << " " << std::hex << it->second << "\r\n";
  414. }
  415. checksum_ref.close();
  416. }
  417. ////////////////////////////////////////////////////
  418. ///
  419. /// Performs or generates image tests using image I/O
  420. ///
  421. ////////////////////////////////////////////////////
  422. extern const string in_dir;
  423. extern const string out_dir;
  424. extern const string ref_dir;
  425. const string in_dir=""; // directory of source images
  426. const string out_dir=in_dir+"image-out/"; // directory where to write output
  427. const string ref_dir=in_dir+"image-ref/"; // reference directory to compare written with actual output
  428. void static_checks() {
  429. gil_function_requires<ImageConcept<rgb8_image_t> >();
  430. static_assert(view_is_basic<rgb8_step_view_t>::value, "");
  431. static_assert(view_is_basic<cmyk8c_planar_step_view_t>::value, "");
  432. static_assert(view_is_basic<rgb8_planar_view_t>::value, "");
  433. static_assert(view_is_step_in_x<rgb8_step_view_t>::value, "");
  434. static_assert(view_is_step_in_x<cmyk8c_planar_step_view_t>::value, "");
  435. static_assert(!view_is_step_in_x<rgb8_planar_view_t>::value, "");
  436. static_assert(!is_planar<rgb8_step_view_t>::value, "");
  437. static_assert(is_planar<cmyk8c_planar_step_view_t>::value, "");
  438. static_assert(is_planar<rgb8_planar_view_t>::value, "");
  439. static_assert(view_is_mutable<rgb8_step_view_t>::value, "");
  440. static_assert(!view_is_mutable<cmyk8c_planar_step_view_t>::value, "");
  441. static_assert(view_is_mutable<rgb8_planar_view_t>::value, "");
  442. static_assert(std::is_same
  443. <
  444. derived_view_type<cmyk8c_planar_step_view_t>::type,
  445. cmyk8c_planar_step_view_t
  446. >::value, "");
  447. static_assert(std::is_same
  448. <
  449. derived_view_type
  450. <
  451. cmyk8c_planar_step_view_t, std::uint16_t, rgb_layout_t
  452. >::type,
  453. rgb16c_planar_step_view_t
  454. >::value, "");
  455. static_assert(std::is_same
  456. <
  457. derived_view_type
  458. <
  459. cmyk8c_planar_step_view_t, use_default, rgb_layout_t, std::false_type, use_default, std::false_type
  460. >::type,
  461. rgb8c_step_view_t
  462. >::value, "");
  463. // test view get raw data (mostly compile-time test)
  464. {
  465. rgb8_image_t rgb8(100,100);
  466. unsigned char* data=interleaved_view_get_raw_data(view(rgb8));
  467. const unsigned char* cdata=interleaved_view_get_raw_data(const_view(rgb8));
  468. error_if(data!=cdata);
  469. }
  470. {
  471. rgb16s_planar_image_t rgb8(100,100);
  472. short* data=planar_view_get_raw_data(view(rgb8),1);
  473. const short* cdata=planar_view_get_raw_data(const_view(rgb8),1);
  474. error_if(data!=cdata);
  475. }
  476. }
  477. using image_test_t = checksum_image_test;
  478. using image_generate_t = checksum_image_generate;
  479. #ifdef BOOST_GIL_GENERATE_REFERENCE_DATA
  480. using image_mgr_t = image_generate_t;
  481. #else
  482. using image_mgr_t = image_test_t;
  483. #endif
  484. void test_image(const char* ref_checksum) {
  485. image_mgr_t mgr(ref_checksum);
  486. cerr << "Reading checksums from " << ref_checksum << endl;
  487. mgr.run();
  488. static_checks();
  489. }
  490. int main(int argc, char* argv[])
  491. {
  492. try
  493. {
  494. if (argc != 2)
  495. throw std::runtime_error("No file with reference checksums specified");
  496. std::string local_name = argv[1];
  497. std::ifstream file_is_there(local_name.c_str());
  498. if (!file_is_there)
  499. throw std::runtime_error("Unable to open gil_reference_checksums.txt");
  500. test_image(local_name.c_str());
  501. return EXIT_SUCCESS;
  502. }
  503. catch (std::exception const& e)
  504. {
  505. std::cerr << e.what() << std::endl;
  506. return EXIT_FAILURE;
  507. }
  508. catch (...)
  509. {
  510. return EXIT_FAILURE;
  511. }
  512. }