在對圖像進行 dct 變換后,原圖像的高頻分量集中在左上,低頻部分集中在右下。在此情況下,將圖像將成一維,用簡單的逐行逐列效果不會很好,故需用Z字形掃描的方式進行展開。下圖給出了奇數行列和偶數行列的情況示意圖(僅供參考,行列數可以不相等,但一般圖像處理里,分塊都是8*8的小塊)。
下面給出了代碼,注釋寫得比較清楚。請結合圖像理解。幾個關鍵點:
1、在不考慮邊界時,根據行和列數和是奇數還是偶數來區分前面的方向是右上還是左下;
2、在考慮邊界時,需要轉彎,轉彎時需要判斷是哪個邊界、或者頂點位置;
在將情況討論后,發現代碼其實是可以合並的。這里為了方便理解,不進行合並
import cv2 as cv ''' define : zigzag 掃描 input : 二維矩陣, shape: (row, col) output : 列表, shape: (row*col,) variable: k 列表序號, i 行序號, j 列序號, row 行數, col 列數 method : 假設 (0, 0) 在左上角, (row-1, col-1) 在右下角的情況. 考慮非邊界的情況, 只有右上/左下兩個方向. 以從 (0, 0) 先向右(下)為例, 則會有 i+j 為偶數時右上(左下)前進, 為奇數時左下(右上)的情況前進. 如果遇到邊界, 某個方向收到限制, 移動允許的直線方向''' def zigzag(data): row = data.shape[0] col = data.shape[1] num = row * col list = np.zeros(num,) k = 0 i = 0 j = 0 while i < row and j < col and k < num: list[k] = data.item(i, j) k = k + 1 # i + j 為偶數, 右上移動. 下面情況是可以合並的, 但是為了方便理解, 分開寫 if (i + j) % 2 == 0: # 右邊界超出, 則向下 if (i-1) in range(row) and (j+1) not in range(col): i = i + 1 # 上邊界超出, 則向右 elif (i-1) not in range(row) and (j+1) in range(col): j = j + 1 # 上右邊界都超出, 即處於右上頂點的位置, 則向下 elif (i-1) not in range(row) and (j+1) not in range(col): i = i + 1 else: i = i - 1 j = j + 1 # i + j 為奇數, 左下移動 elif (i + j) % 2 == 1: # 左邊界超出, 則向下 if (i+1) in range(row) and (j-1) not in range(col): i = i + 1 # 下邊界超出, 則向右 elif (i+1) not in range(row) and (j-1) in range(col): j = j + 1 # 左下邊界都超出, 即處於左下頂點的位置, 則向右 elif (i+1) not in range(row) and (j-1) not in range(col): j = j + 1 else: i = i + 1 j = j - 1 return list if __name__ == "__main__": data = np.matrix([[1,2,6],[3,5,7],[4,8,9]]) print(data) result = zigzag(data) print(result)