2014-01-29 74 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