前言:我不确定是否将其归类为更多的数学问题或编程问题,而且我是线性代数中的一个菜鸟并且这样做是为了一个爱好。非常感谢任何帮助。
假设我有一些任意编程语言没有任何已建立的机制来对位图图像(或任何x,y值的任意集合)执行线性变换。假设我想执行一些任意的旋转,缩放和翻译。
现在我将迭代每个x,y,获取像素颜色,然后对其执行变换,舍入到最近的新x,y以将我的像素颜色值复制到,然后生成最终图像。它适用于我已经预先计算的简单旋转,但是在i5下面的TransformImage方法中需要几秒钟来计算,所以我想知道什么是更快的方式?
这是我目前使用C#进行测试的方法:
Color[,] BackupOriginal = OriginalColorData.Clone() as Color[,];
float angle = 25.0f;
float angleRadians = (float)(angle * (Math.PI / 180f));
float cosAngle = (float)Math.Cos(angleRadians);
float sinAngle = (float)Math.Sin(angleRadians);
BackupOriginal = LinearTransformation.TransformImage(BackupOriginal, new float[2, 2] {
{cosAngle,-1f * sinAngle},
{sinAngle,cosAngle}
});
...
public static Color[,] TransformImage(Color[,] originalImage, float[,] transformationMatrix)
{
if (transformationMatrix.GetUpperBound(1) < 1 || transformationMatrix.GetUpperBound(0) < 1) return null;
int width = originalImage.GetUpperBound(1) + 1;
int height = originalImage.GetUpperBound(0) + 1;
Color[,] newImage = new Color[height, width];
for (int y=0;y<height;y++)
{
for (int x=0;x<width;x++)
{
Color currentPixel = originalImage[y, x];
int newX = (int)Math.Round((x * transformationMatrix[0, 0]) + (y * transformationMatrix[0, 1]));
int newY = (int)Math.Round((x * transformationMatrix[1, 0]) + (y * transformationMatrix[1, 1]));
if (IsValidPixel(newX, newY, width, height))
newImage[newY, newX] = currentPixel;
}
}
return newImage;
}
答案 0 :(得分:0)
基本上,这是一种您不希望以任意语言自己实现它的操作。您需要考虑几个问题:
我们可以在这里停下来,只考虑你现在为每个像素做的操作次数,超出了琐碎的任务。
然而,更重要的是:
然后,您有关于如何处理别名的问题。没有简单的方法可以保证newImage中的每个像素都映射到originalImage中的一个且只有一个像素。您最终可能会多次写入同一像素(您可能真的想要混合结果),而某些像素可能最终为空。
那么,在一个相当短的代码片段中可以做些什么呢?不是太多。如果你正在寻找性能,我至少会试图摆脱Math.Round(在转换为粗略舍入之前添加.5),理想情况下完全避免浮点数。一个选项是存储整数乘数,然后将结果(>>
运算符)移回相同范围,即将cosAngle
存储为cosAngle * 65536
并将newX
移位16根据之前的评论,甚至可能将变换矩阵存储为四个单独的浮点值可能比那里的2D阵列更可取。我希望JIT编译器处理这种情况。
但是,最终,没有任何魔力。高性能实现往往更长,也倾向于用其他语言编写。相同逻辑的AC或C ++实现可以加速一些事情,但你仍然必须处理特别是内存带宽问题,其中在完整源图像上的顺序循环将给你一个不利的内存访问模式在目标中任意角。那部分你可以测试自己,0的角度明显快于比如.4?
C实现的大部分加速都来自优化编译器正在积极调整以便为计算密集型循环发出简洁代码,而.NET环境实际上更侧重于业务线应用程序。
我不认为这里使用Color
类型是一个问题,因为.NET结构往往很快,但如果你想评估性能,我可能会尝试使用一个简单的int或float数组灰度值,以了解OO抽象是否会妨碍正确的优化。