如何将这个 PGM 渐变翻转 90 度? (存储在向量中)
How to flip this PGM gradient 90 degrees? (stored in vectors)
我一直致力于使用不同的抖动方法实现灰度渐变,但该任务要求渐变是水平的,从左侧的黑色开始。
在尝试水平旋转图像时,我尝试过:
std::reverse(result.begin(), result.end())
我也试过像处理二维数组一样处理矢量:
temp = result[i][j];
result[i][j] = result[i][width - 1 - j];
result[i][width - 1 - j] = temp;
None 这些方法到目前为止都有效。
这是我正在使用的代码:
//***headers n stuff***
vector<vector<int>> gradient(int height, int width)
{
assert(height > 0 && width > 0);
int cf = height / 255;
int color = 0;
vector<vector<int>> result(width, vector<int>(height));
for (int i = 0; i < height; i += cf)
{
for (int j = 0; j < cf; j++)
{
fill(result[i + j].begin(), result[i + j].end(), color % 255);
}
color--;
}
stable_sort(result.begin(), result.end());
return result;
}
vector<vector<int>> Ordered(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
vector<vector<int>> temp(height, vector<int>(width));
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int xlocal = i%ditherSize;
int ylocal = j%ditherSize;
int requiredShade = diterLookup[xlocal + ylocal * 3]*255/9;
if (requiredShade >= result[i][j])
{
result[i][j] = 0;
}
else {
result[i][j] = 255;
}
}
}
return temp;
}
vector<vector<int>> Random(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
//vector<vector<int>> result(height, vector<int>(width));
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int requiredShade = rand() % 255;
if (requiredShade >= result[i][j]) {
result[i][j] = 0;
}
else {
result[i][j] = 255;
}
}
}
return result;
}
vector<vector<int>> Floyd_Steinberg(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int oldpixel = result[i][j];
int newpixel;
if (oldpixel<=127) {
newpixel = 0;
}
else {
newpixel = 255;
}
result[i][j] = newpixel;
int quanterror = oldpixel - newpixel;
if (j < width - 1) {
result[i][j+1] += quanterror * 7 / 16;
}
if (i < height - 1) {
if (j > 0){
result[i + 1][j - 1] += quanterror * 3 / 16;
}
result[i+1][j] += quanterror * 5 / 16;
if (j < width - 1) {
result[i + 1][j + 1] += quanterror * 1 / 16;
}
}
}
}
return result;
}
vector<vector<int>> JJN(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int oldpixel = result[i][j];
int newpixel;
if (oldpixel <= 127) {
newpixel = 0;
}
else {
newpixel = 255;
}
result[i][j] = newpixel;
int quanterror = oldpixel - newpixel;
if (j < width - 1) {
result[i][j + 1] += quanterror * 7 / 48;
if(j<width-2)
result[i][j + 2] += quanterror * 5 / 48;
}
if (i < height - 1) {
if (j > 0) {
if (j > 1)
result[i + 1][j - 2] += quanterror * 3 / 48;
result[i + 1][j - 1] += quanterror * 5 / 48;
}
result[i + 1][j] += quanterror * 7 / 48;
if (j < width - 1) {
result[i + 1][j + 1] += quanterror * 5 / 48;
if (j < width - 2)
result[i + 1][j + 2] += quanterror * 3 / 48;
}
}
if (i < height - 2) {
if (j > 0) {
if(j>1)
result[i + 2][j - 2] += quanterror * 1 / 48;
result[i + 2][j - 1] += quanterror * 3 / 48;
}
result[i + 2][j] += quanterror * 5 / 48;
if (j < width - 1) {
result[i + 2][j + 1] += quanterror * 3 / 48;
if (j < width - 2)
result[i + 2][j + 2] += quanterror * 1 / 48;
}
}
}
}
return result;
}
int main(int argc, char *argv[])
{
if (argc < 5) {
cout << "usage:" << endl << "prog.exe <filename> <width> <height> <dithering>"<<endl;
return 0;
}
stringstream w(argv[2]);
stringstream h(argv[3]);
stringstream d(argv[4]);
int numcols, numrows, dithering;
//***handling error cases ***
srand(time(0));
ofstream file;
file.open(argv[1]);
if (!file)
{
cout << "can't open file" << endl;
return 0;
}
file << "P5" << "\n";
file << numrows << " " << numcols << "\n";
file << 255 << "\n";
vector<vector<int>> pixmap{ gradient(numrows, numcols) };
switch (dithering) {
case 1:
pixmap = Ordered(numrows, numcols, pixmap);
break;
case 2:
pixmap = Random(numrows, numcols, pixmap);
break;
case 3:
pixmap = Floyd_Steinberg(numrows, numcols, pixmap);
break;
case 4:
pixmap = JJN(numrows, numcols, pixmap);
break;
default:
break;
}
for_each(pixmap.begin(), pixmap.end(), [&](const auto& v) {
copy(v.begin(), v.end(), ostream_iterator<char>{file, ""});
});
file.close();
}
这是结果Using Ordered Dither
如果你的灰度图像存储为std::vector<std::vector<int>>
,我已经为你编写了以下代码。
它将图像沿三角方向旋转90度:
#include <iostream>
#include <vector>
typedef std::vector<std::vector<int>> GrayScaleImage;
// To check is the GrayScaleImage is valid (rectangular and not empty matrix)
bool isValid(const GrayScaleImage & gsi)
{
bool valid(true);
if(!gsi.empty())
{
size_t width(gsi[0].size());
for(unsigned int i = 1; valid && (i < gsi.size()); ++i)
{
if(gsi[i].size() != width)
valid = false;
}
}
else
valid = false;
return valid;
}
// To print the GrayScaleImage in the console (for the test)
void display(const GrayScaleImage & gsi)
{
for(const std::vector<int> & line : gsi)
{
for(size_t i = 0; i < line.size(); ++i)
std::cout << line[i] << ((i < line.size()-1) ? " " : "");
std::cout << '\n';
}
std::cout << std::flush;
}
// To rotate the GrayScaleImage by 90 degrees in the trigonometric direction
bool rotate90(const GrayScaleImage & gsi, GrayScaleImage & result)
{
bool success(false);
if(isValid(gsi))
{
result = GrayScaleImage(gsi[0].size());
for(const std::vector<int> & line : gsi)
{
for(unsigned int i = 0; i < line.size(); ++i)
result[gsi[0].size()-1 - i].push_back(line[i]);
}
success = true;
}
return success;
}
// Test
int main()
{
GrayScaleImage original { {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11} };
GrayScaleImage rotated;
rotate90(original, rotated);
std::cout << "Original:" << std::endl;
display(original);
std::cout << "\nRotated:" << std::endl;
display(rotated);
return 0;
}
您感兴趣的函数是rotate90()
。
写在main()
函数中的测试输出为:
Original:
0 1 2
3 4 5
6 7 8
9 10 11
Rotated:
2 5 8 11
1 4 7 10
0 3 6 9
如您所见,它运行成功。
希望对你有所帮助
编辑:
我尝试使用生成的真实灰度图像,rotate90()
函数运行良好。
这是旋转图像前后的视图(2 个示例,横向和纵向):
所以现在我们知道该功能运行良好。
我看到你的结果不符合预期(添加了黑色区域,维度不匹配),当你对矩阵的维度有错误时,就会出现这种行为。
编辑2:
无效输出不是由于rotate90()
,而是由于 PGM 文件生成。我认为这是因为数据是作为二进制文件而不是 header 写入的。
我编写的以下函数创建了有效的 PGM 文件:
typedef std::vector<std::vector<uint8_t>> GrayScaleImage;
bool createPGMImage(const std::string & file_path, const GrayScaleImage & img)
{
bool success(false);
if(isValid(img))
{
std::ofstream out_s(file_path, std::ofstream::binary);
if(out_s)
{
out_s << "P5\n" << img[0].size() << ' ' << img.size() << '\n' << 255 << '\n';
for(const std::vector<uint8_t> & line : img)
{
for(uint8_t p : line)
out_s << p;
out_s << std::flush;
}
success = true;
out_s.close();
}
}
return success;
}
isValid()
函数与我在 rotate90()
中给出的函数相同。
我还将 int
值替换为 uint8_t
(unsigned char
) 值,以便在我们写入单字节值 (0-255) 时更加一致。
我一直致力于使用不同的抖动方法实现灰度渐变,但该任务要求渐变是水平的,从左侧的黑色开始。 在尝试水平旋转图像时,我尝试过:
std::reverse(result.begin(), result.end())
我也试过像处理二维数组一样处理矢量:
temp = result[i][j];
result[i][j] = result[i][width - 1 - j];
result[i][width - 1 - j] = temp;
None 这些方法到目前为止都有效。 这是我正在使用的代码:
//***headers n stuff***
vector<vector<int>> gradient(int height, int width)
{
assert(height > 0 && width > 0);
int cf = height / 255;
int color = 0;
vector<vector<int>> result(width, vector<int>(height));
for (int i = 0; i < height; i += cf)
{
for (int j = 0; j < cf; j++)
{
fill(result[i + j].begin(), result[i + j].end(), color % 255);
}
color--;
}
stable_sort(result.begin(), result.end());
return result;
}
vector<vector<int>> Ordered(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
vector<vector<int>> temp(height, vector<int>(width));
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int xlocal = i%ditherSize;
int ylocal = j%ditherSize;
int requiredShade = diterLookup[xlocal + ylocal * 3]*255/9;
if (requiredShade >= result[i][j])
{
result[i][j] = 0;
}
else {
result[i][j] = 255;
}
}
}
return temp;
}
vector<vector<int>> Random(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
//vector<vector<int>> result(height, vector<int>(width));
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int requiredShade = rand() % 255;
if (requiredShade >= result[i][j]) {
result[i][j] = 0;
}
else {
result[i][j] = 255;
}
}
}
return result;
}
vector<vector<int>> Floyd_Steinberg(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int oldpixel = result[i][j];
int newpixel;
if (oldpixel<=127) {
newpixel = 0;
}
else {
newpixel = 255;
}
result[i][j] = newpixel;
int quanterror = oldpixel - newpixel;
if (j < width - 1) {
result[i][j+1] += quanterror * 7 / 16;
}
if (i < height - 1) {
if (j > 0){
result[i + 1][j - 1] += quanterror * 3 / 16;
}
result[i+1][j] += quanterror * 5 / 16;
if (j < width - 1) {
result[i + 1][j + 1] += quanterror * 1 / 16;
}
}
}
}
return result;
}
vector<vector<int>> JJN(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int oldpixel = result[i][j];
int newpixel;
if (oldpixel <= 127) {
newpixel = 0;
}
else {
newpixel = 255;
}
result[i][j] = newpixel;
int quanterror = oldpixel - newpixel;
if (j < width - 1) {
result[i][j + 1] += quanterror * 7 / 48;
if(j<width-2)
result[i][j + 2] += quanterror * 5 / 48;
}
if (i < height - 1) {
if (j > 0) {
if (j > 1)
result[i + 1][j - 2] += quanterror * 3 / 48;
result[i + 1][j - 1] += quanterror * 5 / 48;
}
result[i + 1][j] += quanterror * 7 / 48;
if (j < width - 1) {
result[i + 1][j + 1] += quanterror * 5 / 48;
if (j < width - 2)
result[i + 1][j + 2] += quanterror * 3 / 48;
}
}
if (i < height - 2) {
if (j > 0) {
if(j>1)
result[i + 2][j - 2] += quanterror * 1 / 48;
result[i + 2][j - 1] += quanterror * 3 / 48;
}
result[i + 2][j] += quanterror * 5 / 48;
if (j < width - 1) {
result[i + 2][j + 1] += quanterror * 3 / 48;
if (j < width - 2)
result[i + 2][j + 2] += quanterror * 1 / 48;
}
}
}
}
return result;
}
int main(int argc, char *argv[])
{
if (argc < 5) {
cout << "usage:" << endl << "prog.exe <filename> <width> <height> <dithering>"<<endl;
return 0;
}
stringstream w(argv[2]);
stringstream h(argv[3]);
stringstream d(argv[4]);
int numcols, numrows, dithering;
//***handling error cases ***
srand(time(0));
ofstream file;
file.open(argv[1]);
if (!file)
{
cout << "can't open file" << endl;
return 0;
}
file << "P5" << "\n";
file << numrows << " " << numcols << "\n";
file << 255 << "\n";
vector<vector<int>> pixmap{ gradient(numrows, numcols) };
switch (dithering) {
case 1:
pixmap = Ordered(numrows, numcols, pixmap);
break;
case 2:
pixmap = Random(numrows, numcols, pixmap);
break;
case 3:
pixmap = Floyd_Steinberg(numrows, numcols, pixmap);
break;
case 4:
pixmap = JJN(numrows, numcols, pixmap);
break;
default:
break;
}
for_each(pixmap.begin(), pixmap.end(), [&](const auto& v) {
copy(v.begin(), v.end(), ostream_iterator<char>{file, ""});
});
file.close();
}
这是结果Using Ordered Dither
如果你的灰度图像存储为std::vector<std::vector<int>>
,我已经为你编写了以下代码。
它将图像沿三角方向旋转90度:
#include <iostream>
#include <vector>
typedef std::vector<std::vector<int>> GrayScaleImage;
// To check is the GrayScaleImage is valid (rectangular and not empty matrix)
bool isValid(const GrayScaleImage & gsi)
{
bool valid(true);
if(!gsi.empty())
{
size_t width(gsi[0].size());
for(unsigned int i = 1; valid && (i < gsi.size()); ++i)
{
if(gsi[i].size() != width)
valid = false;
}
}
else
valid = false;
return valid;
}
// To print the GrayScaleImage in the console (for the test)
void display(const GrayScaleImage & gsi)
{
for(const std::vector<int> & line : gsi)
{
for(size_t i = 0; i < line.size(); ++i)
std::cout << line[i] << ((i < line.size()-1) ? " " : "");
std::cout << '\n';
}
std::cout << std::flush;
}
// To rotate the GrayScaleImage by 90 degrees in the trigonometric direction
bool rotate90(const GrayScaleImage & gsi, GrayScaleImage & result)
{
bool success(false);
if(isValid(gsi))
{
result = GrayScaleImage(gsi[0].size());
for(const std::vector<int> & line : gsi)
{
for(unsigned int i = 0; i < line.size(); ++i)
result[gsi[0].size()-1 - i].push_back(line[i]);
}
success = true;
}
return success;
}
// Test
int main()
{
GrayScaleImage original { {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11} };
GrayScaleImage rotated;
rotate90(original, rotated);
std::cout << "Original:" << std::endl;
display(original);
std::cout << "\nRotated:" << std::endl;
display(rotated);
return 0;
}
您感兴趣的函数是rotate90()
。
写在main()
函数中的测试输出为:
Original:
0 1 2
3 4 5
6 7 8
9 10 11Rotated:
2 5 8 11
1 4 7 10
0 3 6 9
如您所见,它运行成功。
希望对你有所帮助
编辑:
我尝试使用生成的真实灰度图像,rotate90()
函数运行良好。
这是旋转图像前后的视图(2 个示例,横向和纵向):
所以现在我们知道该功能运行良好。
我看到你的结果不符合预期(添加了黑色区域,维度不匹配),当你对矩阵的维度有错误时,就会出现这种行为。
编辑2:
无效输出不是由于rotate90()
,而是由于 PGM 文件生成。我认为这是因为数据是作为二进制文件而不是 header 写入的。
我编写的以下函数创建了有效的 PGM 文件:
typedef std::vector<std::vector<uint8_t>> GrayScaleImage;
bool createPGMImage(const std::string & file_path, const GrayScaleImage & img)
{
bool success(false);
if(isValid(img))
{
std::ofstream out_s(file_path, std::ofstream::binary);
if(out_s)
{
out_s << "P5\n" << img[0].size() << ' ' << img.size() << '\n' << 255 << '\n';
for(const std::vector<uint8_t> & line : img)
{
for(uint8_t p : line)
out_s << p;
out_s << std::flush;
}
success = true;
out_s.close();
}
}
return success;
}
isValid()
函数与我在 rotate90()
中给出的函数相同。
我还将 int
值替换为 uint8_t
(unsigned char
) 值,以便在我们写入单字节值 (0-255) 时更加一致。