图像量化与量子算法问题
Posted
技术标签:
【中文标题】图像量化与量子算法问题【英文标题】:Image Quantization with quantums Algorithm question 【发布时间】:2021-11-01 01:13:14 【问题描述】:我遇到了一个问题,无法找到可行的解决方案。
图像量化
给定一个灰度图像,每个像素的颜色范围从(0到255),将值的范围压缩到给定数量的量子值。
目标是以所需成本的最小总和来做到这一点,像素的成本被定义为其颜色与其最接近的量子值之间的绝对差。
例子
有3行3列,图像[[7,2,8], [8,2,3], [9,8 255]]量子= 3个量子值。最优量子值是(2 ,8,255) 导致最小总成本 |7-8| + |2-2| + |8-8| + |8-8| + |2-2| + |3-2| + |9-8| + |8-8| + |255-255| = 1+0+0+0+0+1+1+0+0 = 3
功能说明
完成编辑器中提供的求解功能。该函数采用以下 4 个参数,并返回成本的最小总和。
n 表示图像中的行数
m 表示图像中的列数
image 表示图片
quantums 表示量子值的个数。
输出: 打印单个整数的最小成本总和/
Constraints:
1<=n,m<=100
0<=image|i||j|<=255
1<=quantums<=256
Sample Input 1
3
3
7 2 8
8 2 3
9 8 255
10
Sample output 1
0
说明
最佳量子值是 0,1,2,3,4,5,7,8,9,255 领先于成本的最小总和 |7-7| + |2-2| + |8-8| + |8-8| + |2-2| + |3-3| + |9-9| + |8-8| + |255-255| = 0+0+0+0+0+0+0+0+0 = 0
谁能帮我找到解决办法?
【问题讨论】:
当量子数 = 1 时,这个问题就简化为求中位数(或第 50 个百分位数)。基于此,我猜想对此的第一个切割/启发式方法是将量子分配给等于100% / (#quantums+1)
的累积百分位数。因此,对于三个量程,将它们分配到第 25、50 和 75 个百分位数。
... 最初,无论如何。然后我会找到最接近它的量子值,然后我会尝试递增/递减它,直到我得到一个局部最小值,然后对其他量子重复此操作。
这能回答你的问题吗? 1D Number Array Clustering
@Welbog 以上建议的问题无论如何都不能回答这个问题!请收回您的关闭请求
其实是同一个问题。您正在尝试识别一维数据中的 N 个集群,以最小化到这些集群中心的总距离。
【参考方案1】:
很明显,如果我们有与不同像素一样多或更多的可用量子,我们可以返回 0,因为我们设置了至少足够的量子,每个量子都等于一个不同的像素。现在考虑将量程设置为已排序、分组列表的最小数字。
M = [
[7, 2, 8],
[8, 2, 3],
[9, 8, 255]
]
[(2, 2), (3, 1), (7, 1), (8, 3), (9, 1), (255, 1)]
2
我们记录所需的差异总和:
0 + 0 + 1 + 5 + 6 + 6 + 6 + 7 + 253 = 284
现在通过将量子增加 1 进行更新,我们观察到每个元素的移动量为 1,因此我们需要的只是受影响元素的计数。
递增 2 到 3
3
1 + 1 + 0 + 4 + 5 + 5 + 5 + 6 + 252 = 279
或
284 + 2 * 1 - 7 * 1
= 284 + 2 - 7
= 279
考虑使用单个量程从左侧遍历,仅计算对已排序、分组列表中位于量程值左侧的像素的影响。
要在添加量程时仅更新左侧,我们有:
left[k][q] = min(left[k-1][p] + effect(A, p, q))
其中effect
是对A
(已排序、分组列表)中元素的影响,因为我们逐渐减少p
并根据它们是否在[p, q]
范围内更新对像素的影响更接近p
或q
。随着我们为每一轮k
增加q
,我们可以使用递增移动的指针将相关位置保留在已排序、分组的像素列表中。
如果我们有解决方案
left[k][q]
当包含k
量子且最右边的量子集为数字q
时,q
左侧的像素是最佳的,那么完整的候选解决方案将由下式给出:
left[k][q] + effect(A, q, list_end)
where there is no quantum between q and list_end
时间复杂度为O(n + k * q * q) = O(n + quantums ^ 3)
,其中n
是输入矩阵中的元素数。
Python 代码:
def f(M, quantums):
pixel_freq = [0] * 256
for row in M:
for colour in row:
pixel_freq[colour] += 1
# dp[k][q] stores the best solution up
# to the qth quantum value, with
# considering the effect left of
# k quantums with the rightmost as q
dp = [[0] * 256 for _ in range(quantums + 1)]
pixel_count = pixel_freq[0]
for q in range(1, 256):
dp[1][q] = dp[1][q-1] + pixel_count
pixel_count += pixel_freq[q]
predecessor = [[None] * 256 for _ in range(quantums + 1)]
# Main iteration, where the full
# candidate includes both right and
# left effects while incrementing the
# number of quantums.
for k in range(2, quantums + 1):
for q in range(k - 1, 256):
# Adding a quantum to the right
# of the rightmost doesn't change
# the left cost already calculated
# for the rightmost.
best_left = dp[k-1][q-1]
predecessor[k][q] = q - 1
q_effect = 0
p_effect = 0
p_count = 0
for p in range(q - 2, k - 3, -1):
r_idx = p + (q - p) // 2
# When the distance between p
# and q is even, we reassign
# one pixel frequency to q
if (q - p - 1) % 2 == 0:
r_freq = pixel_freq[r_idx + 1]
q_effect += (q - r_idx - 1) * r_freq
p_count -= r_freq
p_effect -= r_freq * (r_idx - p)
# Either way, we add one pixel frequency
# to p_count and recalculate
p_count += pixel_freq[p + 1]
p_effect += p_count
effect = dp[k-1][p] + p_effect + q_effect
if effect < best_left:
best_left = effect
predecessor[k][q] = p
dp[k][q] = best_left
# Records the cost only on the right
# of the rightmost quantum
# for candidate solutions.
right_side_effect = 0
pixel_count = pixel_freq[255]
best = dp[quantums][255]
best_quantum = 255
for q in range(254, quantums-1, -1):
right_side_effect += pixel_count
pixel_count += pixel_freq[q]
candidate = dp[quantums][q] + right_side_effect
if candidate < best:
best = candidate
best_quantum = q
quantum_list = [best_quantum]
prev_quantum = best_quantum
for i in range(k, 1, -1):
prev_quantum = predecessor[i][prev_quantum]
quantum_list.append(prev_quantum)
return best, list(reversed(quantum_list))
输出:
M = [
[7, 2, 8],
[8, 2, 3],
[9, 8, 255]
]
k = 3
print(f(M, k)) # (3, [2, 8, 255])
M = [
[7, 2, 8],
[8, 2, 3],
[9, 8, 255]
]
k = 10
print(f(M, k)) # (0, [2, 3, 7, 8, 9, 251, 252, 253, 254, 255])
【讨论】:
请注意,我注意到这个算法在 #quantums 为 100 或更大的情况下会产生不正确的值(在其他情况下可能存在。)我不确定这是否表示一个简单的错误或者这种方法存在更大的潜在问题。你能证明这个算法的正确性吗? @Idog 似乎实际上是您的优化功能失败了。见这里:https://***.com/questions/69032311/image-quantization-with-quantums-algorithm-question#comment122378224_69234029 这个算法似乎有问题。看起来它可能过于乐观,并根据量子配置无法达到的值来选择配置。例如,请参阅此案例,该案例显示重新计算量子值与算法预期的不同:ideone.com/NhTYBk 根据f
报告的量子配置重新计算时,f
找到的量子最佳值似乎不一样。此外,f
在这种情况下声称的最佳值是20
,但是当根据配置重新计算它时,它实际上是22
。同时维特比方法表明最佳值应该是21
。
@ldog 请停止诽谤我的回答 -- ideone.com/59cbNU【参考方案2】:
我会提出以下建议:
步骤 0
输入是:
image = 7 2 8
8 2 3
9 8 255
quantums = 3
步骤 1
然后您可以根据输入图像计算直方图。由于您的图像是灰度图像,因此它只能包含 0-255 之间的值。
这意味着您的直方图数组的长度等于 256。
hist = int[256] // init the histogram array
for each pixel color in image // iterate over image
hist[color]++ // and increment histogram values
hist:
value 0 0 2 1 0 0 0 1 2 1 0 . . . 1
---------------------------------------------
color 0 1 2 3 4 5 6 7 8 9 10 . . . 255
如何读取直方图:
color 3 has 1 occurrence
color 8 has 2 occurrences
使用 tis 方法,我们将问题从 N(像素数量)减少到 256(直方图大小)。 这一步的时间复杂度是O(N)
第二步
一旦我们有了直方图,我们就可以计算它的# of quantums
局部最大值。在我们的例子中,我们可以计算 3 个局部最大值。
为了简单起见,我不会写伪代码,网上有很多例子。只是谷歌('在数组中找到局部最大值/极值'
重要的是你最终得到 3 个最大的局部最大值。在我们的例子中是:
hist:
value 0 0 2 1 0 0 0 1 2 1 0 . . . 1
---------------------------------------------
color 0 1 2 3 4 5 6 7 8 9 10 . . . 255
^ ^ ^
这些值(2、8、266)是您的tops of the mountains
。
这一步的时间复杂度是O(quantums) 我可以解释为什么它不是 O(1) 或 O(256),因为您可以在一次通过中找到局部最大值。如果需要,我会添加评论。
第三步
拥有tops of the mountains
后,您希望以具有最大可能表面的方式隔离每个mountain
。
所以,您将通过 finding the minimum value between two tops
执行此操作
在我们的例子中是:
value 0 0 2 1 0 0 0 1 2 1 0 . . . 1
---------------------------------------------
color 0 1 2 3 4 5 6 7 8 9 10 . . . 255
^ ^
| \ / \
- - _ _ _ _ . . . _ ^
所以我们的目标是在索引值之间进行查找:
from 0 to 2 (not needed, first mountain start from beginning)
from 2 to 8 (to see where first mountain ends, and second one starts)
from 8 to 255 (to see where second one ends, and third starts)
from 255 to end (just noted, also not needed, last mountain always reaches the end)
有多个候选者(多个零),您选择哪个最小并不重要。山的最终面总是一样的。
假设我们的算法返回两个最小值。我们将在下一步中使用它们。
min_1_2 = 6
min_2_3 = 254
这一步的时间复杂度是O(256)。您只需要一次通过直方图即可计算所有最小值(实际上您将进行多次较小的迭代,但总的来说您只访问每个元素一次。
有人可以认为这是 O(1)
第四步
计算每座山的median
。
这可能是一个棘手的问题。为什么?因为我们想使用原始值(颜色)而不是计数器(出现次数)来计算中位数。
还有一个公式可以给我们很好的估计,而且这个可以很快执行(只看直方图值)(https://medium.com/analytics-vidhya/descriptive-statistics-iii-c36ecb06a9ae)
如果这还不够精确,那么唯一的选择就是“展开”计算值。然后,我们可以对这些“原始”像素进行排序并轻松找到中位数。
在我们的例子中,这些中位数是2, 8, 255
如果我们必须对整个原始图像进行排序,这一步的时间复杂度是 O(nlogn)。如果逼近效果很好,那么这一步的时间复杂度几乎是常数。
步骤 5
这是最后一步。
您现在知道“山”的开始和结束。 你也知道属于那个“山”的中位数
同样,您可以遍历每座山并计算 DIFF。
diff = 0
median_1 = 2
median_2 = 8
median_3 = 255
for each hist value (color, count) between START and END // for first mountain -> START = 0, END = 6
// for second mountain -> START = 6, END = 254
// for third mountain -> START = 254, END = 255
diff = diff + |color - median_X| * count
这一步的时间复杂度又是O(256),可以认为是常数时间O(1)
【讨论】:
以上是关于图像量化与量子算法问题的主要内容,如果未能解决你的问题,请参考以下文章
Atitit 图像处理Depixelizing Pixel Art像素风格画的矢量化
图像增强基于matlab量子遗传算法优化beta自适应图像增强含Matlab源码 2259期