2014-01-29 113 views
1

對於一個任務,我們被要求創建一個程序,可以緩衝512x512灰度圖像(它被分解爲32x32塊進行混洗)。灰度圖像通過文本文件導入到項目中,然後使用預定義函數將值轉換爲1d數組。使用這個我們的任務是創建一個矩陣類,它可以存儲和最終操縱圖像,以恢復混洗圖像。C++創建一個子矩陣

我在創建使用比較方式的子表中存在問題(我的一般想法是從混洗和正常圖像中選擇第一個32x32塊,然後比較它們的像素值以找到匹配)。我getBlock函數的函數如下:

Matrix Matrix::getBlock(int startRow, int endRow, int startColumn, int endColumn) 
{ 
    int Row = endRow - startRow; 
    int Column = endColumn - startColumn; 
    double* block = new double[(Row) *(Column)]; 
    int n = endColumn - startColumn; 
    for (int ii = startRow; ii < endRow; ii++) 
    { 
     for (int jj = startColumn; jj < endColumn; jj++) 
     { 
      int k = ii*n + jj; 
      block[k] = data[ii*N + jj]; 
     } 
    } 
    Matrix t(Row, Column, block); 
    return t; 
    delete[] block; 
} 

而且在我的main()我試圖實現功能如下:

for (int x = 0; x < 480; x += 32) // so starts at 0 and continues if x less than 480 as 480 + 32 = 512 
{ 
    for (int y = 0; y < 480; y += 32) // same as x but with y 
    {   
     Matrix block = ShuffledCode.getBlock(x, (x + 32), y, (y + 32)); 

     cout << block.sum() << endl;     
    } 
} 

我的問題出現時啓動欄和開始行成爲0以外的任何東西,例如在上面的代碼中,正確顯示第一個塊(startrow 0,endrow 32,startcolumn 0,endcolumn 32)的值,但是當循環迭代時,我得到堆損壞錯誤,弄清楚發生了什麼問題。另一個觀察是,如果我增加32以上的endrow和endcolumn(例如,如果我增加他們到64)它似乎運作良好,並返回正確的值。

如果有人有任何想法可能導致它,我將非常感激,一直在努力了好幾天,並沒有取得任何進展。如果問題與程序的另一部分有關,我還包括了下面的所有代碼。該source.cpp文件:

#include <sstream> // stringstream 
#include <iostream> // cout, cerr 
#include <fstream> // ifstream 
#include <istream> 
#include <assert.h> 
#include "Matrix.H" 

using namespace std; 

// Input data are provided in .txt format and can be converted to .pgm files for  visualization 
// Download (free) ImageJ for plotting images in .pgm format 
// http://rsb.info.nih.gov/ij/download.html 

// Reads .txt file representing an image of R rows and C Columns stored in filename 
// and converts it to a 1D array of doubles of size R*C 
// Memory allocation is performed inside readTXT 
double* readTXT(char *fileName, int sizeR, int sizeC); 

// Converts a 1D array of doubles of size R*C to .pgm image of R rows and C Columns 
// and stores .pgm in filename 
// Use Q = 255 for greyscale images and Q=1 for binary images. 
void WritePGM(char *filename, double *data, int sizeR, int sizeC, int Q); 


