卷积后错误的图像结果
Wrong image results after convolution
我正在做一个不使用外部库执行卷积的作业。问题是生成的图像应该是模糊的,但生成的图像是错误的。
这是我正在谈论的图片的link。
程序将灰度 RAW 图像的前 5 个字节作为 header,并将其余部分转换为 2D 向量。每个像素强度 (0-255) 由 unsigned char 中的一个字节表示。二维向量用于卷积,然后将生成的向量写入具有 header.
的新 RAW 图像中
#include <iostream>
#include <string>
#include <fstream>
#include <stdio.h>
#include <vector>
#include <math.h>
using namespace std;
vector<unsigned char> header;
vector < vector<unsigned char> > img;
short int width = 0;
short int height = 0;
void read(string filename, short int &width, short int &height, vector < vector<unsigned char> > &img, vector<unsigned char> &header)
{
const char* path = (char*)filename.c_str();
cout << endl << "Opening: " << path << endl << endl;
ifstream inputfile;
inputfile.open(path, ios::binary);
inputfile.seekg(0);
if (!inputfile)
{
inputfile.clear();
string pathin;
cout << "File not found "<< endl <<"Enter name of image to open : ";
getline(cin, pathin);
read(pathin, width, height, img, header);
}
else
{ //copy header into array
unsigned char h = 0;
for (int x = 0; x < 5; x++)
{
inputfile >>(h);
header.push_back(h);
}
//extract width and height from array
width = (header[1]<<8 | header[0]);
height = (header[3]<<8 | header[2]);
//copy image data into array
char a = '0';
for (int x = 0; x < width; x++)
{
vector <unsigned char> row;
for (int y = 0; y < height; y++)
{
inputfile.get(a);
row.push_back(a);
a = '0';
}
img.push_back(row);
}
inputfile.close();
}
return;
}
void convolution(vector < vector<unsigned char> > &img, short int width, short int height)
{
vector < vector<int> > mask = { { 1, 1, 1 },
{ 1, 1, 1 },
{ 1, 1, 1 } };
int sum;
double min = 0, max = 0, norm = 0;
vector<vector<int>> temp;
for (int i = 0; i < width; ++i)
{
vector<int>temprow;
for (int j = 0; j < height; ++j)
{
temprow.push_back(0);
}
temp.push_back(temprow);
}
for (int i = 1; i < (width-1); i++)
{
for (int j = 1; j < (height-1); j++)
{
sum = 0;
for (int u = -1; u <= 1; u++)
{
for (int v = -1; v <= 1; v++)
{
sum = sum + img[i + u][j + v] * (mask[u+1][v+1]);
}
}
if (sum > max)
max = sum;
if (sum < min)
sum = min;
temp[i][j] = sum;
}
}
//normalize pixels
norm = ceil(max / 255);
cout << "norm = "<<norm<<endl;
for (int i = 1; i < width; i++)
{
for (int j = 1; j < height; j++)
{
temp[i][j] = temp[i][j] /norm ;
}
}
//get max and min again
cout << "max = " << max << endl << "min = " << min<<endl;
max = 0; min = 0;
for (int i = 1; i < width-1; i++)
{
for (int j = 1; j < height-1; j++)
{
if (temp[i][j] > max)
max = temp[i][j];
if (temp[i][j] < min)
min = temp[i][j];
}
}
cout << "max = " << max << endl << "min = " << min << endl;
//display temp
cout << "temp: ";
for (int i = 0; i < 5; i++)
{
cout << endl;
for (int j = 0; j < 5; j++)
{
cout << temp[i][j] << " ";
}
}
//convert int to char
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
img[i][j] = temp[i][j] & 0xff;
}
}
cout << endl;
//display img
cout << "img: ";
for (int i = 0; i < 5; ++i)
{
cout << endl;
for (int j = 0; j < 5; ++j)
printf("%d ", ((unsigned char)(img[i][j])));
}
cout << endl << endl;
}
void write(short int width, short int height, vector < vector<unsigned char> > img, vector<unsigned char> header)
{
string path = "test.raw";
ofstream output;
output.open(path, ios::binary);
for (int i = 0; i < 5; ++i)
{
cout << endl;
for (int j = 0; j < 5; ++j)
printf("%d ", ((unsigned char)(img[i][j])));
}
if (!output)
{
cout << "Error saving file." << endl;
return;
}
else
{
for (int x = 0; x < 5; x++)
output.put (header[x]);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
output.put (img[x][y]);
}
output.close();
cout << "File is saved as: " << path << endl << endl;
}
}
int main()
{
string pathin;
cout << "Enter name of image to open: ";
cin >> pathin;
read(pathin, width, height, img, header);
convolution(img, width, height);
write(width, height, img, header);
system("PAUSE");
return 0;
}
在这一点上,我确信在写作阶段出了点问题,因为应该有一个黑色边框,但它在图像中丢失了。我可以用 openCV 显示数据,但也无法正常工作。我希望有人能指出导致这个问题的原因。
这不是一个完整的、已解决的 "do it all for you" 类型的答案,而是一些帮助您入门的一般指南。
一般来说,对于图像处理,您需要能够看到您正在处理的内容,因为您的格式似乎不寻常,如果您可以使用可靠的程序查看您的输入和输出图像,将会有所帮助.
因此,首先,您可以使用 ImageMagick(它安装在大多数 Linux 发行版上,可用于 macOS 和 Windows)将图像转换为 JPEG 或 PNG,如下所示:
在终端中将 5 字节 header 的 512x479 图像转换为 JPEG:
magick -depth 8 -size 512x479+5 gray:cana.raw result.jpg
更好 - 现在您可以轻松、一致地查看结果。
接下来,拥有一些合理的示例图像是个好主意,因此通过从图像中取出前 5 header 个字节并附加一堆(恰好 245,248 个)零(黑色像素)来使用 Perl 生成这些图像):
perl -e 'print `head -c5 cana.raw` . "\x00"x245248' > black.raw
然后也做一个白色的:
perl -e 'print `head -c5 cana.raw` . "\xff"x245248' > white.raw
还有一个mid-grey一个:
perl -e 'print `head -c5 cana.raw` . "\x80"x245248' > grey.raw
因此,尝试应用您的阅读和写作,不对每一个进行任何处理,并确保它们保持不变。然后添加你的卷积并再次测试。
最后,和你的调试器成为朋友。您没有说您使用的是什么编译器,所以我不能在这里非常具体,但请检查您的图像大小是否正确,并且您正在处理正确的行数和每行的正确元素数。
至于您的代码...您忘记将 max
设置为 255。
此外,您似乎使用与存储输入图像相同的数组来存储输出图像。这对于卷积来说效果不是很好,因为每个新像素都取决于其上方(和下方)像素的值,并且如果您已经在上一次循环中处理了上方的行并将输出值在那里......你会造成混乱,一半取决于原始图像,一半取决于新图像 - 这意味着你会得到重影和重复的元素 - 就像你的图像出现一样。尝试为输出图像创建第二个数组。
我正在做一个不使用外部库执行卷积的作业。问题是生成的图像应该是模糊的,但生成的图像是错误的。
这是我正在谈论的图片的link。
程序将灰度 RAW 图像的前 5 个字节作为 header,并将其余部分转换为 2D 向量。每个像素强度 (0-255) 由 unsigned char 中的一个字节表示。二维向量用于卷积,然后将生成的向量写入具有 header.
的新 RAW 图像中#include <iostream>
#include <string>
#include <fstream>
#include <stdio.h>
#include <vector>
#include <math.h>
using namespace std;
vector<unsigned char> header;
vector < vector<unsigned char> > img;
short int width = 0;
short int height = 0;
void read(string filename, short int &width, short int &height, vector < vector<unsigned char> > &img, vector<unsigned char> &header)
{
const char* path = (char*)filename.c_str();
cout << endl << "Opening: " << path << endl << endl;
ifstream inputfile;
inputfile.open(path, ios::binary);
inputfile.seekg(0);
if (!inputfile)
{
inputfile.clear();
string pathin;
cout << "File not found "<< endl <<"Enter name of image to open : ";
getline(cin, pathin);
read(pathin, width, height, img, header);
}
else
{ //copy header into array
unsigned char h = 0;
for (int x = 0; x < 5; x++)
{
inputfile >>(h);
header.push_back(h);
}
//extract width and height from array
width = (header[1]<<8 | header[0]);
height = (header[3]<<8 | header[2]);
//copy image data into array
char a = '0';
for (int x = 0; x < width; x++)
{
vector <unsigned char> row;
for (int y = 0; y < height; y++)
{
inputfile.get(a);
row.push_back(a);
a = '0';
}
img.push_back(row);
}
inputfile.close();
}
return;
}
void convolution(vector < vector<unsigned char> > &img, short int width, short int height)
{
vector < vector<int> > mask = { { 1, 1, 1 },
{ 1, 1, 1 },
{ 1, 1, 1 } };
int sum;
double min = 0, max = 0, norm = 0;
vector<vector<int>> temp;
for (int i = 0; i < width; ++i)
{
vector<int>temprow;
for (int j = 0; j < height; ++j)
{
temprow.push_back(0);
}
temp.push_back(temprow);
}
for (int i = 1; i < (width-1); i++)
{
for (int j = 1; j < (height-1); j++)
{
sum = 0;
for (int u = -1; u <= 1; u++)
{
for (int v = -1; v <= 1; v++)
{
sum = sum + img[i + u][j + v] * (mask[u+1][v+1]);
}
}
if (sum > max)
max = sum;
if (sum < min)
sum = min;
temp[i][j] = sum;
}
}
//normalize pixels
norm = ceil(max / 255);
cout << "norm = "<<norm<<endl;
for (int i = 1; i < width; i++)
{
for (int j = 1; j < height; j++)
{
temp[i][j] = temp[i][j] /norm ;
}
}
//get max and min again
cout << "max = " << max << endl << "min = " << min<<endl;
max = 0; min = 0;
for (int i = 1; i < width-1; i++)
{
for (int j = 1; j < height-1; j++)
{
if (temp[i][j] > max)
max = temp[i][j];
if (temp[i][j] < min)
min = temp[i][j];
}
}
cout << "max = " << max << endl << "min = " << min << endl;
//display temp
cout << "temp: ";
for (int i = 0; i < 5; i++)
{
cout << endl;
for (int j = 0; j < 5; j++)
{
cout << temp[i][j] << " ";
}
}
//convert int to char
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
img[i][j] = temp[i][j] & 0xff;
}
}
cout << endl;
//display img
cout << "img: ";
for (int i = 0; i < 5; ++i)
{
cout << endl;
for (int j = 0; j < 5; ++j)
printf("%d ", ((unsigned char)(img[i][j])));
}
cout << endl << endl;
}
void write(short int width, short int height, vector < vector<unsigned char> > img, vector<unsigned char> header)
{
string path = "test.raw";
ofstream output;
output.open(path, ios::binary);
for (int i = 0; i < 5; ++i)
{
cout << endl;
for (int j = 0; j < 5; ++j)
printf("%d ", ((unsigned char)(img[i][j])));
}
if (!output)
{
cout << "Error saving file." << endl;
return;
}
else
{
for (int x = 0; x < 5; x++)
output.put (header[x]);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
output.put (img[x][y]);
}
output.close();
cout << "File is saved as: " << path << endl << endl;
}
}
int main()
{
string pathin;
cout << "Enter name of image to open: ";
cin >> pathin;
read(pathin, width, height, img, header);
convolution(img, width, height);
write(width, height, img, header);
system("PAUSE");
return 0;
}
在这一点上,我确信在写作阶段出了点问题,因为应该有一个黑色边框,但它在图像中丢失了。我可以用 openCV 显示数据,但也无法正常工作。我希望有人能指出导致这个问题的原因。
这不是一个完整的、已解决的 "do it all for you" 类型的答案,而是一些帮助您入门的一般指南。
一般来说,对于图像处理,您需要能够看到您正在处理的内容,因为您的格式似乎不寻常,如果您可以使用可靠的程序查看您的输入和输出图像,将会有所帮助.
因此,首先,您可以使用 ImageMagick(它安装在大多数 Linux 发行版上,可用于 macOS 和 Windows)将图像转换为 JPEG 或 PNG,如下所示:
在终端中将 5 字节 header 的 512x479 图像转换为 JPEG:
magick -depth 8 -size 512x479+5 gray:cana.raw result.jpg
更好 - 现在您可以轻松、一致地查看结果。
接下来,拥有一些合理的示例图像是个好主意,因此通过从图像中取出前 5 header 个字节并附加一堆(恰好 245,248 个)零(黑色像素)来使用 Perl 生成这些图像):
perl -e 'print `head -c5 cana.raw` . "\x00"x245248' > black.raw
然后也做一个白色的:
perl -e 'print `head -c5 cana.raw` . "\xff"x245248' > white.raw
还有一个mid-grey一个:
perl -e 'print `head -c5 cana.raw` . "\x80"x245248' > grey.raw
因此,尝试应用您的阅读和写作,不对每一个进行任何处理,并确保它们保持不变。然后添加你的卷积并再次测试。
最后,和你的调试器成为朋友。您没有说您使用的是什么编译器,所以我不能在这里非常具体,但请检查您的图像大小是否正确,并且您正在处理正确的行数和每行的正确元素数。
至于您的代码...您忘记将 max
设置为 255。
此外,您似乎使用与存储输入图像相同的数组来存储输出图像。这对于卷积来说效果不是很好,因为每个新像素都取决于其上方(和下方)像素的值,并且如果您已经在上一次循环中处理了上方的行并将输出值在那里......你会造成混乱,一半取决于原始图像,一半取决于新图像 - 这意味着你会得到重影和重复的元素 - 就像你的图像出现一样。尝试为输出图像创建第二个数组。