2012-11-12 42 views
7

Tôi đang nén luồng nhị phân được tạo thành từ góiTìm kiếm một kỹ thuật nén tốt hơn

Một gói gồm 256 số nguyên 32 bit (mẫu). Vấn đề là hầu hết các số nguyên chỉ thay đổi một vài bit từ số nguyên trước đó (thường là 0 - 4 bit thay đổi nhiều nhất so với mẫu trước đó trong luồng).

Dưới đây là một ví dụ:

3322 2222 2222 1111 1111 1110 0000 0000 BIT POSITIONS 
9817 6543 2109 8765 4321 
-------------------------------------------------------- 
1100 1001 1110 0010 0001 0101 0110 1101 Sample 1 
       *     * 
1100 1001 1110 1010 0001 0101 0110 0101 Sample 2  changes: bit 19, 4 

1100 1001 1110 1010 0001 0101 0110 0101 Sample 3  changes: none 
    *   *   * 
1100 0001 1110 1011 0001 0101 0010 0101 Sample 4  changes: bit 27, 17, 7 
... 

My hiện tại, chương trình lossles nén được dựa trên Nibbles. Về cơ bản tôi đang sử dụng một byte điều khiển nơi tôi đang mã hóa-sử dụng các bit đơn - mà nibbles đã thay đổi từ mẫu trước đó; Nếu có thay đổi, tôi sẽ bao gồm các nibbles đã sửa đổi trên luồng nén, nếu không chúng sẽ được tạo lại từ mẫu trước khi giải nén.

Sau đây là cách dòng ví dụ tôi cung cấp sẽ được nén:

Control Byte: 11111111  // all nibbles change, since this is first sample 
Data:   1100 1001 1110 0010 0001 0101 0110 1101 // data for all nibbles 
Control Byte: 00010001  // only nibbles 3 and 7 have changes 
Data:   1010 0101 // data for nibbles 3 and 7 
Control Byte: 00000000  // no nibbles are changing 
Data:      // no data is required 
Control Byte: 01010010  // nibbles 1, 3 and 6 have changes 
Data:   0001 1011 0010 // nibbles 1, 3 and 6 
... 

Sử dụng chương trình này, chúng tôi có một chi phí cố định là 256 byte (kiểm soát byte), với mức trung bình, chiều dài biến nén dữ liệu 260 byte (các nibbles đang thay đổi từ mẫu thành mẫu). Xem xét các gói không nén là 1024 byte, điều này thực tế cho chúng ta một tỷ lệ nén trung bình 50%.

Điều này không tệ, nhưng cảm giác ruột của tôi là cách tiếp cận tốt hơn nhiều là có thể. Có ai biết về một chiến lược nén tốt hơn mà khai thác một thực tế là rất ít bit thay đổi từ mẫu để lấy mẫu? Nén mất dữ liệu là một thay thế miễn là tỷ lệ lỗi bit sau khi giải nén nhỏ (dưới 3%) - đối với luồng dữ liệu cụ thể này, trọng số bằng số của các vị trí bit không liên quan, do đó, lỗi trong các bit cao hơn là không có mối quan tâm nào cả.

Cảm ơn mọi người trước!

+0

Thứ tự các mẫu trong gói có quan trọng không? Nếu không, bạn có thể sắp xếp trong mỗi gói để giảm thiểu số byte điều khiển. – cmh

+0

@cmh, đề xuất tốt - không may thứ tự hoặc các mẫu có liên quan: ( –

Trả lời

5

Đặt cược tốt nhất của bạn là sử dụng các kỹ thuật hiện có (ví dụ: Lempel-Ziv-Welch; flate) hoặc trước một phương pháp có mã hóa khác biệt (có thể tốt hơn). Với sự khác biệt mã hóa bạn đang thay thế mỗi byte (ngoại trừ đầu tiên) với sự khác biệt giữa byte đó và trước đó. Bây giờ bạn sẽ nhận được rất nhiều số không, và một vài giá trị nhỏ xen kẽ. Huffman mã hóa hoặc một cái gì đó như LZW sẽ nén xuống chuỗi chủ yếu là zeroes khá kỹ lưỡng.

+0

@RVic: +1 Điều này có vẻ rất hứa hẹn. Thực tế là sử dụng mã hóa khác biệt, chúng tôi kết thúc bằng chuỗi bit gần như bằng không. chắc chắn thử điều này. =) –

