Skip to content
This repository was archived by the owner on Aug 30, 2023. It is now read-only.

Commit 5583aae

Browse files
authored
Merge pull request #3 from obee58/librarify
Refactor Complete, before proj5 implementation
2 parents 5b36f0e + 201797b commit 5583aae

File tree

8 files changed

+609
-1234
lines changed

8 files changed

+609
-1234
lines changed

Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ endif
1111

1212
# I have spent an hour on fixing this makefile and make refuses to read a list one-by-one
1313
# just copy the lines and replace the filenames
14-
default: clean project4
14+
default: recompile
1515

1616
project1: imgview
1717
project3: alphamask compose
@@ -21,13 +21,13 @@ all: imgview alphamask compose convolve
2121
recompile: clean all
2222

2323
imgview:
24-
${CXX} ${CPPFLAGS} -o imgview src/imgview.cpp ${LD}
24+
${CXX} ${CPPFLAGS} -o imgview src/imgview.cpp src/gloiioFuncs.cpp ${LD}
2525
alphamask:
26-
${CXX} ${CPPFLAGS} -o alphamask src/alphamask.cpp ${LD}
26+
${CXX} ${CPPFLAGS} -o alphamask src/alphamask.cpp src/gloiioFuncs.cpp ${LD}
2727
compose:
28-
${CXX} ${CPPFLAGS} -o compose src/compose.cpp ${LD}
28+
${CXX} ${CPPFLAGS} -o compose src/compose.cpp src/gloiioFuncs.cpp ${LD}
2929
convolve:
30-
${CXX} ${CPPFLAGS} -o convolve src/convolve.cpp ${LD}
30+
${CXX} ${CPPFLAGS} -o convolve src/convolve.cpp src/gloiioFuncs.cpp ${LD}
3131

3232
clean:
3333
rm -f core.* *.o *~ imgview alphamask compose convolve

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
# cpsc4040-GLOIIO project4 (v0.4)
1+
# cpsc4040-GLOIIO (v1.0.-1 "librarified")
22
#### OpenGL/GLUT Program Suite to read, display, modify, and write images using the OpenImageIO API
3-
Dr. Karamouzas "Convolution"
4-
53
by Owen Book ([email protected])
64

7-
*CPSC 4040 | Fall 2022*
5+
*CPSC 4040 | Dr. Karamouzas | Fall 2022*
86

97
### Compilation
108
Makefile is included. You can run these commands:
@@ -33,8 +31,6 @@ I: invert colors of current image
3331

3432
N: randomly add black noise to current image
3533

36-
*P: display the first set of bytes of the image data in hex*
37-
3834
Q or ESC: quit program
3935

4036
#### Command line usage

src/alphamask.cpp

Lines changed: 5 additions & 258 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
// Input can be any image type, output will be png
66
//
77
// CPSC 4040 | Owen Book | October 2022
8-
8+
#include "gloiioFuncs.h"
99
#include <OpenImageIO/imageio.h>
1010
#include <iostream>
1111
#include <string>
12-
#include <cmath>
12+
#include <exception>
1313

1414
#ifdef __APPLE__
1515
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -25,266 +25,13 @@ OIIO_NAMESPACE_USING
2525
//default window dimensions
2626
#define DEFAULT_WIDTH 600
2727
#define DEFAULT_HEIGHT 600
28-
//assumed maximum value of pixel data - change if modifying for int, float, etc.
29-
#define MAX_VAL 255
30-
//preprocess macros
31-
#define maximum(x,y,z) ((x) > (y)? ((x) > (z)? (x) : (z)) : ((y) > (z)? (y) : (z)))
32-
#define minimum(x,y,z) ((x) < (y)? ((x) < (z)? (x) : (z)) : ((y) < (z)? (y) : (z)))
33-
34-
//utility struct that holds RGBA 4-tuple of chars
35-
typedef struct pixel_rgba_t {
36-
unsigned char red, green, blue, alpha;
37-
} pxRGBA;
38-
//utility struct that holds RGB 3-tuple of chars
39-
typedef struct pixel_rgb_t {
40-
unsigned char red, green, blue;
41-
} pxRGB;
42-
//utility struct that holds HSV 3-tuple of doubles
43-
typedef struct pixel_hsv_t {
44-
double hue, saturation, value;
45-
} pxHSV;
46-
47-
//struct to tie image spec and pixels together
48-
typedef struct image_rgba_uint8_t {
49-
ImageSpec spec;
50-
pxRGBA* pixels;
51-
} ImageRGBA;
52-
5328

