C :操纵PPM文件的问题

C++: Issues with manipulating a PPM file

本文关键字:问题 文件 PPM 操纵      更新时间:2023-10-16

我正在研究一个可以在ppm文件上执行各种效果和操纵的程序。但是,出于测试原因,它使用CIN而不是输入文件。它应该能够一次执行多种效果,但是我什至很难做到。我将在将有效的行上运行一个removeBlue(),然后以不同的值重试,然后将其删除红色或绿色。之类的东西。有很多代码,所以我将尝试仅包括必要的内容。

#include <vector>
#include <stdlib.h>
#include <cstdlib>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
class SimpleImageEffect
{
public:
    virtual void processImage(vector<Point> &points) = 0;
};
class RemoveRed : public SimpleImageEffect
{
public:
    virtual void processImage(vector<Point> &points)
    {
        for (Point& p : points)
        {
            p.setRed(0);
        }
    }
};
//Just an example of one of the effect classes. 
//The code in them is correct, so I won't include the others unless needed.
vector<Point> parse_line(string line)
{
    istringstream scanner{line};
    vector<Point> result{};
    int red = -1;
    int green = -1;
    int blue = -1;
    int counter = 0;
    while(scanner.good())
    {
        if (counter == 0)
        {
            counter++;
            scanner >> red;
        }
        else if (counter == 1)
        {
            counter++;
            scanner >> green;
        }
        else if (counter == 2)
        {
            scanner >> blue;
            Point p{ red, green, blue };
            result.push_back(p);
            counter = 0;
        }
    }
    return result;
}
void readFromCin()
{
    string line = "";
    vector<string> lines_in_file{};
    int i, effect_choice;
    SimpleImageEffect *effect = nullptr;
    getline(cin, line);
    while (line.length() > 0)
    {
        lines_in_file.push_back(line);
        getline(cin, line);
    }
    for (int i = 0; i < lines_in_file.size(); i++)
    {
        if (lines_in_file[i] != "P3")
        {
            effect_choice = strToInt(lines_in_file[i]);
        }
        else if (lines_in_file[i] == "P3")
        {
            cout << lines_in_file[i] << endl;
            cout << lines_in_file[i+1] << endl;
            cout << lines_in_file[i+2] << endl;
        }
        vector<Point> points = parse_line(lines_in_file[i]);
        if (effect_choice == 1) effect = new RemoveRed;
        if (effect_choice == 2) effect = new RemoveGreen;
        if (effect_choice == 3) effect = new RemoveBlue;
        if (effect_choice == 4) effect = new NegateRed;
        if (effect_choice == 5) effect = new NegateGreen;
        if (effect_choice == 6) effect = new NegateBlue;
        if (effect_choice == 7) effect = new AddNoise;
        if (effect_choice == 8) effect = new HighContrast;
        if (effect_choice == 9) effect = new ConvertToGrayscale;
        effect->processImage(points);
        for (auto p : points)
        {
            cout << p;
            cout << endl;
        }
    }
}
int main(int argc, char** argv)
{
    string menu_choice;
    getline(cin, menu_choice);
    if (menu_choice == "1")
    {
        readFromFile();
    }
    else
    {
        readFromCin();
    }
    return 0;
}

因此,以

的输入运行它
2
1
P3
1 1
255
50 50 50

将返回

P3
1 1
255
0 50 50

,但是如果我用

运行它
2
3
P3
1 2
255
50 50 50
1 2 3

它返回

P3
1 2
255
0 50 50
0 2 3

我绝对不知道是什么原因引起了问题,因此,任何帮助都将不胜感激。谢谢。

您的算法逻辑结构闻起来很大,这就是我看到的:

  • 将所有非空线读为lines_in_file(对我来说看起来不错)
  • 对于每行(有问题,都需要内部循环中的其他逻辑):
    • 如果不是" p3",请尝试解析[ every ]行作为整数并设置effect_choice(从您的代码中不清楚,在提供几个整数的行上发生了什么,但是从您的代码中进行了判断问题描述第一个整数通过strToInt函数成功解析)
    • 如果" p3",则将当前行和下两条复制到输出
    • [每个]线被解析为数字的三胞胎向量
    • effect是按新的效果设置的effect_choice的实际效果(对于每行,您也不会结束delete CC_6,因此您正在以每条线计数泄漏内存。您当前的效果看起来像是它们可能是可能的作为"过程"功能类型的静态函数实现,因此您无需分配每个功能,只需存储请求函数的特定内存地址即可。您将其称为 processImage,而您仅处理线路,而不是整个图像。
    • effect用于当前线三重态
    • 输出线三联
  • 循环到下一行(!)

所以输入:

2
3
P3
1 2
255
50 50 50
1 2 3

我相信(由于您没有提供很多代码),这发生了:

行已读取,并且根据特定行的情况:

line" 2":effect_choice = 2effect = RemoveGreen,零三重序列分解为pointsRemoveGreen::processImage()在空矢量上运行,空矢量打印(即没有)。

行" 3": effect_choice = 3effect = RemoveBlue,零三重序列分解为 pointsRemoveBlue::processImage()在空的矢量上运行,空矢量打印。

行" p3":线: {"P3", "1 2", "255"}打印,零三重序列解析为 pointsRemoveGreen::processImage()在空的矢量上运行,空矢量打印。

行" 1 2":effect_choice = 1effect = RemoveRed,零三重序列分解为pointsRemoveRed::processImage()在空矢量上运行,空矢量打印。

行" 255":effect_choice = 255,零三重序列分解为pointsRemoveRed::processImage()在空矢量上运行,空矢量打印。

线" 50 50 50":effect_choice = 50,一个三重态{50, 50, 50}分解为pointsRemoveRed::processImage()运行,修改三重态输出{0, 50, 50}

行" 1 2 3":effect_choice = 1effect = RemoveRed,一个三重态{1, 2, 3}分解为pointsRemoveRed::processImage()越过它,修改了三重态输出{0, 2, 3}

所有这些都应该在调试器中清晰可见,同时介绍代码,因此您可能不会调试它,这会使我的问题退缩,并且您会随着时间的流逝而付出巨大的痛苦,因为没有调试器的调试是,更加困难。

还编写代码而无需考虑算法和代码体系结构,因此需要更大的可能调试,因此从编写代码开始,您在这里浪费了更多时间。

您应该首先设计一些算法和代码体系结构(处理了哪些数据,如何,何时需要新内存,如何释放它,代码需要循环,需要跳过或仅运行一次,等)。

仅写概述它将如何在单行注释中工作,然后将太通用的注释分为更简单的步骤,直到可以通过几行C 代码实现它们,然后将它们移动/修改它们,直到您觉得想要的算法将会用最小的" cruft"来实现(大多数评论确实可以,真正请求的内容,例如"将红色设置为零"为零",并且任何处理/准备/移动/etc et et et eq它通过智能设计)。(例如,在当前代码中,您可以在不循环的情况下通过文件标头读取,并且仅在像素数据倒入后才开始循环)

然后编写代码,可能从某个空功能定义开始,以便您已经可以在调试器中"运行"它并验证空虚的作品,然后实现您认为足够清楚的评论(或其中的一小组)实施并可以轻松测试(对尚未实现的零件没有很大的依赖)。调试 测试新代码。如果有效,请尝试清理源以删除实际不需要的任何内容,进行工作的变量名称等...然后验证它在最终版本中工作。

并再次进行另一个评论(组),直到完成为止。

使用单元测试使写入折叠代码,测试 调试,清理源回合更容易,尤其是在这种情况下,I/O是纯数据,因此很容易喂养专业的测试输入输入数据进入测试并验证预期的输出数据。