按alpha角度旋转2D图像数组的Java代码输出黑图,问题出在哪?
图像旋转代码全黑问题排查
你代码存在多个逻辑错误,其中直接导致全黑的是循环遍历范围错误,其余错误也会导致旋转结果不符合预期,具体问题如下:
- 最直接原因:你没有遍历目标图像的全部像素。内层循环起始值设置为
height - i - 1,导致大量目标像素没有被赋值,int数组默认初始化值为0,对应图像就是纯黑色。 - 坐标变换没有做中心对齐。图像默认的坐标原点在左上角,旋转是绕图像中心进行的,你直接对左上角为原点的坐标做旋转变换,会导致绝大多数像素旋转后超出原图像范围,取不到有效值。
- 目标图像尺寸设置错误。图像旋转后外接矩形的宽高会发生变化,计算公式为
新宽度 = 原宽度 * |cosα| + 原高度 * |sinα|,新高度 = 原宽度 * |sinα| + 原高度 * |cosα|,你沿用原始图像的宽高会直接裁掉大部分旋转后的内容。 - 坐标计算逻辑错误。你用
img[i].length、img[j].length取值,二维图像每一行的宽度是固定的,直接用提前计算好的width即可,img[j].length当j超过原图像高度时会直接触发数组越界;同时你混淆了x/y坐标和宽高的对应关系,旋转变换的公式应用完全错误。 - 没有做坐标有效性校验。计算得到的原图像坐标如果超出原图像范围,应该直接赋值为透明/黑色,你没有做校验直接下标取值,要么触发越界崩溃,要么取到错误值。
下面是修正后的参考实现(针对ARGB格式的二维int像素数组):
public static int[][] rotate(int[][] img, double alpha) { double rad = Math.toRadians(alpha); double sin = Math.abs(Math.sin(rad)); double cos = Math.abs(Math.cos(rad)); int originalHeight = img.length; int originalWidth = img[0].length; // 计算旋转后新图像的宽高 int newWidth = (int) Math.floor(originalWidth * cos + originalHeight * sin); int newHeight = (int) Math.floor(originalWidth * sin + originalHeight * cos); int[][] rotated = new int[newHeight][newWidth]; // 原图像和新图像的中心坐标 double originalCenterX = originalWidth / 2.0; double originalCenterY = originalHeight / 2.0; double newCenterX = newWidth / 2.0; double newCenterY = newHeight / 2.0; // 遍历新图像所有像素,反向映射找原图像对应坐标 for (int y = 0; y < newHeight; y++) { for (int x = 0; x < newWidth; x++) { // 把新图像坐标转换到以中心为原点的坐标系 double offsetX = x - newCenterX; double offsetY = y - newCenterY; // 旋转变换,得到原图像的相对坐标 double originalOffsetX = offsetX * cos + offsetY * sin; double originalOffsetY = -offsetX * sin + offsetY * cos; // 转换回原图像左上角为原点的坐标系 int originalX = (int) Math.round(originalOffsetX + originalCenterX); int originalY = (int) Math.round(originalOffsetY + originalCenterY); // 校验坐标在原图像范围内才取值,否则保留默认黑色 if (originalX >= 0 && originalX < originalWidth && originalY >=0 && originalY < originalHeight) { rotated[y][x] = img[originalY][originalX]; } } } return rotated; }
如果你传入的是RGB三通道的3D数组,只需要把参数和返回值改为int[][][],赋值的时候对应三个通道分别赋值即可。
内容的提问来源于stack exchange,提问作者Mabadai
相关产品推荐
相关产品推荐

