6. ZigZag Conversion

https://leetcode.com/problems/zigzag-conversion/description/

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

P   A   H   N
A P L S I I G
Y   I   R

And then read line by line: "PAHNAPLSIIGYIR"

Write the code that will take a string and make this conversion given a number of rows:

string convert(string s, int numRows);
Input: s = "PAYPALISHIRING", numRows = 3
Output: "PAHNAPLSIIGYIR"

The idea is just clear: use numRows character strings to record characters in each row.  Traverse the original string s, we need to know which direction are we going, up or down, use True or False to represent this status. Finally, merge all rows.

class Solution(object):
    def convert(self, s, numRows):
        """
        :type s: str
        :type numRows: int
        :rtype: str
        """
        if numRows == 1 or numRows >= len(s):
            return s
        rows = ['' for _ in range(numRows)]
        curr = [0, True]
        for char in s:
            rows[curr[0]] += char
            if curr[1]:
                curr[0] += 1
            else:
                curr[0] -= 1
            if curr[0] == 0:
                curr[1] = True
            if curr[0] == numRows - 1:
                curr[1] = False
        return ''.join(rows)

好的,这是一个比较复杂的编码过程,需要较多的代码实现。我会尽可能详细地介绍每一步的实现方法。 首先,我们需要读取一张图片。假设这张图片的名称为"test.jpg",我们可以使用MATLAB自带的imread函数来读取这张图片。 ```matlab img = imread('test.jpg'); ``` 接下来,我们将图片转为YCrCb颜色空间。这可以使用MATLAB自带的rgb2ycbcr函数来实现。 ```matlab img_ycbcr = rgb2ycbcr(img); ``` 将图片分为8*8的矩阵,并进行离散余弦变换(DCT)。这可以使用MATLAB自带的dct2函数来实现。在实现过程中,我们需要对每个8*8的块进行DCT处理。 ```matlab Q = [16 11 10 16 24 40 51 61; 12 12 14 19 26 58 60 55; 14 13 16 24 40 57 69 56; 14 17 22 29 51 87 80 62; 18 22 37 56 68 109 103 77; 24 35 55 64 81 104 113 92; 49 64 78 87 103 121 120 101; 72 92 95 98 112 100 103 99]; % 将每个8*8的块进行DCT处理 for i = 1:size(img_ycbcr,1)/8 for j = 1:size(img_ycbcr,2)/8 block = img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:); block_dct = dct2(block); img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:) = block_dct; end end ``` 将DCT后的矩阵量子化。这一步需要先定义一个量化矩阵Q,然后将DCT后的矩阵除以量化矩阵Q,并向下取整。这可以使用MATLAB自带的round函数来实现。 ```matlab % 将每个8*8的块进行量化 for i = 1:size(img_ycbcr,1)/8 for j = 1:size(img_ycbcr,2)/8 block_dct = img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:); block_quant = round(block_dct./Q); img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:) = block_quant; end end ``` 进行ZIGZAG排序。这一步需要将每个8*8的块中的元素按照ZIGZAG顺序排列。这可以通过一个循环来实现。 ```matlab % 将每个8*8的块进行ZIGZAG排序 for i = 1:size(img_ycbcr,1)/8 for j = 1:size(img_ycbcr,2)/8 block_quant = img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:); block_zigzag = zeros(1,64*3); index = 1; for k = 1:8 if mod(k,2) == 0 for l = k:-1:1 block_zigzag(index,:) = block_quant(l,k+1-l,:); index = index + 1; end else for l = 1:k block_zigzag(index,:) = block_quant(l,k+1-l,:); index = index + 1; end end end for k = 2:8 if mod(k,2) == 0 for l = k:8 block_zigzag(index,:) = block_quant(k+9-l,l,:); index = index + 1; end else for l = 8:-1:k block_zigzag(index,:) = block_quant(k+9-l,l,:); index = index + 1; end end end img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:) = block_zigzag; end end ``` 将DC分量和AC分量进行DPCM和RLE编码。这一步需要先对每个8*8的块的DC分量进行DPCM编码,然后对每个8*8的块的AC分量进行RLE编码。在编码AC分量时,我们需要注意到0的个数和非0数值的大小对压缩率的影响。因此,我们需要将连续的0的个数进行编码,同时对非0数值的大小进行编码。这可以使用MATLAB自带的diff函数和find函数来实现。 ```matlab % 将DC分量和AC分量进行DPCM和RLE编码 dc_code = ''; ac_code = ''; for i = 1:size(img_ycbcr,1)/8 for j = 1:size(img_ycbcr,2)/8 block_zigzag = img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:); % 对DC分量进行DPCM编码 dc_diff = diff(block_zigzag(:,1,:)); dc_diff = [block_zigzag(1,1,:); dc_diff]; dc_code = [dc_code num2str(dc_diff(1))]; % 对AC分量进行RLE编码 ac_code_block = ''; zero_count = 0; for k = 2:size(block_zigzag,1)*size(block_zigzag,2)*size(block_zigzag,3) if block_zigzag(k) == 0 zero_count = zero_count + 1; else ac_code_block = [ac_code_block num2str(zero_count) num2str(block_zigzag(k))]; zero_count = 0; end end ac_code = [ac_code ac_code_block]; end end ``` 将整体信息进行哈夫曼(Huffman)编码。这一步需要先构建一个Huffman编码表,然后将DC分量和AC分量分别进行Huffman编码。在编码过程中,我们需要注意到Huffman编码的字典表需要存储在文件中,以便解码时使用。 ```matlab % 构建Huffman编码表 dc_prob = hist(dc_diff(:),unique(dc_diff(:))); dc_prob = dc_prob/sum(dc_prob); dc_dict = huffmandict(unique(dc_diff(:)), dc_prob); ac_prob = hist(str2num(ac_code(:)),unique(str2num(ac_code(:)))); ac_prob = ac_prob/sum(ac_prob); ac_dict = huffmandict(unique(str2num(ac_code(:))), ac_prob); % 将DC分量和AC分量进行Huffman编码 dc_huff = huffmanenco(dc_diff(:), dc_dict); ac_huff = huffmanenco(str2num(ac_code(:)), ac_dict); % 将Huffman编码的字典表存储在文件中 save('huffmandict.mat', 'dc_dict', 'ac_dict'); ``` 至此,我们已经完成了整个JPEG编码的过程。为了方便解码,我们需要将DC分量的DPCM编码和AC分量的RLE编码以及Huffman编码后的结果存储在文件中,以便解码时使用。这可以使用MATLAB自带的save函数来实现。 ```matlab % 将编码结果存储在文件中 save('jpeg_code.mat', 'dc_diff', 'ac_code', 'dc_huff', 'ac_huff'); ``` 完整代码如下: ```matlab % 读取图片 img = imread('test.jpg'); % 将图片转为YCrCb颜色空间 img_ycbcr = rgb2ycbcr(img); % 定义量化矩阵Q Q = [16 11 10 16 24 40 51 61; 12 12 14 19 26 58 60 55; 14 13 16 24 40 57 69 56; 14 17 22 29 51 87 80 62; 18 22 37 56 68 109 103 77; 24 35 55 64 81 104 113 92; 49 64 78 87 103 121 120 101; 72 92 95 98 112 100 103 99]; % 将每个8*8的块进行DCT处理 for i = 1:size(img_ycbcr,1)/8 for j = 1:size(img_ycbcr,2)/8 block = img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:); block_dct = dct2(block); img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:) = block_dct; end end % 将每个8*8的块进行量化 for i = 1:size(img_ycbcr,1)/8 for j = 1:size(img_ycbcr,2)/8 block_dct = img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:); block_quant = round(block_dct./Q); img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:) = block_quant; end end % 将每个8*8的块进行ZIGZAG排序 for i = 1:size(img_ycbcr,1)/8 for j = 1:size(img_ycbcr,2)/8 block_quant = img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:); block_zigzag = zeros(1,64*3); index = 1; for k = 1:8 if mod(k,2) == 0 for l = k:-1:1 block_zigzag(index,:) = block_quant(l,k+1-l,:); index = index + 1; end else for l = 1:k block_zigzag(index,:) = block_quant(l,k+1-l,:); index = index + 1; end end end for k = 2:8 if mod(k,2) == 0 for l = k:8 block_zigzag(index,:) = block_quant(k+9-l,l,:); index = index + 1; end else for l = 8:-1:k block_zigzag(index,:) = block_quant(k+9-l,l,:); index = index + 1; end end end img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:) = block_zigzag; end end % 将DC分量和AC分量进行DPCM和RLE编码 dc_code = ''; ac_code = ''; for i = 1:size(img_ycbcr,1)/8 for j = 1:size(img_ycbcr,2)/8 block_zigzag = img_ycbcr((i-1)*8+1:i*8,(j-1)*8+1:j*8,:); % 对DC分量进行DPCM编码 dc_diff = diff(block_zigzag(:,1,:)); dc_diff = [block_zigzag(1,1,:); dc_diff]; dc_code = [dc_code num2str(dc_diff(1))]; % 对AC分量进行RLE编码 ac_code_block = ''; zero_count = 0; for k = 2:size(block_zigzag,1)*size(block_zigzag,2)*size(block_zigzag,3) if block_zigzag(k) == 0 zero_count = zero_count + 1; else ac_code_block = [ac_code_block num2str(zero_count) num2str(block_zigzag(k))]; zero_count = 0; end end ac_code = [ac_code ac_code_block]; end end % 构建Huffman编码表 dc_prob = hist(dc_diff(:),unique(dc_diff(:))); dc_prob = dc_prob/sum(dc_prob); dc_dict = huffmandict(unique(dc_diff(:)), dc_prob); ac_prob = hist(str2num(ac_code(:)),unique(str2num(ac_code(:)))); ac_prob = ac_prob/sum(ac_prob); ac_dict = huffmandict(unique(str2num(ac_code(:))), ac_prob); % 将DC分量和AC分量进行Huffman编码 dc_huff = huffmanenco(dc_diff(:), dc_dict); ac_huff = huffmanenco(str2num(ac_code(:)), ac_dict); % 将编码结果存储在文件中 save('jpeg_code.mat', 'dc_diff', 'ac_code', 'dc_huff', 'ac_huff'); % 将Huffman编码的字典表存储在文件中 save('huffmandict.mat', 'dc_dict', 'ac_dict'); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值