ã¿ãªãããããã«ã¡ã¯ãä»æ¥ã¯JPEGå§çž®ã¢ã«ãŽãªãºã ãæ±ããŸããå€ãã®äººã¯ãJPEGãã¢ã«ãŽãªãºã ã»ã©ã®ãã©ãŒãããã§ã¯ãªãããšãç¥ããŸããã衚瀺ãããJPEGç»åã®ã»ãšãã©ã¯JFIFïŒJPEG File Interchange FormatïŒã§ããããã®äžã«JPEGå§çž®ã¢ã«ãŽãªãºã ãé©çšãããŠããŸããèšäºã®çµãããŸã§ã«ããã®ã¢ã«ãŽãªãºã ãããŒã¿ãå§çž®ããæ¹æ³ãšãPythonã§è§£åã³ãŒããäœæããæ¹æ³ã«ã€ããŠã®ç解ãæ·±ãŸããŸããJPEG圢åŒã®ãã¹ãŠã®ãã¥ã¢ã³ã¹ïŒããšãã°ãããã°ã¬ãã·ãã¹ãã£ã³ïŒã«ã€ããŠã¯èæ ®ããŸããããç¬èªã®ãã³ãŒããŒãäœæããŠããéã¯ã圢åŒã®åºæ¬çãªæ©èœã«ã€ããŠã®ã¿èª¬æããŸãã
åæžã
ãã§ã«äœçŸãã®èšäºãæžãããŠããã®ã«ããªãJPEGã«å¥ã®èšäºãæžãã®ã§ããïŒéåžžããã®ãããªèšäºã§ã¯ãèè ã¯ãã©ãŒããããäœã§ãããã«ã€ããŠã®ã¿è©±ããŸããé梱ãšãã³ãŒãã®ã³ãŒãã¯èšè¿°ããŸããããããŠãããªããäœããæžãããšããŠããããã¯C / C ++ã«ãªãããã®ã³ãŒãã¯å¹ åºã人ã ãã¢ã¯ã»ã¹ã§ããªããªããŸãããã®äŒçµ±ãæã¡ç ŽããPython3ã§åºæ¬çãªJPEGãã³ãŒããŒãã©ã®ããã«æ©èœãããã瀺ããããšæããŸããMITãéçºãããã®ã³ãŒãã«åºã¥ããŠããŸãããèªã¿ããããšæ確ãã®ããã«å€§å¹ ã«å€æŽããŸãããã®èšäºã®å€æŽãããã³ãŒãã¯ãç§ã®ãªããžããªã«ãããŸãã
JPEGã®ããŸããŸãªéšå
ã¢ã³ãžã¥ã»ã¢ã«ãã«ãã£ãŒãã äœã£ãåçããå§ããŸããããåçŽãªJPEGãã¡ã€ã«ã®ãã¹ãŠã®éšåãäžèŠ§è¡šç€ºãããŸããåã»ã°ã¡ã³ããåæããèšäºãèªããšããã®å³ã«äœåºŠãæ»ããŸãã
ã»ãšãã©ãã¹ãŠã®ãã€ããªãã¡ã€ã«ã«ã¯ãããã€ãã®ããŒã«ãŒïŒãŸãã¯ããããŒïŒãå«ãŸããŠããŸãããããã¯ããçš®ã®ããã¯ããŒã¯ãšèããããšãã§ããŸãããããã¯ãã¡ã€ã«ã®æäœã«äžå¯æ¬ ã§ããããã¡ã€ã«ïŒMacããã³Linuxã®å ŽåïŒãªã©ã®ããã°ã©ã ã«ãã£ãŠäœ¿çšããããã¡ã€ã«ã®è©³çŽ°ã確èªã§ããŸããããŒã«ãŒã¯ãç¹å®ã®æ å ±ããã¡ã€ã«ã®ã©ãã«ä¿åãããŠããããæ£ç¢ºã«ç€ºããŸããã»ãšãã©ã®å ŽåãããŒã«ãŒã¯
length
ç¹å®ã®ã»ã°ã¡ã³ãã®é·ãïŒïŒã«åŸã£ãŠé
眮ãããŸãã
ãã¡ã€ã«ã®éå§ãšçµäº
ç§ãã¡ã«ãšã£ãŠéèŠãªæåã®ããŒã«ãŒã¯
FF D8
ã§ããç»åã®å§ãŸããå®çŸ©ããŸããèŠã€ãããªãå Žåã¯ãããŒã«ãŒãä»ã®ãã¡ã€ã«ã«ãããšèŠãªãããšãã§ããŸããããŒã«ãŒã¯ããã»ã©éèŠã§ã¯ãããŸããFF D9
ãç»åãã¡ã€ã«ã®æåŸã«å°éãããšè¡šç€ºãããŸããç¯å²FFD0
-FFD9
ãšFF01
ããé€ããŠãåããŒã«ãŒã®åŸã«ããã®ããŒã«ãŒã®ã»ã°ã¡ã³ãé·ã®å€ãããã«è¡šç€ºãããŸãããŸãããã¡ã€ã«ã®æåãšæåŸã®ããŒã«ãŒã¯åžžã«2ãã€ãã®é·ãã§ãã
ãã®ç»åã䜿çšããŸãã
éå§ããŒã«ãŒãšçµäºããŒã«ãŒãèŠã€ããããã®ã³ãŒããæžããŠã¿ãŸãããã
from struct import unpack
marker_mapping = {
0xffd8: "Start of Image",
0xffe0: "Application Default Header",
0xffdb: "Quantization Table",
0xffc0: "Start of Frame",
0xffc4: "Define Huffman Table",
0xffda: "Start of Scan",
0xffd9: "End of Image"
}
class JPEG:
def __init__(self, image_file):
with open(image_file, 'rb') as f:
self.img_data = f.read()
def decode(self):
data = self.img_data
while(True):
marker, = unpack(">H", data[0:2])
print(marker_mapping.get(marker))
if marker == 0xffd8:
data = data[2:]
elif marker == 0xffd9:
return
elif marker == 0xffda:
data = data[-2:]
else:
lenchunk, = unpack(">H", data[2:4])
data = data[2+lenchunk:]
if len(data)==0:
break
if __name__ == "__main__":
img = JPEG('profile.jpg')
img.decode()
# OUTPUT:
# Start of Image
# Application Default Header
# Quantization Table
# Quantization Table
# Start of Frame
# Huffman Table
# Huffman Table
# Huffman Table
# Huffman Table
# Start of Scan
# End of Image
ã€ã¡ãŒãžã®ãã€ãã解åããããã«ãstructã䜿çšããŸããã
>H
åããstruct
ããŒã¿åèªã¿åãããã«ãããunsigned short
ããã°ãšã³ãã£ã¢ã³é ã«åœŒããšä»äºãã JPEGããŒã¿ã¯ãæé«ããæäœã®åœ¢åŒã§ä¿åãããŸãã EXIFããŒã¿ã®ã¿ããªãã«ãšã³ãã£ã¢ã³åœ¢åŒã«ããããšãã§ããŸãïŒãã ããéåžžã¯ããã§ã¯ãããŸããïŒããŸãããµã€ãºshort
ã¯2ãªã®ã§ãunpack
ãã2ãã€ãã転éããŸãimg_data
ããããäœã§ããããã©ããã£ãŠç¥ããŸãããshort
ïŒããŒã«ãŒãJPEGã§ããããšãããã£ãŠããã®ã§ã4ã€ã®16é²æåã§ç€ºãããŸãffd8
ããã®ãããª1æåã¯4ãããïŒ1/2ãã€ãïŒã«çžåœããããã4æåã¯short
ããšåæ§ã«2ãã€ãã«çžåœããŸãã
[ã¹ãã£ã³ã®éå§]ã»ã¯ã·ã§ã³ã®çŽåŸã«ãç¹å®ã®é·ããæããªãã¹ãã£ã³ãããç»åããŒã¿ãç¶ããŸãããããã¯ãã¡ã€ã«ããŒã«ãŒã®çµãããŸã§ç¶ããããä»ã®ãšãããã¹ãã£ã³éå§ããŒã«ãŒãèŠã€ãã£ããæåã§ãæ€çŽ¢ãããŸãã
ããã§ã¯ãæ®ãã®ç»åããŒã¿ãæ±ããŸãããããããè¡ãã«ã¯ãæåã«çè«ãç 究ãã次ã«ããã°ã©ãã³ã°ã«ç§»ããŸãã
JPEGãšã³ã³ãŒãã£ã³ã°
ãŸããJPEGã§äœ¿çšãããåºæ¬çãªæŠå¿µãšã³ãŒãã£ã³ã°ææ³ã«ã€ããŠèª¬æããŸãããŸããã³ãŒãã£ã³ã°ã¯éã®é åºã§è¡ãããŸããç§ã®çµéšã§ã¯ããã³ãŒãã¯ãããªãã§ã¯ç解ããã®ãé£ããã§ãããã
以äžã®å³ã¯ãŸã æ確ã§ã¯ãããŸãããããšã³ã³ãŒããšãã³ãŒãã®ããã»ã¹ãåŠç¿ãããšãã«ãã³ããæäŸããŸããJPEGãšã³ã³ãŒãã£ã³ã°ã®æé ã¯æ¬¡ã®ãšããã§ãïŒãœãŒã¹ïŒã
JPEGã«ã©ãŒã¹ããŒã¹
JPEGä»æ§ïŒISO / IEC 10918-6ïŒ2013ïŒEïŒã»ã¯ã·ã§ã³6.1ïŒã«ãããšïŒ
- 1ã€ã®ã³ã³ããŒãã³ãã®ã¿ã§ãšã³ã³ãŒããããç»åã¯ãã°ã¬ãŒã¹ã±ãŒã«ããŒã¿ãšããŠæ±ãããŸããããã§ã0ã¯é»ã255ã¯çœã§ãã
- 3ã€ã®ã³ã³ããŒãã³ãã§ãšã³ã³ãŒããããç»åã¯ãYCbCr空éã§ãšã³ã³ãŒããããRGBããŒã¿ãšèŠãªãããŸããã»ã¯ã·ã§ã³6.5.3ã§èª¬æãããŠããAPP14ããŒã«ãŒã»ã°ã¡ã³ããç»åã«å«ãŸããŠããå ŽåãAPP14ããŒã«ãŒã»ã°ã¡ã³ãã®æ å ±ã«åŸã£ãŠãè²åãã¯RGBãŸãã¯YCbCrãšèŠãªãããŸããRGBãšYCbCrã®é¢ä¿ã¯ãITU-T T.871 |ã«åŸã£ãŠå®çŸ©ãããŠããŸããISO / IEC10918-5ã
- , , CMYK-, (0,0,0,0) . APP14, 6.5.3, CMYK YCCK APP14. CMYK YCCK 7.
JPEGã¢ã«ãŽãªãºã ã®ã»ãšãã©ã®å®è£ ã§ã¯ãRGBã®ä»£ããã«èŒåºŠãšã¯ãããã³ã¹ïŒYUVãšã³ã³ãŒãã£ã³ã°ïŒã䜿çšããŸãã人éã®ç®ã¯å°ããªé åã®æããã®é«åšæ³¢å€åãåºå¥ããã®ãéåžžã«èŠæãªã®ã§ãããã¯éåžžã«äŸ¿å©ã§ãããã®ãããåšæ³¢æ°ãäžããããšãã§ãã人ã¯éãã«æ°ä»ããªãã§ããããããã¯äœãããããã®ãã®ãïŒå質ã®äœäžãã»ãšãã©æããããªããé«åºŠã«å§çž®ãããç»åã
RGBãšåæ§ã«ãåãã¯ã»ã«ã¯3ãã€ãã®è²ïŒèµ€ãç·ãéïŒã§ãšã³ã³ãŒãããããããYUVã§ã¯3ãã€ãã䜿çšãããŸããããã®æå³ã¯ç°ãªããŸãã Yã³ã³ããŒãã³ãã¯ãè²ã®æããïŒèŒåºŠããŸãã¯èŒåºŠïŒãå®çŸ©ããŸãã UãšVã¯è²ïŒåœ©åºŠïŒãå®çŸ©ããŸããUã¯éãéšåãæ åœããVã¯èµ€ãéšåãæ åœããŸãã
ãã®ãã©ãŒãããã¯ããã¬ãããŸã ããã»ã©äžè¬çã§ã¯ãªãã£ãæ代ã«éçºããããã®ã§ããšã³ãžãã¢ã¯ã«ã©ãŒãšçœé»ã®ãã¬ãæŸéã®äž¡æ¹ã«åãç»åãšã³ã³ãŒãã£ã³ã°ãã©ãŒãããã䜿çšããããšèããŠããŸãããããã«ã€ããŠè©³ããã¯ããã¡ããã芧ãã ããã
é¢æ£ã³ãµã€ã³å€æãšéåå
JPEGã¯ãç»åã8x8ãããã¯ã®ãã¯ã»ã«ïŒMCUãæå°ã³ãŒãã£ã³ã°ãŠããããšåŒã°ããŸãïŒã«å€æããäžå¿ã0ã«ãªãããã«ãã¯ã»ã«å€ã®ç¯å²ãå€æŽããŠãããåãããã¯ã«é¢æ£äœåŒŠå€æãé©çšããéååã䜿çšããŠçµæãå§çž®ããŸãããããäœãæå³ããã®ãèŠãŠã¿ãŸãããã
ãã£ã¹ã¯ãªãŒãã³ãµã€ã³å€æïŒDCTïŒã¯ããã£ã¹ã¯ãªãŒãããŒã¿ãã³ãµã€ã³æ³¢ã®çµã¿åããã«å€æããæ¹æ³ã§ããåçãã³ãµã€ã³ã®ã»ããã«å€æããããšã¯ãäžèŠç¡é§ãªç·Žç¿ã®ããã«èŠããŸããã次ã®ã¹ãããã«ã€ããŠåŠã¶ãšãã®çç±ãããããŸãã DCTã¯8x8ãã¯ã»ã«ã®ãããã¯ãåãã8x8ã®äœåŒŠé¢æ°ã®ãããªãã¯ã¹ã䜿çšããŠãã®ãããã¯ãåçŸããæ¹æ³ã説æããŸãã詳现ã¯ãã¡ãã
ãããªãã¯ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
DCTã¯åãã¯ã»ã«ã³ã³ããŒãã³ãã«åå¥ã«é©çšãããŸãããã®çµæãä¿æ°ã®8x8ãããªãã¯ã¹ãåŸãããŸããããã¯ãå ¥å8x8ãããªãã¯ã¹å ã®ïŒ64åãã¹ãŠã®ïŒã³ãµã€ã³é¢æ°ã®å¯äžã瀺ããŠããŸãã DCTä¿æ°ã®ãããªãã¯ã¹ã§ã¯ãæ倧å€ã¯éåžžå·Šäžé ã«ãããæå°å€ã¯å³äžé ã«ãããŸããå·Šäžãæäœåšæ³¢æ°ã®äœåŒŠé¢æ°ã§ãå³äžãæé«ã§ãã
ããã¯ãã»ãšãã©ã®ç»åã«å€§éã®äœåšæ³¢æ å ±ããããé«åšæ³¢æ å ±ã®å²åãå°ãªãããšãæå³ããŸããåDCTãããªãã¯ã¹ã®å³äžã®ã³ã³ããŒãã³ãã«å€0ãå²ãåœãŠãããŠããå Žåã人ã¯é«åšæ³¢ã®å€åãããŸãåºå¥ã§ããªããããçµæã®ç»åã¯åãããã«èŠããŸããããã¯ã次ã®ã¹ãããã§è¡ãããšã§ãã
ãã®ãããã¯ã«é¢ãããã°ããããããªãèŠã€ããŸãããPrEPã®æå³ãããããªãå Žåã¯ã次ã確èªããŠãã ããã
JPEGãæ倱ã®å€ãå§çž®ã¢ã«ãŽãªãºã ã§ããããšã¯èª°ããç¥ã£ãŠããŸãããããããããŸã§ã®ãšãããç§ãã¡ã¯äœã倱ã£ãŠããŸãããæ å ±ã倱ãããšãªãã8x8ã³ãµã€ã³é¢æ°ã®ãããã¯ã«å€æããã8x8YUVã³ã³ããŒãã³ãã®ãããã¯ã®ã¿ããããŸããããŒã¿æ倱ã®æ®µéã¯éååã§ãã
éååã¯ãç¹å®ã®ç¯å²ãã2ã€ã®å€ãååŸããããããåå¥ã®å€ã«å€æããããã»ã¹ã§ããç§ãã¡ã®å Žåãããã¯ãçµæã®DCTãããªãã¯ã¹ã®æé«åšæ³¢æ°ä¿æ°ã0ã«æžããããã®åãªãååã§ããJPEGã䜿çšããŠç»åãä¿åããå Žåãã»ãšãã©ã®ç»åãšãã£ã¿ã§ã¯ãèšå®ããå§çž®ã¬ãã«ãå°ããããŸããããã¯ãé«åšæ³¢æ å ±ã®æ倱ãçºçããå Žæã§ããçµæã®JPEGç»åããå ã®ç»åãåäœæããããšã¯ã§ããªããªããŸãã
å§çž®çã«å¿ããŠç°ãªãéååãããªãã¯ã¹ã䜿çšãããŸãïŒé¢çœãäºå®ïŒã»ãšãã©ã®éçºè ã¯éååããŒãã«ãäœæããããã®ç¹èš±ãæã£ãŠããŸãïŒãä¿æ°ã®DCTãããªãã¯ã¹ãèŠçŽ ããšã«éååãããªãã¯ã¹ã§é€ç®ããçµæãæŽæ°ã«äžžããŠãéååããããããªãã¯ã¹ãååŸããŸãã
äŸãèŠãŠã¿ãŸãããããã®ãããªDCTãããªãã¯ã¹ããããšããŸãããïŒ
ãããŠããããéåžžã®éååãããªãã¯ã¹ã§ãã
éååããããããªãã¯ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
人éã¯é«åšæ³¢æ å ±ãèŠãããšãã§ããŸãããã8x8ãã¯ã»ã«ã®ãããã¯ããå€ãã®ããŒã¿ãåé€ãããšãç»åãç²ããªããããŸãããã®ãããªéååããããããªãã¯ã¹ã§ã¯ãæåã®å€ã¯DCå€ãšåŒã°ããä»ã®ãã¹ãŠã®å€ã¯ACå€ãšåŒã°ããŸãããã¹ãŠã®éååããããããªãã¯ã¹ã®DCå€ãååŸããŠæ°ããç»åãçæããå Žåãå ã®ç»åã®8åã®1ã®è§£å床ã§ãã¬ãã¥ãŒã衚瀺ãããŸãã
ãŸããéååã䜿çšãããããè²ã[0.255]ã®ç¯å²å ã«ããããšã確èªããå¿ èŠãããããšã«ã泚æããŠãã ãããããããé£ã³åºãå Žåã¯ãæåã§ãã®ç¯å²ã«ç§»åããå¿ èŠããããŸãã
ãžã°ã¶ã°
éåååŸãJPEGã¢ã«ãŽãªãºã ã¯ãžã°ã¶ã°ã¹ãã£ã³ã䜿çšããŠãããªãã¯ã¹ã1次å 圢åŒã«å€æããŸãã
ãœãŒã¹ã
ãã®ãããªéååããããããªãã¯ã¹ãäœæããŸãããã
ãã®å Žåããžã°ã¶ã°ã¹ãã£ã³ã®çµæã¯æ¬¡ã®ããã«ãªããŸãã
[15 14 13 12 11 10 9 8 0 ... 0]
éåååŸãã»ãšãã©ã®äœåšæ³¢ïŒæãéèŠãªïŒæ å ±ããããªãã¯ã¹ã®å é ã«é 眮ããããžã°ã¶ã°ã¹ãã£ã³ããã®ããŒã¿ã1次å ãããªãã¯ã¹ã®å é ã«æ ŒçŽããããããã®ã³ãŒãã£ã³ã°ãæšå¥šãããŸããããã¯ã次ã®ã¹ãããã§ããå§çž®ã«åœ¹ç«ã¡ãŸãã
ã©ã³ã¬ã³ã°ã¹ã³ãŒãã£ã³ã°ãšãã«ã¿ã³ãŒãã£ã³ã°
ã©ã³ã¬ã³ã°ã¹ãšã³ã³ãŒãã£ã³ã°ã¯ãå埩ããŒã¿ãå§çž®ããããã«äœ¿çšãããŸãããžã°ã¶ã°ã¹ãã£ã³ã®åŸãé åã®æåŸã«ã»ãšãã©ãŒããããããšãããããŸããé·ãã®ãšã³ã³ãŒãã«ããããã®ç¡é§ãªã¹ããŒã¹ãå©çšãã䜿çšãããã€ãæ°ãæžãããŠãã¹ãŠã®ãŒããè¡šãããšãã§ããŸãã次ã®ããŒã¿ããããšããŸãããã
10 10 10 10 10 10 10
ã·ãªãŒãºã®é·ãããšã³ã³ãŒãããåŸã次ã®ããã«ãªããŸãã
7 10
7ãã€ãã2ãã€ãã«å§çž®ããŸããã
ãã«ã¿ãšã³ã³ãŒãã£ã³ã°ã¯ããã®åã®ãã€ããåºæºã«ãããã€ããè¡šãããã«äœ¿çšãããŸããäŸãæããŠèª¬æããæ¹ãç°¡åã§ãã次ã®ããŒã¿ãçšæããŸãããã
10 11 12 13 10 9
ãã«ã¿ã³ãŒãã£ã³ã°ã䜿çšãããšã次ã®ããã«è¡šãããšãã§ããŸãã
10 1 2 3 0 -1
JPEGã§ã¯ãDCTãããªãã¯ã¹ã®åDCå€ã¯ãåã®DCå€ã«å¯ŸããŠãã«ã¿ãšã³ã³ãŒããããŸããããã¯ãç»åã®æåã®DCTä¿æ°ãå€æŽããããšã«ãããå šäœåãç Žå£ããããšãæå³ããŸãããã ããæåŸã®DCTãããªãã¯ã¹ã®æåã®å€ãå€æŽãããšãç»åã®éåžžã«å°ããªãã©ã°ã¡ã³ãã«ã®ã¿åœ±é¿ããŸãã
éåžžãç»åã®æåã®DCå€ãæãå€åããããããã®ã¢ãããŒãã¯äŸ¿å©ã§ãããã«ã¿ã³ãŒãã£ã³ã°ã䜿çšããŠãæ®ãã®DCå€ã0ã«è¿ã¥ãããããã³ã³ãŒãã£ã³ã°ã«ããå§çž®ãæ¹åããŸãã
ãããã³ã³ãŒãã£ã³ã°
ç¡æ倱ã®å§çž®æ¹æ³ã§ããããæ¥ããããã³ã¯ãããªãŒããã¹ããä¿åããããã«äœ¿çšã§ãããããã®æå°æ°ã¯ããã€ã§ããïŒããšçåã«æããŸããããã®çµæããšã³ã³ãŒã圢åŒãäœæãããŸãããããã¹ãããããšããŸãããïŒ
a b c d e
éåžžãåæåã¯1ãã€ãã®ã¹ããŒã¹ãå æããŸãã
a: 01100001
b: 01100010
c: 01100011
d: 01100100
e: 01100101
ããããã€ããªASCIIãšã³ã³ãŒãã£ã³ã°ã®åçã§ãããããã³ã°ãå€æŽãããšã©ããªããŸããïŒ
# Mapping
000: 01100001
001: 01100010
010: 01100011
100: 01100100
011: 01100101
åãããã¹ããä¿åããããã«å¿ èŠãªãããæ°ãå€§å¹ ã«æžããŸããã
a: 000
b: 001
c: 010
d: 100
e: 011
ããã¯ãã¹ãŠããŸããã£ãŠããŸãããããã«å€ãã®ã¹ããŒã¹ãç¯çŽããå¿ èŠãããå Žåã¯ã©ããªããŸããïŒããšãã°ã次ã®ããã«ãªããŸãã
# Mapping
0: 01100001
1: 01100010
00: 01100011
01: 01100100
10: 01100101
a: 0
b: 1
c: 00
d: 01
e: 10
ãããã³ã³ãŒãã£ã³ã°ã¯ããã®ãããªå¯å€é·ã®ãããã³ã°ãå¯èœã«ããŸããå ¥åããŒã¿ãååŸãããæãäžè¬çãªæåã¯ãããã®å°ããªçµã¿åãããšç §åãããé »åºŠã®äœãæåã¯å€§ããªçµã¿åãããšç §åãããŸãããããŠãçµæã®ãããã³ã°ã¯ãã€ããªããªãŒã«åéãããŸãã JPEGã§ã¯ããããã³ã³ãŒãã£ã³ã°ã䜿çšããŠDCTæ å ±ãä¿åããŸãã DCå€ã®ãã«ã¿ã³ãŒãã£ã³ã°ã«ãããããã³ã³ãŒãã£ã³ã°ã容æã«ãªããšè¿°ã¹ãããšãèŠããŠããŸããïŒãã®çç±ããç解ããã ããã°å¹žãã§ãããã«ã¿ãšã³ã³ãŒãã£ã³ã°ã®åŸãäžèŽãããæåããå°ãªããªããããªãŒãµã€ãºãå°ãããªããŸãã
ãã ã¹ã³ããã¯ããããã³ã¢ã«ãŽãªãºã ãã©ã®ããã«æ©èœãããã説æããçŽ æŽããããããªãæã£ãŠããŸããèªãåã«èŠãŠãã ããã
JPEGã«ã¯ãæ倧4ã€ã®ãããã³ããŒãã«ãå«ãŸãããããã¯ããããã³ããŒãã«ã®å®çŸ©ãïŒã§å§ãŸã
0xffc4
ïŒã«æ ŒçŽãããŸãã DCTä¿æ°ã¯ã2ã€ã®ç°ãªããããã³ããŒãã«ã«æ ŒçŽãããŸãã1ã€ã¯ãžã°ã¶ã°ããŒãã«ã®DCå€ããã1ã€ã¯ãžã°ã¶ã°ããŒãã«ã®ACå€ã§ããããã¯ãã³ãŒãã£ã³ã°æã«ã2ã€ã®ãããªãã¯ã¹ããã®DCå€ãšACå€ãçµã¿åãããå¿
èŠãããããšãæå³ããŸããèŒåºŠãã£ãã«ãšè²åºŠãã£ãã«ã®DCTæ
å ±ã¯å¥ã
ã«ä¿åãããããã2ã»ããã®DCæ
å ±ãš2ã»ããã®ACæ
å ±ãåèš4ã€ã®ãããã³ããŒãã«ããããŸãã
ç»åãã°ã¬ãŒã¹ã±ãŒã«ã®å Žåãè²ã¯å¿ èŠãªãããããããã³ããŒãã«ã¯2ã€ïŒDCçšãšACçšïŒãããããŸããããåç¥ãããããŸãããã2ã€ã®ç°ãªãç»åã¯éåžžã«ç°ãªããããã³ããŒãã«ãæã€å¯èœæ§ããããããåJPEGå ã«ä¿åããããšãéèŠã§ãã
ããã§ãJPEGç»åã®äž»ãªå 容ãããããŸããããã³ãŒãã«ç§»ããŸãããã
JPEGãã³ãŒã
ãã³ãŒãã¯æ¬¡ã®æ®µéã«åããããšãã§ããŸãã
- ãããã³ããŒãã«ã®æœåºãšãããã®ãã³ãŒãã
- ã©ã³ã¬ã³ã°ã¹ããã³ãã«ã¿ã³ãŒãã£ã³ã°ã®ããŒã«ããã¯ã䜿çšããŠDCTä¿æ°ãæœåºããŸãã
- DCTä¿æ°ã䜿çšããŠäœåŒŠæ³¢ãçµã¿åãããå8x8ãããã¯ã®ãã¯ã»ã«å€ãåæ§ç¯ããŸãã
- ãã¯ã»ã«ããšã«YCbCrãRGBã«å€æããŸãã
- çµæã®RGBç»åã衚瀺ããŸãã
JPEGæšæºã¯ã次ã®4ã€ã®å§çž®åœ¢åŒããµããŒãããŠããŸãã
- ããŒã¹
- æ¡åŒµã·ãªã¢ã«
- ããã°ã¬ãã·ã
- æ倱ãªã
åºæ¬çãªå§çž®ã䜿çšããŸããããã«ã¯ãäºãã«ç¶ãäžé£ã®8x8ãããã¯ãå«ãŸããŠããŸããä»ã®åœ¢åŒã§ã¯ãããŒã¿ãã³ãã¬ãŒãã¯ãããã«ç°ãªããŸããæ確ã«ããããã«ãç»åã®16é²æ°ã®ã³ã³ãã³ãã®ããŸããŸãªã»ã°ã¡ã³ãã«è²ãä»ããŸããã
ãããã³ããŒãã«ã®æœåº
JPEGã«ã¯4ã€ã®ãããã³ããŒãã«ãå«ãŸããŠããããšã¯ãã§ã«ããã£ãŠããŸãããããæåŸã®ãšã³ã³ãŒãã£ã³ã°ãªã®ã§ãããã䜿çšããŠãã³ãŒããéå§ããŸããè¡šã®åã»ã¯ã·ã§ã³ã«ã¯ã次ã®æ å ±ãå«ãŸããŠããŸãã
ãã£ãŒã«ã | ãµã€ãº | 説æ |
---|---|---|
ããŒã«ãŒID | 2ãã€ã | 0xffããã³0xc4ã¯DHTãèå¥ããŸã |
é·ã | 2ãã€ã | ããŒãã«ã®é·ã |
ãããã³ããŒãã«æ å ± | 1ãã€ã | ããã0 ... 3ïŒããŒãã«ã®æ°ïŒ0 ... 3ããã以å€ã®å Žåã¯ãšã©ãŒïŒããã4ïŒããŒãã«ã®ã¿ã€ãã0 = DCããŒãã«ã1 = ACããŒãã«ããã5 ... 7ïŒäœ¿çšããªãã0ã§ããå¿ èŠããããŸã |
ãã£ã©ã¯ã¿ãŒ | 16ãã€ã | ã³ãŒãã®é·ãã1 ... 16ã®æåæ°ããããã®ãã€ãã®åèšïŒnïŒã¯ã<= 256ã§ãªããã°ãªããªãã³ãŒãã®ç·æ°ã§ãã |
ã·ã³ãã« | nãã€ã | ãã®è¡šã«ã¯ãã³ãŒãé·ã®æé ã§æåãå«ãŸããŠããŸãïŒn =ã³ãŒãã®ç·æ°ïŒã |
次ã®ãããªãããã³ããŒãã«ããããšããŸãããïŒãœãŒã¹ïŒïŒ
ã·ã³ãã« | ãããã³ã³ãŒã | ã³ãŒãã®é·ã |
---|---|---|
a | 00 | 2 |
b | 010 | 3 |
c | 011 | 3 |
d | 100 | 3 |
e | 101 | 3 |
f | 110 | 3 |
g | 1110 | 4 |
h | 11110 | äº |
ç§ | 111110 | 6 |
j | 1111110 | 7 |
k | 11111110 | 8 |
l | 111111110 | ãã€ã³ |
ããã¯ã次ã®ãããªJFIFãã¡ã€ã«ã«ä¿åãããŸãïŒãã€ããªåœ¢åŒãããããããããããã«ASCIIã䜿çšããŠããŸãïŒã
0 1 5 1 1 1 1 1 1 0 0 0 0 0 0 0 a b c d e f g h i j k l
0ã¯ãé·ã1ã®ãããã³ã³ãŒãããªãããšãæå³ããŸãã1ã¯ãé·ã2ã®ãããã³ã³ãŒãã1ã€ããããšãæå³ããŸããDHTã»ã¯ã·ã§ã³ã§ã¯ãã¯ã©ã¹ãšIDã®çŽåŸã«ãããŒã¿ã¯åžžã«16ãã€ãã®é·ãã§ããDHTããé·ããšèŠçŽ ãæœåºããã³ãŒããæžããŠã¿ãŸãããã
class JPEG:
# ...
def decodeHuffman(self, data):
offset = 0
header, = unpack("B",data[offset:offset+1])
offset += 1
# Extract the 16 bytes containing length data
lengths = unpack("BBBBBBBBBBBBBBBB", data[offset:offset+16])
offset += 16
# Extract the elements after the initial 16 bytes
elements = []
for i in lengths:
elements += (unpack("B"*i, data[offset:offset+i]))
offset += i
print("Header: ",header)
print("lengths: ", lengths)
print("Elements: ", len(elements))
data = data[offset:]
def decode(self):
data = self.img_data
while(True):
# ---
else:
len_chunk, = unpack(">H", data[2:4])
len_chunk += 2
chunk = data[4:len_chunk]
if marker == 0xffc4:
self.decodeHuffman(chunk)
data = data[len_chunk:]
if len(data)==0:
break
ã³ãŒããå®è¡ãããšã次ã®ããã«ãªããŸãã
Start of Image
Application Default Header
Quantization Table
Quantization Table
Start of Frame
Huffman Table
Header: 0
lengths: (0, 2, 2, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
Elements: 10
Huffman Table
Header: 16
lengths: (0, 2, 1, 3, 2, 4, 5, 2, 4, 4, 3, 4, 8, 5, 5, 1)
Elements: 53
Huffman Table
Header: 1
lengths: (0, 2, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
Elements: 8
Huffman Table
Header: 17
lengths: (0, 2, 2, 2, 2, 2, 1, 3, 3, 1, 7, 4, 2, 3, 0, 0)
Elements: 34
Start of Scan
End of Image
åªããïŒé·ããšèŠçŽ ããããŸãã次ã«ãååŸããé·ããšèŠçŽ ãããã€ããªããªãŒãåæ§ç¯ããããã«ãç¬èªã®ãããã³ããŒãã«ã¯ã©ã¹ãäœæããå¿ èŠããããŸããããããã³ãŒããã³ããŒããŸãïŒ
class HuffmanTable:
def __init__(self):
self.root=[]
self.elements = []
def BitsFromLengths(self, root, element, pos):
if isinstance(root,list):
if pos==0:
if len(root)<2:
root.append(element)
return True
return False
for i in [0,1]:
if len(root) == i:
root.append([])
if self.BitsFromLengths(root[i], element, pos-1) == True:
return True
return False
def GetHuffmanBits(self, lengths, elements):
self.elements = elements
ii = 0
for i in range(len(lengths)):
for j in range(lengths[i]):
self.BitsFromLengths(self.root, elements[ii], i)
ii+=1
def Find(self,st):
r = self.root
while isinstance(r, list):
r=r[st.GetBit()]
return r
def GetCode(self, st):
while(True):
res = self.Find(st)
if res == 0:
return 0
elif ( res != -1):
return res
class JPEG:
# -----
def decodeHuffman(self, data):
# ----
hf = HuffmanTable()
hf.GetHuffmanBits(lengths, elements)
data = data[offset:]
GetHuffmanBits
é·ããšèŠçŽ ãåãåããèŠçŽ ãç¹°ãè¿ãåŠçããŠããªã¹ãã«å
¥ããŸãroot
ãããã¯ãã€ããªããªãŒã§ããããã¹ãããããªã¹ããå«ãŸããŠããŸãããããã³ããªãŒãã©ã®ããã«æ©èœããPythonã§ãã®ãããªããŒã¿æ§é ãäœæããæ¹æ³ãã€ã³ã¿ãŒãããã§èªãããšãã§ããŸããæåã®DHTïŒèšäºã®åé ã®åçããïŒã«ã¯ã次ã®ããŒã¿ãé·ããèŠçŽ ããããŸãã
Hex Data: 00 02 02 03 01 01 01 00 00 00 00 00 00 00 00 00
Lengths: (0, 2, 2, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
Elements: [5, 6, 3, 4, 2, 7, 8, 1, 0, 9]
åŒã³åºãåŸã
GetHuffmanBits
ãªã¹ãroot
ã«ã¯æ¬¡ã®ããŒã¿ãå«ãŸããŸãã
[[5, 6], [[3, 4], [[2, 7], [8, [1, [0, [9]]]]]]]
HuffmanTable
ãŸãGetCode
ãããªãŒããŠã©ãŒã¯ã¹ã«ãŒãããããã³ããŒãã«ã䜿çšããŠãã³ãŒããããããããè¿ãã¡ãœãããå«ãŸããŠããŸãããã®ã¡ãœããã¯ãå
¥åãšããŠãããã¹ããªãŒã ãåãåããŸããããã¯ãããŒã¿ã®ãã€ããªè¡šçŸã«ãããŸãããããšãã°ãã®ãããã¹ããªãŒã ã¯ã«abc
ãªããŸã011000010110001001100011
ããŸããåæåãASCIIã³ãŒãã«å€æããããããã€ããªã«å€æããŸããæååããããã«å€æãããããã1ã€ãã€ã«ãŠã³ãããã®ã«åœ¹ç«ã€ã¯ã©ã¹ãäœæããŸãããã
class Stream:
def __init__(self, data):
self.data= data
self.pos = 0
def GetBit(self):
b = self.data[self.pos >> 3]
s = 7-(self.pos & 0x7)
self.pos+=1
return (b >> s) & 1
def GetBitN(self, l):
val = 0
for i in range(l):
val = val*2 + self.GetBit()
return val
åæåãããšããã¯ã©ã¹ã«ãã€ããªããŒã¿ãäžããŠããããšã䜿çš
GetBit
ããŠãããèªã¿åããŸãGetBitN
ã
éååããŒãã«ã®ãã³ãŒã
[éååããŒãã«ã®å®çŸ©]ã»ã¯ã·ã§ã³ã«ã¯ã次ã®ããŒã¿ãå«ãŸããŠããŸãã
ãã£ãŒã«ã | ãµã€ãº | 説æ |
---|---|---|
ããŒã«ãŒID | 2ãã€ã | 0xffããã³0xdbã¯DQTã»ã¯ã·ã§ã³ãèå¥ããŸã |
é·ã | 2ãã€ã | éååããŒãã«ã®é·ã |
å®éåæ å ± | 1ãã€ã | ããã0 ... 3ïŒéååããŒãã«ã®æ°ïŒ0 ... 3ããã以å€ã®å Žåã¯ãšã©ãŒïŒããã4 ... 7ïŒéååããŒãã«ã®ç²ŸåºŠã0 = 8ãããããã以å€ã®å Žåã¯16ããã |
ãã€ã | nãã€ã | éååããŒãã«ã®å€ãn = 64 *ïŒç²ŸåºŠ+ 1ïŒ |
JPEGèŠæ Œã«ãããšãããã©ã«ãã®JPEGç»åã«ã¯ãèŒåºŠãšåœ©åºŠã®2ã€ã®éååããŒãã«ããããŸãããããã¯ããŒã«ãŒã§å§ãŸããŸã
0xffdb
ãã³ãŒãã®çµæã«ã¯ããã§ã«2ã€ã®ãã®ãããªããŒã«ãŒãå«ãŸããŠããŸããéååããŒãã«ããã³ãŒãããæ©èœãè¿œå ããŸãããã
def GetArray(type,l, length):
s = ""
for i in range(length):
s =s+type
return list(unpack(s,l[:length]))
class JPEG:
# ------
def __init__(self, image_file):
self.huffman_tables = {}
self.quant = {}
with open(image_file, 'rb') as f:
self.img_data = f.read()
def DefineQuantizationTables(self, data):
hdr, = unpack("B",data[0:1])
self.quant[hdr] = GetArray("B", data[1:1+64],64)
data = data[65:]
def decodeHuffman(self, data):
# ------
for i in lengths:
elements += (GetArray("B", data[off:off+i], i))
offset += i
# ------
def decode(self):
# ------
while(True):
# ----
else:
# -----
if marker == 0xffc4:
self.decodeHuffman(chunk)
elif marker == 0xffdb:
self.DefineQuantizationTables(chunk)
data = data[len_chunk:]
if len(data)==0:
break
æåã«ã¡ãœãããå®çŸ©ããŸãã
GetArray
ãããã¯ããã€ããªããŒã¿ããå¯å€æ°ã®ãã€ãããã³ãŒãããããã®äŸ¿å©ãªææ³ã§ãããŸãdecodeHuffman
ãæ°ããé¢æ°ãå©çšããããã«ãã¡ãœããã®äžéšã®ã³ãŒãã眮ãæããŸããã次ã«ãã¡ãœãããå®çŸ©ãããŸããDefineQuantizationTables
ãéååããŒãã«ãå«ãã»ã¯ã·ã§ã³ã®ã¿ã€ãã«ãèªã¿åããããããŒã®å€ãããŒãšããŠäœ¿çšããŠãéååããŒã¿ãèŸæžã«é©çšããŸãããã®å€ã¯ãèŒåºŠã®å Žåã¯0ãè²åºŠã®å Žåã¯1ã«ããããšãã§ããŸããJFIFã®éååããŒãã«ãæã€åã»ã¯ã·ã§ã³ã«ã¯ã64ãã€ãã®ããŒã¿ãå«ãŸããŠããŸãïŒ8x8éååãããªãã¯ã¹ã®å ŽåïŒã
ç»åã®éååè¡åãåºåãããšã次ã®ããã«ãªããŸãã
3 2 2 3 2 2 3 3
3 3 4 3 3 4 5 8
5 5 4 4 5 10 7 7
6 8 12 10 12 12 11 10
11 11 13 14 18 16 13 14
17 14 11 11 16 22 16 17
19 20 21 21 21 12 15 23
24 22 20 24 18 20 21 20
3 2 2 3 2 2 3 3
3 2 2 3 2 2 3 3
3 3 4 3 3 4 5 8
5 5 4 4 5 10 7 7
6 8 12 10 12 12 11 10
11 11 13 14 18 16 13 14
17 14 11 11 16 22 16 17
19 20 21 21 21 12 15 23
24 22 20 24 18 20 21 20
ãã¬ãŒã ã®éå§ããã³ãŒããã
[ãã¬ãŒã ã®éå§]ã»ã¯ã·ã§ã³ã«ã¯ã次ã®æ å ±ãå«ãŸããŠããŸãïŒãœãŒã¹ïŒã
ãã£ãŒã«ã | ãµã€ãº | 説æ |
---|---|---|
ããŒã«ãŒID | 2ãã€ã | 0xff 0xc0 SOF |
2 | 8 + *3 | |
1 | , 8 (12 16 ). | |
2 | > 0 | |
2 | > 0 | |
1 | 1 = , 3 = YcbCr YIQ | |
3 | 3 . (1 ) (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), (1 ) ( 0...3 , 4...7 ), (1 ). |
ããã§ã¯ããã¹ãŠã«é¢å¿ãããããã§ã¯ãããŸãããç»åã®å¹ ãšé«ããããã³åã³ã³ããŒãã³ãã®éååããŒãã«ã®æ°ãæœåºããŸããå¹ ãšé«ãã¯ã[ã¹ãã£ã³ã®éå§]ã»ã¯ã·ã§ã³ããç»åã®å®éã®ã¹ãã£ã³ã®ãã³ãŒããéå§ããããã«äœ¿çšãããŸããäž»ã«YCbCrã€ã¡ãŒãžã䜿çšããããã3ã€ã®ã³ã³ããŒãã³ããããããããã®ã¿ã€ãã¯ãããã1ã2ãããã³3ã§ãããšæ³å®ã§ããŸãããã®ããŒã¿ããã³ãŒãããã³ãŒããæžããŠã¿ãŸãããã
class JPEG:
def __init__(self, image_file):
self.huffman_tables = {}
self.quant = {}
self.quantMapping = []
with open(image_file, 'rb') as f:
self.img_data = f.read()
# ----
def BaselineDCT(self, data):
hdr, self.height, self.width, components = unpack(">BHHB",data[0:6])
print("size %ix%i" % (self.width, self.height))
for i in range(components):
id, samp, QtbId = unpack("BBB",data[6+i*3:9+i*3])
self.quantMapping.append(QtbId)
def decode(self):
# ----
while(True):
# -----
elif marker == 0xffdb:
self.DefineQuantizationTables(chunk)
elif marker == 0xffc0:
self.BaselineDCT(chunk)
data = data[len_chunk:]
if len(data)==0:
break
JPEGã¯ã©ã¹ã«listå±æ§ãè¿œå ããSOFã»ã¯ã·ã§ã³ããå¿ èŠãªããŒã¿ããã³ãŒãããåã³ã³ããŒãã³ãã®éååããŒãã«ã®æ°ããªã¹ãã«å ¥ãã
quantMapping
ã¡ãœããBaselineDCT
ãå®çŸ©ããŸããquantMapping
ããã¹ãã£ã³ã®éå§ãã»ã¯ã·ã§ã³ãèªã¿å§ãããšãã«ããããå©çšããŸãããããã£ãŠãç§ãã¡ã®åçã§ã¯ã次ã®ããã«ãªããŸãquantMapping
ã
Quant mapping: [0, 1, 1]
ã¹ãã£ã³éå§ã®ãã³ãŒã
ããã¯JPEGç»åã®ãèãã§ãããç»åèªäœã®ããŒã¿ãå«ãŸããŠããŸããç§ãã¡ã¯æãéèŠãªæ®µéã«å°éããŸããã以åã«ãã³ãŒããããã®ã¯ãã¹ãŠãç»åèªäœããã³ãŒãããã®ã«åœ¹ç«ã€ã«ãŒããšèŠãªãããšãã§ããŸãããã®ã»ã¯ã·ã§ã³ã«ã¯ãç»åèªäœïŒãšã³ã³ãŒãããããã®ïŒãå«ãŸããŠããŸããã»ã¯ã·ã§ã³ãèªã¿ããã§ã«ãã³ãŒããããããŒã¿ã䜿çšããŠåŸ©å·åããŸãã
ãã¹ãŠã®ããŒã«ãŒã¯
0xff
ãã§å§ãŸããŸãããã®å€ã¯ã¹ãã£ã³ãããç»åã®äžéšã«ããããšãã§ããŸããããã®ã»ã¯ã·ã§ã³ã«ååšããå Žåã¯ãåžžã«ãšãç¶ã0x00
ãŸãã JPEGãšã³ã³ãŒããŒã¯ãããèªåçã«æ¿å
¥ããŸããããã¯ãã€ãã¹ã¿ããã£ã³ã°ãšåŒã°ããŸãããããã£ãŠããã³ãŒããŒã¯ããããåé€ããå¿
èŠããããŸã0x00
ããã®ãããªé¢æ°ãå«ãSOSãã³ãŒãã¡ãœããããå§ããŠãæ¢åã®é¢æ°ãåãé€ããŸããã0x00
ãã¹ãã£ã³ããã»ã¯ã·ã§ã³ã®åçã«ã¯ãããŸãã0xff
ããããããã§ã䟿å©ãªè¿œå ã§ãã
def RemoveFF00(data):
datapro = []
i = 0
while(True):
b,bnext = unpack("BB",data[i:i+2])
if (b == 0xff):
if (bnext != 0):
break
datapro.append(data[i])
i+=2
else:
datapro.append(data[i])
i+=1
return datapro,i
class JPEG:
# ----
def StartOfScan(self, data, hdrlen):
data,lenchunk = RemoveFF00(data[hdrlen:])
return lenchunk+hdrlen
def decode(self):
data = self.img_data
while(True):
marker, = unpack(">H", data[0:2])
print(marker_mapping.get(marker))
if marker == 0xffd8:
data = data[2:]
elif marker == 0xffd9:
return
else:
len_chunk, = unpack(">H", data[2:4])
len_chunk += 2
chunk = data[4:len_chunk]
if marker == 0xffc4:
self.decodeHuffman(chunk)
elif marker == 0xffdb:
self.DefineQuantizationTables(chunk)
elif marker == 0xffc0:
self.BaselineDCT(chunk)
elif marker == 0xffda:
len_chunk = self.StartOfScan(data, len_chunk)
data = data[len_chunk:]
if len(data)==0:
break
以åã¯ãããŒã«ãŒ
0xffda
ãèŠã€ãã£ããšãã«ãã¡ã€ã«ã®æ«å°Ÿãæåã§æ€çŽ¢ããŠããŸãããããã¡ã€ã«å
šäœãäœç³»çã«è¡šç€ºã§ããããŒã«ãã§ããã®ã§ãããŒã«ãŒã®æ€çŽ¢æ¡ä»¶ãæŒç®åå
ã«ç§»åããŸãelse
ãé¢æ°RemoveFF00
ã¯ã0x00
åŸã§ã¯ãªãäœãä»ã®ãã®ãèŠã€ãããšå£ã0xff
ãŸããé¢æ°ããèŠã€ãã0xffd9
ãšã«ãŒããäžæãããããäºæãã¬ããšãæããã«ãã¡ã€ã«ã®çµãããæ€çŽ¢ã§ããŸãããã®ã³ãŒããå®è¡ãããšãã¿ãŒããã«ã«æ°ãããã®ã¯äœã衚瀺ãããŸããã
JPEGã¯ç»åã8x8ã®ãããªãã¯ã¹ã«åå²ããããšãå¿ããªãã§ãã ããã次ã«ãã¹ãã£ã³ããç»åããŒã¿ããããã¹ããªãŒã ã«å€æãã8x8ãã£ã³ã¯ã§åŠçããå¿ èŠããããŸããã¯ã©ã¹ã«ã³ãŒããè¿œå ããŸãããïŒ
class JPEG:
# -----
def StartOfScan(self, data, hdrlen):
data,lenchunk = RemoveFF00(data[hdrlen:])
st = Stream(data)
oldlumdccoeff, oldCbdccoeff, oldCrdccoeff = 0, 0, 0
for y in range(self.height//8):
for x in range(self.width//8):
matL, oldlumdccoeff = self.BuildMatrix(st,0, self.quant[self.quantMapping[0]], oldlumdccoeff)
matCr, oldCrdccoeff = self.BuildMatrix(st,1, self.quant[self.quantMapping[1]], oldCrdccoeff)
matCb, oldCbdccoeff = self.BuildMatrix(st,1, self.quant[self.quantMapping[2]], oldCbdccoeff)
DrawMatrix(x, y, matL.base, matCb.base, matCr.base )
return lenchunk +hdrlen
ããŒã¿ããããã¹ããªãŒã ã«å€æããããšããå§ããŸããããåã®DCèŠçŽ ãšæ¯èŒããŠãéååãããªãã¯ã¹ã®DCèŠçŽ ïŒãã®æåã®èŠçŽ ïŒã«ãã«ã¿ã³ãŒãã£ã³ã°ãé©çšãããŠããããšãèŠããŠããŸããïŒãããã£ãŠãæã ã¯ãåæå
oldlumdccoeff
ãoldCbdccoeff
ããã³oldCrdccoeff
ãŒãå€ã§ã圌ãã¯ç§ãã¡ã以åã®DC-èŠçŽ ã®å€ã远跡ããã®ã«åœ¹ç«ã¡ãŸãããããŠ0ã¯ãæã
ãæåã«DC-èŠçŽ ãèŠã€ããããã©ã«ãã§èšå®ãããŸãã
ã«ãŒã
for
ã¯å¥åŠã«èŠãããããããŸãããself.height//8
é«ãã88ã§å²ãããšãã§ããåæ°ã瀺ããŸãself.width//8
ãããã¯ãå¹
ãšããšåãã§ãã
BuildMatrix
éååããŒãã«ãååŸããŠãã©ã¡ãŒã¿ãè¿œå ããéé¢æ£äœåŒŠå€æè¡åãäœæããŠãYãCrãããã³Cbè¡åãååŸããŸãããããŠãé¢æ°ã¯DrawMatrix
ããããRGBã«å€æããŸãã
ãŸããã¯ã©ã¹ãäœæããŸããã
IDCT
ã次ã«ã¡ãœããã®å
¥åãéå§ãBuildMatrix
ãŸãã
import math
class IDCT:
"""
An inverse Discrete Cosine Transformation Class
"""
def __init__(self):
self.base = [0] * 64
self.zigzag = [
[0, 1, 5, 6, 14, 15, 27, 28],
[2, 4, 7, 13, 16, 26, 29, 42],
[3, 8, 12, 17, 25, 30, 41, 43],
[9, 11, 18, 24, 31, 40, 44, 53],
[10, 19, 23, 32, 39, 45, 52, 54],
[20, 22, 33, 38, 46, 51, 55, 60],
[21, 34, 37, 47, 50, 56, 59, 61],
[35, 36, 48, 49, 57, 58, 62, 63],
]
self.idct_precision = 8
self.idct_table = [
[
(self.NormCoeff(u) * math.cos(((2.0 * x + 1.0) * u * math.pi) / 16.0))
for x in range(self.idct_precision)
]
for u in range(self.idct_precision)
]
def NormCoeff(self, n):
if n == 0:
return 1.0 / math.sqrt(2.0)
else:
return 1.0
def rearrange_using_zigzag(self):
for x in range(8):
for y in range(8):
self.zigzag[x][y] = self.base[self.zigzag[x][y]]
return self.zigzag
def perform_IDCT(self):
out = [list(range(8)) for i in range(8)]
for x in range(8):
for y in range(8):
local_sum = 0
for u in range(self.idct_precision):
for v in range(self.idct_precision):
local_sum += (
self.zigzag[v][u]
* self.idct_table[u][x]
* self.idct_table[v][y]
)
out[y][x] = local_sum // 4
self.base = out
ã¯ã©ã¹ãåæããŠã¿ãŸããã
IDCT
ã MCUãæœåºãããšãå±æ§ã«æ ŒçŽãããŸãbase
ã次ã«ãã¡ãœããã䜿çšããŠãžã°ã¶ã°ã¹ãã£ã³ãããŒã«ããã¯ããããšã«ãããMCUãããªãã¯ã¹ãå€æããŸãrearrange_using_zigzag
ãæåŸã«ãã¡ãœãããåŒã³åºããŠé¢æ£ã³ãµã€ã³å€æãããŒã«ããã¯ãperform_IDCT
ãŸãã
ãåç¥ã®ããã«ãDCããŒãã«ã¯åºå®ãããŠããŸãã DCTãã©ã®ããã«æ©èœãããã«ã€ããŠã¯èæ ®ããŸãããããã¯ãããã°ã©ãã³ã°ãããæ°åŠã«é¢é£ããŠããŸãããã®ããŒãã«ãã°ããŒãã«å€æ°ãšããŠä¿åããå€ã®ãã¢ãç §äŒã§ããŸã
x,y
ãIDCT
ããã¹ããèªã¿ãããããããã«ãããŒãã«ãšãã®èšç®ãã¯ã©ã¹ã«å
¥ããããšã«ããŸãããå€æãããMCUãããªãã¯ã¹ã®åèŠçŽ ã«å€ãä¹ç®ããidc_variable
ãYãCrãããã³Cbã®å€ãååŸãããŸãã
ããã¯ãã¡ãœãããè¿œå ãããšããæ確ã«ãªã
BuildMatrix
ãŸãã
ãžã°ã¶ã°ããŒãã«ã次ã®ããã«å€æŽãããšã次ã®ããã«ãªããŸãã
[[ 0, 1, 5, 6, 14, 15, 27, 28],
[ 2, 4, 7, 13, 16, 26, 29, 42],
[ 3, 8, 12, 17, 25, 30, 41, 43],
[20, 22, 33, 38, 46, 51, 55, 60],
[21, 34, 37, 47, 50, 56, 59, 61],
[35, 36, 48, 49, 57, 58, 62, 63],
[ 9, 11, 18, 24, 31, 40, 44, 53],
[10, 19, 23, 32, 39, 45, 52, 54]]
ãã®çµæãåŸãããŸãïŒå°ããªã¢ãŒãã£ãã¡ã¯ãã«æ³šæããŠãã ããïŒïŒ
ãããŠãåæ°ãããã°ããžã°ã¶ã°ããŒãã«ãããã«å€æŽã§ããŸãã
[[12, 19, 26, 33, 40, 48, 41, 34,],
[27, 20, 13, 6, 7, 14, 21, 28,],
[ 0, 1, 8, 16, 9, 2, 3, 10,],
[17, 24, 32, 25, 18, 11, 4, 5,],
[35, 42, 49, 56, 57, 50, 43, 36,],
[29, 22, 15, 23, 30, 37, 44, 51,],
[58, 59, 52, 45, 38, 31, 39, 46,],
[53, 60, 61, 54, 47, 55, 62, 63]]
ãã®å Žåãçµæã¯æ¬¡ã®ããã«ãªããŸãã
ç§ãã¡ã®æ¹æ³ãå®æãããŸããã
BuildMatrix
ïŒ
def DecodeNumber(code, bits):
l = 2**(code-1)
if bits>=l:
return bits
else:
return bits-(2*l-1)
class JPEG:
# -----
def BuildMatrix(self, st, idx, quant, olddccoeff):
i = IDCT()
code = self.huffman_tables[0 + idx].GetCode(st)
bits = st.GetBitN(code)
dccoeff = DecodeNumber(code, bits) + olddccoeff
i.base[0] = (dccoeff) * quant[0]
l = 1
while l < 64:
code = self.huffman_tables[16 + idx].GetCode(st)
if code == 0:
break
# The first part of the AC quantization table
# is the number of leading zeros
if code > 15:
l += code >> 4
code = code & 0x0F
bits = st.GetBitN(code)
if l < 64:
coeff = DecodeNumber(code, bits)
i.base[l] = coeff * quant[l]
l += 1
i.rearrange_using_zigzag()
i.perform_IDCT()
return i, dccoeff
ãŸããé¢æ£ã³ãµã€ã³å€æå転ã¯ã©ã¹ïŒ
IDCT()
ïŒãäœæããŸãã次ã«ãããŒã¿ããããã¹ããªãŒã ã«èªã¿èŸŒã¿ããããã³ããŒãã«ã䜿çšããŠãã³ãŒãããŸãã
self.huffman_tables[0]
ãããŠself.huffman_tables[1]
ããããããèŒåºŠåã³åœ©åºŠã®ããã®DCããŒãã«ãåç
§ããself.huffman_tables[16]
ãããŠself.huffman_tables[17]
ãããããlumaåã³chromaã®ããã®ACããŒãã«ãåç
§ããŸãã
ãããã¹ããªãŒã ããã³ãŒãããåŸãé¢æ°ã䜿çšã
DecodeNumber
ãŠæ°ãããã«ã¿ã³ãŒãåãããDCä¿æ°ãæœåºããããolddccoefficient
ã«è¿œå ããŠãã«ã¿ãã³ãŒããããDCä¿æ°ãååŸããŸãã
次ã«ãéååãããªãã¯ã¹ã®ACå€ã䜿çšããŠåããã³ãŒãæé ãç¹°ãè¿ããŸããã³ãŒãã®æå³
0
ãããã¯ã®çµããïŒEOBïŒããŒã«ãŒã«å°éããåæ¢ããå¿
èŠãããããšã瀺ããŸããããã«ãACéååããŒãã«ã®æåã®éšåã¯ãå
è¡ãŒããããã€ãããã瀺ããŠããŸããããã§ã¯ãã·ãªãŒãºã®é·ãã®ã³ãŒãã£ã³ã°ã«ã€ããŠèŠããŠãããŸãããããã®ããã»ã¹ãéã«ããŠããããã®å€ãã®ãããããã¹ãŠã¹ãããããŸããããã¯ã©ã¹ã§ã¯ãIDCT
æ瀺çã«ãŒããå²ãåœãŠãããŸãã
MCUã®DCå€ãšACå€ããã³ãŒãããåŸãMCUãå€æãããåŒã³åºããŠãžã°ã¶ã°ã¹ãã£ã³ãå転ã
rearrange_using_zigzag
ãŸãã次ã«ãDCTãå転ããŠããã³ãŒããããMCUã«é©çšããŸãã
ãã®ã¡ãœãã
BuildMatrix
ã¯ãå転ãããDCTãããªãã¯ã¹ãšDCä¿æ°ã®å€ãè¿ããŸããããã¯ã1ã€ã®æå°8x8ãšã³ã³ãŒãã£ã³ã°ãŠãããã®ã¿ã®ãããªãã¯ã¹ã«ãªãããšã«æ³šæããŠãã ããããã¡ã€ã«å
ã®ä»ã®ãã¹ãŠã®MCUã«å¯ŸããŠãããå®è¡ããŸãããã
ç»é¢ã«ç»åã衚瀺ãã
ããã§ã¯ãã¡ãœããå ã®ã³ãŒãã§
StartOfScan
Tkinter Canvasãäœæãããã³ãŒãåŸã«åMCUãæç»ããŠã¿ãŸãããã
def Clamp(col):
col = 255 if col>255 else col
col = 0 if col<0 else col
return int(col)
def ColorConversion(Y, Cr, Cb):
R = Cr*(2-2*.299) + Y
B = Cb*(2-2*.114) + Y
G = (Y - .114*B - .299*R)/.587
return (Clamp(R+128),Clamp(G+128),Clamp(B+128) )
def DrawMatrix(x, y, matL, matCb, matCr):
for yy in range(8):
for xx in range(8):
c = "#%02x%02x%02x" % ColorConversion(
matL[yy][xx], matCb[yy][xx], matCr[yy][xx]
)
x1, y1 = (x * 8 + xx) * 2, (y * 8 + yy) * 2
x2, y2 = (x * 8 + (xx + 1)) * 2, (y * 8 + (yy + 1)) * 2
w.create_rectangle(x1, y1, x2, y2, fill=c, outline=c)
class JPEG:
# -----
def StartOfScan(self, data, hdrlen):
data,lenchunk = RemoveFF00(data[hdrlen:])
st = Stream(data)
oldlumdccoeff, oldCbdccoeff, oldCrdccoeff = 0, 0, 0
for y in range(self.height//8):
for x in range(self.width//8):
matL, oldlumdccoeff = self.BuildMatrix(st,0, self.quant[self.quantMapping[0]], oldlumdccoeff)
matCr, oldCrdccoeff = self.BuildMatrix(st,1, self.quant[self.quantMapping[1]], oldCrdccoeff)
matCb, oldCbdccoeff = self.BuildMatrix(st,1, self.quant[self.quantMapping[2]], oldCbdccoeff)
DrawMatrix(x, y, matL.base, matCb.base, matCr.base )
return lenchunk+hdrlen
if __name__ == "__main__":
from tkinter import *
master = Tk()
w = Canvas(master, width=1600, height=600)
w.pack()
img = JPEG('profile.jpg')
img.decode()
mainloop()
é¢æ°
ColorConversion
ãšããå§ããŸãããClamp
ãColorConversion
YãCrãCbã®å€ãåããåŒã§RGBæåã«å€æããéèšããRGBå€ãåºåããŸãããªããããã«128ãè¿œå ããã®ã§ããïŒJPEGã¢ã«ãŽãªãºã ã®åã«ãDCTãMCUã«é©çšãããã«ã©ãŒå€ãã128ãæžç®ããããšãå¿ããªãã§ãã ãããè²ãå
ã
[0.255]ã®ç¯å²ã«ãã£ãå ŽåãJPEGã¯ãããã[-128ã+ 128]ã®ç¯å²ã«é
眮ããŸãããã³ãŒãæã«ãã®ãšãã§ã¯ããããŒã«ããã¯ããå¿
èŠããããããRGBã«128ãè¿œå ããŸããClamp
é梱æã«ãçµæã®å€ã¯ãç¯å²[0.255]ã®å€ã«è¡ãããšããç§ãã¡ã¯[0.255]ãã®ç¯å²ã«ä¿ç®¡ããŠãã ããã
æ¹æ³ã§
DrawMatrix
YãCrãCbã®ãã³ãŒããããå8x8ãããªãã¯ã¹ãã«ãŒãããåãããªãã¯ã¹èŠçŽ ãRGBå€ã«å€æããŸããå€æåŸcanvas
ãã¡ãœããã䜿çšããŠTkinterã§ãã¯ã»ã«ãæç»ããŸãcreate_rectangle
ããã¹ãŠã®ã³ãŒãã¯GitHubã«ãããŸããå®è¡ãããšãç§ã®é¡ãç»é¢ã«è¡šç€ºãããŸãã
çµè«
ç§ã®é¡ãèŠããããã«ã¯ã6,000èªä»¥äžã®èª¬æãæžããªããã°ãªããªããšèª°ãæã£ãã§ããããããã€ãã®ã¢ã«ãŽãªãºã ã®äœè ãã©ãã»ã©è³¢ãã£ããã¯é©ãã¹ãããšã§ãïŒããªããèšäºã楜ããã ããšãæã¿ãŸãããã®ãã³ãŒããŒãæžããŠããéãç§ã¯å€ããåŠã³ãŸãããåçŽãªJPEGç»åã®ãšã³ã³ãŒãã«ããã»ã©å€ãã®èšç®ãå¿ èŠã ãšã¯æããŸããã§ããã次åã¯ãPNGïŒãŸãã¯å¥ã®åœ¢åŒïŒçšã®ãã³ãŒããŒãäœæããŠã¿ãããšãã§ããŸãã
è¿œå è³æ
詳现ã«èå³ãããå Žåã¯ãç§ãèšäºãæžãããšãã«äœ¿çšããè³æãšãããã€ãã®è¿œå ã®äœæ¥ãèªãã§ãã ããã
- JPEG解æã®å³è§£ã¬ã€ã
- JPEGã§ã®ãããã³ãšã³ã³ãŒãã£ã³ã°ã«é¢ããéåžžã«è©³çŽ°ãªèšäº
- C ++ã§ç°¡åãªJPEGã©ã€ãã©ãªãäœæãã
- Python3ã®structã®ããã¥ã¡ã³ã
- FBãJPEGã®ç¥èãã©ã®ããã«æŽ»çšããã
- JPEGã®ã¬ã€ã¢ãŠããšãã©ãŒããã
- JPEGãã©ã¬ã³ãžãã¯ã«é¢ããèå³æ·±ãDoDãã¬ãŒã³ããŒã·ã§ã³