将数字范围转换为另一个范围,保持比例
我想把一组数字转换成另一组,同时保持它们之间的比例关系。数学对我来说不是强项。
我有一个图片文件,里面的点值可能在-16000.00到16000.00之间,不过通常情况下这个范围会小很多。我想把这些值压缩到0到100的整数范围内,其中0代表最小的点值,100代表最大的点值。中间的所有点也要保持相对的比例,虽然这样会损失一些精度。我想用Python来实现这个,但如果有一个通用的算法也可以。我希望这个算法能让最小值和最大值都可以调整(比如,第二个范围可以是-50到800,而不是0到100)。
21 个回答
29
其实有些情况下,上面的答案可能会出问题。比如说输入的值不对、输入的范围不对,或者输入/输出的范围是负数。
def remap( x, oMin, oMax, nMin, nMax ):
#range check
if oMin == oMax:
print "Warning: Zero input range"
return None
if nMin == nMax:
print "Warning: Zero output range"
return None
#check reversed input range
reverseInput = False
oldMin = min( oMin, oMax )
oldMax = max( oMin, oMax )
if not oldMin == oMin:
reverseInput = True
#check reversed output range
reverseOutput = False
newMin = min( nMin, nMax )
newMax = max( nMin, nMax )
if not newMin == nMin :
reverseOutput = True
portion = (x-oldMin)*(newMax-newMin)/(oldMax-oldMin)
if reverseInput:
portion = (oldMax-x)*(newMax-newMin)/(oldMax-oldMin)
result = portion + newMin
if reverseOutput:
result = newMax - portion
return result
#test cases
print remap( 25.0, 0.0, 100.0, 1.0, -1.0 ), "==", 0.5
print remap( 25.0, 100.0, -100.0, -1.0, 1.0 ), "==", -0.25
print remap( -125.0, -100.0, -200.0, 1.0, -1.0 ), "==", 0.5
print remap( -125.0, -200.0, -100.0, -1.0, 1.0 ), "==", 0.5
#even when value is out of bound
print remap( -20.0, 0.0, 100.0, 0.0, 1.0 ), "==", -0.2
89
这只是一个简单的线性转换。
new_value = ( (old_value - old_min) / (old_max - old_min) ) * (new_max - new_min) + new_min
所以,把10000从-16000到16000的范围转换到0到100的新范围,结果是:
old_value = 10000
old_min = -16000
old_max = 16000
new_min = 0
new_max = 100
new_value = ( ( 10000 - -16000 ) / (16000 - -16000) ) * (100 - 0) + 0
= 81.25
751
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