5429
/** CONTROL & GLOBAL STATICS **/
5530
//list of read images for multi-image viewing mode
5631
static vector<ImageRGBA> imageCache;
5732
//current index in vector to attempt to load (probably won't be touched in this program)
5833
static int cacheIndex = 0;
5934

60-
/** UTILITY FUNCTIONS **/
61-
/* clean up memory of unneeded ImageRGBA
62-
don't forget to remove it from imageCache first! */
63-
void discardImage(ImageRGBA image) {
64-
delete image.pixels;
65-
}
66-
67-
/* functions to quickly create pxRGB, pxRGBA, pxHSV,... from arbitrary values*/
68-
pxRGB linkRGB(unsigned char r, unsigned char g, unsigned char b) {
69-
pxRGB px;
70-
px.red = r;
71-
px.green = g;
72-
px.blue = b;
73-
return px;
74-
}
75-
pxRGBA linkRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
76-
pxRGBA px;
77-
px.red = r;
78-
px.green = g;
79-
px.blue = b;
80-
px.alpha = a;
81-
return px;
82-
}
83-
pxHSV linkHSV(double h, double s, double v) {
84-
pxHSV px;
85-
px.hue = h;
86-
px.saturation = s;
87-
px.value = v;
88-
return px;
89-
}
90-
91-
/*convert RGB values into HSV values*/
92-
pxHSV RGBtoHSV(pxRGB rgb) {
93-
pxHSV hsv;
94-
double huer, hueg, hueb, max, min, delta;
95-
/* convert from 0-255 to 0~1 */
96-
huer = rgb.red / 255.0;
97-
hueg = rgb.green / 255.0;
98-
hueb = rgb.blue / 255.0;
99-
100-
max = maximum(huer, hueg, hueb);
101-
min = minimum(huer, hueg, hueb);
102-
hsv.value = max;
103-
104-
if (max==0) {
105-
hsv.hue = 0;
106-
hsv.value = 0;
107-
}
108-
else {
109-
delta = max-min;
110-
hsv.saturation = delta/max; //https://youtu.be/QYbG1AMSdiY
111-
if (delta == 0) {
112-
hsv.hue = 0;
113-
}
114-
else {
115-
/* determine hue */
116-
if (huer == max) {
117-
hsv.hue = (hueg - hueb) / delta;
118-
}
119-
else if (hueg == max) {
120-
hsv.hue = 2.0 + (hueb - huer) / delta;
121-
}
122-
else {
123-
hsv.hue = 4.0 + (huer - hueg) / delta;
124-
}
125-
hsv.hue *= 60.0;
126-
if (hsv.hue < 0) {
127-
hsv.hue += 360.0;
128-
}
129-
}
130-
}
131-
132-
return hsv;
133-
}
134-
135-
/* shorthand function that double-converts RGBA to HSV, ignoring alpha channel */
136-
pxHSV RGBAtoHSV(pxRGBA rgba) {
137-
return RGBtoHSV(linkRGB(rgba.red, rgba.green, rgba.blue));
138-
}
139-
140-
/** PROCESSING FUNCTIONS **/
141-
/* reads in image from specified filename as RGBA 8bit pixmap
142-
puts a new ImageRGBA in the imageCache vector if successful */
143-
void readImage(string filename) {
144-
std::unique_ptr<ImageInput> in = ImageInput::open(filename);
145-
if (!in) {
146-
std::cerr << "could not open input file! " << geterror();
147-
//cancel routine
148-
return;
149-
}
150-
151-
//store spec and get metadata from it
152-
ImageRGBA image;
153-
image.spec = in->spec();
154-
int xr = image.spec.width;
155-
int yr = image.spec.height;
156-
int channels = image.spec.nchannels;
157-
158-
//declare temp memory to read raw image data
159-
unsigned char temp_px[xr*yr*channels];
160-
161-
// read the image into the temp_px from the input file, flipping it upside down using negative y-stride,
162-
// since OpenGL pixmaps have the bottom scanline first, and
163-
// oiio expects the top scanline first in the image file.
164-
int scanlinesize = xr * channels * sizeof(unsigned char);
165-
if(!in->read_image(TypeDesc::UINT8, temp_px+((yr-1)*scanlinesize), AutoStride, -scanlinesize)){
166-
cerr << "Could not read image from " << filename << ", error = " << geterror() << endl;
167-
//cancel routine
168-
return;
169-
}
170-
171-
//allocate data for converted pxRGBA version
172-
image.pixels = new pxRGBA[xr*yr];
173-
//convert and store raw image data as pxRGBAs
174-
for (int i=0; i<yr*xr; i++) {
175-
switch(channels) {
176-
//this could be more cleanly programmed but the less convoluted the better
177-
case 1: //grayscale
178-
image.pixels[i].red = temp_px[i];
179-
image.pixels[i].green = temp_px[i];
180-
image.pixels[i].blue = temp_px[i];
181-
image.pixels[i].alpha = 255;
182-
break;
183-
case 2: //weird grayscale with alpha (just covering my ass here)
184-
image.pixels[i].red = temp_px[2*i];
185-
image.pixels[i].green = temp_px[2*i];
186-
image.pixels[i].blue = temp_px[2*i];
187-
image.pixels[i].alpha = temp_px[(2*i)+1];
188-
break;
189-
case 3: //RGB
190-
image.pixels[i].red = temp_px[(3*i)];
191-
image.pixels[i].green = temp_px[(3*i)+1];
192-
image.pixels[i].blue = temp_px[(3*i)+2];
193-
image.pixels[i].alpha = 255;
194-
break;
195-
case 4: //RGBA
196-
image.pixels[i].red = temp_px[(4*i)];
197-
image.pixels[i].green = temp_px[(4*i)+1];
198-
image.pixels[i].blue = temp_px[(4*i)+2];
199-
image.pixels[i].alpha = temp_px[(4*i)+3];
200-
break;
201-
default: //something weird, just do nothing
202-
break;
203-
}
204-
}
205-
206-
//close input
207-
in->close();
208-
//store struct in cache and switch to display this image
209-
imageCache.push_back(image);
210-
cacheIndex = imageCache.size()-1;
211-
}
212-
213-
/* writes currently dixplayed pixmap (as RGBA) to a file
214-
(mostly the same as sample code) */
215-
void writeImage(string filename){
216-
int xr = imageCache[cacheIndex].spec.width;
217-
int yr = imageCache[cacheIndex].spec.height;
218-
int channels = 4;
219-
//temporary 1d array to stick all the pxRGBA data into
220-
//write_image does not like my structs >:(
221-
unsigned char temp_px[xr*yr*channels];
222-
for (int i=0; i<xr*yr; i++) {
223-
temp_px[(4*i)] = imageCache[cacheIndex].pixels[i].red;
224-
temp_px[(4*i)+1] = imageCache[cacheIndex].pixels[i].green;
225-
temp_px[(4*i)+2] = imageCache[cacheIndex].pixels[i].blue;
226-
temp_px[(4*i)+3] = imageCache[cacheIndex].pixels[i].alpha;
227-
}
228-
229-
// create the oiio file handler for the image
230-
std::unique_ptr<ImageOutput> outfile = ImageOutput::create(filename);
231-
if(!outfile){
232-
cerr << "could not create output file! " << geterror() << endl;
233-
//cancel routine
234-
return;
235-
}
236-
237-
// open a file for writing the image. The file header will indicate an image of
238-
// width xr, height yr, and 4 channels per pixel (RGBA). All channels will be of
239-
// type unsigned char
240-
ImageSpec spec(xr, yr, channels, TypeDesc::UINT8);
241-
if(!outfile->open(filename, spec)){
242-
cerr << "could not open output file! " << geterror() << endl;
243-
return;
244-
}
245-
246-
// write the image to the file. All channel values in the pixmap are taken to be
247-
// unsigned chars. flip using stride to undo same effort in readImage
248-
int scanlinesize = xr * channels * sizeof(unsigned char);
249-
if(!outfile->write_image(TypeDesc::UINT8, temp_px+((yr-1)*scanlinesize), AutoStride, -scanlinesize)){
250-
cerr << "could not write to file! " << geterror() << endl;
251-
return;
252-
}
253-
else cout << "successfully written image to " << filename << endl;
254-
255-
// close the image file after the image is written
256-
if(!outfile->close()){
257-
cerr << "could not close output file! " << geterror() << endl;
258-
return;
259-
}
260-
}
261-
262-
/* chroma-key image to create alphamask using HSV differences
263-
"fuzz" arguments determine max difference for each value to keep */
264-
void chromaKey(pxHSV target, double huefuzz, double satfuzz, double valfuzz) {
265-
ImageRGBA image = imageCache[cacheIndex];
266-
int xr = image.spec.width;
267-
int yr = image.spec.height;
268-
for (int i=0; i<xr*yr; i++) {
269-
pxHSV comp = RGBAtoHSV(image.pixels[i]);
270-
//cut out based on absolute distance from target values
271-
//if all three are in range, hide it!
272-
double huediff = fabs(comp.hue - target.hue);
273-
double satdiff = fabs(comp.saturation - target.saturation);
274-
double valdiff = fabs(comp.value - target.value);
275-
if (huediff < huefuzz && satdiff < satfuzz && valdiff < valfuzz) {
276-
//some smoothing function for pixels way less close
277-
double maskalpha = (0.2*(huediff/huefuzz) + 0.4*(satdiff/satfuzz) + 0.4*(valdiff/valfuzz)) - 0.2;
278-
//clamp to 0.0~1.0; if the result is like 0.012 don't bother with it
279-
maskalpha = (maskalpha < 0.02? 0.0 : maskalpha);
280-
maskalpha = (maskalpha > 1.0? 1.0 : maskalpha);
281-
282-
//cout << "masking pixel: " << comp.hue << " " << comp.saturation << " " << comp.value << " to alpha value " << maskalpha << endl;
283-
image.pixels[i].alpha = (unsigned char)255*maskalpha;
284-
}
285-
}
286-
}
287-
28835
/** OPENGL FUNCTIONS **/
28936
/* main display callback: displays the image of current index from imageCache.
29037
if no images are loaded, only draws a black background */
@@ -381,10 +128,10 @@ int main(int argc, char* argv[]){
381128
}
382129

383130
//do the things
384-
readImage(instr);
385-
chromaKey(target,fuzz.hue,fuzz.saturation,fuzz.value);
131+
imageCache.push_back(readImage(instr));
132+
chromaKey(imageCache[0],target,fuzz.hue,fuzz.saturation,fuzz.value);
386133
cout << "writing alphamask to file " << outstr << endl;
387-
writeImage(outstr);
134+
writeImage(outstr, imageCache[0]);
388135
cout << "press ESC or Q to close" << endl;
389136
}
390137
else {

0 commit comments

Comments
 (0)