-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathImage.cpp
172 lines (142 loc) · 5.59 KB
/
Image.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/******************************************************************************
* @file Image.cpp
* @author Andrés Gavín Murillo, 716358
* @author Abel Naya Forcano, 544125
* @date Enero 2020
* @coms Informática Gráfica - Trabajo 4: Path tracer
******************************************************************************/
#include "Image.hpp"
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
Image initImage(int width, int height) {
return {
.width = width,
.height = height,
.pixels = vector<Color>(width * height)
};
}
void setPixel(Image &image, int i, int j, Color pixel) {
image.pixels[i + j * image.width] = pixel;
}
float getMaxVal(const Image &image){
float maxVal = 0;
for (auto pixel : image.pixels)
maxVal = max(pixel.max(), maxVal);
return maxVal;
}
///////////////////////////////////////////////////////
static const string MAX_SPECIFICATION = "#MAX=";
static const string HEADER = "P3";
static const char COMMENT = '#';
static const char SPACE = ' ';
// Load and store operations
void storePPM(const std::string &name, const Image &image, int resolution) {
cout << "[INFO] Storing image as ppm " << name << endl;
// open output file stream
ofstream fout(name);
if (!fout.is_open()) {
// can't open, exit
cerr << "The file " << name << " can't be opened to write." << endl;
exit(10);
}
// write header
fout << HEADER << endl;
// write maxval (if not 1)
float maxVal = getMaxVal(image);
if (maxVal != 1.0f) {
fout << MAX_SPECIFICATION << maxVal << endl;
}
// write width/height
fout << image.width << SPACE << image.height << endl;
// write color resolution
fout << resolution << endl;
// write rgb pixels
int r, g, b;
for (int i = 0; i < image.width * image.height; i++) {
// foreach pixel, compute
r = (int) (image.pixels[i].r / maxVal) * resolution; // Red
g = (int) (image.pixels[i].g / maxVal) * resolution; // Green
b = (int) (image.pixels[i].b / maxVal) * resolution; // Blue
fout << r << SPACE << g << SPACE << b << string(5, SPACE);
}
}
void storeBMP(const std::string &name, const Image &image) {
// adapted from https://stackoverflow.com/a/2654860
cout << "[INFO] Storing image as bmp " << name << endl;
#define WRITE(A, F) F.write(reinterpret_cast<const char *>(A), sizeof(A))
// open output file stream
ofstream f(name, ios::binary);
if (!f.is_open()) {
// can't open, exit
cerr << "The file " << name << " can't be opened to write." << endl;
exit(1);
}
// write header
unsigned char header[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0};
int filesize = 54 + 3 * image.width * image.height; //w is your image width, h is image height, both int
header[2] = (unsigned char) (filesize);
header[3] = (unsigned char) (filesize >> 8);
header[4] = (unsigned char) (filesize >> 16);
header[5] = (unsigned char) (filesize >> 24);
WRITE(header, f);
// write file info
unsigned char info[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0};
info[4] = (unsigned char) (image.width);
info[5] = (unsigned char) (image.width >> 8);
info[6] = (unsigned char) (image.width >> 16);
info[7] = (unsigned char) (image.width >> 24);
info[8] = (unsigned char) (image.height);
info[9] = (unsigned char) (image.height >> 8);
info[10] = (unsigned char) (image.height >> 16);
info[11] = (unsigned char) (image.height >> 24);
WRITE(info, f);
// write data
float maxVal = getMaxVal(image);
unsigned char padding[(4 - (image.width * 3) % 4) % 4];
for (int j = 0; j < image.height; j++) {
for (int i = 0; i < image.width; i++) {
int x = i;
int y = (image.height - 1) - j;
unsigned char r = (int) (image.pixels[x + y * image.width].r / maxVal * 255);
unsigned char g = (int) (image.pixels[x + y * image.width].g / maxVal * 255);
unsigned char b = (int) (image.pixels[x + y * image.width].b / maxVal * 255);
f << b << g << r;
}
WRITE(padding, f);
}
}
// Tone mapping operators
Image equalizeAndClamp(const Image &image, float v) {
cout << "[INFO] equalizeAndClamp -> ";
return clampAndGammaCurve(image, v, 1);
}
Image clamping(const Image &image) {
cout << "[INFO] clamping -> ";
return clampAndGammaCurve(image, 1, 1);
}
Image equalization(const Image &image) {
cout << "[INFO] equalization -> ";
return clampAndGammaCurve(image, getMaxVal(image), 1);
}
Image gammaCurve(const Image &image, float gamma) {
cout << "[INFO] gammaCurve -> ";
return clampAndGammaCurve(image, getMaxVal(image), gamma);
}
Image clampAndGammaCurve(const Image &image, float v, float gamma) {
cout << "[INFO] Clamping image with v=" << v << " and applying gamma curve with gamma=" << gamma << endl;
Image imageOut = {
.width = image.width,
.height = image.height,
.pixels = vector<Color>(image.width * image.height)
};
imageOut.pixels.resize(imageOut.width * imageOut.height); // Fix capacity
for (int i = 0; i < imageOut.width * imageOut.height; i++) {
// foreach pixel, compute
imageOut.pixels[i].r = image.pixels[i].r >= v ? 1.0f : pow(image.pixels[i].r / v, 1.0f / gamma);
imageOut.pixels[i].g = image.pixels[i].g >= v ? 1.0f : pow(image.pixels[i].g / v, 1.0f / gamma);
imageOut.pixels[i].b = image.pixels[i].b >= v ? 1.0f : pow(image.pixels[i].b / v, 1.0f / gamma);
}
return imageOut;
}