C++ 创建子矩阵

标签 c++ image-processing matrix

对于一项作业,我们被要求创建一个程序,该程序可以对跳跃的 512x512 灰度图像进行打乱(通过将其分解为 32x32 block 进行打乱)。灰度图像通过文本文件导入到项目中,然后使用预定义函数将值转换为一维数组。使用它,我们的任务是创建一个矩阵类,该矩阵类可以存储并最终操纵图像,以恢复打乱的图像。

我在创建用于比较方式的子矩阵时遇到问题(我的一般想法是从混洗图像和正常图像中选择第一个 32x32 block ,然后比较它们的像素值以找到匹配项)。我的 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 以外的任何值时,我的问题就会出现,例如在上面的代码中,第一个 block (开始行 0、结束行 32、开始列 0、结束列 32)的值正确显示但是当循环迭代我得到一个堆损坏错误,我无法弄清楚出了什么问题。另一个观察结果是,如果我将 endrow 和 endcolumn 增加到 32 以上(例如,如果我将它们增加到 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 方法中查看:

return t;
delete[] block;

返回后的删除意味着堆内存泄漏,因为 block 永远不会被删除。

现在为什么会有堆损坏:

你总是要分配一个 32*32 的 block (看看你是如何计算结束 - 开始的?它总是 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,end row 是 64。但是你的矩阵只有 32!

关于C++ 创建子矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21420676/

相关文章:

hadoop - 在mahout中输出项目 Material 相似度矩阵

hadoop - Hadoop中的矩阵求逆,乘法和本征计算

c++ - C++ 运算符如何工作

c++ - 为什么在使用<set>迭代器时不能使用成员函数获取成员变量?

objective-c - 与图像或 key 数据库进行图像比较

python - 使用openCV-python将两个轮廓分割成两个相同大小的不同图像

r - 具有整数随机行的矩阵

c++ - C++ 的 JSON 解析器

C++ 复制构造函数和运算符

image-processing - 使用 SciKit-Image 和 SciKit-Learn 进行图像预处理和聚类 - 需要一些建议