-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
198 lines (148 loc) · 5.87 KB
/
main.cpp
File metadata and controls
198 lines (148 loc) · 5.87 KB
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
#include <iostream>
#include <QApplication>
#include <QFrame>
#include "imageiolib.h"
#include "main.h"
using namespace std;
//-------------------------------------------------------------
//Custom Filters:
Image makeAqua();
Image makeGradient();
Image redShift(const Image& source, int shiftAmount);
Image blur(const Image& source);
Image rotateRight(const Image& source);
//-------------------------------------------------------------
//Helpers and Main:
/** @brief clamp Forces a value into range 0-255
* @param value double value to clamp
* @return 0 if value < 0, 255 if value > 255, value otherwise
*/
byte clamp(double value) {
value = min(value, 255.0);
value = max(value, 0.0);
return static_cast<byte>(value);
}
int main(int argc, char *argv[])
{
//Setup work for the GUI that will draw the images
QApplication myApp(argc, argv);
QFrame mainWindow;
QHBoxLayout mainLayout;
mainWindow.setLayout(&mainLayout);
//Create an image struct from a file - don't have to worry about details
Image crabOriginal = readImage("crab.bmp");
//Show the image in the GUI - definately don't worry about details
displayImage(crabOriginal, "Original", mainLayout);
//Use redShift function to make a new image, then draw it to GUI
Image redCrab = redShift(crabOriginal, 100);
displayImage(redCrab, "Red", mainLayout);
Image blurCrab = blur(crabOriginal);
displayImage(blurCrab, "Blurred", mainLayout);
Image gradient = makeGradient();
displayImage(gradient, "Gradient", mainLayout);
Image aqua = makeAqua();
displayImage(aqua, "Aqua", mainLayout);
Image rotatedCrab = rotateRight(crabOriginal);
displayImage(rotatedCrab, "Rotated", mainLayout);
//Show the GUI... exec will keep program running until GUI window is closed
mainWindow.show();
return myApp.exec();
}
//-------------------------------------------------------------
//Filter Implementation
/**
* @brief makeAqua Make an image with pure aqua color
* @return the created image
*/
Image makeAqua() {
Image newImage = {0}; //all black
for(int i = 0; i < IMG_HEIGHT; i++) { //for each row
for(int j = 0; j < IMG_WIDTH; j++) { //for each column
newImage.data[i][j][GREEN] = 128;
newImage.data[i][j][BLUE] = 255;
//no red needed...
}
}
return newImage;
}
/**
* @brief makeGradient Make an image with black to white vertical gradient
* @return the created image
*/
Image makeGradient() {
Image newImage = {0}; //all black
for(int i = 0; i < IMG_HEIGHT; i++) { //for each row
for(int j = 0; j < IMG_WIDTH; j++) { //for each column
for(int k = 0; k < NUM_CHANNELS; k++) { //for each color channel
//set each color to the row index * 2... will make 0-254
newImage.data[i][j][k] = i * 2;
}
}
}
return newImage;
}
/**
* @brief redShift copy an image but add the given amount to the red value of each pixel
* @param source iamge to copy
* @param shiftAmount value to add to red channel of each pixel
* @return the modified copy
*/
Image redShift(const Image& source, int shiftAmount) {
Image newImage = {0}; //all black
for(int i = 0; i < IMG_HEIGHT; i++) { //for each row
for(int j = 0; j < IMG_WIDTH; j++) { //for each column
//clamp function makes sure we don't go past 255 and wrap back around to 0
newImage.data[i][j][RED] = clamp(source.data[i][j][RED] + shiftAmount);
//blue and green are not modified
newImage.data[i][j][BLUE] = source.data[i][j][BLUE];
newImage.data[i][j][GREEN] = source.data[i][j][GREEN];
}
}
return newImage;
}
/**
* @brief blur makes a blurred copy of an image. Leaves a 1-pixel black border around the
* new image
* @param source image to copy
* @return the modified copy
*/
Image blur(const Image& source) {
Image newImage = {0}; //all black
//skip first and last row and column... avoids stepping off edges when do neighbors
// alternative would be special logic to handle those cases
for(int i = 1; i < IMG_HEIGHT - 1; i++) { //for each row but first and last
for(int j = 1; j < IMG_WIDTH - 1; j++) { //for each column but first and last
for(int k = 0; k < NUM_CHANNELS; k++) { //for each color channel
//get value of this and 4 neighbors
byte currentPixelValue = source.data[i][j][k];
byte abovePixelValue = source.data[i - 1][j][k];
byte belowPixelValue = source.data[i + 1][j][k];
byte leftPixelValue = source.data[i][j - 1][k];
byte rightPixelValue = source.data[i][j + 1][k];
byte avgValue = (currentPixelValue + abovePixelValue + belowPixelValue +
leftPixelValue + rightPixelValue) / 5;
newImage.data[i][j][k] = avgValue;
}
}
}
return newImage;
}
/**
* @brief rotateRight makes a copy of an image that is rotated 90 degrees clockwise
* @param source Image to be rotated. This MUST be a square image.
* @return the rotated copy
*/
Image rotateRight(const Image& source) {
Image newImage = {0}; //all black
for(int i = 0; i < IMG_HEIGHT; i++) { //for each row
for(int j = 0; j < IMG_WIDTH; j++) { //for each column
for(int k = 0; k < NUM_CHANNELS; k++) { //for each color channel
//calculate where i, j should rotate to
int newRow = j; //new row = old column
int newCol = (IMG_WIDTH - 1) - i; //new column = last column - old row
newImage.data[newRow][newCol][k] = source.data[i][j][k];
}
}
}
return newImage;
}