int main() 
{ 
// This part will show you how to use the two functions. 

//M and N represent the number of rows and columns in the image, 
//e.g. for task 1: logo_with_noise and logo_shuffled, M = 512, N = 512 
//e.g. for task 2, Cluttered_scene, M = 768, N = 1024 
//e.g. for task 2, Wally_grey, M = 49, N = 36 
int M = 512; int N = 512; int count = 0; 
// input_data is a pointer to a 1D array of M*N doubles stored in heap. Memory allocation is performed 
// inside readTXT. readTXT will read an image (in .pgm format) of size MxN and will store the result in input_data. 
// once you're done with data DO NOT forget to delete the memory as in the end of this main() function 
double* input_data = 0; 
double* noise_data = 0; 

cout << endl; 
cout << "Data from text file -------------------------------------------" << endl; 

// shuffled image is stored in inputFileName, input_data holds the data in a 1d array 
char* inputFileName = "C:\\Users\\Jamie\\SkyDrive\\Documents\\SoftwareDevAss\\ADS_Assignment\\Datafile\\logo_shuffled.txt"; 
input_data = readTXT(inputFileName, M, N); 

// the img with noise is stored in inputFileName2, noise_data holds the data in a 1d array 
char* inputFileName2 = "C:\\Users\\Jamie\\SkyDrive\\Documents\\SoftwareDevAss\\ADS_Assignment\\Datafile\\logo_with_noise.txt"; 
noise_data = readTXT(inputFileName2, M, N); 

// this loop reduces the noise on the provided image to make it clear, uses threshold 170 as i found that gives the best results 
for (int x = 0; x < 262144; x++) 
{ 

    if (noise_data[x] < 170) 
    { 
     noise_data[x] = 0; 
    } 
    else 
    { 
     noise_data[x] = 255; 
    } 
} 


/*long int pLength = 262144; // total length in pixels of 1d array holding the image 
long int bLength = 1024; // total length in pixels of each block (32x32) 
long int cLength = 262144; // current remaning length in pixels of 1d array holding the image 
long int sum = 0; // theoretical limit of 262144 (if all pixels are white thus have the value 255) 
for (int rBlocks = 0; rBlocks < 254; rBlocks++) 
{ 
    sum = 0; 
    cLength = pLength - ((rBlocks) * 1024); 
    double *sub = noise_data - cLength; 
    assert(sub[0] == noise_data[bLength * rBlocks]); 

    for (int i = 0; i < 1024; i++) 
    { 
     sum += sub[i]; 
    } 
    cout << sum << endl; 

} 

*/ 


// at this point noise_data holds the original image. 
Matrix ShuffledCode(512, 512, input_data); 
Matrix SortedCode(512, 512, noise_data); 
bool wedone = false; 
int val = 1024; 

// issue with increasing the start row and column above 0, end row and column can be increased fine. 
for (int x = 0; x < 480; x += 32) // so starts at 0 and continues if x less than 480 as 480 + 32 = 512 
{ 
    for (int y = 0; y < 480; y += 32) // same as x but with y 
    {   
     Matrix block = ShuffledCode.getBlock(x, (x + 32), y, (y + 32)); 

     cout << block.sum() << endl;     
    } 
} 


/*for (int x = 0; x < 262144; x++) 
{ 

      input_data[x] = noise_data[x]; 

} 
*/ 

/*int MAX = 262144; 
for (int i=0; i<MAX; i++) 
{ 
    for (int j = i + 1; j < MAX; j++) 
    { 
     if (input_data[i] == input_data[j] && noise_data[i] == noise_data[j]) 
     { 

     } 
     else 
     { 
      input_data[i] = noise_data[i]; 
      input_data[j] = noise_data[j]; 
     } 
    } 
} 
*/ 


// writes data back to .pgm file stored in outputFileName 
char* outputFileName = "C:\\Users\\Jamie\\SkyDrive\\Documents\\SoftwareDevAss\\ADS_Assignment\\Datafile\\logo_restored.pgm"; 
char* cleanFile = "C:\\Users\\Jamie\\SkyDrive\\Documents\\SoftwareDevAss\\ADS_Assignment\\Datafile\\logo_clean.pgm"; 
char* tester = "C:\\Users\\Jamie\\SkyDrive\\Documents\\SoftwareDevAss\\ADS_Assignment\\Datafile\\tester.pgm"; 
// Use Q = 255 for greyscale images and 1 for binary images. 
int Q = 255; 
WritePGM(outputFileName, input_data, M, N, Q); 
WritePGM(cleanFile, noise_data, M, N, Q); 

delete[] noise_data; 
delete[] input_data; 


return 0; 
} 

//Consructor 
Matrix::Matrix(int sizeR, int sizeC, double* input_data) 
{ 
M = sizeR; 
N = sizeC; 
data = new double[M*N]; 
for (int ii = 0; ii < M*N; ii++) 
{ 
    data[ii] = input_data[ii]; 
} 
} 

Matrix::Matrix(int sizeR, int sizeC) 
{ 
M = sizeR; 
N = sizeC; 
data = new double[M*N]; 

for (int ii = 0; ii < M*N; ii++) 
{ 
    *(data + ii) = 0; 
} 
} 

//Destructor 
Matrix::~Matrix() 
{ 
delete[] data; 
} 

//Copy Constructor 
Matrix::Matrix(const Matrix& existingMatrix) 
{ 
M = existingMatrix.getM(); 
N = existingMatrix.getN(); 
data = new double[M*N]; 

for (int ii = 0; ii < M; ii++) 
{ 
    for (int jj = 0; jj < N; jj++) 
    { 
     int k = ii*N + jj; 
     data[k] = existingMatrix.get(ii, jj); 
    } 
} 
} 

