2017-03-03 99 views
-1

我正在研究可以對PPM文件執行各種效果和操作的程序。但是出於測試的原因,它使用cin而不是輸入文件。它應該能夠一次執行多種效果,但我甚至無法獲得一個正確的效果。我將在一個可以工作的行上運行removeBlue(),然後使用不同的值再次嘗試,並且它將刪除紅色或綠色。之類的東西。有很多代碼,所以我會嘗試僅包含必要的內容。C++:操作PPM文件的問題

#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 

我完全不知道是什麼原因引起的問題,所以任何幫助都將不勝感激。謝謝。

回答

0

你的算法邏輯結構,聞起來有很多,這是我看到:

  • 讀取所有非空行到lines_in_file(對我來說很好)
  • 的每一行(有問題的,需要額外的邏輯內環):
    • 如果不是「P3」,嘗試解析[EVERY]線爲整數,並設置effect_choice(它不是從你的代碼清楚,是什麼在這裏提供了幾個整數線,但猶發生從你的問題描述蔓莖的第一個整數成功通過strToInt功能解析)
    • 如果「P3」,當前行和下兩被複制到輸出
    • [EVERY]行被解析爲數字三元組的矢量
    • effect由實際值effect_choice的新效果設置(對於每條線,最後也不是delete,effect,因此您在每行計數中泄漏內存。此外,您當前的效果看起來像是可以作爲「過程」函數類型的靜態函數實現的,因此您不需要分配它們中的每一個,只需存儲所請求函數的特定內存地址即可。而你稱之爲processImage,而你只處理線條,而不是整個圖像。
    • effect運行的當前行三胞胎
    • 行三胞胎被輸出
  • 循環到下一行(!)

因此,例如輸入:

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

我相信(不能運行它,因爲你沒有提供大量的代碼)出現這種情況:

線被讀取,和每特定線路發生這種情況:

線「2」:effect_choice = 2effect = RemoveGreen,零個三胞胎解析成pointsRemoveGreen::processImage()在空載體運行,空載體印刷(即沒有)。

線 「3」:effect_choice = 3effect = RemoveBlue,零個三胞胎解析成points,碾過空載體,空載體打印。

行「P3」:行:{"P3", "1 2", "255"}被打印,零三元組被解析爲points,RemoveGreen::processImage()運行在空載體上,空載體被打印。

線 「1 2」:effect_choice = 1effect = RemoveRed,零個三胞胎解析成pointsRemoveRed::processImage()在空載體運行,空載體打印。

行「255」:effect_choice = 255,零三元組解析爲points,RemoveRed::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」(大多數評論確實需要什麼,例如「將紅色設置爲零」),並且任何處理/準備/移動/等都會最小化,只有在您不能通過更智能的設計避免它)。(例如,在您當前的代碼中,您可以通過文件標題讀取而不循環,並且僅在像素數據流入後開始循環)

然後編寫代碼,可能會啓動一些空函數定義,以便您可以在調試器中「運行」它並驗證虛擬是否奏效,然後實施您認爲足夠清晰並可以輕鬆測試的評論(或其中的一小部分)(對於尚未實現的部分沒有大的依賴性)。調試+測試新代碼。如果有效,請嘗試清理源代碼以刪除不需要的任何內容,正在工作的變量名稱等...然後驗證它在最終版本中是否有效。

然後再做另一個評論(組),直到實現完成。

使用單元測試可以使寫入短代碼,測試+調試,清理源代碼變得更加容易,特別是在這種情況下,I/O是純數據,因此很容易提供專門的測試將數據輸入到測試中,並驗證預期的輸出數據是否已經生成。