C#:500万像素RGB数据转PictureBox降采样后图像异常排查
首先看你给出的代码片段,能发现几个明显的问题,这些应该就是导致输出图像异常的核心原因:
数组索引起始错误:
C#里数组默认从0开始索引,但你的循环从i=1和j=1起步,直接跳过了原图像左上角的第一行第一列像素块。原图像宽度2448刚好是3的整数倍(2448/3=816),正确的起始索引应该是i=0,每次加3,这样才能覆盖到原图像所有间隔3个的像素(0,3,6,...,2445),否则最后一行像素(索引2447)也会被漏掉。目标数组坐标未递增:
你初始化x和y为0后,完全没在循环里对它们做递增操作!这意味着所有采样到的像素值都会被重复赋值到Sy[0,0]这个位置,最后整个输出图像只会显示最后一次采样的像素颜色,这肯定会导致图像彻底异常。正确的做法是:在内层j循环结束后执行y++,在外层i循环结束后执行x++,才能把每个采样像素放到目标数组对应的位置上。目标数组维度与循环范围不匹配:
原图像高度是2048,2048除以3等于682.666,但你创建的目标数组是[816,683]。如果按照j +=3的方式循环,最多只能得到682个有效的行(0,3,...,2046),最后一行(2047)无法被采样到。如果必须适配PictureBox的683高度,你需要额外处理最后一行的像素(比如复制倒数第二行的像素,或者对剩余的2行像素做简单平均)。代码遗漏关键逻辑:
你给出的代码不仅没写完Sy[x, y] = greenar[i, j]...的赋值逻辑,还缺少return Sy;的返回语句,这会导致方法根本没有输出结果,自然也无法得到正确的降采样图像。
修正后的参考代码如下:
public int[,] lowered(int[,] greenar) { int[,] Sy = new int[816, 683]; int x = 0; for (int i = 0; i < 2448; i += 3) { int y = 0; // 每次外层循环开始时重置y的起始位置 for (int j = 0; j < 2048; j += 3) { Sy[x, y] = greenar[i, j]; y++; // 内层循环递增y,移动到下一列目标像素 } // 适配683高度,手动补全最后一行的最后一个像素 if (x == 815) { Sy[x, 682] = greenar[i, 2047]; } x++; // 外层循环递增x,移动到下一行目标像素 } return Sy; // 必须返回处理后的目标数组 }
另外还要注意,C#里二维数组的维度是[行数,列数],你需要确认greenar的维度是否和原图像的宽高对应,要是原图像的存储顺序是[高度,宽度],那索引顺序搞反也会导致图像变形。
内容的提问来源于stack exchange,提问作者余昀哲

