Tham số đầu tiên là đường dẫn chứa hình ảnh. Tham số thứ hai là cờ cho chúng ta biết hình ảnh nên được đọc như thế nào. Các tùy chọn cho tham số cờ là
- cv2. IMREAD_COLOR hoặc 1. Đây là giá trị mặc định và sẽ tải hình ảnh màu
- cv2. IMREAD_GRAYSCALE hoặc 0. sẽ tải hình ảnh theo thang độ xám
- cv2. IMREAD_UNCHANGED hoặc -1. Tải hình ảnh như vậy, bao gồm cả kênh alpha
imshow[] hiển thị hình ảnh trong cửa sổ
Tham số đầu tiên là tên cửa sổ và tham số thứ hai là hình ảnh
waitKey[] là một chức năng liên kết bàn phím
Nếu bạn chỉ định một giá trị số khác 0, thì giá trị này sẽ đợi trong một phần nghìn giây đã chỉ định cho bất kỳ sự kiện bàn phím nào. Nếu bạn nhấn bất kỳ phím nào, thì chương trình sẽ tiếp tục. Nếu bạn chỉ định 0 làm giá trị, thì nó sẽ đợi vô thời hạn
destroyAllWindows[] sẽ hủy tất cả các cửa sổ đã tạo
Để hủy các cửa sổ cụ thể, bạn có thể sử dụng destroyWindow[] mà bạn sẽ chuyển tên cửa sổ vào đó
import cv2
image_cv2= cv2.imread[r'\dogs-v-cats\dog.1.png']
cv2.imshow["Dog Image using OpenCV", image_cv2]
cv2.waitKey[6000]
cv2.destroyWindow["Dog Image using OpenCV"]
Lưu hình ảnh bằng OpenCV
result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
imwrite[] lưu tệp hình ảnh vào đường dẫn đã chỉ định. Tham số đầu tiên là đường dẫn mà bạn muốn lưu tệp và tham số thứ hai là hình ảnh sẽ được lưu
Tải hình ảnh bằng matplotlib
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
imread[] của matplotlib đọc tệp hình ảnh từ đường dẫn đã chỉ định vào một mảng. Tham số thứ hai là tùy chọn và chỉ định định dạng của tệp như 'JPEG' hoặc "PNG". Giá trị mặc định là 'PNG. ’
imshow[] của matplotlib hiển thị mảng dữ liệu dưới dạng hình ảnh
bạn cũng có thể sử dụng plt. show[] để hiển thị hình ảnh
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
%matplotlib inline
image_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg’, “JPG”]
imgplot=plt.imshow[image_mp]
plt.show[]
Ở cấp độ rất cơ bản, hầu hết mọi tệp nhị phân đều chứa một vài điểm đánh dấu [hoặc tiêu đề]. Bạn có thể coi những điểm đánh dấu này giống như những dấu trang. Chúng rất quan trọng để hiểu ý nghĩa của tệp và được các chương trình như
10 10 10 10 10 10 10
9 [trên Mac/Linux] sử dụng để cho chúng tôi biết chi tiết về tệp. Các điểm đánh dấu này xác định nơi lưu trữ một số thông tin cụ thể trong tệp. Hầu hết các điểm đánh dấu được theo sau bởi thông tin 7 10
0 cho đoạn đánh dấu cụ thể. Điều này cho chúng tôi biết đoạn cụ thể đó dài bao lâuBắt đầu tệp & Kết thúc tệp
Điểm đánh dấu đầu tiên mà chúng tôi quan tâm là
7 10
1. Nó cho chúng ta biết rằng đây là điểm bắt đầu của hình ảnh. Nếu chúng tôi không nhìn thấy nó, chúng tôi có thể cho rằng đây là một số tệp khác. Một điểm đánh dấu quan trọng không kém khác là 7 10
2. Nó cho chúng tôi biết rằng chúng tôi đã đến cuối tệp hình ảnh. Mọi điểm đánh dấu, ngoại trừ 7 10
3 đến 7 10
4 và 7 10
5, ngay sau đó là một bộ xác định độ dài sẽ cung cấp cho bạn độ dài của đoạn đánh dấu đó. Đối với các điểm đánh dấu bắt đầu và kết thúc tệp hình ảnh, chúng sẽ luôn dài hai byte mỗi dấuTrong suốt hướng dẫn này, chúng tôi sẽ làm việc với hình ảnh này
Hãy viết một số mã để xác định các điểm đánh dấu này
result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
2Chúng tôi đang sử dụng cấu trúc để giải nén byte dữ liệu hình ảnh.
7 10
6 yêu cầu 7 10
7 coi dữ liệu là big-endian và thuộc loại 7 10
8. Dữ liệu trong JPEG được lưu trữ ở định dạng big-endian. Chỉ dữ liệu EXIF có thể ở dạng cuối nhỏ [mặc dù nó không phổ biến]. Và một đoạn ngắn có kích thước 2, vì vậy chúng tôi cung cấp 7 10
9 hai byte từ result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
70 của chúng tôi. Bạn có thể tự hỏi làm thế nào chúng tôi biết đó là một result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
71. Chà, chúng tôi biết rằng các điểm đánh dấu trong JPEG là 4 chữ số hex. result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
72. Một chữ số hex bằng 4 bit [1⁄2 byte] nên 4 chữ số hex sẽ bằng 2 byte và một chữ số ngắn bằng 2 bytePhần Bắt đầu quét ngay sau đó là dữ liệu quét hình ảnh và dữ liệu quét hình ảnh đó không có độ dài được chỉ định. Nó tiếp tục cho đến khi tìm thấy điểm đánh dấu “cuối tệp”, vì vậy hiện tại chúng tôi đang “tìm kiếm” điểm đánh dấu EOF theo cách thủ công bất cứ khi nào chúng tôi nhìn thấy điểm đánh dấu SOC
Bây giờ chúng ta đã có khung cơ bản, hãy tiếp tục và tìm hiểu xem phần còn lại của dữ liệu hình ảnh chứa gì. Trước tiên chúng ta sẽ xem qua một số lý thuyết cần thiết và sau đó bắt đầu viết mã
Mã hóa JPEG
Trước tiên tôi sẽ giải thích một số khái niệm cơ bản và kỹ thuật mã hóa được sử dụng bởi JPEG và sau đó giải mã sẽ diễn ra một cách tự nhiên từ đó ngược lại với nó. Theo kinh nghiệm của tôi, việc trực tiếp cố gắng hiểu ý nghĩa của việc giải mã là hơi khó
Mặc dù hình ảnh dưới đây không có nhiều ý nghĩa đối với bạn ngay bây giờ, nhưng nó sẽ cung cấp cho bạn một số mỏ neo để bám vào trong khi chúng tôi thực hiện toàn bộ quá trình mã hóa/giải mã. Nó cho thấy các bước liên quan đến quá trình mã hóa JPEG. [src]
Không gian màu JPEG
Theo thông số JPEG [ISO/IEC 10918-6. 2013 [E], mục 6. 1]
- Hình ảnh được mã hóa chỉ với một thành phần được coi là dữ liệu thang độ xám trong đó 0 là màu đen và 255 là màu trắng
- Hình ảnh được mã hóa với ba thành phần được coi là dữ liệu RGB được mã hóa thành YCbCr trừ khi hình ảnh chứa đoạn nhãn APP14 như được chỉ định trong 6. 5. 3, trong trường hợp đó, mã hóa màu được coi là RGB hoặc YCbCr theo dữ liệu ứng dụng của đoạn đánh dấu APP14. Mối quan hệ giữa RGB và YCbCr được xác định như được chỉ định trong Rec. ITU-T T. 871. ISO/IEC 10918-5
- Hình ảnh được mã hóa với bốn thành phần được coi là CMYK, với [0,0,0,0] biểu thị màu trắng trừ khi hình ảnh chứa đoạn đánh dấu APP14 như được chỉ định trong 6. 5. 3, trong trường hợp đó, mã hóa màu được coi là CMYK hoặc YCCK theo dữ liệu ứng dụng của đoạn đánh dấu APP14. Mối quan hệ giữa CMYK và YCCK được xác định như quy định tại khoản 7
Hầu hết các triển khai thuật toán JPEG đều sử dụng độ chói và sắc độ [mã hóa YUV] thay vì RGB. Điều này cực kỳ hữu ích trong JPEG vì mắt người khá tệ khi nhìn thấy sự thay đổi độ sáng ở tần số cao trên một khu vực nhỏ, vì vậy về cơ bản chúng ta có thể giảm lượng tần số và mắt người sẽ không thể nhận ra sự khác biệt. Kết quả?
Giống như mỗi pixel trong không gian màu RGB được tạo thành từ 3 byte dữ liệu màu [Đỏ, Xanh lục, Xanh lam], mỗi pixel trong YUV cũng sử dụng 3 byte nhưng mỗi byte thể hiện hơi khác nhau. Thành phần Y xác định độ sáng của màu [còn được gọi là độ chói hoặc độ sáng], trong khi thành phần U và V xác định màu [còn được gọi là sắc độ]. Thành phần U đề cập đến lượng màu xanh lam và thành phần V đề cập đến lượng màu đỏ
Định dạng màu này được phát minh khi TV màu không quá phổ biến và các kỹ sư muốn sử dụng một định dạng mã hóa hình ảnh cho cả TV màu và đen trắng. YUV có thể được hiển thị an toàn trên TV đen trắng nếu không có màu. Bạn có thể đọc thêm về lịch sử của nó trên Wikipedia
Biến đổi Cosine rời rạc và lượng tử hóa
JPEG chuyển đổi một hình ảnh thành các khối pixel 8x8 [được gọi là MCU hoặc Đơn vị mã hóa tối thiểu], thay đổi phạm vi giá trị của pixel để chúng tập trung vào 0 và sau đó áp dụng Biến đổi Cosine rời rạc cho từng khối và sau đó sử dụng lượng tử hóa để nén . Hãy hiểu rõ hơn về ý nghĩa của tất cả các thuật ngữ này
Biến đổi Cosine rời rạc là một phương pháp để chuyển đổi các điểm dữ liệu rời rạc thành sự kết hợp của các sóng cosine. Có vẻ khá vô ích khi dành thời gian chuyển đổi một hình ảnh thành một loạt cosin nhưng sẽ hợp lý khi chúng ta hiểu DCT kết hợp với cách hoạt động của bước tiếp theo. Trong JPEG, DCT sẽ lấy một khối hình ảnh 8x8 và cho chúng tôi biết cách tái tạo nó bằng cách sử dụng ma trận hàm cosine 8x8. Đọc thêm tại đây]
Ma trận 8x8 của các hàm cosin trông như thế này
Chúng tôi áp dụng DCT cho từng thành phần của pixel một cách riêng biệt. Đầu ra của việc áp dụng DCT là một ma trận hệ số 8x8 cho chúng ta biết mỗi hàm cosin [trong tổng số 64 hàm] đóng góp bao nhiêu vào ma trận đầu vào 8x8. Ma trận hệ số của DCT thường chứa các giá trị lớn hơn ở góc trên cùng bên trái của ma trận hệ số và các giá trị nhỏ hơn ở góc dưới cùng bên phải. Góc trên cùng bên trái biểu thị hàm cosin tần số thấp nhất và góc dưới bên phải biểu thị hàm cosin tần số cao nhất
Điều này cho chúng ta biết rằng hầu hết các hình ảnh chứa một lượng lớn thông tin tần số thấp và một lượng nhỏ thông tin tần số cao. Nếu chúng ta biến các thành phần dưới cùng bên phải của mỗi ma trận DCT thành 0, thì hình ảnh thu được sẽ vẫn giống như vậy bởi vì, như tôi đã đề cập, con người rất tệ trong việc quan sát các thay đổi tần số cao. Đây chính xác là những gì chúng tôi làm trong bước tiếp theo
Tôi tìm thấy một video tuyệt vời về chủ đề này. Xem nó nếu DCT không có quá nhiều ý nghĩa
Tất cả chúng ta đều đã nghe nói rằng JPEG là một thuật toán nén bị mất dữ liệu nhưng cho đến nay chúng tôi vẫn chưa thực hiện bất kỳ điều gì làm mất dữ liệu. Chúng tôi chỉ chuyển đổi các khối 8x8 của các thành phần YUV thành các khối hàm cosine 8x8 mà không làm mất thông tin. Phần mất dữ liệu xuất hiện trong bước lượng tử hóa
Lượng tử hóa là một quá trình trong đó chúng tôi lấy một vài giá trị trong một phạm vi cụ thể và biến chúng thành một giá trị riêng biệt. Đối với trường hợp của chúng tôi, đây chỉ là một cái tên ưa thích để chuyển đổi các hệ số tần số cao hơn trong ma trận đầu ra DCT thành 0. Khi bạn lưu ảnh bằng JPEG, hầu hết các chương trình chỉnh sửa ảnh đều hỏi bạn cần nén bao nhiêu. Tỷ lệ phần trăm bạn cung cấp ở đó ảnh hưởng đến mức độ lượng tử hóa được áp dụng và lượng thông tin tần số cao hơn bị mất. Đây là nơi áp dụng nén mất dữ liệu. Khi bạn mất thông tin tần số cao, bạn không thể tạo lại hình ảnh gốc chính xác từ hình ảnh JPEG thu được
Tùy thuộc vào mức độ nén được yêu cầu, một số ma trận lượng tử hóa phổ biến được sử dụng [thực tế thú vị. Hầu hết các nhà cung cấp đều có bằng sáng chế về xây dựng bảng lượng tử hóa]. Chúng tôi chia phần tử ma trận hệ số DCT với ma trận lượng tử hóa, làm tròn kết quả thành một số nguyên và nhận ma trận lượng tử hóa. Hãy đi qua một ví dụ
Nếu bạn có ma trận DCT này
Ma trận lượng tử hóa [phổ biến] này
Sau đó, ma trận lượng tử hóa kết quả sẽ là thế này
Mặc dù con người không thể nhìn thấy thông tin tần số cao, nhưng nếu bạn loại bỏ quá nhiều thông tin khỏi khối hình ảnh 8x8, hình ảnh tổng thể sẽ trông có vẻ khối. Trong ma trận lượng tử hóa này, giá trị đầu tiên được gọi là giá trị DC và các giá trị còn lại là giá trị AC. Nếu chúng tôi lấy các giá trị DC từ tất cả các ma trận được lượng tử hóa và tạo một hình ảnh mới, về cơ bản chúng tôi sẽ có một hình thu nhỏ với độ phân giải 1/8 của hình ảnh gốc
Cũng cần lưu ý rằng vì chúng tôi áp dụng lượng tử hóa trong khi giải mã, chúng tôi sẽ phải đảm bảo màu sắc nằm trong phạm vi [0,255]. Nếu chúng nằm ngoài phạm vi này, chúng tôi sẽ phải tự kẹp chúng vào phạm vi này
ngoằn ngoèo
Sau khi lượng tử hóa, JPEG sử dụng mã hóa zig-zag để chuyển đổi ma trận thành 1D [img src]
Hãy tưởng tượng chúng ta có ma trận lượng tử hóa này
Đầu ra của mã hóa zig-zag sẽ là thế này
import matplotlib.pyplot as plt0
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Mã hóa này được ưu tiên vì hầu hết thông tin tần số thấp [quan trọng nhất] được lưu trữ ở đầu ma trận sau khi lượng tử hóa và mã hóa zig-zag lưu trữ tất cả thông tin đó ở đầu ma trận 1D. Điều này hữu ích cho quá trình nén xảy ra trong bước tiếp theo
Độ dài chạy và mã hóa Delta
Mã hóa độ dài chạy được sử dụng để nén dữ liệu lặp lại. Khi kết thúc quá trình mã hóa zig-zag, chúng ta đã thấy hầu hết các mảng 1D được mã hóa zig-zag đều có rất nhiều số 0 ở cuối. Mã hóa độ dài chạy cho phép chúng tôi lấy lại tất cả dung lượng bị lãng phí đó và sử dụng ít byte hơn để biểu thị tất cả các số 0 đó. Hãy tưởng tượng bạn có một số dữ liệu như thế này
10 10 10 10 10 10 10
Mã hóa độ dài chạy sẽ chuyển đổi nó thành
7 10
Chúng tôi đã có thể nén thành công 7 byte dữ liệu thành chỉ 2 byte
Mã hóa delta là một kỹ thuật được sử dụng để biểu diễn một byte so với byte trước nó. Nó dễ hiểu hơn với một ví dụ. Giả sử bạn có dữ liệu sau
result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
7Bạn có thể sử dụng mã hóa delta để lưu trữ nó như thế này
import matplotlib.pyplot as plt4
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Trong JPEG, mọi giá trị DC trong ma trận hệ số DCT được mã hóa delta tương ứng với giá trị DC trước nó. Điều này có nghĩa là nếu bạn thay đổi hệ số DCT đầu tiên của hình ảnh, toàn bộ hình ảnh sẽ bị hỏng nhưng nếu bạn sửa đổi giá trị đầu tiên của ma trận DCT cuối cùng, thì chỉ một phần rất nhỏ của hình ảnh sẽ bị ảnh hưởng. Điều này rất hữu ích vì giá trị DC đầu tiên trong hình ảnh của bạn thường đa dạng nhất và bằng cách áp dụng mã hóa Delta, chúng tôi đưa các giá trị DC còn lại về gần 0 và điều đó dẫn đến khả năng nén tốt hơn trong bước tiếp theo của Mã hóa Huffman
Mã hóa Huffman
Mã hóa Huffman là một phương pháp nén thông tin không mất dữ liệu. Huffman đã từng tự hỏi: “Số lượng bit nhỏ nhất mà tôi có thể sử dụng để lưu trữ một đoạn văn bản tùy ý là bao nhiêu?”. Định dạng mã hóa này là câu trả lời của anh ấy. Hãy tưởng tượng bạn phải lưu trữ văn bản này
import matplotlib.pyplot as plt5
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Trong một kịch bản bình thường, mỗi ký tự sẽ chiếm 1 byte dung lượng
import matplotlib.pyplot as plt6
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Điều này dựa trên ASCII để ánh xạ nhị phân. Nhưng nếu chúng ta có thể đưa ra một ánh xạ tùy chỉnh thì sao?
import matplotlib.pyplot as plt7
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Bây giờ chúng ta có thể lưu trữ cùng một văn bản bằng cách sử dụng ít bit hơn
import matplotlib.pyplot as plt8
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Điều này là tốt và tốt nhưng nếu chúng ta muốn chiếm ít không gian hơn thì sao?
import matplotlib.pyplot as plt00
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Mã hóa Huffman cho phép chúng tôi sử dụng loại ánh xạ có độ dài thay đổi này. Nó lấy một số dữ liệu đầu vào, ánh xạ các ký tự thường xuyên nhất thành các mẫu bit nhỏ hơn và các ký tự ít thường xuyên nhất thành các mẫu bit lớn hơn và cuối cùng tổ chức ánh xạ thành cây nhị phân. Trong JPEG, chúng tôi lưu trữ thông tin DCT [Biến đổi Cosine rời rạc] bằng cách sử dụng mã hóa Huffman. Hãy nhớ rằng tôi đã nói với bạn rằng việc sử dụng mã hóa delta cho các giá trị DC sẽ giúp ích cho Mã hóa Huffman? . Sau khi mã hóa delta, chúng tôi kết thúc với ít “ký tự” hơn để lập bản đồ và tổng kích thước của cây Huffman của chúng tôi bị giảm
Tom Scott có một video tuyệt vời với hình ảnh động về cách hoạt động của mã hóa Huffman nói chung. Hãy xem nó trước khi tiếp tục
Một JPEG chứa tối đa 4 bảng Huffman và những bảng này được lưu trữ trong phần “Xác định bảng Huffman” [bắt đầu bằng
result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
73]. Các hệ số DCT được lưu trữ trong 2 bảng Huffman khác nhau. Một cái chỉ chứa các giá trị DC từ các bảng zig-zag và cái kia chứa các giá trị AC từ các bảng zig-zag. Điều này có nghĩa là trong quá trình giải mã, chúng ta sẽ phải hợp nhất các giá trị DC và AC từ hai ma trận riêng biệt. Thông tin DCT cho kênh độ chói và màu sắc được lưu trữ riêng biệt, vì vậy chúng tôi có 2 bộ thông tin DC và 2 bộ thông tin AC, cung cấp cho chúng tôi tổng cộng 4 bảng HuffmanTrong một hình ảnh thang độ xám, chúng tôi sẽ chỉ có 2 bảng Huffman [1 cho DC và 1 cho AC] vì chúng tôi không quan tâm đến màu sắc. Như bạn có thể hình dung, 2 hình ảnh có thể có các bảng Huffman rất khác nhau, vì vậy điều quan trọng là phải lưu trữ các bảng này bên trong mỗi JPEG
Vì vậy, chúng tôi biết các chi tiết cơ bản về những gì hình ảnh JPEG chứa. Hãy bắt đầu với việc giải mã
giải mã JPEG
Chúng ta có thể chia quá trình giải mã thành nhiều bước
- Trích xuất các bảng Huffman và giải mã các bit
- Trích xuất các hệ số DCT bằng cách hoàn tác mã hóa độ dài chạy và mã hóa delta
- Sử dụng các hệ số DCT để kết hợp các sóng cosin và tạo lại các giá trị pixel cho mỗi khối 8x8
- Chuyển đổi YCbCr sang RGB cho từng pixel
- Hiển thị hình ảnh RGB kết quả
Chuẩn JPEG hỗ trợ 4 định dạng nén
- đường cơ sở
- tuần tự mở rộng
- Cấp tiến
- Không mất mát
Chúng tôi sẽ làm việc với nén Baseline và theo tiêu chuẩn, đường cơ sở sẽ chứa một loạt các khối 8x8 ngay cạnh nhau. Các định dạng nén khác bố trí dữ liệu hơi khác một chút. Chỉ để tham khảo, tôi đã tô màu các phân đoạn khác nhau trong nội dung hex của hình ảnh chúng tôi đang sử dụng. Cái này nó thì trông như thế nào
Trích xuất các bảng Huffman
Chúng ta đã biết rằng một JPEG chứa 4 bảng Huffman. Đây là bước cuối cùng trong quy trình mã hóa, vì vậy đây phải là bước đầu tiên trong quy trình giải mã. Mỗi phần DHT chứa các thông tin sau
FieldSizeDescriptionMarker Identifier2 bytes0xff, 0xc4 để xác định DHT markerLength2 bytesĐiều này chỉ định độ dài của bảng HuffmanThông tin HT1 bytebit 0. 3. số HT [0. 3, nếu không thì lỗi]bit 4. loại HT, 0 = bảng DC, 1 = bảng AC
bit 5. 7. không được sử dụng, phải là 0Số ký hiệu16 byteSố ký hiệu có mã độ dài 1. 16, tổng[n] của các byte này là tổng số mã, phải là
Giả sử bạn có một bảng DH tương tự như thế này [src]
Ký hiệu Mã HuffmanĐộ dài mã a002b0103c0113d1003e1013f1103g11104h111105i1111106j11111107k111111108l1111111109Nó sẽ được lưu trữ trong tệp JFIF đại khái như thế này [chúng sẽ được lưu trữ ở dạng nhị phân. Tôi đang sử dụng ASCII chỉ cho mục đích minh họa]
import matplotlib.pyplot as plt01
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
0 có nghĩa là không có mã Huffman có độ dài 1. 1 nghĩa là có 1 mã Huffman độ dài 2. Và như thế. Luôn có dữ liệu độ dài 16 byte trong phần DHT ngay sau thông tin lớp và ID. Hãy viết một số mã để trích xuất độ dài và các phần tử trong DHT
import matplotlib.pyplot as plt02
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Nếu bạn chạy mã, nó sẽ tạo ra đầu ra sau
import matplotlib.pyplot as plt03
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Ngọt. Chúng tôi có độ dài và các yếu tố. Bây giờ chúng ta cần tạo một lớp bảng Huffman tùy chỉnh để chúng ta có thể tạo lại cây nhị phân từ các phần tử và độ dài này. Tôi xấu hổ sao chép mã này từ đây
import matplotlib.pyplot as plt04
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
74 lấy độ dài và phần tử, lặp qua tất cả các phần tử và đặt chúng vào danh sách result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
75. Danh sách này chứa các danh sách lồng nhau và đại diện cho một cây nhị phân. Bạn có thể đọc trực tuyến cách thức hoạt động của Cây Huffman và cách tạo cấu trúc dữ liệu cây Huffman của riêng bạn bằng Python. Đối với DHT đầu tiên của chúng tôi [sử dụng hình ảnh tôi đã liên kết khi bắt đầu hướng dẫn này], chúng tôi có các dữ liệu, độ dài và thành phần sauimport matplotlib.pyplot as plt05
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Sau khi gọi
result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
74 về điều này, danh sách result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
75 sẽ chứa dữ liệu nàyimport matplotlib.pyplot as plt06
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
78 cũng chứa phương thức result=cv2.imwrite[r'\dogs-v-cats\dog.100.png’, image_cv2]
if result==True:
print[“File saved successfully”]
else:
print[“Error in saving file”]
79 duyệt cây cho chúng ta và trả lại cho chúng ta các bit đã giải mã bằng bảng Huffman. Phương pháp này mong đợi một dòng bit làm đầu vào. Dòng bit chỉ là biểu diễn nhị phân của dữ liệu. Ví dụ: dòng bit điển hình của import matplotlib.pyplot as plt40 sẽ là
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt41. Trước tiên, chúng tôi chuyển đổi từng ký tự thành mã ASCII của nó và sau đó chuyển đổi mã ASCII đó thành nhị phân. Hãy tạo một lớp tùy chỉnh cho phép chúng ta chuyển đổi một chuỗi thành bit và đọc từng bit một. Đây là cách chúng tôi sẽ thực hiện nó
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt07
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Chúng tôi cung cấp cho lớp này một số dữ liệu nhị phân trong khi khởi tạo nó và sau đó sử dụng các phương thức
import matplotlib.pyplot as plt42 và
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt43 để đọc nó
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Giải mã bảng lượng tử hóa
Phần Xác định bảng lượng tử chứa dữ liệu sau
FieldSizeDescriptionMarker Identifier2 byte0xff, 0xdb xác định DQTLength2 byteĐiều này cho biết độ dài của QT. Thông tin QT1 bytebit 0. 3. số lượng QT [0. 3, nếu không thì lỗi] bit 4. 7. độ chính xác của QT, 0 = 8 bit, nếu không thì 16 bitBytesn byteĐiều này mang lại giá trị QT, n = 64*[độ chính xác+1]Theo chuẩn JPEG, có 2 bảng lượng tử hóa mặc định trong một ảnh JPEG. Một cho độ chói và một cho sắc độ. Các bảng này bắt đầu từ điểm đánh dấu
import matplotlib.pyplot as plt44. Trong mã ban đầu chúng tôi đã viết, chúng tôi đã thấy rằng đầu ra chứa hai điểm đánh dấu
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt44. Hãy mở rộng mã mà chúng tôi đã có và thêm khả năng giải mã các bảng lượng tử hóa
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt08
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Chúng tôi đã làm một vài điều ở đây. Đầu tiên, tôi định nghĩa một phương thức
import matplotlib.pyplot as plt46. Nó chỉ là một phương pháp tiện dụng để giải mã một số lượng byte khác nhau từ dữ liệu nhị phân. Tôi đã thay thế một số mã trong phương thức
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt47 để sử dụng chức năng mới này. Sau đó, tôi đã định nghĩa phương thức
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt48. Phương pháp này chỉ cần đọc tiêu đề của phần Bảng lượng tử hóa và sau đó nối thêm dữ liệu lượng tử hóa vào từ điển với giá trị tiêu đề là khóa. Giá trị tiêu đề sẽ là 0 cho độ chói và 1 cho sắc độ. Mỗi phần Bảng lượng tử hóa trong JFIF chứa 64 byte dữ liệu QT [đối với ma trận lượng tử hóa 8x8 của chúng tôi]
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Nếu chúng ta in ma trận lượng tử hóa cho hình ảnh của mình. Họ sẽ trông như thế này
import matplotlib.pyplot as plt09
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Giải mã bắt đầu khung hình
Phần Bắt đầu của Khung chứa các thông tin sau [src]
FieldSizeDescriptionĐịnh danh Marker2 byte0xff, 0xc0 để xác định điểm đánh dấu SOF0Độ dài2 byteGiá trị này bằng 8 + thành phần*3 giá trịĐộ chính xác của dữ liệu1 byteĐây là bit/mẫu, thường là 8 [12 và 16 không được hầu hết các phần mềm hỗ trợ]. Chiều cao hình ảnh2 byteĐây phải là > 0Chiều rộng hình ảnh2 byteĐây phải là > 0Số lượng thành phần1 byteThông thường 1 = thang màu xám, 3 = màu YcbCr hoặc YIQMỗi thành phần3 byteĐọc từng dữ liệu thành phần gồm 3 byte. Nó chứa, [Id thành phần[1byte][1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q], hệ số lấy mẫu [1byte] [bit 0-3 dọc. , 4-7 ngang. ], số bảng lượng tử hóa [1 byte]]Trong số dữ liệu này, chúng tôi chỉ quan tâm đến một số điều. Chúng tôi sẽ trích xuất chiều rộng và chiều cao của hình ảnh và số bảng lượng tử hóa của từng thành phần. Chiều rộng và chiều cao sẽ được sử dụng khi chúng tôi bắt đầu giải mã các bản quét hình ảnh thực tế từ phần Bắt đầu quét. Vì chúng ta sẽ chủ yếu làm việc với ảnh YCbCr, nên chúng ta có thể mong đợi số lượng thành phần bằng 3 và loại thành phần lần lượt bằng 1, 2 và 3. Hãy viết một số mã để giải mã dữ liệu này
10 10 10 10 10 10 10
0Chúng tôi đã thêm thuộc tính danh sách
import matplotlib.pyplot as plt49 vào lớp JPEG của mình và giới thiệu phương thức
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt50. Phương pháp
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt50 giải mã dữ liệu cần thiết từ phần SOF và đặt số bảng lượng tử hóa của từng thành phần trong danh sách
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt49. Chúng tôi sẽ sử dụng ánh xạ này khi chúng tôi bắt đầu đọc phần Bắt đầu quét. Đây là giao diện của
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt49 đối với hình ảnh của chúng tôi
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
10 10 10 10 10 10 10
1Giải mã Bắt đầu quét
Ngọt. Chúng ta chỉ còn một phần nữa để giải mã. Đây là phần chính của hình ảnh JPEG và chứa dữ liệu "hình ảnh" thực tế. Đây cũng là bước phức tạp nhất. Mọi thứ khác mà chúng tôi đã giải mã cho đến nay có thể được coi là tạo bản đồ để giúp chúng tôi điều hướng và giải mã hình ảnh thực tế. Phần này chứa chính hình ảnh thực tế [mặc dù ở dạng được mã hóa]. Chúng tôi sẽ đọc phần này và sử dụng dữ liệu chúng tôi đã giải mã để hiểu ý nghĩa của hình ảnh
Tất cả các điểm đánh dấu chúng tôi đã thấy cho đến nay đều bắt đầu bằng
import matplotlib.pyplot as plt54.
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt54 cũng có thể là một phần của dữ liệu quét hình ảnh nhưng nếu
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt54 có trong dữ liệu quét thì nó sẽ luôn đứng trước ________ 257. Đây là điều mà bộ mã hóa JPEG thực hiện tự động và được gọi là nhồi byte. Nhiệm vụ của người giải mã là loại bỏ thủ tục tố tụng này
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt57. Hãy bắt đầu phương thức giải mã SOS với chức năng này và loại bỏ
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt57 nếu nó hiện diện. Trong hình ảnh mẫu tôi đang sử dụng, chúng tôi không có
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt54 trong dữ liệu quét hình ảnh nhưng nó vẫn là một bổ sung hữu ích
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
10 10 10 10 10 10 10
2Trước đây, tôi đã tìm kiếm thủ công đến cuối tệp bất cứ khi nào tôi gặp điểm đánh dấu
import matplotlib.pyplot as plt61 nhưng bây giờ chúng tôi đã có sẵn công cụ cần thiết để duyệt qua toàn bộ tệp theo thứ tự có hệ thống, tôi đã chuyển điều kiện đánh dấu vào bên trong mệnh đề
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt62. Hàm
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt63 chỉ bị ngắt bất cứ khi nào nó quan sát thấy thứ gì đó không phải là
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt57 sau
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt54. Do đó, nó sẽ thoát ra khỏi vòng lặp khi gặp phải
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt66 và bằng cách đó chúng ta có thể tìm kiếm đến cuối tệp một cách an toàn mà không gặp bất kỳ sự cố nào. Nếu bạn chạy mã này ngay bây giờ, sẽ không có gì mới xuất ra thiết bị đầu cuối
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Nhớ lại rằng JPEG đã chia hình ảnh thành ma trận 8x8. Bước tiếp theo đối với chúng tôi là chuyển đổi dữ liệu quét hình ảnh của chúng tôi thành luồng bit và xử lý luồng theo khối dữ liệu 8x8. Hãy thêm một số mã vào lớp của chúng tôi
10 10 10 10 10 10 10
3Chúng tôi bắt đầu bằng cách chuyển đổi dữ liệu quét của mình thành luồng bit. Sau đó, chúng tôi khởi tạo
import matplotlib.pyplot as plt67,
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt68,
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt69 thành 0. Những điều này là bắt buộc vì hãy nhớ rằng chúng ta đã nói về cách phần tử DC trong ma trận lượng tử hóa [phần tử đầu tiên của ma trận] được mã hóa delta so với phần tử DC trước đó?
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Vòng lặp
import matplotlib.pyplot as plt70 có vẻ hơi thú vị.
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt71 cho biết chúng ta có thể chia chiều cao cho 8 bao nhiêu lần. Điều tương tự cũng xảy ra với
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt72. Tóm lại, điều này cho chúng ta biết hình ảnh được chia thành bao nhiêu ma trận 8x8
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt73 sẽ lấy bảng lượng tử hóa và một số tham số bổ sung, tạo Ma trận biến đổi Cosine rời rạc nghịch đảo và cung cấp cho chúng ta ma trận Y, Cr và Cb. Việc chuyển đổi thực tế các ma trận này thành RGB sẽ xảy ra trong hàm
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt74
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Trước tiên, hãy tạo lớp IDCT của chúng ta và sau đó chúng ta có thể bắt đầu bổ sung phương thức
import matplotlib.pyplot as plt73
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
10 10 10 10 10 10 10
4Hãy cố gắng hiểu lớp IDCT này từng bước. Khi chúng tôi trích xuất MCU từ JPEG, thuộc tính
import matplotlib.pyplot as plt76 của lớp này sẽ lưu trữ nó. Sau đó, chúng tôi sẽ sắp xếp lại ma trận MCU bằng cách hoàn tác mã hóa ngoằn ngoèo thông qua phương pháp
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt77. Cuối cùng, chúng tôi sẽ hoàn tác Biến đổi Cosine rời rạc bằng cách gọi phương thức
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt78
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Nếu bạn còn nhớ, bảng Discrete Cosine là cố định. Cách tính toán thực tế cho một DCT hoạt động nằm ngoài phạm vi của hướng dẫn này vì nó thiên về toán hơn là lập trình. Chúng ta có thể lưu trữ bảng này dưới dạng một biến toàn cục và sau đó truy vấn giá trị đó dựa trên các cặp x, y. Tôi quyết định đặt bảng và tính toán của nó trong lớp
import matplotlib.pyplot as plt79 cho mục đích dễ đọc. Mỗi phần tử của ma trận MCU được sắp xếp lại được nhân với các giá trị của
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt80 và cuối cùng chúng tôi lấy lại các giá trị Y, Cr và Cb
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Điều này sẽ có ý nghĩa hơn khi chúng ta viết ra phương thức
import matplotlib.pyplot as plt73
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Nếu bạn sửa đổi bảng ngoằn ngoèo thành một cái gì đó như thế này
10 10 10 10 10 10 10
5Bạn sẽ có đầu ra sau [chú ý các đồ tạo tác nhỏ]
Và nếu bạn dũng cảm, bạn có thể sửa đổi bảng ngoằn ngoèo hơn nữa
10 10 10 10 10 10 10
6Nó sẽ dẫn đến đầu ra này
Bây giờ, hãy kết thúc phương pháp
import matplotlib.pyplot as plt73 của chúng ta
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
10 10 10 10 10 10 10
7Chúng tôi bắt đầu bằng cách tạo một lớp Biến đổi Cosine rời rạc nghịch đảo [
import matplotlib.pyplot as plt83]. Sau đó, chúng tôi đọc trong luồng bit và giải mã nó bằng bảng Huffman của chúng tôi
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt84 và
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt85 lần lượt đề cập đến các bảng DC về độ chói và sắc độ và
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt86 và
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt87 lần lượt đề cập đến các bảng AC về độ chói và sắc độ
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Sau khi chúng tôi giải mã luồng bit, chúng tôi trích xuất hệ số DC được mã hóa delta mới bằng cách sử dụng hàm
import matplotlib.pyplot as plt88 và thêm
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt89 vào nó để có được hệ số DC được giải mã delta
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Sau đó, chúng tôi lặp lại quy trình giải mã tương tự nhưng đối với các giá trị AC trong ma trận lượng tử hóa. Giá trị mã của
import matplotlib.pyplot as plt000 gợi ý rằng chúng tôi đã gặp phải điểm đánh dấu Kết thúc Khối [EOB] và chúng tôi cần dừng. Hơn nữa, phần đầu tiên của bảng lượng tử AC cho chúng ta biết chúng ta có bao nhiêu số 0 đứng đầu. Hãy nhớ mã hóa độ dài chạy mà chúng ta đã nói trong phần đầu tiên? . Chúng tôi giải mã mã hóa độ dài chạy và bỏ qua nhiều bit đó. Tất cả các bit bị bỏ qua đều được đặt thành 0 hoàn toàn trong lớp
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt79
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Khi chúng tôi đã giải mã các giá trị DC và AC cho một MCU, chúng tôi sắp xếp lại MCU và hoàn tác mã hóa ngoằn ngoèo bằng cách gọi
import matplotlib.pyplot as plt77 và sau đó chúng tôi thực hiện đảo ngược DCT trên MCU đã giải mã
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Phương thức
import matplotlib.pyplot as plt73 sẽ trả về ma trận DCT nghịch đảo và giá trị của hệ số DC. Hãy nhớ rằng, ma trận DCT nghịch đảo này chỉ dành cho một ma trận MCU [Đơn vị được mã hóa tối thiểu] 8x8 nhỏ. Chúng tôi sẽ làm điều này cho tất cả các MCU riêng lẻ trong toàn bộ tệp hình ảnh
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Hiển thị hình ảnh trên màn hình
Hãy sửa đổi mã của chúng ta một chút và tạo một Tkinter Canvas và vẽ từng MCU sau khi giải mã nó theo phương thức
import matplotlib.pyplot as plt004
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
10 10 10 10 10 10 10
8Hãy bắt đầu với các hàm
import matplotlib.pyplot as plt005 và
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt006.
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt005 nhận các giá trị Y, Cr và Cb, sử dụng công thức để chuyển đổi các giá trị này thành các giá trị RGB của chúng, sau đó xuất các giá trị RGB được kẹp. Bạn có thể thắc mắc tại sao chúng tôi lại thêm 128 vào các giá trị RGB. Nếu bạn còn nhớ, trước khi máy nén JPEG áp dụng DCT trên MCU, nó sẽ trừ 128 khỏi các giá trị màu. Nếu màu ban đầu nằm trong phạm vi [0,255], JPEG sẽ đặt chúng vào phạm vi [-128,+128]. Vì vậy, chúng tôi phải hoàn tác hiệu ứng đó khi giải mã JPEG và đó là lý do tại sao chúng tôi thêm 128 vào RGB. Đối với
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt006, trong quá trình giải nén, giá trị đầu ra có thể vượt quá [0,255] nên chúng tôi kẹp chúng trong khoảng [0,255]
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Trong phương thức
import matplotlib.pyplot as plt74, chúng tôi lặp qua từng ma trận Y, Cr và Cb được giải mã 8x8 và chuyển đổi từng phần tử của ma trận 8x8 thành các giá trị RGB. Sau khi chuyển đổi, chúng tôi vẽ từng pixel trên Tkinter
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt010 bằng phương pháp
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
import matplotlib.pyplot as plt011. Bạn có thể tìm thấy mã hoàn chỉnh trên GitHub. Bây giờ nếu bạn chạy mã này, khuôn mặt của tôi sẽ hiển thị trên màn hình của bạn 😄
import matplotlib.image as mpimg
%matplotlib inlineimage_mp= mpimg.imread[r'\dogs-v-cats\dog.1.jpg']
imgplot=plt.imshow[image_mp]
plt.plot[]
Phần kết luận
Oh Boy. Ai có thể nghĩ rằng nó sẽ mất 6000 từ + lời giải thích để hiển thị khuôn mặt của tôi trên màn hình. Tôi ngạc nhiên bởi sự thông minh của một số nhà phát minh thuật toán này. Tôi hy vọng bạn thích bài viết này nhiều như tôi thích viết nó. Tôi đã học được rất nhiều điều khi viết bộ giải mã này. Tôi chưa bao giờ nhận ra có bao nhiêu phép toán phức tạp đi vào quá trình mã hóa một hình ảnh JPEG đơn giản. Tôi có thể làm việc với hình ảnh PNG tiếp theo và thử viết bộ giải mã cho hình ảnh PNG. Bạn cũng nên thử viết bộ giải mã cho PNG [hoặc một số định dạng khác]. Tôi chắc chắn rằng nó sẽ liên quan đến rất nhiều việc học và thậm chí còn thú vị hơn nữa 😅
Dù bằng cách nào, bây giờ tôi mệt mỏi. Tôi đã nhìn chằm chằm vào hex quá lâu và tôi nghĩ rằng mình đã kiếm được một kỳ nghỉ xứng đáng. Tất cả các bạn hãy cẩn thận và nếu bạn có bất kỳ câu hỏi nào, vui lòng viết chúng trong phần bình luận bên dưới. Tôi còn rất mới với cuộc phiêu lưu viết mã JPEG này nhưng tôi sẽ cố gắng trả lời nhiều nhất có thể 😄
Từ biệt. 👋 ❤️
đọc thêm
Nếu bạn muốn đi sâu vào chi tiết hơn, bạn có thể xem một số tài nguyên tôi đã sử dụng khi viết bài này. Tôi cũng đã thêm một số liên kết bổ sung cho một số nội dung thú vị liên quan đến JPEG