如何快速有效地在 BMP 中收集每个像素的 4 个字节的数据并将它们组装成一个结构体?

如何解决如何快速有效地在 BMP 中收集每个像素的 4 个字节的数据并将它们组装成一个结构体?

我发现了这个 Loading a tga/bmp file in C++/OpenGL,它完美无缺,我想在我的项目中使用它。但是我的项目需要一个 RGB 结构来修改像素缓冲区。

glDrawPixels(win_height,win_width,GL_RGB,GL_FLOAT,myBuffer);

需要进行一些更改才能使其在我的项目中工作。

typedef union PixelInfo
{
    std::uint32_t Colour;
    struct
    {
        float b,g,r,a;
    };
} *PPixelInfo;


class BMP
{
private:
    std::uint32_t width,height;
    std::uint16_t BitsPerPixel;
    std::vector<std::uint8_t> Pixels;

public:
    BMP(const char* FilePath);
    std::vector<std::uint8_t> GetPixels() const {return this->Pixels;}
    std::uint32_t GetWidth() const {return this->width;}
    std::uint32_t GetHeight() const {return this->height;}
    bool HasAlphaChannel() {return BitsPerPixel == 32;}
};

BMP::BMP(const char* FilePath)
{
    std::fstream hFile(FilePath,std::ios::in | std::ios::binary);
    if (!hFile.is_open()) throw std::invalid_argument("Error: File Not Found.");

    hFile.seekg(0,std::ios::end);
    std::size_t Length = hFile.tellg();
    hFile.seekg(0,std::ios::beg);
    std::vector<std::uint8_t> FileInfo(Length);
    hFile.read(reinterpret_cast<char*>(FileInfo.data()),54);

    if(FileInfo[0] != 'B' && FileInfo[1] != 'M')
    {
        hFile.close();
        throw std::invalid_argument("Error: Invalid File Format. Bitmap Required.");
    }

    if (FileInfo[28] != 24 && FileInfo[28] != 32)
    {
        hFile.close();
        throw std::invalid_argument("Error: Invalid File Format. 24 or 32 bit Image Required.");
    }

    BitsPerPixel = FileInfo[28];
    width = FileInfo[18] + (FileInfo[19] << 8);
    height = FileInfo[22] + (FileInfo[23] << 8);
    std::uint32_t PixelsOffset = FileInfo[10] + (FileInfo[11] << 8);
    std::uint32_t size = ((width * BitsPerPixel + 31) / 32) * 4 * height;
    Pixels.resize(size);

    hFile.seekg (PixelsOffset,std::ios::beg);
    hFile.read(reinterpret_cast<char*>(Pixels.data()),size);
    hFile.close();
}

int main()
{
    BMP info = BMP("Fixedsys16x28.bmp");

    //info.
    std::cout << "getwidth: " << info.GetWidth() << endl;
    std::cout << "getheight: " << info.GetHeight()<< endl;

//    for(auto i : info.GetPixels()){
//        //float i_float = float(i);
//        //float res = i_float / 15.0;
//        //std::cout << std::hex << (int)i << " " << endl;
//        std::cout << setprecision(2) << fixed << (float) i / 255 << " " << endl;
//    }
    std::cout << endl;

    std::cout << "size: " << info.GetPixels().size() << endl;
    std::cout << "alpha: " << info.HasAlphaChannel() << endl;

    std::cout << setprecision(2) << fixed;
    for(int i = 0; i < static_cast<int>(info.GetPixels().size()); i++){
        for(int j = 0; j < 3; j++){
            if(j == 0){
                std::cout << (float) info.GetPixels()[i]/ 255 << " ";
            }
            else if(j == 1){
                std::cout  << (float) info.GetPixels()[i] / 255 << " ";
            }
            else{
                std::cout << (float) info.GetPixels()[i] / 255;
            }
        }
        std::cout << endl;
    }

    getchar();

    GLuint texture = 0;
    glGenTextures(1,&texture);
    glBindTexture(GL_TEXTURE_2D,texture);
    glTexImage2D(GL_TEXTURE_2D,info.HasAlphaChannel() ? GL_RGBA : GL_RGB,info.GetWidth(),info.HasAlphaChannel() ? GL_BGRA : GL_BGR,GL_UNSIGNED_BYTE,info.GetPixels().data());
}

这行代码怎么改?

hFile.read(reinterpret_cast<char*>(Pixels.data()),size);

这样矢量就被归档了...

