Difference between revisions of "Savy Cat"
(→Rotate90) |
(→Rotate90) |
||
Line 43: | Line 43: | ||
// CImg[x][y][z] | // CImg[x][y][z] | ||
inline int idx(int x, int y, int w, int h, int z) { | inline int idx(int x, int y, int w, int h, int z) { | ||
− | + | return x + y * w + w * h * z; | |
} | } | ||
Line 49: | Line 49: | ||
// CImg[h - 1 - y][x][z] | // CImg[h - 1 - y][x][z] | ||
inline int idx90(int x, int y, int w, int h, int z) { | inline int idx90(int x, int y, int w, int h, int z) { | ||
− | + | return (h - 1 - y) + x * h + w * h * z; | |
} | } | ||
Line 57: | Line 57: | ||
void display(const cimg_library::CImg<PX_TYPE> img) { | void display(const cimg_library::CImg<PX_TYPE> img) { | ||
− | + | int height = img.height() > 40 ? 40 : img.height(); | |
− | + | int width = img.width() > 40 ? 40 : img.width(); | |
− | + | for (int i = 0; i < img.spectrum(); 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) << (int)img[idx(k, j, img.width(), img.height(), i)]; | |
− | + | } | |
− | + | std::cout << std::endl; | |
− | + | } | |
− | + | std::cout << std::endl; | |
− | + | } | |
− | + | cimg_library::CImg<PX_TYPE> imgCropped(img); | |
− | + | imgCropped.crop(0, 0, width - 1, height - 1, 0); | |
− | + | imgCropped.display(); | |
} | } | ||
Line 85: | Line 85: | ||
void imgStats(const char* title, cimg_library::CImg<PX_TYPE> img) { | void imgStats(const char* title, cimg_library::CImg<PX_TYPE> img) { | ||
− | + | std::cout << title << " Image Data" << std::endl; | |
− | + | std::cout << std::setfill('=') << std::setw(strlen(title) + 11) << "=" << std::setfill(' ') << std::endl; | |
− | + | std::cout << std::setw(17) << std::right << "Width: " << img.width() << "px" << std::endl; | |
− | + | std::cout << std::setw(17) << std::right << "Height: " << img.height() << "px" << std::endl; | |
− | + | std::cout << std::setw(17) << std::right << "Depth: " << img.depth() << std::endl; | |
− | + | std::cout << std::setw(17) << std::right << "Colour Channels: " << img.spectrum() << std::endl; | |
− | + | std::cout << std::setw(17) << std::right << "Pixel Size: " << sizeof(PX_TYPE) << " bytes" << std::endl; | |
− | + | std::cout << std::setw(17) << std::right << "Total Size: " << img.size() << " bytes" << std::endl; | |
− | + | std::cout << std::endl; | |
} | } | ||
Line 102: | Line 102: | ||
void rotate90(cimg_library::CImg<PX_TYPE> src, cimg_library::CImg<PX_TYPE> &dst) { | void rotate90(cimg_library::CImg<PX_TYPE> src, cimg_library::CImg<PX_TYPE> &dst) { | ||
− | + | for (int i = 0; i < src.spectrum(); i++) { | |
− | + | for (int j = 0; j < src.height(); j++) { | |
− | + | for (int k = 0; k < src.width(); k++) | |
− | + | dst[idx90(k, j, src.width(), src.height(), i)] = src[idx(k, j, src.width(), src.height(), i)]; | |
− | + | } | |
− | + | } | |
} | } | ||
Line 114: | Line 114: | ||
void rotate90x4(cimg_library::CImg<PX_TYPE> src, cimg_library::CImg<PX_TYPE> dst) { | void rotate90x4(cimg_library::CImg<PX_TYPE> src, cimg_library::CImg<PX_TYPE> dst) { | ||
− | + | rotate90(src, dst); | |
− | + | rotate90(dst, src); | |
− | + | rotate90(src, dst); | |
− | + | rotate90(dst, src); | |
− | }</nowiki> | + | } |
+ | </nowiki> | ||
;Rotate.cpp | ;Rotate.cpp | ||
Line 131: | Line 132: | ||
int main(int argc, char** argv) { | int main(int argc, char** argv) { | ||
− | + | // Allocate memory for 3 CImg structures, initializing colour values from speficied files. | |
− | + | cimg_library::CImg<PX_TYPE> img_tiny("C:\\School\\DPS915\\Project\\CImg-Rotate\\Debug\\Tiny-Shay.jpg"); | |
− | + | cimg_library::CImg<PX_TYPE> img_med("C:\\School\\DPS915\\Project\\CImg-Rotate\\Debug\\Medium-Shay.jpg"); | |
− | + | cimg_library::CImg<PX_TYPE> img_large("C:\\School\\DPS915\\Project\\CImg-Rotate\\Debug\\Large-Shay.jpg"); | |
− | + | // Allocate memory for rotated versions of above, initializing colour values to 0. | |
− | + | cimg_library::CImg<PX_TYPE> img_tiny90(img_tiny.height(), img_tiny.width(), 1, 3, 0); | |
− | + | cimg_library::CImg<PX_TYPE> img_med90(img_med.height(), img_med.width(), 1, 3, 0); | |
− | + | cimg_library::CImg<PX_TYPE> img_large90(img_large.height(), img_large.width(), 1, 3, 0); | |
− | + | // Un-comment to print pixel values to console and display image for 4 rotations | |
− | + | /* | |
− | + | display(img_tiny); | |
− | + | rotate90(img_tiny, img_tiny90); | |
− | + | display(img_tiny90); | |
− | + | rotate90(img_tiny90, img_tiny); | |
− | + | display(img_tiny); | |
− | + | rotate90(img_tiny, img_tiny90); | |
− | + | display(img_tiny90); | |
− | + | rotate90(img_tiny90, img_tiny); | |
− | + | display(img_tiny); | |
− | + | */ | |
− | + | // Display image statistics and rotate 12 times each. | |
− | + | imgStats("Tiny Shay", img_tiny); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | std::cout << "Rotating 4x..." << std::endl; | |
+ | rotate90x4(img_tiny, img_tiny90); | ||
+ | std::cout << "Rotating 8x..." << std::endl; | ||
+ | rotate90x4(img_tiny, img_tiny90); | ||
+ | std::cout << "Rotating 12x..." << std::endl; | ||
+ | rotate90x4(img_tiny, img_tiny90); | ||
+ | std::cout << "Shay is dizzy!" << std::endl << std::endl; | ||
− | + | imgStats("Medium Shay", img_med); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | std::cout << "Rotating 4x..." << std::endl; | |
+ | rotate90x4(img_med, img_med90); | ||
+ | std::cout << "Rotating 8x..." << std::endl; | ||
+ | rotate90x4(img_med, img_med90); | ||
+ | std::cout << "Rotating 12x..." << std::endl; | ||
+ | rotate90x4(img_med, img_med90); | ||
+ | std::cout << "Shay is dizzy!" << std::endl << std::endl; | ||
− | + | imgStats("Large Shay", img_large); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | std::cout << "Rotating 4x..." << std::endl; | |
+ | rotate90x4(img_large, img_large90); | ||
+ | std::cout << "Rotating 8x..." << std::endl; | ||
+ | rotate90x4(img_large, img_large90); | ||
+ | std::cout << "Rotating 12x..." << std::endl; | ||
+ | rotate90x4(img_large, img_large90); | ||
+ | std::cout << "Shay is dizzy!" << std::endl << std::endl; | ||
− | }</nowiki> | + | return 0; |
+ | |||
+ | } | ||
+ | </nowiki> | ||
==== Pre-profile ==== | ==== Pre-profile ==== | ||
− | We can un-comment the "test" section to attempt reading a .jpg, verify colour channel values that were stored, and otherwise make sure everything is working as expected. Here is Tiny-Shay.jpg, | + | We can un-comment the "test" section to attempt reading a .jpg, verify colour channel values that were stored, and otherwise make sure everything is working as expected. Here is Tiny-Shay.jpg, 30px x 21px top-down image of my cat laying on the floor. Mousing over a pixel will display the X and Y coordinates, along with the corresponding red, green, blue values. |
[[File:Verify-1.png|800px]] | [[File:Verify-1.png|800px]] |
Revision as of 17:47, 25 March 2018
GPU610/DPS915 | Student List | Group and Project Index | Student Resources | Glossary
Contents
Rotate90
Team Members
Progress
Assignment 1
I kept things very simple and created a function that rotates an image 90° clockwise.
Then, I profile and evaluate performance of rotating a tiny, medium, and large sized image file 12 times each.
Dependencies
Two open-source utilities are required in order to run the project code:
- CImg
- Download and extract the CImg Library (Standard Package). This provides the template class used to store image information. The library contains many useful image manipulation functions and methods, including rotate, but we will only be making use of the CImg class and the Display function. Make sure your project include path can find CImg.h, which should be located in the root of the extracted files.
- libjpeg
- libjpeg provides the functionality of reading .jpg file data into a CImg object. It's not quite as strait forward as getting CImg, as you need to compile libjpeg from source. I used the most recent (Jan 2018) version named jpegsr9c.zip from this listing.
- If you have trouble building the solution, this article on Stackoverflow helped me compile it.
- Once libjpeg has been built, it should result in creation of "libjpeg.lib". Be sure to link this file with compilation of the project code.
Initial Code
- Rotate.h
// Evan Marinzel - DPS915 Project // Rotate.h #pragma once #define cimg_use_jpeg #define PX_TYPE unsigned char #include <CImg.h> #include <iostream> #include <iomanip> // 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; } // Indexing function for accessing pixel location rotated 90 degrees relative to current location // CImg[h - 1 - y][x][z] inline int idx90(int x, int y, int w, int h, int z) { return (h - 1 - y) + x * h + 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 cimg_library::CImg<PX_TYPE> img) { int height = img.height() > 40 ? 40 : img.height(); int width = img.width() > 40 ? 40 : img.width(); for (int i = 0; i < img.spectrum(); 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) << (int)img[idx(k, j, img.width(), img.height(), i)]; } std::cout << std::endl; } std::cout << std::endl; } cimg_library::CImg<PX_TYPE> imgCropped(img); imgCropped.crop(0, 0, width - 1, height - 1, 0); imgCropped.display(); } // Print image dimensions and size to console. void imgStats(const char* title, cimg_library::CImg<PX_TYPE> img) { std::cout << title << " Image Data" << std::endl; std::cout << std::setfill('=') << std::setw(strlen(title) + 11) << "=" << std::setfill(' ') << std::endl; std::cout << std::setw(17) << std::right << "Width: " << img.width() << "px" << std::endl; std::cout << std::setw(17) << std::right << "Height: " << img.height() << "px" << std::endl; std::cout << std::setw(17) << std::right << "Depth: " << img.depth() << std::endl; std::cout << std::setw(17) << std::right << "Colour Channels: " << img.spectrum() << std::endl; std::cout << std::setw(17) << std::right << "Pixel Size: " << sizeof(PX_TYPE) << " bytes" << std::endl; std::cout << std::setw(17) << std::right << "Total Size: " << img.size() << " bytes" << std::endl; std::cout << std::endl; } // Rotate src image 90 degrees clockwise. // Works by assigning pixel values from src to dst. // - dst must be allocated as valid size void rotate90(cimg_library::CImg<PX_TYPE> src, cimg_library::CImg<PX_TYPE> &dst) { for (int i = 0; i < src.spectrum(); i++) { for (int j = 0; j < src.height(); j++) { for (int k = 0; k < src.width(); k++) dst[idx90(k, j, src.width(), src.height(), i)] = src[idx(k, j, src.width(), src.height(), i)]; } } } // Rotate image 360 degrees by calling rotate90 4 times. void rotate90x4(cimg_library::CImg<PX_TYPE> src, cimg_library::CImg<PX_TYPE> dst) { rotate90(src, dst); rotate90(dst, src); rotate90(src, dst); rotate90(dst, src); }
- Rotate.cpp
// Evan Marinzel - DPS915 Project // Rotate.cpp #include "Rotate.h" int main(int argc, char** argv) { // Allocate memory for 3 CImg structures, initializing colour values from speficied files. cimg_library::CImg<PX_TYPE> img_tiny("C:\\School\\DPS915\\Project\\CImg-Rotate\\Debug\\Tiny-Shay.jpg"); cimg_library::CImg<PX_TYPE> img_med("C:\\School\\DPS915\\Project\\CImg-Rotate\\Debug\\Medium-Shay.jpg"); cimg_library::CImg<PX_TYPE> img_large("C:\\School\\DPS915\\Project\\CImg-Rotate\\Debug\\Large-Shay.jpg"); // Allocate memory for rotated versions of above, initializing colour values to 0. cimg_library::CImg<PX_TYPE> img_tiny90(img_tiny.height(), img_tiny.width(), 1, 3, 0); cimg_library::CImg<PX_TYPE> img_med90(img_med.height(), img_med.width(), 1, 3, 0); cimg_library::CImg<PX_TYPE> img_large90(img_large.height(), img_large.width(), 1, 3, 0); // Un-comment to print pixel values to console and display image for 4 rotations /* display(img_tiny); rotate90(img_tiny, img_tiny90); display(img_tiny90); rotate90(img_tiny90, img_tiny); display(img_tiny); rotate90(img_tiny, img_tiny90); display(img_tiny90); rotate90(img_tiny90, img_tiny); display(img_tiny); */ // Display image statistics and rotate 12 times each. imgStats("Tiny Shay", img_tiny); std::cout << "Rotating 4x..." << std::endl; rotate90x4(img_tiny, img_tiny90); std::cout << "Rotating 8x..." << std::endl; rotate90x4(img_tiny, img_tiny90); std::cout << "Rotating 12x..." << std::endl; rotate90x4(img_tiny, img_tiny90); std::cout << "Shay is dizzy!" << std::endl << std::endl; imgStats("Medium Shay", img_med); std::cout << "Rotating 4x..." << std::endl; rotate90x4(img_med, img_med90); std::cout << "Rotating 8x..." << std::endl; rotate90x4(img_med, img_med90); std::cout << "Rotating 12x..." << std::endl; rotate90x4(img_med, img_med90); std::cout << "Shay is dizzy!" << std::endl << std::endl; imgStats("Large Shay", img_large); std::cout << "Rotating 4x..." << std::endl; rotate90x4(img_large, img_large90); std::cout << "Rotating 8x..." << std::endl; rotate90x4(img_large, img_large90); std::cout << "Rotating 12x..." << std::endl; rotate90x4(img_large, img_large90); std::cout << "Shay is dizzy!" << std::endl << std::endl; return 0; }
Pre-profile
We can un-comment the "test" section to attempt reading a .jpg, verify colour channel values that were stored, and otherwise make sure everything is working as expected. Here is Tiny-Shay.jpg, 30px x 21px top-down image of my cat laying on the floor. Mousing over a pixel will display the X and Y coordinates, along with the corresponding red, green, blue values.
After rotate90: