我试图将一个范围的数字转换为另一个,保持比率。数学不是我的强项。
I have an image file where point values may range from -16000.00 to 16000.00 though the typical range may be much less. What I want to do is compress these values into the integer range 0-100, where 0 is the value of the smallest point, and 100 is the value of the largest. All points in between should keep a relative ratio even though some precision is being lost I'd like to do this in python but even a general algorithm should suffice. I'd prefer an algorithm where the min/max or either range can be adjusted (ie, the second range could be -50 to 800 instead of 0 to 100).
我个人使用支持泛型的helper类(Swift 3,4)。x兼容)
struct Rescale<Type : BinaryFloatingPoint> {
typealias RescaleDomain = (lowerBound: Type, upperBound: Type)
var fromDomain: RescaleDomain
var toDomain: RescaleDomain
init(from: RescaleDomain, to: RescaleDomain) {
self.fromDomain = from
self.toDomain = to
}
func interpolate(_ x: Type ) -> Type {
return self.toDomain.lowerBound * (1 - x) + self.toDomain.upperBound * x;
}
func uninterpolate(_ x: Type) -> Type {
let b = (self.fromDomain.upperBound - self.fromDomain.lowerBound) != 0 ? self.fromDomain.upperBound - self.fromDomain.lowerBound : 1 / self.fromDomain.upperBound;
return (x - self.fromDomain.lowerBound) / b
}
func rescale(_ x: Type ) -> Type {
return interpolate( uninterpolate(x) )
}
}
Ex:
let rescaler = Rescale<Float>(from: (-1, 1), to: (0, 100))
print(rescaler.rescale(0)) // OUTPUT: 50
NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
或者更容易读懂:
OldRange = (OldMax - OldMin)
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
或者如果你想保护旧范围为0的情况(OldMin = OldMax):
OldRange = (OldMax - OldMin)
if (OldRange == 0)
NewValue = NewMin
else
{
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
}
注意,在这种情况下,我们被迫任意选择一个可能的新范围值。根据上下文,明智的选择可能是:NewMin(见示例),NewMax或(NewMin + NewMax) / 2
在由PenguinTD提供的清单中,我不明白为什么范围是颠倒的,它不需要颠倒范围就能工作。线性范围转换基于线性方程Y=Xm+n,其中m和n是从给定的范围推导出来的。与其将范围称为min和max,不如将它们称为1和2。所以公式是:
Y = (((X - x1) * (y2 - y1)) / (x2 - x1)) + y1
当X=x1时Y=y1,当X=x2时Y=y2。X1, x2, y1和y2可以取任意正值或负值。在宏中定义表达式使其更有用,它可以与任何参数名称一起使用。
#define RangeConv(X, x1, x2, y1, y2) (((float)((X - x1) * (y2 - y1)) / (x2 - x1)) + y1)
在所有实参都是整数值的情况下,浮点强制转换将确保浮点除法。
根据应用程序的不同,可能不需要检查x1=x2和y1==y2的范围。
增加了KOTLIN版本的数学解释
假设我们有一个介于(OMin, Omax)之间的刻度,我们在这个范围内有一个值X
我们要把它转换成比例(NMin, NMax)
我们知道X,我们需要找到Y,比值必须相等:
=> (Y-NMin)/(NMax-NMin) = (X-OMin)/(OMax-OMin)
=> (Y-NMin)/NewRange = (X-OMin)/OldRange
=> Y = ((X-OMin)*NewRange)/oldRange)+NMin Answer
从实用主义的角度来看,我们可以这样写这个问句:
private fun convertScale(oldValueToConvert:Int): Float {
// Old Scale 50-100
val oldScaleMin = 50
val oldScaleMax = 100
val oldScaleRange= (oldScaleMax - oldScaleMin)
//new Scale 0-1
val newScaleMin = 0.0f
val newScaleMax = 1.0f
val newScaleRange= (newScaleMax - newScaleMin)
return ((oldValueToConvert - oldScaleMin)* newScaleRange/ oldScaleRange) + newScaleMin
}
JAVA
/**
*
* @param x
* @param inMin
* @param inMax
* @param outMin
* @param outMax
* @return
*/
private long normalize(long x, long inMin, long inMax, long outMin, long outMax) {
long outRange = outMax - outMin;
long inRange = inMax - inMin;
return (x - inMin) *outRange / inRange + outMin;
}
用法:
float brightness = normalize(progress, 0, 10, 0,255);