typedef union PixelInfo
{
    std::uint32_t Colour;
    struct
    {
        float B,G,R,A;
    };
} *PPixelInfo;

收藏。

在更改矢量设置后或使用另一个。 什么样的方法/函数,可以代替Pixels.data() ,所以它收集这4个字节并在结构PixelInfo的类型中相应地组装它们?

因为 Pixels.data() 基本上提供了一个指向像素向量的指针。 可以执行请求的任务的方法是什么样的? 收集 4 个字节的数据并相应地对其进行格式化,然后将它们放入 vector<PixelInfo> 同时将“std::uint8_t”转换为浮点数。快速高效。

它应该考虑到这一点“info.HasAlphaChannel()”。

附带的图片数据为:

char array


512×84,像素矢量大小为“129024”。 43008×3 字节 = 129024。

我在像素向量上做了这个循环:

std::cout << setprecision(2) << fixed;
for(int i = 0; i < static_cast<int>(info.GetPixels().size()); i++){
    for(int j = 0; j < 3; j++){
        if(j == 0){
            std::cout << (float) info.GetPixels()[i]/ 255 << " ";
        }
        else if(j == 1){
            std::cout  << (float) info.GetPixels()[i] / 255 << " ";
        }
        else{
            std::cout << (float) info.GetPixels()[i] / 255;
        }
    }
    std::cout << endl;
}

看起来工作正常,甚至最后一行也包含 3 个“字节”的数据。

对于 400 x 400 像素的图像,此例程需要 20 秒。

vector<PixelInfo> pixelStore (info->GetPixels().size() / 3);
int counter = 0;
for(int i = 0; i < size; i+=3){
    PixelInfo temp;
    temp.r = 0;
    temp.g = 0;
    temp.b = 0;
    for(int j = 0; j < 3; j++){
        if(j == 0){
            temp.r = info->GetPixels()[i + j];
        }
        else if(j == 1){
            temp.g = info->GetPixels()[i + j];
        }
        else{
            temp.b = info->GetPixels()[i + j];
        }

        if(j == 2){
            //pixelStore.push_back(temp);
            pixelStore[counter] = temp;
            counter++;
        }
    }
}

解决方法

您的代码显示 std::vector<std::uint8_t> Pixels;,我想这是一个 8 位像素序列。你想要一个 PixelInfo 的向量吗?现在该结构是否与文件中的字节格式匹配?如果是这样,那有什么问题?
如果文件中的字节与您的结构布局(包括机器的 Endian!)相匹配,只需按照相同的方式进行操作:

vector<PixelInfo> Pixels;
size_t pixels_to_read = ....??? ;
Pixels.resize(pixels_to_read);
hFile.read (reinterpret_cast<char*>(Pixels.data()),pixels_to_read*sizeof(PixelInfo));

更新

收集 4 个字节的数据并相应地格式化它们并将它们放入向量中,同时将“std::uint8_t”转换为浮点数。快速高效。

std::byte buf[4];
hFile.read (reinterpret_cast<char*>(buf),4);  // read 4 bytes from file
PixelInfo px;
px.R = buf[0];  // converts 8-bit integer to float
px.G = buf[1];
px.B = buf[2];
px.A = buf[3];

请注意,您的 PixelInfo 并集没有意义——32 位颜色如何与 4 个 32 位组件的布局相匹配?此外,我不认为这个定义是合法的,因为没有匿名结构这样的东西。如果可以编译,则它必须是编译器扩展。

至于快速: 一次读取很多,而不是一个像素。如果将整个文件读入内存不切实际,那么整行就很好。然后您只需沿着您加载的缓冲区前进。

您可以希望优化器对 4 个单独的语句进行自动向量化。如果您只围绕该部分(处理整行)有一个紧凑而简单的循环,您可能会让编译器对其进行矢量化。

由于左侧使用不同的名称而不是索引,因此您必须编写 4 个单独的语句,这一事实不应影响整体速度。

400×400 像素的图像需要 20 秒?我认为它会是瞬间的。我有加载/转换/解码图形文件的经验,早在 90 年代初就为 DOS 和裸机(16 位 x86 代码)编写了一个库。您可以尝试对执行上面列出的这种转换的代码进行基准测试,看看这是否是您的瓶颈。查看生成的代码(在调试器中,或使用编译器资源管理器)以查看它是否正在矢量化。如果您的编译器可用,请考虑直接调用向量原语内部指令。看看您是否使用了所有正确的编译器优化标志。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res