C++将32位深BMP图片转为8位深

#include <iostream>
#include <fstream>
#include <vector>
#include <stdint.h>
#include <immintrin.h>

#pragma pack(push, 1)
struct BMPHeader {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
};

struct BMPInfoHeader {
    uint32_t biSize;
    int32_t biWidth;
    int32_t biHeight;
    uint16_t biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    int32_t biXPelsPerMeter;
    int32_t biYPelsPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImportant;
};
#pragma pack(pop)

void Convert32bppTo8bpp_SSE(const std::vector<uint32_t>& input, std::vector<uint8_t>& output, int width, int height) {
    output.resize(width * height);
    size_t num_pixels = width * height;

    // 定义SSE常量
    __m128i zero = _mm_setzero_si128();
    __m128i red_coeff = _mm_set1_epi32((int)(0.299 * 256));
    __m128i green_coeff = _mm_set1_epi32((int)(0.587 * 256));
    __m128i blue_coeff = _mm_set1_epi32((int)(0.114 * 256));
    __m128i shift_right = _mm_set1_epi32(8);

    size_t i = 0;
    for (; i + 4 <= num_pixels; i += 4) {
        __m128i pixels = _mm_loadu_si128((__m128i*)&input[i]);

        __m128i blue = _mm_and_si128(pixels, _mm_set1_epi32(0xFF));
        __m128i green = _mm_and_si128(_mm_srli_epi32(pixels, 8), _mm_set1_epi32(0xFF));
        __m128i red = _mm_and_si128(_mm_srli_epi32(pixels, 16), _mm_set1_epi32(0xFF));

        __m128i gray = _mm_add_epi32(_mm_add_epi32(_mm_mullo_epi32(red, red_coeff),
                                                    _mm_mullo_epi32(green, green_coeff)),
                                     _mm_mullo_epi32(blue, blue_coeff));

        gray = _mm_srli_epi32(gray, 8);

        // 提取并存储结果
        uint32_t temp[4];
        _mm_storeu_si128((__m128i*)temp, gray);
        for (size_t j = 0; j < 4; ++j) {
            output[i + j] = static_cast<uint8_t>(temp[j]);
        }
    }

    // 处理剩余的像素
    for (; i < num_pixels; ++i) {
        uint32_t pixel = input[i];
        uint8_t blue = pixel & 0xFF;
        uint8_t green = (pixel >> 8) & 0xFF;
        uint8_t red = (pixel >> 16) & 0xFF;
        uint8_t gray = static_cast<uint8_t>(0.299 * red + 0.587 * green + 0.114 * blue);
        output[i] = gray;
    }
}

bool ReadBMP(const std::string& filename, std::vector<uint32_t>& data, int& width, int& height) {
    std::ifstream file(filename, std::ios::binary);
    if (!file) return false;

    BMPHeader header;
    BMPInfoHeader infoHeader;
    file.read(reinterpret_cast<char*>(&header), sizeof(header));
    file.read(reinterpret_cast<char*>(&infoHeader), sizeof(infoHeader));

    if (header.bfType != 0x4D42 || infoHeader.biBitCount != 32) {
        return false;
    }

    width = infoHeader.biWidth;
    height = infoHeader.biHeight;
    data.resize(width * height);

    file.seekg(header.bfOffBits, std::ios::beg);
    file.read(reinterpret_cast<char*>(data.data()), data.size() * sizeof(uint32_t));

    return true;
}

bool WriteBMP(const std::string& filename, const std::vector<uint8_t>& data, int width, int height) {
    std::ofstream file(filename, std::ios::binary);
    if (!file) return false;

    BMPHeader header = {};
    BMPInfoHeader infoHeader = {};

    header.bfType = 0x4D42;
    header.bfSize = sizeof(BMPHeader) + sizeof(BMPInfoHeader) + data.size();
    header.bfOffBits = sizeof(BMPHeader) + sizeof(BMPInfoHeader);

    infoHeader.biSize = sizeof(BMPInfoHeader);
    infoHeader.biWidth = width;
    infoHeader.biHeight = height;
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = 8;
    infoHeader.biCompression = 0;
    infoHeader.biSizeImage = data.size();
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed = 256;
    infoHeader.biClrImportant = 256;

    file.write(reinterpret_cast<char*>(&header), sizeof(header));
    file.write(reinterpret_cast<char*>(&infoHeader), sizeof(infoHeader));

    // 写入颜色表
    for (int i = 0; i < 256; ++i) {
        uint8_t color[4] = { (uint8_t)i, (uint8_t)i, (uint8_t)i, 0 };
        file.write(reinterpret_cast<char*>(color), sizeof(color));
    }

    file.write(reinterpret_cast<const char*>(data.data()), data.size());

    return true;
}

int main() {
    std::vector<uint32_t> inputImage;
    std::vector<uint8_t> outputImage;
    int width, height;

    if (!ReadBMP("input.bmp", inputImage, width, height)) {
        std::cerr << "Error reading input.bmp" << std::endl;
        return 1;
    }

    Convert32bppTo8bpp_SSE(inputImage, outputImage, width, height);

    if (!WriteBMP("output.bmp", outputImage, width, height)) {
        std::cerr << "Error writing output.bmp" << std::endl;
        return 1;
    }

    std::cout << "Conversion to 8-bit successful!" << std::endl;
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值