93
edits
Changes
Savy Cat
,→Assignment 2
==== Dependencies ====
Figuring out how to use the CImg library in a parallel solution was fairly strait forward. In order to do so, I had to isolate any reference to CImg to it's own .cpp file. Trying to include the CImg library in the CUDA .cu file caused compilation errors. We use the function getImage defined in Imageimage.h and available to Rotate.cu in order to retrieve image data as a one dimensional float array. We can do the opposite and pass the float array back to Image.cpp for it to construct a CImg object and display the image to the screen (or utilize any other CImg functionality).
Getting libjpeg to work, (the functionality of reading RGB pixel values from the .jpg file and storing them in a CImg object), took much longer to figure out. Linking the previous windows .lib build did not work, I suspect because our parallel version is being compiled in 64bit and libjpeg is 32bit. My first attempt (which did not work, so I would not recommend trying), was to replace libjpeg with [https://libjpeg-turbo.org/ turbo-jpeg], which is a 64bit library that overloads every libjpeg function so that it should be able to replace libjpeg functionality as-is, and is supposed to run faster due to optimization. By installing turbo-jpeg and moving jpeg62.dll to the project executable folder, I was able to get the solution to compile, however, it froze during run-time upon opening a .jpg file.
What finally did work was installing the windows 64bit version of [https://www.imagemagick.org/script/download.php#windows ImageMagick], and then removing the line of code "#define cimg_use_jpeg" which told CImg to use libjpeg. By default, it finds ImageMagick from it's default installation directory and uses its functionality instead when initializing a CImg object from file. Oddly enough, I tried to use ImageMagick at the very beginning of the project, and could not get it to work, thus using libjpeg instead. Now for the CUDA version, it works. Either way, you will notice the pixel values themselves slightly different than in the first time run example. This simply shows that libjpeg and ImageMagick use different logic to determine colour values.
==== Initial CUDA Code ====
;image.h
<nowiki>
// Evan Marinzel - DPS915 Project
// image.h
#pragma once
#define PX_TYPE float
PX_TYPE* getImage(char* filename, int &w, int &h);
void display(const PX_TYPE* img, int h, int w);
</nowiki>
;image.cpp
<nowiki>
// Evan Marinzel - DPS915 Project
// image.cpp
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include "image.h"
#include "CImg.h"
// Indexing function for CImg object.
// CImg[x][y][z]
inline int idx(int x, int y, int w, int h, int z) {
return x + y * w + w * h * z;
}
// Prints colour channel values of img to console.
// Opens image, mouse-over pixels to verify indexing is correct.
// Uses 40 x 40 pixel sample from the top left corner if img is larger than 40 x 40
void display(const PX_TYPE* img, int w, int h) {
int height = h > 40 ? 40 : h;
int width = w > 40 ? 40 : w;
int size = w * h * 3;
for (int i = 0; i < 3; i++) {
if (i == 0)
std::cout << "Red:" << std::endl;
else if (i == 1)
std::cout << "Green:" << std::endl;
else if (i == 2)
std::cout << "Blue:" << std::endl;
for (int j = 0; j < height; j++) {
for (int k = 0; k < width; k++) {
std::cout << std::setw(4) << img[idx(k, j, w, h, i)];
}
std::cout << std::endl;
}
std::cout << std::endl;
}
cimg_library::CImg<PX_TYPE> cimg(w, h, 1, 3, 0);
for (int i = 0; i < size; i++) {
cimg[i] = img[i];
}
cimg_library::CImg<PX_TYPE> imgCropped(cimg);
imgCropped.crop(0, 0, width - 1, height - 1, 0);
imgCropped.display();
}
float* getImage(char* filename, int &w, int &h) {
std::cout << "Trying to read " << filename << std::endl;
cimg_library::CImg<PX_TYPE> cimg(filename);
std::cout << "Done reading " << filename << std::endl;
w = cimg.width();
h = cimg.height();
int size = w * h * cimg.spectrum();
float* img = new PX_TYPE[size];
for (int i = 0; i < size; i++) {
img[i] = cimg[i];
}
return img;
}</nowiki>
=== Assignment 3 ===