基于Bitmap生成int[,]数组:ASCOM驱动DNG转图像阵列异常
问题分析与修复步骤
1. ReadBitmap函数:修复Stride处理错误
当前代码忽略了Bitmap的Stride属性(每行实际占用的字节数,必须是4的倍数),直接按总像素索引*3读取字节,会误读到行尾的对齐padding数据,导致像素错位,这是图像异常的核心原因。
修复后的代码:
public int[,] ReadBitmap(Bitmap img) { BitmapData data = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadOnly, img.PixelFormat); IntPtr ptr = data.Scan0; int stride = Math.Abs(data.Stride); var result = new int[img.Width, img.Height]; byte[] bytesArray = new byte[stride * img.Height]; Marshal.Copy(ptr, bytesArray, 0, bytesArray.Length); img.UnlockBits(data); int width = img.Width; int height = img.Height; Parallel.For(0, height, row => { int rowStart = row * stride; for (int col = 0; col < width; col++) { int pixelOffset = rowStart + col * 3; byte b = bytesArray[pixelOffset]; byte g = bytesArray[pixelOffset + 1]; byte r = bytesArray[pixelOffset + 2]; result[col, row] = (int)(0.299 * r + 0.587 * g + 0.114 * b); } }); return result; }
关键修改:
- 按行处理数据,每行起始位置为
row * stride - 每个像素的偏移计算为行起始+列索引*3,彻底避开行尾padding
- 改用行循环+列循环的结构,逻辑更直观且避免Stride冲突
2. DNG转Bitmap步骤:修复颜色通道与内存复制问题
现存问题:
- libraw默认输出RGB顺序的像素数据,但
Format24bppRgb格式的Bitmap实际存储为BGR顺序,直接复制会导致颜色反转 - 手动拼接padding后,内存复制长度错误,仅复制了原始数据,未包含对齐padding字节
修复后的代码片段:
// ... 保留libraw初始化与处理的前序代码 ... // 计算Bitmap要求的4字节对齐Stride int bitmapStride = ((img.width * 3) + 3) & ~3; int totalBytes = bitmapStride * img.height; byte[] bitmapData = new byte[totalBytes]; for (int i = 0; i < img.height; i++) { int srcRowStart = i * img.width * 3; int dstRowStart = i * bitmapStride; // 将RGB转换为Bitmap要求的BGR顺序 for (int j = 0; j < img.width; j++) { byte r = img.data[srcRowStart + j * 3]; byte g = img.data[srcRowStart + j * 3 + 1]; byte b = img.data[srcRowStart + j * 3 + 2]; bitmapData[dstRowStart + j * 3] = b; bitmapData[dstRowStart + j * 3 + 1] = g; bitmapData[dstRowStart + j * 3 + 2] = r; } } // 释放libraw内存 NativeMethods.libraw_dcraw_clear_mem(ptr); // 创建Bitmap并写入数据 var bmp = new Bitmap(img.width, img.height, PixelFormat.Format24bppRgb); var bmd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); Marshal.Copy(bitmapData, 0, bmd.Scan0, totalBytes); bmp.UnlockBits(bmd); NativeMethods.libraw_close(data); // 保存JPEG var outJPEG = path.Replace(Path.GetExtension(path), ".jpg"); bmp.Save(outJPEG, ImageFormat.Jpeg); CurrentFilePath = outJPEG;
关键修改:
- 显式转换RGB→BGR通道顺序,解决颜色反转问题
- 自动计算Bitmap的对齐Stride,避免手动拼接padding的繁琐操作
- 使用
Marshal.Copy完整复制包含padding的Bitmap数据,确保图像完整性
3. 额外优化:跳过JPEG中间步骤
当前DNG→Bitmap→JPEG→Bitmap→int[,]的流程存在冗余,JPEG压缩会损失画质且增加开销,建议直接从libraw处理后的内存数据生成ASCOM图像阵列:
public int[,] ConvertLibrawDataToImageArray(libraw_processed_image_t img) { int width = img.width; int height = img.height; int[,] result = new int[width, height]; Parallel.For(0, height, row => { int rowStart = row * width * 3; for (int col = 0; col < width; col++) { int pixelOffset = rowStart + col * 3; byte r = img.data[pixelOffset]; byte g = img.data[pixelOffset + 1]; byte b = img.data[pixelOffset + 2]; result[col, row] = (int)(0.299 * r + 0.587 * g + 0.114 * b); } }); return result; }
此方式可直接跳过JPEG转换环节,提升效率并避免画质损失。
内容的提问来源于stack exchange,提问作者Alvin F
相关产品推荐
相关产品推荐

