我有一个表示强度(黑到白)的值数组(介于-1.0和1.0之间)。我需要一种方法将双值从-1.0映射到1.0到0到255并返回。
更一般化,我有一个数据数组,我需要从数据的最小值和最大值映射到提供的最小值和最大值。基本结构应该是:
private static int[] NormalizeData(double[] data, int min, int max)
{
var sorted = data.OrderBy(d => d);
double dataMax = sorted.First();
double dataMin = sorted.Last();
int[] ret = new int[data.Length];
for (int i = 0; i < data.Length; i++)
{
ret[i] = (int)data[i]; // Normalization here
}
return ret;
}
答案 0 :(得分:7)
这有效:
private static int[] NormalizeData(IEnumerable<double> data, int min, int max)
{
double dataMax = data.Max();
double dataMin = data.Min();
double range = dataMax - dataMin;
return data
.Select(d => (d - dataMin) / range)
.Select(n => (int)((1 - n) * min + n * max))
.ToArray();
}
第一个选择将输入标准化为0到1(0表示最小值,1表示最大值)。第二个选择采用该标准化数字,并将其映射到新的最小值和最大值。
请注意,使用LINQ Min()
和Max()
函数比为较大数据集排序输入要快:O(n)与O(n * lg(n))。
另外,如果你想走另一条路,那么你会希望它返回双打而不是整数。
答案 1 :(得分:2)
public static double Scale(this double elementToScale,
double rangeMin, double rangeMax,
double scaledRangeMin, double scaledRangeMax)
{
var scaled = scaledRangeMin + ((elementToScale - rangeMin) * (scaledRangeMax - scaledRangeMin) / (rangeMax - rangeMin));
return scaled;
}
用法:
// double [-1,1] to int [0-255]
int[] integers = doubles.Select(x => x.Scale(-1,1,0,255)).ToArray();
// int [0-255] to double [-1,1]
double[] doubles = integers.Select(x => ((double)x).Scale(0,255,-1,1)).ToArray();
如果您事先不知道最小值和最大值(示例中为[0-255]
和[-1,1]
),则可以使用LINQ Min()
和Max()
答案 2 :(得分:0)
修改强> 怎么样:
private static int[] NormalizeData(double[] data, int min, int max)
{
var sorted = data.OrderBy(d => d);
double dataMax = sorted.First();
double dataMin = sorted.Last();
int[] ret = new int[data.Length];
double avgIn = (double)((min + max) / 2.0);
double avgOut = (dataMax + dataMin) / 2.0);
for (int i = 0; i < data.Length; i++)
{
ret[i] = (int) Math.Round(avgOut * (data[i] + avgIn) / 2);
}
return ret;
}
答案 3 :(得分:0)
private static int[] NormalizeData(double[] data, int min, int max) {
int[] ret = new int[data.Length];
for (int i = 0; i < data.Length; i++) {
ret[i] = (int)((max * (data[i] + 1)) / 2);
}
return ret;
}
static void Main(string[] args) {
double[] data = { 1.0, -1, 0, -.5, .5 };
int[] normalized = NormalizeData(data, 0, 255);
foreach (var v in normalized) {
Console.WriteLine(v);
}
}
答案 4 :(得分:0)
假设进行了严格的线性转换,并希望dataMin
映射到min
和dataMax
以映射到max
:
double dataRange = dataMax - dataMin;
int newRange = max - min;
double pct = (data[i] - dataMin) / dataRange;
int newValue = Math.Round(min + (pct * newRange));
这肯定可以优化,但它显示了基本的想法。基本上,您可以计算出原始范围内值的位置(百分比),然后将该百分比映射到目标范围。
请注意,如果dataMin
为-0.5且dataMax
为0.5,则可能无法生成您正在查找的结果,因为-0.5将映射为0而0.5将映射到255。如果您希望事物完全按照规定进行映射,您还必须定义源范围。
顺便说一下,没有特别的理由对项目进行排序只是为了获得最小值和最大值。你可以写:
double dataMax = data.Max();
double dataMin = data.Min();
答案 5 :(得分:0)
为了能够规范化您的数组,在此示例中以数学方式处理向量,您需要定义向量的长度(多少维度)。 从示例中可以清楚地了解是否要将整个数组规范化,同时考虑数组中的所有元素。如果是,则计算数组的点积,将点积平方根存储为数组的长度。然后将每个术语除以该长度,以将数组规范化为1.0的长度。
在上面的情况中,您实际上没有描述数据的规范化,而是转换。要解决这个问题,您可以使用以下内容:
private static double[] convertToScale(double[] data, double oldMin, double oldMax,double min, double max)
{
double oldDiff = 0 - oldMin;
double oldScale = oldMax - oldMin;
double diff = 0 - min;
double scale = max - min;
int[] ret = new double[data.Length];
for (int i = 0; i < data.Length; i++)
{
double scaledFromZeroToOne = (oldDiff+data[i])/oldScale; // Normalization here [0,1]
double value = (scaledFromZeroToOne*scale)-diff;
ret[i] = value;
}
return ret;
}
我认为这个功能可以解决上述问题。 您可以将其称为以下行:
double[] result = convertToScale(input,-1.0,1.0,0,255);
如果您希望将值表示为整数,则将所有内容都转换为int。
希望它有所帮助。