使用c++代码实现图像的颜色切换

Color switching of an image using C++ code

本文关键字:颜色 图像 c++ 代码 实现 使用      更新时间:2023-10-16

因为我对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 %sn", filename);
        exit(1); //abnormal termination
    }
    printf("Read an image from: %sn", 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, %dn", 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 typen");
        exit(1); //abnormal termination
    }
    if (Range != 255){
        printf("Invalid datan");
        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, "P5n");
    }
    else{
        fprintf(file, "P6n");
    }
    fprintf(file, "%d %dn", this->mW, this->mH);
    fprintf(file, "255n");
    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);
}

我的错误:
在函数__tmaincrtstartup中引用的未解析的外部符号_main
错误LNK1120: 1未解析的外部

首先,您没有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中,并且肯定没有必要检查值是否在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);
        }
    }
}