//Pass by constant value 
double Matrix::get(int i, int j) const 
{ 
int k = i*N + j; 
return data[k]; 
} 

//Pass by Refrence 
const void Matrix::set(int i, int j, double& val) 
{ 
int k = i*N + j; 
val = data[k]; 
} 

//Return Value of M 
int Matrix::getM() const 
{ 
return M; 
} 

//Return Value of N 
int Matrix::getN() const 
{ 
return N; 
} 

//Returns part of the matrix 
Matrix Matrix::getBlock(int startRow, int endRow, int startColumn, int endColumn) 
{ 
int Row = endRow - startRow; 
int Column = endColumn - startColumn; 
double* block = new double[(Row) *(Column)]; 
int n = endColumn - startColumn; 
for (int ii = startRow; ii < endRow; ii++) 
{ 
    for (int jj = startColumn; jj < endColumn; jj++) 
    { 
     int k = ii*n + jj; 
     block[k] = data[ii*N + jj]; 
    } 
} 
Matrix t(Row, Column, block); 
return t; 
delete[] block; 
} 

//Allows for addion of Matricies, Operation Overloading. 
Matrix Matrix::operator +(const Matrix& B) 
{ 
Matrix C = Matrix(M, N, 0); 
double temp; 
for (int ii = 0; ii < M; ii++) 
{ 
    for (int jj = 0; jj < N; jj++) 
    { 
     temp = data[ii*N + jj] + B.get(ii, jj); 
     C.set(ii, jj, temp); 
    } 
} 

return C; 
} 

//Makes x and y equal, Opperation Overloading. 
Matrix Matrix::operator =(const Matrix& B) 
{ 
if (this == &B) 
{ 
    return *this; 
} 

else 
{ 
    M = B.getM(); 
    N = B.getN(); 
    delete[] data; 
    data = new double[M*N]; 
    for (int ii = 0; ii < M; ii++) 
    { 
     for (int jj = 0; jj < N; jj++) 
     { 
      data[ii*N + jj] = B.get(ii, jj); 
     } 
    } 
    return *this; 
} 
} 

//Allows for subtraction of matricies, Operation Overloading. 
Matrix Matrix::operator -(const Matrix& B) 
{ 
Matrix C = Matrix(M, N); 
double temp; 
for (int ii = 0; ii < M - 1; ii++) 
{ 
    for (int jj = 0; jj < N - 1; jj++) 
    { 
     temp = data[ii*N + jj] - B.get(ii, jj); 
     C.set(ii, jj, temp); 
    } 
} 

return C; 
} 

//Allows for multiplication of Matricies, Operation Overloading. 
Matrix Matrix::operator *(const Matrix& B) 
{ 
Matrix C = Matrix(M, B.getN()); 
double temp; 
for (int ii = 0; ii < M; ii++) 
{ 
    for (int jj = 0; jj < N; jj++) 
    { 
     temp = data[ii*N + jj] * B.get(ii, jj); 
     C.set(ii, jj, temp); 
    } 
} 

return C; 
} 

//Allows for addition of Matricies, Operation Overloading. 
Matrix Matrix::operator /(const Matrix& B) 
{ 
Matrix C = Matrix(M, B.getN(), 0); 
double temp; 
for (int ii = 0; ii < M; ii++) 
{ 
    for (int jj = 0; jj < N; jj++) 
    { 
     temp = data[ii*N + jj]/B.get(ii, jj); 
     C.set(ii, jj, temp); 
    } 
} 

return C; 
} 

//Incrmentation of all values in Matrix by 1, Operation Overloading. 
Matrix Matrix::operator ++() 
{ 
for (int ii = 0; ii < M*N; ii++) 
{ 
    data[ii] = data[ii]++; 
} 

return *this; 
} 


//Allows calling of "get" function indirectly. 
double Matrix::operator() (int i, int j) 
{ 
return data[i*N + j]; 
} 

double Matrix::sum() 
{ 
double total = 0.0; 
for (int ii = 0; ii < M*N; ii++) 
{ 
    total = total + data[ii]; 
} 


return total; 
} 

void Matrix::out() 
{ 
for (int ii = 0; ii < M*N; ii++) 
{ 
    if (data[ii] == 255) 
     cout << "1 "; 
    else 
     cout << data[ii] << " "; 
} 
} 