+0

Wow, sử dụng kỹ thuật ban đầu của tôi, một luồng 24 giờ đo khoảng 14MB. Sử dụng đề xuất mã hóa sự khác biệt của bạn, sau đó là LZMA. Một tập tin 24 giờ đo 37KB! Tôi bị choáng ngợp với niềm vui! –

+0

Cảm ơn bạn rất nhiều vì đề xuất của bạn @DRVic. Và cũng nhờ tất cả những người đưa ra những gợi ý thông minh như vậy, ý tưởng về mã hóa sự khác biệt (xor) về cơ bản được đề xuất bởi tất cả mọi người đã không vượt qua tâm trí của tôi trước đây. –

6

Nếu bạn gửi số nguyên đầu tiên chưa nén và cho 255 số nguyên khác tính XOR giữa số nguyên này và số nguyên trước, bạn sẽ nhận được một luồng bit trong đó các bit không phải là rất hiếm. Luồng bit này có thể được mã hóa với Arithmetic coding.

Nếu sau khi tính toán XOR giữa các giá trị lân cận, chúng ta có luồng bit trong đó bit độc lập với nhau (mỗi bit "0" hoặc "1" có cùng xác suất, độc lập với vị trí bit trong số nguyên và độc lập trên vị trí số nguyên trong gói dữ liệu), mã hóa số học đảm bảo tốc độ nén lossless tối ưu.

+0

+1 - cũng thử dùng mã hóa số học. Cảm ơn –

1

Từ ví dụ của bạn, có vẻ như một vài bit thay đổi không phải lúc nào cũng giống nhau (ví dụ: luôn thấp nhất 4). Vì vậy, tôi sẽ đề nghị một mã hóa độ dài chạy đơn giản của các bit trên mảng transposed. Nếu không có phân phối các số/dữ liệu của bạn, tôi khuyên bạn nên bắt đầu với 4 bit cho độ dài, nhưng ở đó bạn có thể thử một chút với một số đầu vào ví dụ của mình.

Các giả (đối với nén) sẽ trông như thế này:

