-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathmain.cpp
115 lines (99 loc) · 3.87 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <iostream>
#include <chrono>
// image io
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
// fast blur
#include "fast_gaussian_blur_template.h"
typedef unsigned char uchar;
// #define USE_FLOAT
int main(int argc, char * argv[])
{
// helper
if( argc < 4 )
{
printf("%s [input] [output] [sigma] [order - optional] [border - optional]\n", argv[0]);
printf("\n");
printf("- input: extension should be any of [.jpg, .png, .bmp, .tga, .psd, .gif, .hdr, .pic, .pnm].\n");
printf("- output: extension should be any of [.png, .jpg, .bmp]. Unknown extensions will be saved as .png by default.\n");
printf("- sigma: Gaussian standard deviation (float). Should be positive.\n");
printf("- order: optional filter order [1: box, 2: bilinear, 3: biquadratic, 4. bicubic, ..., 10]. Should be positive.\n");
printf(" Default is 3 and current implementation supports up to 10 box blur passes, but one can easily add more in the code.\n");
printf("- border: optional treatment of image boundaries [mirror, extend, crop, wrap]. Default is mirror.\n");
printf("\n");
exit(1);
}
// load image
int width, height, channels;
uchar * image_data = stbi_load(argv[1], &width, &height, &channels, 0);
printf("Source image: %s %dx%d (%d)\n", argv[1], width, height, channels);
// read parameters
const float sigma = std::atof(argv[3]);
const int passes = argc > 4 ? std::atoi(argv[4]) : 3;
const std::string policy = argc > 5 ? std::string(argv[5]) : "mirror";
Border border;
if (policy == "mirror") border = Border::kMirror;
else if (policy == "extend") border = Border::kExtend;
else if (policy == "crop") border = Border::kKernelCrop;
else if (policy == "wrap") border = Border::kWrap;
else border = Border::kMirror;
// temporary data
std::size_t size = width * height * channels;
#ifdef USE_FLOAT
float * new_image = new float[size];
float * old_image = new float[size];
#else
uchar * new_image = new uchar[size];
uchar * old_image = new uchar[size];
#endif
// channels copy r,g,b
for(std::size_t i = 0; i < size; ++i)
{
#ifdef USE_FLOAT
old_image[i] = (float)image_data[i] / 255.f;
#else
old_image[i] = image_data[i];
#endif
}
// stats
auto start = std::chrono::system_clock::now();
// perform gaussian blur
// note: the implementation can work on any buffer types (uint8, uint16, uint32, int, float, double)
// note: both old and new buffer are modified
fast_gaussian_blur(old_image, new_image, width, height, channels, sigma, passes, border);
// stats
auto end = std::chrono::system_clock::now();
float elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
printf("Time %.4fms\n", elapsed);
// convert result
for(std::size_t i = 0; i < size; ++i)
{
#ifdef USE_FLOAT
image_data[i] = (uchar)(new_image[i] * 255.f);
#else
image_data[i] = (uchar)(new_image[i]);
#endif
}
// save image
std::string file(argv[2]), ext = file.substr(file.size()-3);
if( ext == "bmp" )
stbi_write_bmp(argv[2], width, height, channels, image_data);
else if( ext == "jpg" )
stbi_write_jpg(argv[2], width, height, channels, image_data, 90);
else
{
if( ext != "png" )
{
printf("Image format '%s' not supported, writing default png\n", ext.c_str());
file = file.substr(0, file.size()-4) + std::string(".png");
}
stbi_write_png(file.c_str(), width, height, channels, image_data, channels*width);
}
// clean memory
stbi_image_free(image_data);
delete[] new_image;
delete[] old_image;
return 0;
}