-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlab_intro.cpp
220 lines (185 loc) · 6.98 KB
/
lab_intro.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#include <iostream>
#include <cmath>
#include <cstdlib>
//#include "cs221util/RGBA_PNG.h"
#include "cs221util/RGBAPixel.h"
#include "lab_intro.h"
using namespace cs221util;
/**
* Returns an image that has been transformed to grayscale.
*
* We are still representing the image using RGBA, but each pixel
* will be adjusted so that it is a shade of gray with equal RGB values.
*
* Note that while setting each RGB channel to the simple average may seem
* intuitive, the resulting image will not be visually accurate due to the
* human eye's varying sensitivity to different wavelengths.
* Therefore the grayscale value for each channel will instead be weighted
* by the perceived luminosity as 0.229*R + 0.587*G + 0.114*B.
*
* Finally, as each channel is stored in a variable of type unsigned char,
* ensure that the computed grayscale value is truncated to an appropriate
* value for storage. Also be aware that sufficient precision must be
* maintained during intermediate computations.
*
* @return The grayscale image.
*/
RGBA_PNG grayscale(RGBA_PNG image) {
/// This function is partially written for you so you can see how to
/// interact with our RGBA_PNG class.
for (unsigned x = 0; x < image.width(); x++) {
for (unsigned y = 0; y < image.height(); y++) {
RGBAPixel* pixel = image.getPixel(x, y);
// `pixel` is a pointer to the memory stored inside of the RGBA_PNG `image`,
// which means you're changing the image directly. No need to `set`
// the pixel since you're directly changing the memory of the image.
double grayvalue = 0.0; // this will be changed once you determine what the adjusted RGB values will be below!
double adjusted_red = 0.229 * pixel->r;
double adjusted_green = 0.507 * pixel->g;
double adjusted_blue = 0.114 * pixel->b;
grayvalue = adjusted_red + adjusted_blue + adjusted_green;
pixel->r = (unsigned char) grayvalue;
pixel->b = (unsigned char) grayvalue;
pixel->g = (unsigned char) grayvalue;
}
}
return image;
}
/**
* Returns an image with a spotlight centered at (`centerX`, `centerY`).
*
* A spotlight adjusts the brightness of a pixel based on the distance the pixel
* is away from the center by decreasing the RGB channel values by 0.5% per
* 1 pixel euclidean distance away from the center.
*
* For example, a pixel 3 pixels above and 4 pixels to the right of the center
* is a total of `sqrt((3 * 3) + (4 * 4)) = sqrt(25) = 5` pixels away and
* its brightness is decreased by 2.5% (0.975x its original value). At a
* distance over 200 pixels away, the brightness will always 0.
*
* The modified RGBA_PNG is then returned.
*
* @param image A RGBA_PNG object which holds the image data to be modified.
* @param centerX The center x coordinate of the crosshair which is to be drawn.
* @param centerY The center y coordinate of the crosshair which is to be drawn.
*
* @return The image with a spotlight.
*/
RGBA_PNG createSpotlight(RGBA_PNG image, int centerX, int centerY) {
for (unsigned x = 0; x < image.width(); x++) {
for (unsigned y = 0; y < image.height(); y++) {
RGBAPixel* pixel = image.getPixel(x, y);
double distance = sqrt((x-centerX) * (x-centerX) + (y-centerY) * (y-centerY));
if(distance > 200){
pixel->r = 0;
pixel->b = 0;
pixel->g = 0;
} else {
pixel->r = ((1-(0.005 * distance)) * pixel->r);
pixel->b = ((1-(0.005 * distance)) * pixel->b);
pixel->g = ((1-(0.005 * distance)) * pixel->g);
}
}
}
return image;
}
/**
* Returns a image transformed to UBC colors.
*
* The color of every pixel is set to the same value of either UBC yellow or
* UBC blue, based on if the pixel's color value is closer to yellow than blue.
* Use the "colordist" function defined in lab_intro.h (and implemented
* at the bottom of this file). In case of equal distances, set the color to yellow.
*
* @param image A RGBA_PNG object which holds the image data to be modified.
*
* @return The UBCify'd image.
**/
RGBA_PNG ubcify(RGBA_PNG image) {
RGBAPixel ubcYellow(247, 184, 0);
RGBAPixel ubcBlue(12,35,68);
for (unsigned x = 0; x < image.width(); x++) {
for (unsigned y = 0; y < image.height(); y++) {
RGBAPixel* pixel = image.getPixel(x, y);
double distanceYellow = colordist(ubcYellow, *pixel);
double distanceBlue = colordist(ubcBlue, *pixel);
if(distanceYellow < distanceBlue || distanceBlue == distanceYellow){
pixel->r = 247;
pixel->g = 184;
pixel->b = 0;
} else {
pixel->r = 12;
pixel->g = 35;
pixel->b = 68;
}
}
}
return image;
}
/**
* Returns an image that has been watermarked by another image.
*
* The color of every pixel of the second image is checked - if that
* pixel's color is pure white, then the pixel at the same location on
* the first image has each color channel increased by by 40 (up to a maximum
* of 255).
*
* @param firstImage The first of the two RGBA_PNGs.
* @param secondImage The second of the two RGBA_PNGs.
*
* @return The watermarked image.
*/
RGBA_PNG watermark(RGBA_PNG firstImage, RGBA_PNG secondImage) {
for (unsigned int x = 0; x < min(firstImage.width(), secondImage.width()); x++) {
for (unsigned int y = 0; y < min(firstImage.height(), secondImage.height()); y++) {
// check the second image's pixel
RGBAPixel* px2 = secondImage.getPixel(x, y);
if (px2->r == 255 && px2->g == 255 && px2->b == 255) {
// increase first image pixel channels by 40 (up to maximum of 255)
RGBAPixel* px1 = firstImage.getPixel(x, y);
if (px1->r <= 215)
px1->r += 40;
else
px1->r = 255;
if (px1->g <= 215)
px1->g += 40;
else
px1->g = 255;
if (px1->b <= 215)
px1->b += 40;
else
px1->b = 255;
}
}
}
return firstImage;
}
/**
* Computes the color "distance" between two pixels.
* @param px1 first pixel whose color will be compared
* @param px2 second pixel whose color will be compared
*/
double colordist(RGBAPixel px1, RGBAPixel px2) {
// scale each channel to [0,1] range and pre-multiply alpha
double dbl_r_px1 = (double)px1.r / 255.0 * px1.a;
double dbl_r_px2 = (double)px2.r / 255.0 * px2.a;
double dbl_g_px1 = (double)px1.g / 255.0 * px1.a;
double dbl_g_px2 = (double)px2.g / 255.0 * px2.a;
double dbl_b_px1 = (double)px1.b / 255.0 * px1.a;
double dbl_b_px2 = (double)px2.b / 255.0 * px2.a;
double delta_a = px1.a - px2.a;
// compute maximum of each channel blended on white, and blended on black
// red channel
double black = dbl_r_px1 - dbl_r_px2;
double white = black + delta_a;
double diff_r = max(black * black, white * white);
// green channel
black = dbl_g_px1 - dbl_g_px2;
white = black + delta_a;
double diff_g = max(black * black, white * white);
// blue channel
black = dbl_b_px1 - dbl_b_px2;
white = black + delta_a;
double diff_b = max(black * black, white * white);
return diff_r + diff_g + diff_b;
}