今天來說說im2col和col2im函數,這是MATLAB中兩個內置函數,經常用於數字圖像處理中。其中im2col函數在《MATLAB中的im2col函數》一文中已經進行了簡單的介紹。
一般來說:
- 如是將圖像分割成塊的時候用的im2col參數為'distinct',那么用col2im函數時參數也是'distinct',即可將轉換后的數組復原。
- 如果將圖像分割成塊的時候用的im2col參數為'sliding',我目前還不知道MATLAB中使用內置函數是如何復原的。
今天,來看看Python中是如何實現這兩個函數的(sliding類型)。
- 對於im2col的實現,我們沿着原始矩陣逐行計算,將得到的新的子矩陣展開成列,放置在列塊矩陣中。
- 對於col2im的實現,我們沿着列塊矩陣逐行計算,將得到的行展成子矩陣,然后將子矩陣放置在最終結果對應的位置(每次當前值進行相加),同時記錄每個位置的值放置的次數。最后,將當前位置的值除以放置的次數,即可得到結果(原始矩陣)。
def im2col(mtx, block_size):
mtx_shape = mtx.shape
sx = mtx_shape[0] - block_size[0] + 1
sy = mtx_shape[1] - block_size[1] + 1
# 如果設A為m×n的,對於[p q]的塊划分,最后矩陣的行數為p×q,列數為(m−p+1)×(n−q+1)。
result = np.empty((block_size[0] * block_size[1], sx * sy))
# 沿着行移動,所以先保持列(i)不動,沿着行(j)走
for i in range(sy):
for j in range(sx):
result[:, i * sx + j] = mtx[j:j + block_size[0], i:i + block_size[1]].ravel(order='F')
return result
def col2im(mtx, image_size, block_size):
p, q = block_size
sx = image_size[0] - p + 1
sy = image_size[1] - q + 1
result = np.zeros(image_size)
weight = np.zeros(image_size) # weight記錄每個單元格的數字重復加了多少遍
col = 0
# 沿着行移動,所以先保持列(i)不動,沿着行(j)走
for i in range(sy):
for j in range(sx):
result[j:j + p, i:i + q] += mtx[:, col].reshape(block_size, order='F')
weight[j:j + p, i:i + q] += np.ones(block_size)
col += 1
return result / weight
測試代碼:
if __name__ == '__main__':
mtx = np.around(np.random.rand(5, 5) * 100)
print('原始矩陣:')
print(mtx)
a1 = im2col(mtx, (2, 3))
print('im2col(分塊大小2x3):')
print(a1)
b1 = col2im(a1, (5, 5), (2, 3))
print('col2im復原:')
print(b1)
a2 = im2col(mtx, (3, 3))
print('im2col(分塊大小3x3):')
print(a2)
b2 = col2im(a2, (5, 5), (3, 3))
print('col2im復原:')
print(b2)
運行結果:
原始矩陣:
[[ 48. 38. 38. 59. 38.]
[ 38. 11. 25. 52. 44.]
[ 60. 69. 49. 93. 66.]
[ 88. 8. 47. 14. 47.]
[ 96. 37. 56. 86. 54.]]
im2col(分塊大小2x3):
[[ 48. 38. 60. 88. 38. 11. 69. 8. 38. 25. 49. 47.]
[ 38. 60. 88. 96. 11. 69. 8. 37. 25. 49. 47. 56.]
[ 38. 11. 69. 8. 38. 25. 49. 47. 59. 52. 93. 14.]
[ 11. 69. 8. 37. 25. 49. 47. 56. 52. 93. 14. 86.]
[ 38. 25. 49. 47. 59. 52. 93. 14. 38. 44. 66. 47.]
[ 25. 49. 47. 56. 52. 93. 14. 86. 44. 66. 47. 54.]]
col2im復原:
[[ 48. 38. 38. 59. 38.]
[ 38. 11. 25. 52. 44.]
[ 60. 69. 49. 93. 66.]
[ 88. 8. 47. 14. 47.]
[ 96. 37. 56. 86. 54.]]
im2col(分塊大小3x3):
[[ 48. 38. 60. 38. 11. 69. 38. 25. 49.]
[ 38. 60. 88. 11. 69. 8. 25. 49. 47.]
[ 60. 88. 96. 69. 8. 37. 49. 47. 56.]
[ 38. 11. 69. 38. 25. 49. 59. 52. 93.]
[ 11. 69. 8. 25. 49. 47. 52. 93. 14.]
[ 69. 8. 37. 49. 47. 56. 93. 14. 86.]
[ 38. 25. 49. 59. 52. 93. 38. 44. 66.]
[ 25. 49. 47. 52. 93. 14. 44. 66. 47.]
[ 49. 47. 56. 93. 14. 86. 66. 47. 54.]]
col2im復原:
[[ 48. 38. 38. 59. 38.]
[ 38. 11. 25. 52. 44.]
[ 60. 69. 49. 93. 66.]
[ 88. 8. 47. 14. 47.]
[ 96. 37. 56. 86. 54.]]