当前位置: 首页 > article >正文

C# BitmapSource小节

在C#中,处理位图(Bitmap)图像数据时,理解像素格式(PixelFormat)、步幅(stride)和像素数据复制是非常重要的。

BitmapSource常用属性与方法

PixelFormat——Defines a pixel format for images and pixel-based surfaces.即定义图像和基于像素表面的像素格式。

Stride——(步幅)是图像数据中每一行像素所占用的字节数。这个值不一定等于图像宽度乘以每个像素的字节数,因为出于内存对齐的考虑,有些图像格式可能会在行尾添加额外的填充字节(padding bytes)。

PixelFormats——表示受支持像素格式的集合。PixelFormat是一个静态类,描述了位图中每个像素的颜色深度和格式。例如,PixelFormats.Bgra32表示每个像素占用32位,其中包含了透明度(Alpha)、红色(Red)、绿色(Green)和蓝色(Blue)四个分量。

CopyPixels——将位图像素数据复制到具有从指定偏移量开始的指定跨距的像素数组中。(C#中对于BitmapSource像素数据的复制,提供了此方法。)

应用示例

        int pointIndex = 0;
        List<int> nodes = [];
        private void Build3DModelFromTiffData(MeshGeometry3D mesh, BitmapSource bitmap, int layerIndex, bool layer = false)
        {

            // 获取图像的宽度和高度
            int width = bitmap.PixelWidth;
            int height = bitmap.PixelHeight;

            PixelFormat pixelFormat = bitmap.Format;

            int stride = (bitmap.PixelWidth * pixelFormat.BitsPerPixel + 7) / 8;
            int bufferSize = stride * bitmap.PixelHeight;
            byte[] pixels = new byte[bufferSize];
            bitmap.CopyPixels(pixels, stride, 0);


            int minX = int.MaxValue;
            int maxX = int.MinValue;
            int minY = int.MaxValue;
            int maxY = int.MinValue;

            int index1 = 0;
            int index2 = 0;
            int index3 = 0;
            int index4 = 0;
            // 遍历图像的每个像素,根据像素信息构建 3D 模型
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    int offset = y * stride + x * 4;
                    byte blue = pixels[offset];
                    byte green = pixels[offset + 1];
                    byte red = pixels[offset + 2];
                    //byte alpha = pixels[offset + 3];
                    if (blue == 0 && green == 0 && red == 0)
                    {
                        continue;
                    }
                    Point3D point = new(x, y, layerIndex);

                    minX = Math.Min(minX, x);
                    maxX = Math.Max(maxX, x);
                    minY = Math.Min(minY, y);
                    maxY = Math.Max(maxY, y);

                    if (minX == x && minY == y)
                    {
                        index1 = pointIndex;
                    }
                    if (minX == x && maxY == y)
                    {
                        index2 = pointIndex;
                    }
                    if (maxX == x && minY == y)
                    {
                        index3 = pointIndex;
                    }
                    if (maxX == x && maxY == y)
                    {
                        index4 = pointIndex;
                    }
                    pointIndex++;
                    // 将点添加到 MeshGeometry3D 中
                    mesh.Positions.Add(point);
                }
            }
            mesh.TriangleIndices.Add(index1);
            mesh.TriangleIndices.Add(index3);
            mesh.TriangleIndices.Add(index2);

            mesh.TriangleIndices.Add(index2);
            mesh.TriangleIndices.Add(index3);
            mesh.TriangleIndices.Add(index4);

            if (layer)
            {
                nodes.Add(index1);
                nodes.Add(index2);
                nodes.Add(index3);
                nodes.Add(index4);
            }
        }

注意事项

在上述示例中有一些关注点,在开发时需要注意:

  1. stride的求取要注意取整;示例中为了保证stride为整数操作为 (bitmap.PixelWidth * pixelFormat.BitsPerPixel + 7) / 8 ,因为1字节=8位,所以要将位数除以8来得到字节数。加7是为了实现向上取整的效果,比如如果每个像素占用3位,那么(3 * width + 7) / 8将确保每像素至少占用1个字节。
  2. RGBA的存储并不是按RGBA的先后顺序来的,而是B、G、R、A;这个一定要注意,上述代码中如下:
    int offset = y * stride + x * 4;
    byte blue = pixels[offset];
    byte green = pixels[offset + 1];
    byte red = pixels[offset + 2];
    //byte alpha = pixels[offset + 3];


http://www.kler.cn/a/404871.html

相关文章:

  • Jenkins更换主题颜色+登录页面LOGO图片
  • 结合第三方模块requests,文件IO、正则表达式,通过函数封装爬虫应用采集数据
  • 【已解决】“EndNote could not connect to the online sync service”问题的解决
  • 键盘上打出反引号符号(´),即单个上标的撇号(这个符号与反引号 ` 不同,反引号通常位于键盘的左上角)
  • 电解车间铜业机器人剥片技术是现代铜冶炼过程中自动化和智能化的重要体现
  • 【深度学习|目标跟踪】多目标跟踪之训练reid网络
  • TensorFlow如何调用GPU?
  • 【Linux学习】【Ubuntu入门】1-7 ubuntu下磁盘管理
  • 学习路之phpstudy--安装mysql5.7后在my.ini文件中无法修改sql_mode
  • 嵌入式实验报告:家用计时器
  • MFC工控项目实例三十一模拟量转化为工程量
  • Spring 与 Spring MVC 与 Spring Boot三者之间的区别与联系
  • 从 IDC 到云原生:稳定性提升 100%,成本下降 50%,热联集团的数字化转型与未来展望
  • 【MQTT.fx 客户端接入 阿里云平台信息配置】
  • 湘潭大学软件工程算法设计与分析考试复习笔记(二)
  • 【FFmpeg】FFmpeg 内存结构 ③ ( AVPacket 函数简介 | av_packet_ref 函数 | av_packet_clone 函数 )
  • 【Unity】网格系统:物体使用网格坐标定位
  • ceph 18.2.4二次开发,docker镜像制作
  • 【保姆级图文教程】QT下载、安装、入门、配置VS Qt环境
  • C++20 协程入门
  • QT+osg+osgearth显示一个地球(进阶)
  • 《Java核心技术 卷I》链表
  • 多目标优化算法:多目标吸血水蛭优化算法(MOBSLO)求解DTLZ1-DTLZ9,提供完整MATLAB代码
  • 集合卡尔曼滤波(Ensemble Kalman Filter),用于二维滤波(模拟平面上的目标跟踪),MATLAB代码
  • 机器学习——数据隐私与安全学习
  • 排序算法:直接插入排序,希尔排序,选择排序,快速排序,堆排序,归并排序