Skip to content

Commit

Permalink
Enhanced compression time
Browse files Browse the repository at this point in the history
  • Loading branch information
OmarBazaraa committed Apr 28, 2017
1 parent b97ef33 commit 4f6f990
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 186 deletions.
175 changes: 47 additions & 128 deletions Compressor/Compressor.cpp
Original file line number Diff line number Diff line change
@@ -1,62 +1,34 @@
#include "Compressor.h"

Compressor::Compressor(int threshold) {
this->threshold = threshold;
Compressor::Compressor() {

}

Compressor::~Compressor() {
imgMatrix.deallocate();

}

//
// Compression functions
//

void Compressor::compress(const string& imagePath, const string& outputPath) {
cout << "Loading image..." << endl;
loadImage(imagePath);
cout << "Compressing..." << endl;
encodeData();
cout << "Saving compressed file..." << endl;
saveCompressedFile(outputPath);
}

void Compressor::loadImage(const string& path) {
// Load colored image from file
cv::Mat rgbMat = imread(path, CV_LOAD_IMAGE_COLOR);

// Check for invalid input
if (rgbMat.empty() || !rgbMat.data) {
string errorMessage = "Could not load the image at: " + path;
throw exception(errorMessage.c_str());
}

// Get image size
rows = rgbMat.rows;
cols = rgbMat.cols;

// Convert BGR to Gray
cv::cvtColor(rgbMat, imgMatrix, CV_BGR2GRAY);
}

void Compressor::encodeData() {
void Compressor::compress(const cv::Mat& imageMat, vector<uchar>& outputBytes) {
// Clear previous records
compressedBytes.clear();
compressedSizes.clear();

// Store image rows count
compressedSizes.push_back(encodeToBase256(rows));
compressedSizes.push_back(encodeToBase256(imageMat.rows));

// Store image cols count
compressedSizes.push_back(encodeToBase256(cols));
compressedSizes.push_back(encodeToBase256(imageMat.cols));

// Store image pixels
int cnt = 0;
bool pixel, prv = true;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
pixel = ((int)imgMatrix.at<uchar>(i, j) > this->threshold);

if (prv == pixel) {
bool prv = true;
for (int i = 0; i < imageMat.rows; ++i) {
for (int j = 0; j < imageMat.cols; ++j) {
if (prv == imageMat.at<bool>(i, j)) {
++cnt;
}
else {
Expand All @@ -70,9 +42,9 @@ void Compressor::encodeData() {

// Store compression meta-data
encodeMetaData();
/*for (int i = 0; i < compressedSizes.size(); ++i) {
compressedImage.push_back(compressedSizes[i]);
}*/

// Pass compressed data to function caller
outputBytes.swap(compressedBytes);
}

void Compressor::encodeMetaData() {
Expand Down Expand Up @@ -110,101 +82,38 @@ int Compressor::encodeToBase256(int number) {
return cnt;
}

void Compressor::saveCompressedFile(const string& path) {
ofstream fout(path, ofstream::binary);

if (!fout.is_open()) {
string errorMessage = "Could not load the file at: " + path;
throw exception(errorMessage.c_str());
}

fout.write((char*)compressedBytes.data(), compressedBytes.size());

fout.close();
}

//
// Extraction functions
//

void Compressor::extract(const string& compressedFilePath, const string& outputPath) {
cout << "Loading compressed file..." << endl;
loadCompressedFile(compressedFilePath);
cout << "Extracting..." << endl;
decodeData();
cout << "Saving image..." << endl;
saveImage(outputPath);
}

void Compressor::loadCompressedFile(const string& path) {
ifstream fin(path, ifstream::binary);

if (!fin.is_open()) {
string errorMessage = "Could not load the file at: " + path;
throw exception(errorMessage.c_str());
}

// Get file size
fin.seekg(0, fin.end);
int fileSize = fin.tellg();
fin.seekg(0, fin.beg);
void Compressor::extract(vector<uchar>& compressedBytes, cv::Mat& outputImage) {
// Pass data to compressor object
this->compressedBytes.swap(compressedBytes);

// Read all data
compressedBytes.resize(fileSize);
fin.read((char*)compressedBytes.data(), fileSize);

fin.close();
}

void Compressor::decodeData() {
// Retrieve image meta-data
compressedSizes.clear();
int bytesCnt = 0;
int dataIdx = 0, sizeIdx = -1, idx = -1;
int n = compressedBytes.size();
while (n >= 0 && n > bytesCnt) {
int cnt = (compressedBytes[--n] & 63);
int len = (compressedBytes[n] >> 6) + 1;
bytesCnt += cnt * len;

for (int i = 0; i < cnt; ++i) {
compressedSizes.push_back(len);
}
}
// Retrieve compression meta-data
decodeMetaData();

/*compressedSizes.clear();
int bytesCnt = 0;
int dataIdx = 0, sizeIdx = -1;
int n = compressedImage.size();
while (n >= 0 && n > bytesCnt) {
bytesCnt += (int)compressedImage[--n];
compressedSizes.push_back(compressedImage[n]);
}
reverse(compressedSizes.begin(), compressedSizes.end());*/

if (n != bytesCnt) {
throw exception("Could not extract the given file");
}

// Retrieve image rows count
rows = decodeFromBase256(dataIdx, compressedSizes[++sizeIdx]);
int rows = decodeFromBase256(dataIdx, compressedSizes[++sizeIdx]);
dataIdx += compressedSizes[sizeIdx];

// Retrieve image cols count
cols = decodeFromBase256(dataIdx, compressedSizes[++sizeIdx]);
int cols = decodeFromBase256(dataIdx, compressedSizes[++sizeIdx]);
dataIdx += compressedSizes[sizeIdx];

// Retrieve image pixels
imgMatrix = cv::Mat(rows, cols, CV_8U);
int i = 0, j = 0;
int cnt;
outputImage = cv::Mat(rows, cols, CV_8U);
int i = 0, j = 0, cnt;
bool color = true;
while (dataIdx < n) {

for (int k = 2; k < compressedSizes.size(); ++k) {
cnt = decodeFromBase256(dataIdx, compressedSizes[++sizeIdx]);
dataIdx += compressedSizes[sizeIdx];

while (cnt--) {
imgMatrix.at<uchar>(i, j) = color ? 255 : 0;
outputImage.at<uchar>(i, j) = (color ? 255 : 0);

if (++j >= cols) {
++i;
Expand All @@ -216,6 +125,27 @@ void Compressor::decodeData() {
}
}

void Compressor::decodeMetaData() {
compressedSizes.clear();

int bytesCnt = 0;
int n = compressedBytes.size();

while (n >= 0 && n > bytesCnt) {
int cnt = (compressedBytes[--n] & 63);
int len = (compressedBytes[n] >> 6) + 1;
bytesCnt += cnt * len;

for (int i = 0; i < cnt; ++i) {
compressedSizes.push_back(len);
}
}

if (n != bytesCnt) {
throw exception("Could not extract the given file");
}
}

int Compressor::decodeFromBase256(int idx, int size) {
idx += size;
int num = 0;
Expand All @@ -226,15 +156,4 @@ int Compressor::decodeFromBase256(int idx, int size) {
}

return num;
}

void Compressor::saveImage(const string& path) {
//Mat image(rows, cols, CV_8UC3);

/*int idx = -1;
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
image.at<Vec3b>(i, j) = (binaryImage[++idx] ? Vec3b(255, 255, 255) : Vec3b(0, 0, 0));*/

imwrite(path, imgMatrix);
}
42 changes: 6 additions & 36 deletions Compressor/Compressor.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,20 @@
#include <opencv2/highgui/highgui.hpp>

// Custom libraries
//#include "Utility.h"
using namespace cv;
using namespace std;

class Compressor
{
public:
int rows;
int cols;
int threshold;
private:
vector<int> compressedSizes;
vector<unsigned char> compressedBytes;
cv::Mat imgMatrix;

public:
/**
* Constructor
*/
Compressor(int threshold);
Compressor();

/**
* Destructor
Expand All @@ -39,24 +34,14 @@ class Compressor
/**
* Compress the given black & white jpg image
*/
void compress(const string& imagePath, const string& outputPath);
void compress(const cv::Mat& imageMat, vector<uchar>& outputBytes);

/**
* Extract the given compressed file to a black & white jpg image
*/
void extract(const string& compressedFilePath, const string& outputPath);
void extract(vector<uchar>& compressedBytes, cv::Mat& outputImage);

private:
/**
* Loads grayscaled image from the given path into a matrix
*/
void loadImage(const string& path);

/**
* Encode the loaded image data and save it to compressedBytes vector
*/
void encodeData();

/**
* Encode meta-data needed in decompression process
*/
Expand All @@ -70,29 +55,14 @@ class Compressor
int encodeToBase256(int number);

/**
* Save the compress data to the given path
* Decode image compressed meta-data needed in decompression process
*/
void saveCompressedFile(const string& path);

/**
* Load the compress data from the given path
*/
void loadCompressedFile(const string& path);

/**
* Decode the loaded file data into a binary image
*/
void decodeData();
void decodeMetaData();

/**
* Convert the given size of bytes from compressedBytes vector starting from idx
* from base 256 to decimal.
* Return the converted integer
*/
int decodeFromBase256(int idx, int size);

/**
* Save the loaded image with the given url
*/
void saveImage(const string& path);
};
2 changes: 1 addition & 1 deletion Compressor/Directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ using namespace std;
/**
* Returns a list of files (name, extension) in the given directory
*/
inline void GetFilesInDirectory(vector<pair<string, string>>& files, const string& directory) {
inline void getFilesInDirectory(const string& directory, vector<pair<string, string>>& files) {
// Make sure to change the following command to the corresponding
// one on your operating system when using Linux or MAC
string s = "dir " + directory + "b > dirs.txt";
Expand Down
Loading

0 comments on commit 4f6f990

Please sign in to comment.