问题描述
给定一个形状为 (64,64)(= 图像)的 numpy 数组和一个将该图像作为输入的任意函数,我想找到最小化函数的图像。假设函数计算对比度。
示例:
import numpy as np
def contrast(X):
vmin,vmax = int(np.min(X)),int(np.max(X))
num = vmax - vmin
denom = vmax + vmin
if denom == 0:
return 0
else:
return num / denom
img = np.random.randint(256,size=(64,64),dtype=np.uint8)
res = contrast(img)
Scipy 提供了 fmin()
,但该函数不适用于如此大的输入。任何想法如何找到
使函数最小化的图像?
解决方法
它绝不是完美的,但您至少可以通过简单的梯度下降优化和自动微分来接近局部最小值¹,例如autograd
。为了使自动渐变起作用,您很可能必须将图像数据转换为浮点数,进行优化,然后转换并转换回整数。原则上,这可能会导致您错过最小值或找到错误的最小值或陷入局部最小值。
1:请注意,这绝不保证您在任何情况下都能找到全局最小值,但会找到一个最小值。
import autograd.numpy as np
from autograd import elementwise_grad
def michelson_contrast(image):
vmin,vmax = np.min(image),np.max(image)
if (vmax + vmin) > 1e-15:
return (vmax - vmin) / (vmax + vmin)
return 0
对于您指定的特定函数,Michelson contrast,优化收敛极其缓慢,
f = michelson_contrast
df = elementwise_grad(f)
img = np.random.randint(256,size=(100,100)).astype(np.float64)
# Simple gradient descent.
for i in range(1,(max_iterations := 100000) + 1):
img -= 10**3 * df(img)
# Round and cast the image back to integer values.
img = np.round(img).astype(int)
但是一个 100 x 100
随机测试在大约一分钟内收敛到我的笔记本电脑上。
iter. function
--------------------------------------
0 1.0000000000
10000 0.6198908490
20000 0.4906918649
30000 0.3968742592
40000 0.3204002330
50000 0.2539835041
60000 0.1942016682
70000 0.1386916909
80000 0.0863448569
90000 0.0361678029
100000 0.0003124169
四舍五入为整数,答案是 f = 0
的精确最小值,但当然存在很多(准确地说是 256 个):
[[146 146 146 ... 146 146 146]
[146 146 146 ... 146 146 146]
[146 146 146 ... 146 146 146]
...
[146 146 146 ... 146 146 146]
[146 146 146 ... 146 146 146]
[146 146 146 ... 146 146 146]]
另一个例子,RMS contrast,收敛得更快(不到一秒)
def rms_contrast(image):
N = image.size
image_mean = np.mean(image)
return np.sum((image - image_mean)**2) / N
f = rms_contrast
df = elementwise_grad(f)
img = np.random.randint(256,100)).astype(np.float64)
for i in range(1,(max_iterations := 100) + 1):
img -= 10**3 * df(img)
img = np.round(img).astype(int)
与
iter. function
--------------------------------------
0 5486.3646543900
10 63.2534779216
20 0.7292629494
30 0.0084078294
40 0.0000969357
50 0.0000011176
60 0.0000000129
70 0.0000000001
80 0.0000000000
90 0.0000000000
100 0.0000000000
以及生成的图像(在转换回整数后又是一个完美的最小值)。
[[126 126 126 ... 126 126 126]
[126 126 126 ... 126 126 126]
[126 126 126 ... 126 126 126]
...
[126 126 126 ... 126 126 126]
[126 126 126 ... 126 126 126]
[126 126 126 ... 126 126 126]]
除非函数非常复杂或计算量很大,或者输入图像很大,否则这种方法至少应该让你更接近你的答案。