對於一個任務,我們被要求創建一個程序,可以緩衝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
任何幫助將不勝感激,謝謝。
感謝您的回覆。想想我已經大量誤解了.getBlock意味着要做什麼,我認爲它是在行和列中檢索數據記錄器0-32,然後創建一個包含這些值的較小矩陣,但是如果起始行/列和結束行/列變量僅指示塊的大小如何改變它們包含的值?例如,如果我想將ShuffledCode矩陣的位置32,64,32,64中的值保存到一個塊中? – user2780101
您是否爲該方法編寫了impl? – Lother
獲取塊返回一個32x32矩陣與來自較大矩陣的值。無論如何,你接近一個解決方案。缺少的關鍵在於如何在getBlock雙循環內增加內容。您從計算k中獲得的值將比小矩陣的大小大得多。說服你自己,爲什麼會這樣。然後,解決你如何計算k(這只是縮小到32x32範圍內的問題) – Lother