for bitpos = 0 to 31 
    for datapos = 0 to 255 
     BitString.append(getbit(data[datapos], bitpos); 
    endfor 
endfor 

result=""; 
pos = 0; 
while (notEndOfString) 
    # count 1s 
    count = 0; 
    while (pos < 32*256 AND count < 16 AND BitString[pos]==1) 
     count++; 
     pos++; 
     endwhile 
    result.append4BitNumber(count); 
    # count 0s 
    count = 0; 
    while (pos < 32*256 AND count < 16 AND BitString[pos]==0) 
     count++; 
     pos++; 
     endwhile 
    result.append4BitNumber(count); 
endwhile 

Có lẽ người ta có thể làm tăng nén bằng cách áp dụng sau đó Lempel-Ziv hoặc mã hóa Huffman - nhưng không có thêm thông tin về sự phân bố của dữ liệu đầu vào người ta không thể nói nhiều hơn (điều này giữ cho vấn đề này nói chung - với một thông tin tốt hơn về dữ liệu đầu vào, người ta có thể điều chỉnh một số loại nén cho nó).

EDIT: Một cách tiếp cận dễ dàng sẽ làm cho một mã hóa của các vị trí chút thay đổi: Bạn bắt đầu với từ 32 bit đầu tiên của bạn, sau đó bạn lưu trữ cho mỗi từ dữ liệu 3 bit xác định bao nhiêu bit thay đổi (tức là 0 ..7), và sau đó bạn lưu trữ 0..7 lần 4 bit trong đó 4 bit mã hóa vị trí của bit chaning. Điều đó có nghĩa là, ví dụ: trung bình 2 bit thay đổi bạn cần cho gói 32 * 256 bit 32 + 255 * (3 + 8) = 2837 => xấp xỉ 35% kích thước ban đầu.

Nếu bạn thường có cùng số bit thay đổi, một số mẫu 4 bit này sẽ xuất hiện rất thường xuyên, trong khi một số khác không phải => mã Huffman trên 4 nhóm bit này sẽ nén tối ưu (nếu bạn biết rằng những xác suất mẫu này sẽ không bao giờ thay đổi, thậm chí bạn có thể tạo một cây Huffman tĩnh, vì vậy bạn không cần phải lưu trữ nó).

5

Bạn có thể thực hiện XOR trên dữ liệu đầu vào. Bởi vì chỉ có một vài thay đổi, điều này sẽ cho bạn kết quả bao gồm chủ yếu là 0 với một số ít 1 ở giữa.

1100 1001 1110 0010 0001 0101 0110 1101 Sample 1 
1100 1001 1110 1010 0001 0101 0110 0101 Sample 2  
1100 1001 1110 1010 0001 0101 0110 0101 Sample 3  
1100 0001 1110 1011 0001 0101 0010 0101 Sample 4  

Sau khi giá trị khởi đầu này sẽ mang lại một chuỗi

0b0000 0000 0000 1000 0000 0000 0001 0000, 
0b0000 0000 0000 0000 0000 0000 0000 0000, 
0b0000 1000 0000 0010 0000 0000 1000 0000 

Bây giờ bạn có thể sử dụng các thuật toán nén tiêu chuẩn khác nhau. Huffman mã hóa của 8 chuỗi byte, LZW hoặc mã hóa entropy, nhưng một rất nỗ lực có thể là một mã hóa đơn giản chút chạy dài, đếm số không bit giữa mỗi một chút từ vị trí bit 0 vào lúc:

4, 14, 51, 9, 9 

Nếu bạn giới hạn của bạn chạy dài tới 30 và chọn một biểu tượng thoát 31, có nghĩa là "thêm 31 đến chạy dài tiếp theo", bạn sẽ có được

4, 14, 31, 20, 9, 9 

Đây sẽ là 6 * 5 bit cho toàn bộ chuỗi. Giờ đây, bạn có thể thực hiện mã hóa Huffmann trên rằng ...

1

Ý tưởng của tôi tương tự như ý tưởng của Evgeny Kluev. Số nguyên đầu tiên được gửi không nén, phần còn lại sẽ trở thành XOR của chính nó và số nguyên trước đó.

1100 1001 1110 0010 0001 0101 0110 1101 Sample 1 
       *     * 
0000 0000 0000 1000 0000 0000 0000 1000 Sample 2 

0000 0000 0000 0000 0000 0000 0000 0000 Sample 3 
    *   *   * 
0000 1000 0000 0001 0000 0000 0100 0000 Sample 4 

Bây giờ thay vì phân chia dữ liệu thành các khối thưa thớt và làm Arithmetic Encoding ngay tại đây, tôi chuyển đổi dữ liệu hơn nữa. Bởi vì thực sự, mã hóa số học dựa trên tần suất dữ liệu không bằng nhau. Và nhìn này, bạn có nghĩ

0000 0000 0000 1000 0000 0000 0000 1000 

sẽ xuất hiện thường xuyên hơn

0000 1000 0000 0001 0000 0000 0100 0000 

hoặc ngược lại?

Được rồi, vì vậy, đây là cách tôi sẽ chuyển đổi dữ liệu hơn nữa. Để phần còn lại của dữ liệu trở thành một chuỗi các số mô tả số lượng số không liên tiếp. Ví dụ: dữ liệu trở thành:

1100 1001 1110 0010 0001 0101 0110 1101 Sample 1 followed by decimals 
12, 15, 39, 10, 9, 6 

Bây giờ bạn có thể thực hiện mã hóa số học trên các số thập phân sau đó. Lần này tần số sẽ có ý nghĩa! Bởi vì bạn đã nói trong câu hỏi rằng có rất ít thay đổi, có nghĩa là số số lượng liên tiếp cao hơn sẽ xuất hiện thường xuyên hơn.

EDIT: Câu trả lời này hoàn toàn giống với câu trả lời của hirschhornsalz. ngoại trừ ông cũng đã đề cập rằng bạn có thể đặt giới hạn số lượng tối đa 0 và chia chúng ...

Các vấn đề liên quan