使用C ++代码对图像进行颜色切换

时间:2014-05-11 16:37:58

标签: c++ image-processing

由于我对C ++和图像处理不熟悉,因此在修改代码时添加函数时出现问题。 要求只是在RGB颜色之间切换。

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "ctype.h"
#include "math.h"

class myImageData
{
private:
    int mW;
    int mH;
    int mCH;
    double * mData;

    void SkipComments(FILE *fp)
    {
        int ch;
        char line[100];

        while ((ch = fgetc(fp)) != EOF && isspace(ch))
            ;

        if (ch == '#')
        {
            fgets(line, sizeof(line), fp);
            SkipComments(fp);
        }
        else
        {
            fseek(fp, -1, SEEK_CUR);
        }
    }

public:

    myImageData(void)
    {
        this->mData = NULL;
    }

    ~myImageData()
    {
        if (this->mData != NULL)
        {
            delete[] this->mData;
        }
    }

    void init(int W, int H, int CH)
    {
        this->mW = W;
        this->mH = H;
        this->mCH = CH;

        if (this->mData != NULL)
            delete[] this->mData;

        this->mData = new double[(this->mW)*(this->mH)*(this->mCH)];
    }

    int getWidth(void)
    {
        return this->mW;
    }

    int getHeight(void)
    {
        return this->mH;
    }

    int getCH(void)
    {
        return this->mCH;
    }

    double * getDataPtr(void)
    {
        return this->mData;
    }

    double get(int x, int y)
    {
        return this->mData[y*(this->mW) + x];
    }

    double get(int x, int y, int CH)
    {
        return this->mData[this->mCH * (y*(this->mW) + x) + CH];
    }

    void set(int x, int y, double value)
    {
        this->mData[y*(this->mW) + x] = value;
    }

    void set(int x, int y, int CH, double value)
    {
        this->mData[this->mCH *(y*(this->mW) + x) + CH] = value;
    }

    void read(const char *filename);
    void save(const char *filename);
};


void myImageData::read(const char *filename)
{
    FILE *file = fopen(filename, "r");
    if (file == NULL){
        printf("Cannot open %s\n", filename);
        exit(1); //abnormal termination
    }
    printf("Read an image from: %s\n", filename);

    // read ppm/pgm header

    char buf[256];
    char filetype[256];
    int W, H, Range, CH;

    fgets(buf, sizeof(buf), file);
    sscanf(buf, "%s", filetype);

    SkipComments(file);
    fgets(buf, sizeof(buf), file);
    sscanf(buf, "%d%d", &W, &H);

    SkipComments(file);
    fgets(buf, sizeof(buf), file);
    sscanf(buf, "%d", &Range);
    //printf("Header: %s, %d, %d, %d\n", filetype, W, H, Range);

    SkipComments(file);

    if (strcmp(filetype, "P5") == 0)
    {
        CH = 1;
    }
    else if (strcmp(filetype, "P6") == 0)
    {
        CH = 3;
    }
    else
    {
        printf("Unknown image type\n");
        exit(1); //abnormal termination
    }

    if (Range != 255){
        printf("Invalid data\n");
        exit(1); //abnormal termination
    }

    // create myImageData class

    init(W, H, CH);

    // read ppm data

    int datalength = this->mW * this->mH * this->mCH;
    unsigned char * temp = new unsigned char[datalength];
    fread(temp, sizeof(unsigned char), datalength, file);

    double * ptr1 = this->mData;
    unsigned char *ptr2 = temp;

    for (int i = 0; i < datalength; i++){
        *ptr1 = (double)*ptr2;
        ptr1++;
        ptr2++;
    }

    delete[] temp;

    fclose(file);

}

void myImageData::save(const char *filename){

    char filenamefull[256];
    if (this->mCH == 1){
        sprintf(filenamefull, "%s.pgm", filename);
    }
    else{
        sprintf(filenamefull, "%s.ppm", filename);
    }

    FILE *file = fopen(filenamefull, "w");
    printf("Write an image to: %s \n", filenamefull);

    if (this->mCH == 1){
        fprintf(file, "P5\n");
    }
    else{
        fprintf(file, "P6\n");
    }

    fprintf(file, "%d %d\n", this->mW, this->mH);
    fprintf(file, "255\n");

    int datalength = this->mW * this->mH * this->mCH;
    unsigned char * temp = new unsigned char[datalength];

    double * ptr1 = this->mData;
    unsigned char * ptr2 = temp;

    for (int i = 0; i < datalength; i++){
        double value = *ptr1;
        value = round(value);
        if (value > 255) value = 255;
        if (value < 0) value = 0;
        *ptr2 = (unsigned char)value;
        ptr1++;
        ptr2++;
    }

    fwrite(temp, sizeof(unsigned char), datalength, file);
    delete[] temp;

    fprintf(file, "Â¥n");

    fclose(file);
}

我遇到的错误:
错误LNK2019:函数___tmainCRTStartup中引用了未解析的外部符号_main 错误LNK1120:1个未解析的外部

1 个答案:

答案 0 :(得分:0)

首先,您没有main功能。毫不奇怪你的代码不起作用..你所拥有的只是一个加载,保存和操作PPM图像文件的类。

你在我看来使用Visual Studio,所以你需要一个看起来像这样的函数:

int _tmain(int argc, _TCHAR* argv[])
{
    myImageData image;
    image.read("atestfile.ppm");

    // do some stuff to your image

    image.write("outputfile.ppm");
}

我假设您有一个PPM格式的测试图像,当然可以在这里使用。

现在这很疯狂:

double * ptr1 = this->mData;
unsigned char * ptr2 = temp;

for (int i = 0; i < datalength; i++){
    double value = *ptr1;
    value = round(value);
    if (value > 255) value = 255;
    if (value < 0) value = 0;
    *ptr2 = (unsigned char)value;
    ptr1++;
    ptr2++;
}

您已经从unsigned char读取了内容,因此没有必要将其填入double,而 no指出检查值是否在0到255之外。为什么要存储双打?这没有道理!即使你确实做了一些需要每个通道需要一个完整的双精度浮点值的东西,当你再次将所有东西都压缩到0-255时,你就把它全部扔掉了:

for (int i = 0; i < datalength; i++){
    double value = *ptr1;
    value = round(value);
    if (value > 255) value = 255;
    if (value < 0) value = 0;
    *ptr2 = (unsigned char)value;
    ptr1++;
    ptr2++;
}

此外,这基本上是C打扮成一个薄的C ++单板。没关系,每个人都必须从某个地方开始。但是,您可以执行以下操作,而不是使用new创建数组:

// read ppm data

int datalength = this->mW * this->mH * this->mCH;

// using a std::vector here means that the allocated memory will be freed
// automatically, even in the result of an error occurring.
std::vector<unsigned char> temp(datalength);
fread(&temp[0], sizeof(unsigned char), datalength, file);

我还考虑使用iostream类,例如fstream而不是freadfopen等等。但这并不是进入这些细节的地方。

无论如何,加载后如何处理图像?你已经有了简单的帮助函数来读取和写入像素值,这将让你做任何你想做的事情。这是一个简单的例子,交换R和B通道。当你真正告诉我们你想要的东西时,你可能会得到更好的东西。

void swapRB(myImageData& image)
{
    assert(image.getCH() == 3);

    for (int x = 0; x < image.getWidth())
    {
        for (int y = 0; x < image.getHeight())
        {
            double R = image.get(x, y, 0);
            double G = image.get(x, y, 1);
            double B = image.get(x, y, 2);

            image.set(x, y, 0, B);
            image.set(x, y, 2, R);
        }
    }
}