// Read .txt file with image of size RxC, and convert to an array of doubles 
double* readTXT(char *fileName, int sizeR, int sizeC) 
{ 
double* data = new double[sizeR*sizeC]; 
int i = 0; 
ifstream myfile(fileName); 
if (myfile.is_open()) 
{ 

    while (myfile.good()) 
    { 
     if (i>sizeR*sizeC - 1) break; 
     myfile >> *(data + i); 
     // cout << *(data+i) << ' '; // This line display the converted data  on the screen, you may comment it out. 
     i++; 
    } 
    myfile.close(); 
} 

else cout << "Unable to open file"; 
//cout << i; 

return data; 
} 

// convert data from double to .pgm stored in filename 
void WritePGM(char *filename, double *data, int sizeR, int sizeC, int Q) 
{ 

int i, j; 
unsigned char *image; 
ofstream myfile; 

image = (unsigned char *) new unsigned char[sizeR*sizeC]; 

// convert the integer values to unsigned char 

for (i = 0; i<sizeR*sizeC; i++) 
    image[i] = (unsigned char) data[i]; 

myfile.open(filename, ios::out | ios::binary | ios::trunc); 

if (!myfile) { 
    cout << "Can't open file: " << filename << endl; 
    exit(1); 
} 

myfile << "P5" << endl; 
myfile << sizeC << " " << sizeR << endl; 
myfile << Q << endl; 

myfile.write(reinterpret_cast<char *>(image), (sizeR*sizeC)*sizeof(unsigned char)); 

if (myfile.fail()) { 
    cout << "Can't write image " << filename << endl; 
    exit(0); 
} 

myfile.close(); 

delete[] image; 

} 

Matrix類的頭文件如下:

#pragma 
#ifndef MATRIX_H 
#define MATRIX_H 

class Matrix 
{ 
protected: 
int M; 
int N; 
double* data; 

public: 

Matrix(int sizeR, int sizeC, double* input_data); //Constructor 
Matrix(int sizeR, int sizeC); 
~Matrix(); //Destructor 
Matrix(const Matrix& existingMatrix); //Copy Constructor 
double get(int i, int j) const; //Returns value at specified location 
const void set(int i, int j, double& val);//Changes value at specified location 
int getM() const; //Return value of M 
int getN() const; //Return value of N 
Matrix getBlock(int startRow, int endRow, int startColumn, int endColumn);//Return section of Matrix 
Matrix operator + (const Matrix& B); // addition 
Matrix operator = (const Matrix& B); // equals 
Matrix operator - (const Matrix& B); // subtraction 
Matrix operator * (const Matrix& B); // multiplication 
Matrix operator/(const Matrix& B); // division 
Matrix operator ++(); // increment by 1 
double operator() (int i, int j); 
void out(); 
double sum(); 
}; 

class BinaryImage 
:public Matrix 
{ 

public: 
BinaryImage(int sizeR, int sizeC, double* input_data, double thresh); 
~BinaryImage(); 
BinaryImage(const Matrix& rhs, double thresh); 
BinaryImage(const BinaryImage& existingBinIm); 
const void set(int i, int j, double& val); 
}; 

#endif 

任何幫助將不勝感激,謝謝。

回答

0

對於初學者,看看這個在您的getBlock方法:

return t; 
delete[] block; 

復位裝置,因爲從來沒有塊被刪除堆內存泄漏後刪除。

現在爲什麼你堆腐敗:(?看你是如何計算結束 - 開始它始終將是32)

你總是會分配一個塊是32×32

// This is how you call, x = startRow, x+32 is endRow. 
Matrix block = ShuffledCode.getBlock(x, (x + 32), y, (y + 32)); 

// This is inside your method: (endRow is startRow + 32) = 32 always 
int Row = endRow - startRow; 

但是在該方法中,使用輸入參數訪問的方式超出了32。所以當循環到達i = 1時,startRow是32,最後一行是64.但是你的矩陣只能達到32!

+0

感謝您的回覆。想想我已經大量誤解了.getBlock意味着要做什麼,我認爲它是在行和列中檢索數據記錄器0-32,然後創建一個包含這些值的較小矩陣,但是如果起始行/列和結束行/列變量僅指示塊的大小如何改變它們包含的值?例如,如果我想將ShuffledCode矩陣的位置32,64,32,64中的值保存到一個塊中? – user2780101

+0

您是否爲該方法編寫了impl? – Lother

+0

獲取塊返回一個32x32矩陣與來自較大矩陣的值。無論如何,你接近一個解決方案。缺少的關鍵在於如何在getBlock雙循環內增加內容。您從計算k中獲得的值將比小矩陣的大小大得多。說服你自己,爲什麼會這樣。然後,解決你如何計算k(這只是縮小到32x32範圍內的問題) – Lother