C++ C++;位图上的模糊效果正在工作,但颜色已更改

C++ C++;位图上的模糊效果正在工作,但颜色已更改,c++,bitmap,C++,Bitmap,关于我前面的问题,我已成功使位图模糊,但问题是模糊图片的颜色已更改: 原始照片: 模糊照片: 模糊算法TM的代码与我上一个问题中的代码相同: for (xx = 0; xx < bitmapInfoHeader.biWidth; xx++) { for (yy = 0; yy <bitmapInfoHeader.biHeight; yy++) { avgB = avgG = avgR = 0; Counter = 0;

关于我前面的问题,我已成功使位图模糊,但问题是模糊图片的颜色已更改:

原始照片: 模糊照片:

模糊算法TM的代码与我上一个问题中的代码相同:

for (xx = 0; xx < bitmapInfoHeader.biWidth; xx++)
{
    for (yy = 0; yy <bitmapInfoHeader.biHeight; yy++)
    {
        avgB = avgG = avgR = 0;
        Counter = 0;

        for (x = xx; x < bitmapInfoHeader.biWidth && x < xx + blurSize; x++)
        {


            for (y = yy; y < bitmapInfoHeader.biHeight && y < yy + blurSize; y++)
            {
                avgB += bitmapImage[x *3 + y*bitmapInfoHeader.biWidth * 3 + 0];     //bitmapimage[x][y];
                avgG += bitmapImage[x  *3 + y*bitmapInfoHeader.biWidth * 3 + 1];
                avgR += bitmapImage[x *3 + y*bitmapInfoHeader.biWidth * 3 + 2];
                Counter++;
            }
        }

        avgB = avgB / Counter;
        avgG = avgG / Counter;
        avgR = avgR / Counter;

        bitmapImage[xx * 3 + yy*bitmapInfoHeader.biWidth * 3 + 0] = avgB;
        bitmapImage[xx * 3 + yy*bitmapInfoHeader.biWidth * 3 + 1] = avgG;
        bitmapImage[xx * 3 + yy*bitmapInfoHeader.biWidth * 3 + 2] = avgR;
    }
}
for(xx=0;xx对于(yy=0;yy来说,实际上看起来每行的大小都被填充为4字节的倍数。要获得每行的正确字节偏移量,您需要替换

* bitmapInfoHeader.biWidth * 3

在哪里

padding_bytes_count =
(
    (
        bitmapFileHeader.bfSize - bitmapFileHeader.bfOffBits
        -
        bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 3
    )
    /
    bitmapInfoHeader.biHeight
);

对于tiger图像,padding\u bytes\u count应为2。

实际上,似乎每行的大小都被填充为4字节的倍数。要获得每行的正确字节偏移量,您需要替换

* bitmapInfoHeader.biWidth * 3

在哪里

padding_bytes_count =
(
    (
        bitmapFileHeader.bfSize - bitmapFileHeader.bfOffBits
        -
        bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 3
    )
    /
    bitmapInfoHeader.biHeight
);

对于tiger图像,填充字节数应该是2。

在这里,我创建了一个半便携式位图读取器/写入器。适用于Windows、Linux Mint、MacOS High Sierra。我没有测试其他平台。但应该可以

它有:

  • 便携性
  • 加载24位位图
  • 加载32位位图
  • 编写24位位图
  • 编写32位位图
  • 在24位和32位位图之间转换
  • 在32位和24位位图之间转换
它没有:

  • 支持Alpha透明。Alpha透明需要在标题中设置特殊的字段和标志。我不想写入它们,所以它不支持
只有一部分似乎不太便于携带,那就是
#pragma pack

#include <iostream>
#include <fstream>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif

typedef struct
{
    uint8_t r, g, b, a;
} rgb32;


#if !defined(_WIN32) && !defined(_WIN64)
    #pragma pack(2)
    typedef struct
    {
        uint16_t bfType;
        uint32_t bfSize;
        uint16_t bfReserved1;
        uint16_t bfReserved2;
        uint32_t bfOffBits;
    } BITMAPFILEHEADER;
    #pragma pack()


    #pragma pack(2)
    typedef struct
    {
        uint32_t biSize;
        int32_t biWidth;
        int32_t biHeight;
        uint16_t biPlanes;
        uint16_t biBitCount;
        uint32_t biCompression;
        uint32_t biSizeImage;
        int16_t biXPelsPerMeter;
        int16_t biYPelsPerMeter;
        uint32_t biClrUsed;
        uint32_t biClrImportant;
    } BITMAPINFOHEADER;
    #pragma pack()
#endif

#pragma pack(2)
typedef struct
{
    BITMAPFILEHEADER bfh;
    BITMAPINFOHEADER bih;
} BMPINFO;
#pragma pack()


class bitmap
{
private:
    BMPINFO bmpInfo;
    uint8_t* pixels;

public:
    bitmap(const char* path);
    ~bitmap();

    void save(const char* path, uint16_t bit_count = 24);

    rgb32* getPixel(uint32_t x, uint32_t y) const;
    void setPixel(rgb32* pixel, uint32_t x, uint32_t y);

    uint32_t getWidth() const;
    uint32_t getHeight() const;
    uint16_t bitCount() const;
};

bitmap::bitmap(const char* path) : bmpInfo(), pixels(nullptr)
{
    std::ifstream file(path, std::ios::in | std::ios::binary);

    if (file)
    {
        file.read(reinterpret_cast<char*>(&bmpInfo.bfh), sizeof(bmpInfo.bfh));

        if (bmpInfo.bfh.bfType != 0x4d42)
        {
            throw std::runtime_error("Invalid format. Only bitmaps are supported.");
        }

        file.read(reinterpret_cast<char*>(&bmpInfo.bih), sizeof(bmpInfo.bih));

        if (bmpInfo.bih.biCompression != 0)
        {
            std::cerr<<bmpInfo.bih.biCompression<<"\n";
            throw std::runtime_error("Invalid bitmap. Only uncompressed bitmaps are supported.");
        }

        if (bmpInfo.bih.biBitCount != 24 && bmpInfo.bih.biBitCount != 32)
        {
            throw std::runtime_error("Invalid bitmap. Only 24bit and 32bit bitmaps are supported.");
        }

        file.seekg(bmpInfo.bfh.bfOffBits, std::ios::beg);

        pixels = new uint8_t[bmpInfo.bfh.bfSize - bmpInfo.bfh.bfOffBits];
        file.read(reinterpret_cast<char*>(&pixels[0]), bmpInfo.bfh.bfSize - bmpInfo.bfh.bfOffBits);


        uint8_t* temp = new uint8_t[bmpInfo.bih.biWidth * bmpInfo.bih.biHeight * sizeof(rgb32)];

        uint8_t* in = pixels;
        rgb32* out = reinterpret_cast<rgb32*>(temp);
        int padding = bmpInfo.bih.biBitCount == 24 ? ((bmpInfo.bih.biSizeImage - bmpInfo.bih.biWidth * bmpInfo.bih.biHeight * 3) / bmpInfo.bih.biHeight) : 0;

        for (int i = 0; i < bmpInfo.bih.biHeight; ++i, in += padding)
        {
            for (int j = 0; j < bmpInfo.bih.biWidth; ++j)
            {

                out->b = *(in++);
                out->g = *(in++);
                out->r = *(in++);
                out->a = bmpInfo.bih.biBitCount == 32 ? *(in++) : 0xFF;
                ++out;
            }
        }

        delete[] pixels;
        pixels = temp;
    }
}

bitmap::~bitmap()
{
    delete[] pixels;
}

void bitmap::save(const char* path, uint16_t bit_count)
{
    std::ofstream file(path, std::ios::out | std::ios::binary);

    if (file)
    {
        bmpInfo.bih.biBitCount = bit_count;
        uint32_t size = ((bmpInfo.bih.biWidth * bmpInfo.bih.biBitCount + 31) / 32) * 4 * bmpInfo.bih.biHeight;
        bmpInfo.bfh.bfSize = bmpInfo.bfh.bfOffBits + size;

        file.write(reinterpret_cast<char*>(&bmpInfo.bfh), sizeof(bmpInfo.bfh));
        file.write(reinterpret_cast<char*>(&bmpInfo.bih), sizeof(bmpInfo.bih));
        file.seekp(bmpInfo.bfh.bfOffBits, std::ios::beg);

        uint8_t* out = NULL;
        rgb32* in = reinterpret_cast<rgb32*>(pixels);
        uint8_t* temp = out = new uint8_t[bmpInfo.bih.biWidth * bmpInfo.bih.biHeight * sizeof(rgb32)];
        int padding = bmpInfo.bih.biBitCount == 24 ? ((bmpInfo.bih.biSizeImage - bmpInfo.bih.biWidth * bmpInfo.bih.biHeight * 3) / bmpInfo.bih.biHeight) : 0;

        for (int i = 0; i < bmpInfo.bih.biHeight; ++i, out += padding)
        {
            for (int j = 0; j < bmpInfo.bih.biWidth; ++j)
            {
                *(out++) = in->b;
                *(out++) = in->g;
                *(out++) = in->r;

                if (bmpInfo.bih.biBitCount == 32)
                {
                    *(out++) = in->a;
                }
                ++in;
            }
        }

        file.write(reinterpret_cast<char*>(&temp[0]), size); //bmpInfo.bfh.bfSize - bmpInfo.bfh.bfOffBits
        delete[] temp;
    }
}

rgb32* bitmap::getPixel(uint32_t x, uint32_t y) const
{
    rgb32* temp = reinterpret_cast<rgb32*>(pixels);
    return &temp[(bmpInfo.bih.biHeight - 1 - y) * bmpInfo.bih.biWidth + x];
}

void bitmap::setPixel(rgb32* pixel, uint32_t x, uint32_t y)
{
    rgb32* temp = reinterpret_cast<rgb32*>(pixels);
    memcpy(&temp[(bmpInfo.bih.biHeight - 1 - y) * bmpInfo.bih.biWidth + x], pixel, sizeof(rgb32));
};

uint32_t bitmap::getWidth() const
{
    return bmpInfo.bih.biWidth;
}

uint32_t bitmap::getHeight() const
{
    return bmpInfo.bih.biHeight;
}

uint16_t bitmap::bitCount() const
{
    return bmpInfo.bih.biBitCount;
}

void apply_blur(int x, int y, bitmap* bmp, int blurRadius)
{
    double blurValue = 0.111;
    int r = 0;
    int g = 0 ;
    int b = 0;

    for (int k = y - blurRadius; k <= blurRadius; ++k)
    {
        for (int l = x - blurRadius; l <= blurRadius; ++l)
        {
            rgb32* pixel = bmp->getPixel(l, k);
            r += blurValue * pixel->r;
            g += blurValue * pixel->g;
            b += blurValue * pixel->b;
        }
    }

    rgb32 pixel = *bmp->getPixel(x, y);

    pixel.r = r;
    pixel.g = g;
    pixel.b = b;

    bmp->setPixel(&pixel, x, y);
}

int main(int argc, const char * argv[])
{
    bitmap bmp{"/Users/brandon/Desktop/tiger.bmp"};
    bmp.save("/Users/brandon/Desktop/blurred-tiger-24.bmp");
    bmp.save("/Users/brandon/Desktop/blurred-tiger-32.bmp", 32);
    return 0;
}
#包括
#包括
#如果已定义(_WIN32)| |已定义(_WIN64)
#包括
#恩迪夫
类型定义结构
{
uint8_t r,g,b,a;
}rgb32;
#如果!已定义(_WIN32)和&!已定义(_WIN64)
#布拉格语包(2)
类型定义结构
{
uint16型;
uint32_t bf尺寸;
uint16_t b保留1;
uint16_t b储备2;
uint32_t bOffbit;
}位图文件头;
#pragma pack()
#布拉格语包(2)
类型定义结构
{
uint32_t biSize;
int32_t双宽度;
int32_t biHeight;
uint16双飞机;
uint16_t双比特计数;
uint32_t双压缩;
uint32_t biSizeImage;
int16_t双X渗透计;
int16_t双渗透计;
uint32_t biClrUsed;
uint32_t biclr重要;
}位图信息头;
#pragma pack()
#恩迪夫
#布拉格语包(2)
类型定义结构
{
位图文件头;
BITMAPINFO头bih;
}BMPINFO;
#pragma pack()
类位图
{
私人:
BMPINFO BMPINFO;
uint8_t*像素;
公众:
位图(常量字符*路径);
~bitmap();
无效保存(常量字符*路径,uint16位计数=24);
rgb32*获取像素(uint32_t x,uint32_t y)常数;
void setPixel(rgb32*像素,uint32\u t x,uint32\u t y);
uint32_t getWidth()常量;
uint32_t getHeight()常数;
uint16\u t比特计数()常量;
};
位图::位图(const char*path):bmpInfo(),像素(nullptr)
{
std::ifstream文件(路径,std::ios::in | std::ios::binary);
如果(文件)
{
read(reinterpret_cast(&bmpInfo.bfh),sizeof(bmpInfo.bfh));
如果(bmpInfo.bfh.bfType!=0x4d42)
{
抛出std::runtime_错误(“格式无效。仅支持位图”);
}
read(reinterpret_cast(&bmpInfo.bih),sizeof(bmpInfo.bih));
if(bmpInfo.bih.biCompression!=0)
{
标准::cera=bmpInfo.bih.bibibitcount==32?*(在++):0xFF;
++出去;
}
}
删除[]个像素;
像素=温度;
}
}
位图::~bitmap()
{
删除[]个像素;
}
无效位图::保存(常量字符*路径,uint16位计数)
{
流文件的std::of(路径,std::ios::out | std::ios::binary);
如果(文件)
{
bmpInfo.bih.bibibitcount=位计数;
uint32_t尺寸=((bmpInfo.bih.biWidth*bmpInfo.bih.bibibit计数+31)/32)*4*bmpInfo.bih.bih高度;
bmpInfo.bfh.bfSize=bmpInfo.bfh.bfOffBits+size;
write(reinterpret_cast(&bmpInfo.bfh),sizeof(bmpInfo.bfh));
write(reinterpret_cast(&bmpInfo.bih),sizeof(bmpInfo.bih));
seekp(bmpInfo.bfh.bfOffBits,std::ios::beg);
uint8_t*out=NULL;
rgb32*in=重新解释投影(像素);
uint8_t*temp=out=新uint8_t[bmpInfo.bih.biWidth*bmpInfo.bih.biHeight*sizeof(rgb32)];
int padding=bmpInfo.bih.bibibitcount==24?((bmpInfo.bih.biizeImage-bmpInfo.bih.biWidth*bmpInfo.bih.biHeight*3)/bmpInfo.bih.biHeight):0;
对于(int i=0;ib;
*(out++)=in->g;
*(out++)=in->r;
if(bmpInfo.bih.bibibitcount==32)
{
*(out++)=in->a;
}
++在;
}
}
file.write(reinterpret_cast(&temp[0]),size)//bmpInfo.bfh.bfSize-bmpInfo.bfh.bfOffBits
删除[]临时;
}
}
rgb32*位图::getPixel(uint32\u t x,uint32\u t y)常量
{
rgb32*温度=重新解释投影(像素);
返回和温度[(bmpInfo.bih.bih高度-1-y)*bmpInfo.bih.bih宽度+x];
}
无效位图::设置像素(rgb32*像素,uint32\u t x,uint32\u t y)
{
rgb32*温度=重新解释投影(像素);
memcpy(&temp[(bmpInfo.bih.biHeight-1-y)*bmpInfo.bih.biWidth+x],像素,大小(rgb32));
};
uint32\u t位图::getWidth()常量
{
返回bmpInfo.bih.biWidth;
}
uint32\u t位图::getHeight()常量
{
返回bmpInfo.bih.biHeight;
}
uint16\u t位图::比特计数()常量
{
返回bmpInfo.bih.biBitCount;
}
无效应用模糊(整数x,整数y,位图*bmp,整数模糊半径)
{
双模糊值=0.111;
int r=0;
int g=0;
int b=0;
对于(int k=y-模糊半径;kr;
g+=模糊值*像素->g;
b+=模糊值*像素->b;
    for (x = xx; x < bitmapInfoHeader.biWidth && x < xx + blurSize; **x+=3**)
    {

   for (y = yy; y < bitmapInfoHeader.biHeight && y < yy + blurSize; **y+=3**)