這真的是見鬼了
我家阿坤已經連續好一陣子
都是禮拜二早上晃進來一下
問我有沒有問題
接著就不見人影
跑回辦公室去喝咖啡聊天了
下午小黃的課
反正我也不是重點
只不過是選課的人頭之一
之前還實驗我可以消失多久老師不會發現
都測試到一節課半
想說超過兩節課的話
就可以開始計畫
要利用這段時間做什麼事情了
因為我那個interval和MCU 與data unit的關係
還是不太清楚
所以我程式還是會出錯
昨天做了投影片
有點擔心這樣的進度老闆不會滿意
還偷偷的祈禱
Dr.Bell不要太早走
根據家醜不外揚的法則
只要Dr.Bell還在
老闆應該不會當眾罵出來
誰知道他今天來喝個咖啡之後
就說他要回去改期中考考卷了
噗
事情再壞一定會更糟是吧
真是酷斃了
本來還拼命練習用英文報告投影片
這下Dr.Bell不在
用英文對著一堆中國人講話很奇怪耶
本來想說小黃還沒回來
可以等等在開始
可是阿坤說反正我是講JPEG 小黃不在沒關係
所以我就硬著頭皮上台報告了
BOSS今天心情好像還不錯
有耐著性子聽我講話
我有跟他說我覺得問題是出在哪邊
可是我現在還沒辦法確定
老師還拿我那本規格書去翻
"可欣你最近都仔細看規格書齁"
屙...
薑果然是老的辣
真是一針見血
可是他還是有翻耶
如果是以前他早就生氣跑掉叫我再多看幾遍了
之後討論了一下
老闆有提到想用Group基金出總審專刊給高中生看的事情
然後發票要開什麼時候之類的
我怕忘記
就馬上跑下去跟書雯說
結果在系辦聊了二十分鐘
回來的時候
阿梅跟我說剛剛下去真久
老闆有怨念
"可欣咧 怎麼還沒回來 去哪裡了"
(阿我不是跟你說我去系辦嗎...囧)
"一天到晚跑去系辦鬼混 都不知道誰是他老闆了齁!!"
這句怨念就深了
之後就開始改程式
改好的時候有遇到一點問題
我解出來的值啊
跟我用程式壓縮的值
有些會不一樣耶
不是全不都不一樣
也不是差很多
都差一點點而已(1或2吧)
剛好老闆晃進來
就把他拉過來看了
真難得他願意坐過來我旁邊看耶
之前還說他不想在小螢幕看程式
硬是要投影出來的
不過他有說
這種情況是可能的
因為我不知道photoshop在quantized的時候
是怎麼決定進位
比較好的作法是
將原本的bmp檔
用PhotoImapct再存一次
看是不是也會差一點
接下來的動作
就是requantized ,ReDCT ,color transform and draw the Image了
然後
再多試幾個graylevel的圖
關於color transform
我有問老師那我CbCr的值要怎麼給
你怎麼那麼死腦筋
啊就直接把Y值填入就好了啊
這不是灰階嗎 等這個成功
以後要做三個component的時候
再考慮那個問題吧!!
阿哈哈哈
我還是要調整心態啊
不要一直想讓程式寫成一次for all case的
關於MCU DRI RSTm 那邊
我可能要再多看幾個例子
才會懂吧XDD
星期二, 11月 27, 2007
[日誌]久違的網誌
最近很忙啊
寫程式 交報告 修電腦
聽學長proposal
都沒時間好好寫網誌
連篇研究日誌都沒寫
今天去餵鄭小白的時候
發現了這串文字
"2007/11/24 ■RSS取得中に時間切れになりました。ブログサーバーがメンテナンス中か、RSSのURLが間違っている可能性があります。"
噗哈哈
太久沒寫
她以為我網址設錯嗎!!
其實我看不懂日文
不過我上次很久沒寫也有這樣的東西出現
"2007/11/02 ■RSS取得中に時間切れになりました。ブログサーバーがメンテナンス中か、RSSのURLが間違っている可能性があります。"
根據經驗法則
就套進去一樣的意思亂翻了XD
剛剛做完明天要跟Dr.Bell咪聽的ppt
這時候室友就很好用了
尤其是外國人室友
可以很順利的聽我練習用英文報告XDD
在我不知道要講什麼字或發音錯誤的時候跟我講
真開心
我現在的問題
應該是在那個DRI和MCU之間的關係沒搞懂
所以程式不知道怎麼下手
不過就算我今天不睡應該也寫不完
所以就上來寫個網誌
早點睡比較實際
明天可以比較有精神報告
其實我有點擔心這樣的進度有點少
可是Boss的網誌我看不懂
嘖嘖嘖
還是自己多思考看看好了XD
寫程式 交報告 修電腦
聽學長proposal
都沒時間好好寫網誌
連篇研究日誌都沒寫
今天去餵鄭小白的時候
發現了這串文字
"2007/11/24 ■RSS取得中に時間切れになりました。ブログサーバーがメンテナンス中か、RSSのURLが間違っている可能性があります。"
噗哈哈
太久沒寫
她以為我網址設錯嗎!!
其實我看不懂日文
不過我上次很久沒寫也有這樣的東西出現
"2007/11/02 ■RSS取得中に時間切れになりました。ブログサーバーがメンテナンス中か、RSSのURLが間違っている可能性があります。"
根據經驗法則
就套進去一樣的意思亂翻了XD
剛剛做完明天要跟Dr.Bell咪聽的ppt
這時候室友就很好用了
尤其是外國人室友
可以很順利的聽我練習用英文報告XDD
在我不知道要講什麼字或發音錯誤的時候跟我講
真開心
我現在的問題
應該是在那個DRI和MCU之間的關係沒搞懂
所以程式不知道怎麼下手
不過就算我今天不睡應該也寫不完
所以就上來寫個網誌
早點睡比較實際
明天可以比較有精神報告
其實我有點擔心這樣的進度有點少
可是Boss的網誌我看不懂
嘖嘖嘖
還是自己多思考看看好了XD
星期四, 10月 18, 2007
[不爽]在搞什麼鬼啊
幹幹幹幹幹
好不容易財產快點完了
RFID剩下7個TAG和一個SD reader找不到
也跑去隔壁留言給學長
請他看到跟我聯絡
想說晚上跟學姐去吃飯
之後回實驗室
一鼓作氣的衝程式
雖然知道不可能今天寫完全部
可是還是想把interleaved那邊給KO掉
最好是寫到IDCT那邊
誰知道寫寫寫
想說換張圖片測試
竟然給我跑出bug
還不是每張圖都會跑出來
這下囧了
開始陷入抓蟲地獄
一行一行的看
終於發現是zigzagX裡面的數不對造成的問題
可是我明明zigzagX就有給初值啊
很好
開始從syntax開始看
哈哈哈
在DQT(i)這個function之後
zigzagX 這個陣列
就偷偷的被改變了
機耶
沒差
那我在block function一開始的時候
再給zigzagX一次初值
哼
這樣就耗掉我美好的夜晚時光
機機機機
我竟然還停在block那邊
好想掀桌喔!!!
好不容易財產快點完了
RFID剩下7個TAG和一個SD reader找不到
也跑去隔壁留言給學長
請他看到跟我聯絡
想說晚上跟學姐去吃飯
之後回實驗室
一鼓作氣的衝程式
雖然知道不可能今天寫完全部
可是還是想把interleaved那邊給KO掉
最好是寫到IDCT那邊
誰知道寫寫寫
想說換張圖片測試
竟然給我跑出bug
還不是每張圖都會跑出來
這下囧了
開始陷入抓蟲地獄
一行一行的看
終於發現是zigzagX裡面的數不對造成的問題
可是我明明zigzagX就有給初值啊
很好
開始從syntax開始看
哈哈哈
在DQT(i)這個function之後
zigzagX 這個陣列
就偷偷的被改變了
機耶
沒差
那我在block function一開始的時候
再給zigzagX一次初值
哼
這樣就耗掉我美好的夜晚時光
機機機機
我竟然還停在block那邊
好想掀桌喔!!!
星期一, 10月 08, 2007
[日誌]衝了
掙扎了很久
終於決定把程式碼重寫一遍
為了以後程式的發展著想
還是寫一下比較好
不然debug都要超久的!!!
X的 今天我就要衝了
徹夜跟他奮戰
小黑幫我加油!!!
以下是噁心的舊的程式碼
(我貼來衝字數的....)
沒事千萬不要看
會頭暈的!!!!
敬請期待新的程式碼!!
//---------------------------------------------------------------------------
#include
#include
#include
#include//檔案處理需要用到
#include
#include
#include "IdGlobal.hpp"//IntToBin()函數要用到
using namespace std;
int size;
int* memblock;
int i,j;
int tempI1;
int tempLength;
int Bits[17];//L1~L16
int LastK[2][2],Tc,Th;
int *Huffsize[2][2],*Huffcode[2][2],**Huffcodebin[2][2],*eHufco[2][2],*eHufsize[2][2],huffmancode_number = 0;
int *HuffVal[2][2];
String tempS1,tempS2,sFileName,*sHuffcode[2][2];
ifstream input;
ofstream output;
int treesize;
int NodeNum = 0;
int num = 0;
class node
{
public:
int data;
int Number;
node *left;
node *right;
node();
/*
if data == -1 表示這只是個中間節點
else data == symbol value;
*/
};
node::node()
{
left=NULL;
right=NULL;
}
class Tree
{
private:
node *root;
int *KeyBin;
public:
Tree();
void insert(int Symbol,int huffmancode,int codelength);
String Print();
String visit(node *s);
};
Tree::Tree()
{
root=NULL;
}
void Tree::insert(int Symbol,int huffmancode,int codelength)
{
if(root == NULL)
{
//表示沒有任何節點->建立一個新的節點
root = new node;
root->Number = NodeNum;
NodeNum++;
root->right = NULL;
root->left = NULL;
}
node *p,*r;
if(codelength != 0)
{
p = root; //p 現在的Node
int bit;
int tempTCode,Ta,length,i = 0;
tempTCode = huffmancode;
int *huffBin;
huffBin = new int[codelength];
length = codelength;
while(length > 0)
{
Ta = tempTCode / 2;
bit = tempTCode - 2 * Ta; // b = 判斷bit
huffBin[codelength - i -1] = bit;
tempTCode = Ta; // 取下一個判斷的bit
length--;
i++;
}
for(i = 0;i < codelength;i++)
{
bit = huffBin[i];
if(bit == 0)//判斷要往左邊(bit == 0)
{
if(p->left != NULL)
{
p->data = -1;
p = p->left;
}
else
{
p->data = -1;
r = new node;
r->Number = NodeNum;
NodeNum++;
r->right = NULL;
r->left = NULL;
p->left = r;
p = r;
r = NULL;
}
}
else if(bit == 1)//判斷要往右邊(bit == 1)
{
if(p->right != NULL)
{
p->data = -1;
p = p->right;
}
else
{
p->data = -1;
r = new node;
r->Number = NodeNum;
NodeNum++;
r->right = NULL;
r->left = NULL;
p->right = r;
p = r;
r = NULL;
}
}
}
p->data = Symbol; //p->Number
p = NULL;
}
}
String Tree::visit(node* s)
{
String VisitS,LeftS,RightS;
VisitS += "節點編號 = " + AnsiString(s->Number);
VisitS += ",data = " + AnsiString(s->data);
if (s->left != NULL)
VisitS += ",左節點=" + AnsiString(s->left->Number);
if (s->right != NULL)
VisitS += ",右節點 =" + AnsiString(s->right->Number);
VisitS += " \n";
if (s->left != NULL)
LeftS = visit(s->left);
if (s->right != NULL)
RightS = visit(s->right);
return VisitS + LeftS + RightS ;
}
String Tree::Print()
{
node *p;
p = root;
String tempS ="";
int i = 0;
tempS += visit(p);
return tempS;
}
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
Tree DC0,DC1,AC0,AC1;
//---------------------------------------------------------------------------
void itob(int Tc,int Th,int GCT)
{
int tempindex = Huffsize[Tc][Th][GCT] - 1;
int tempLength = Huffsize[Tc][Th][GCT];
int tempCode = Huffcode[Tc][Th][GCT];
int tempbin = 0;
String tempSSS;
sHuffcode[Tc][Th][GCT] = " ";
while( tempindex >= 0)
{
if(tempCode >= 0)
tempbin = tempCode % 2;
else
tempbin = 0;
Huffcodebin[Tc][Th][GCT][tempindex] = tempbin;
tempCode = tempCode / 2;
tempindex = tempindex - 1;
}
}
void aaa(int begQ)
{
int aaai;
tempS2 += "PqTq=" + IntToHex(memblock[begQ],2) + "\n";
for(aaai = 1; aaai < 65; aaai++)
{
tempS2 += "Q(";
if(aaai < 11)
tempS2 += "0";
tempS2 += AnsiString(aaai-1) + ")=" + IntToHex(memblock[begQ+aaai],2) + " ";
if((aaai-1) % 8 == 7)
tempS2 +="\n";
}
}
int huffLi(int begH)
{
int temoLiCount,countreturn = 0;
tempS2 += "TcTh=" + IntToHex(memblock[begH],2) + "\n";
if(memblock[begH]/16 ==0) //Tc == 0
{
Tc = 0;
tempS2 += "Tc = 0 - - - - - - > DC Table or lossless table. ";
}
else if(memblock[begH]/16 ==1) //Tc == 1
{
Tc = 1;
tempS2 += "Tc = 1 - - - - - - > AC Table. ";
}
if(memblock[begH]%16 == 0) //Th == 0
{
Th = 0;
tempS2 += "Th = 0\n";
}
else if(memblock[begH]%16 == 1) //Th == 0
{
Th = 1;
tempS2 += "Th = 1\n";
}
for(temoLiCount = 1; temoLiCount < 17; temoLiCount++)
{
Bits[temoLiCount] = memblock[begH+temoLiCount];
tempS2 += "L(";
if(temoLiCount < 10)
tempS2 += "0";
tempS2 += AnsiString(temoLiCount) + ")= ";
tempS2 += "(Hex) " + IntToHex(memblock[begH+temoLiCount],2) +" = (DEC) "+ AnsiString(memblock[begH+temoLiCount])+" ";
countreturn += memblock[begH+temoLiCount];
if(temoLiCount % 2 == 0)
tempS2 += "\n";
}
return countreturn;
}
void Generate_size_table(int LiCount,int Tc,int Th)
{
int GSTK = 0, GSTL = 1,GSTJ = 1;
Huffsize[Tc][Th] = new int[LiCount+1];
for(GSTL = 1;GSTL < 17;GSTL++)
{
while(GSTJ <= Bits[GSTL])
{
Huffsize[Tc][Th][GSTK] = GSTL;
//tempS2 += "Huffsize(" + AnsiString(GSTK) + ")=" + AnsiString(GSTL) +"\n";
GSTJ++;
GSTK++;
}
GSTJ = 1;
}
Huffsize[Tc][Th][GSTK] = 0;
//tempS2 += "Huffsize(" + AnsiString(GSTK) + ")= 0, ";
LastK[Tc][Th]= GSTK;
tempS2 += "根據L1~L16產生的huffcode在隔壁頁囉,這裡的LASTK = "+ AnsiString(LastK[Tc][Th]) + "\n";
}
void Generate_code_table(int LiCount,int Tc,int Th)
{
int GCTK = 0, GCTSI = Huffsize[Tc][Th][0],GCTCODE = 0;
Huffcode[Tc][Th] = new int [LiCount+1];
sHuffcode[Tc][Th] = new String [LiCount+1];
Huffcodebin[Tc][Th] = new int* [LiCount+1];
HuffVal[Tc][Th] = new int[LiCount+1];
while(Huffsize[Tc][Th][GCTK] != 0)
{
while(Huffsize[Tc][Th][GCTK] == GCTSI)
{
Huffcode[Tc][Th][GCTK] = GCTCODE;
//tempS2 += "Huffcode(" + AnsiString(GCTK) + ")=" + AnsiString(GCTCODE) +"\n";
Huffcode[Tc][Th][GCTK] = GCTCODE;
Huffcodebin[Tc][Th][GCTK] = new int [Huffsize[Tc][Th][GCTK]];//為了每個Huffcode準備好相對應的陣列
itob(Tc,Th,GCTK);
GCTCODE = GCTCODE +1;
GCTK = GCTK +1;
}
if(Huffsize[Tc][Th][GCTK] != 0)
{
while(Huffsize[Tc][Th][GCTK] != GCTSI)
{
GCTCODE = GCTCODE *2;
GCTSI = GCTSI + 1;
}
}
}
Huffcode[Tc][Th][GCTK] = GCTCODE;
}
void Order_codes(int LiCount,int Tc,int Th)
{
}
void HuffmanTable(int begH,int LiCount,int Tc,int Th)
{
int tempLi,tempi,tempj,tempcount = LiCount;
int HMTK = 0;
for(tempi = 0;tempi < 16;tempi++)
{
tempLi = memblock[begH + tempi];
tempj =1;
while(tempj <= tempLi)
{
tempS2 += "V(" + AnsiString(tempi + 1) + "," + AnsiString(tempj)+") = " + IntToHex(memblock[begH + 16 + LiCount - tempcount],2) + " ";
HuffVal[Tc][Th][HMTK] = memblock[begH + 16 + LiCount - tempcount];
if(tempj == tempLi)
tempS2 += "\n";
HMTK++;
tempj++;
tempcount--;
}
}
}
void DQT(int begQ,int qLength)
{
int tempDQT = 0;
tempS2 += "Lq = 16進位的" + IntToHex(qLength,4) + " = 十進位的 " + AnsiString(qLength) + "\n";
qLength -= 2; //扣掉 qLength 的2個byte;
begQ +=2; //skip掉 qLength 的2個byte;
while(qLength > 1 )
{
tempS2 += " - - - - - -- - - - - - - - Qt- - - - - - - - - - - - - - - - - - \n";
aaa(begQ);
begQ = begQ + 65;//一組量化表 = 65個BYTE (PqTq + 64 個element)
qLength = qLength - 65;
}
}
void SOS(int begS,int sLength)
{
int Ns,tempSi = 1,TdTa,Td,Ta;
tempS2 += "Ls = " + IntToHex(sLength,4) + "(十六進位) = 十進位的 " + AnsiString(sLength) + "\n";
tempS2 += "Ns = " + IntToHex(memblock[begS+2],2) + "\n";
Ns = memblock[begS+2];
sLength -= 3; //扣掉 sLength 的2個byte;
begS += 3; //skip掉 sLength 的2個byte;
int wahaha = 0;
// while(sLength > 0)
// {
while(tempSi <= Ns)
{
tempS2 += "Cs" + AnsiString(tempSi)+ " = " + IntToHex(memblock[begS],2)+ " ";
tempS2 += "Td" + AnsiString(tempSi) + "Ta" + AnsiString(tempSi) +" = "+ IntToHex(memblock[begS+1],2)+"\n";
TdTa = memblock[begS+1];
Td = TdTa /16;
Ta = TdTa %16;
tempS2 += "Td" + AnsiString(tempSi) +" = " + AnsiString(Td)+ " --> 選擇了第"+ AnsiString(Td) + "個 DC Entropy table\n";
tempS2 += "Ta" + AnsiString(tempSi) +" = " + AnsiString(Ta)+ " --> 選擇了第"+ AnsiString(Ta) + "個 AC Entropy table\n";
sLength -=2;
begS +=2;
tempSi++;
}
tempS2 += "Ss = " +IntToHex(memblock[begS],2) +"\n";
tempS2 += "Se = " +IntToHex(memblock[begS+1],2) +"\n";
tempS2 += "AhAl = " +IntToHex(memblock[begS+2],2) +"\n";
begS = begS +3;
sLength = sLength +3;
//}
tempS2 += "- - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - \n";
}
void DHT(int begH,int hLength)
{
int tempDHT = 0,LiCount;
tempS2 += "Lh = 16進位的 " + IntToHex(hLength,4) + " = 十進位的 " + AnsiString(hLength) + "\n";
hLength -= 2;
begH += 2;
//tempS2 += "\nbegH = " + AnsiString(begH) + "\nhLength = " + AnsiString(hLength);
while(hLength > 1)
{
//算L1~L16的數量
tempS2 += "第" + AnsiString(huffmancode_number + 1) + "個huffmantable.\n";
LiCount = 0;
LiCount = huffLi(begH); //Licount = L1 ~ L16 的值相加
Generate_size_table( LiCount,Tc,Th);
Generate_code_table(LiCount,Tc,Th);
Order_codes(LiCount,Tc,Th);
huffmancode_number++;
HuffmanTable(begH+1,LiCount,Tc,Th);//根據Li的數量去產生Vij.加上1是因為TcTh佔了1byte;
begH += (LiCount+17); //用來skip上面那行指令--> HuffmanTable(begH)
hLength -=(17 + LiCount);
hLength = hLength;
//tempS2 += "\nbegH = " + AnsiString(begH) + "\nhLength = " + AnsiString(hLength) + "\nLiCount = " + AnsiString(LiCount);
}
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Open1Click(TObject *Sender)
{
if(OpenPictureDialog1->Execute())
{
String tempT;
char ch;
tempI1 = 0;
int tempI2 = 0,tempget;
sFileName = OpenPictureDialog1->FileName;
TJPEGImage* Jpg = new TJPEGImage;
Jpg->LoadFromFile(sFileName);
Image1->Picture->Bitmap->Assign(Jpg);
input.open(sFileName.c_str(),ios::binary|ios::in|ios::ate);
if(!input)
{
ShowMessage(" ");
}
size = input.tellg();
memblock = new int [size];
input.seekg (0, ios::beg);
tempget = input.get();
tempT = IntToHex(tempget,2);
while(!input.eof())
{
tempS1 += tempT + " ";
memblock[tempI2] = tempget;
tempI1++;
tempI2++;
tempget = input.get();
tempT = IntToHex(tempget,2);
/*if(tempget == 0xff)
tempget = tempget;
*/
if(tempI1 == 16)
{
tempS1 += "\n";
tempI1 = 0;
}
}
input.close();
Label1->Caption = AnsiString(tempS1);
Label2->Caption = AnsiString(tempI2);
}
Button1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
tempS2 = "-我是翻譯分隔線------------------------------------------------------------\n";
i = 0;
tempI1 = 0;
while(i < size)
{
if(memblock[i]== 0xff)
{
tempLength = 0;
if((memblock[i+1] >= 0xc0)&&(memblock[i+1] < 0xc4))
{
//(Start of Frame markers,non-differential,Huffman coding)
if(memblock[i+1] == 0xc0)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Baseline DCT(SOF0)";
if(memblock[i+1] == 0xc1)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Extended sequential DCT";
else if(memblock[i+1] == 0xc2)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Progressive DCT";
else if(memblock[i+1] == 0xc3)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Lossless(Sequential)\n";
tempS2 += "(Start of Frame markers,non-differential,Huffman coding)\n\n";
}
else if(memblock[i+1] == 0xcc)
{
//define arithmetic coding conditioning(s)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"--> Define arithmetic coding conditioning(s).";
tempS2 += "Arithmetic coding conditioning specification\n";
}
else if(memblock[i+1] == 0xc4)
{
//----FFC4:define Huffman table(s)
tempS2 += "\n"+ IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"--> Define Huffman table(s).\n";
tempLength = memblock[i+2]*256 + memblock[i+3];
tempS2 += "- - - - - - - - Huffman table 開始 - - - - - - - -\n";
DHT(i+2,tempLength);
tempS2 += "-- - - - - - - - Huffman table 結束 - - - - - - - -\n";
}
else if((memblock[i+1] >= 0xc5)&& (memblock[i+1] <= 0xC7))
{
if(memblock[i+1] == 0xc5)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential sequential DCT";
else if(memblock[i+1] == 0xc6)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential progressive DCT";
else if(memblock[i+1] == 0xc7)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential lossless(Sequential)";
tempS2 += "(Start of Frame markers,differential,Huffman coding)\n";
}
else if((memblock[i+1] >= 0xc8)&&(memblock[i+1] <= 0xcb))
{
if(memblock[i+1] == 0xc8)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->JPG:Reserved for JPEG extensions";
else if(memblock[i+1] == 0xc9)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Extended sequential DCT";
else if(memblock[i+1] == 0xca)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Extended sequential DCT";
else if(memblock[i+1] == 0xcb)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Lossless(Sequential)";
tempS2 += "(Start of Frame markers,non-differential,arithmetic coding)\n";
}
else if((memblock[i+1] >= 0xcd)&&(memblock[i+1] <= 0xcf))
{
if(memblock[i+1] == 0xcd)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential sequential DCT";
else if(memblock[i+1] == 0xce)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential progressive DCT";
else if(memblock[i+1] == 0xcf)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential lossless(Sequential)";
tempS2 += "(Start of Frame markers,differential,arithmetic coding)\n";
}
else if((memblock[i+1] >= 0xd0)&&(memblock[i+1] <= 0xd7))
{
tempS2 += "RSTm*:Restart with modulo 8 count m\n";
}
else if(memblock[i+1] == 0xd8)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Start of Image\n";
else if(memblock[i+1] == 0xd9)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->EOI:End of Image\n";
else if(memblock[i+1] == 0xda)
{
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->SOS:Start of Scan\n";
tempLength = memblock[i+2]*256 + memblock[i+3];
SOS(i+2,tempLength);
}
else if(memblock[i+1] == 0xdb)
{
//--FFDB:定義量化表-------------------------
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->DQT:Define quantization table\n";
tempLength = memblock[i+2]*256 + memblock[i+3];
tempS2 += "- - - - - - -- - - - - - - - Quqntization Table開始 - - - - - - - - - - - - - - - \n";
DQT(i+2,tempLength);
tempS2 += "- - - - - -- - - - - - - - Quqntization Table結束 - - - - - - - - - - - - - - \n";
}
else if(memblock[i+1] == 0xdc)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->DNL:Define number of line\n";
else if(memblock[i+1] == 0xdd)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->DRI:Define restart interval\n";
else if(memblock[i+1] == 0xde)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->DHP:Define hierarchical progression\n";
else if(memblock[i+1] == 0xdf)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->EXP:Expand reference component.\n";
else if((memblock[i+1] >= 0xe0)&&(memblock[i+1] <= 0xef))
{
//--我是給application的tag------------------------
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->我是給application的tag.\n";
tempLength = memblock[i+2]*256 + memblock[i+3];
tempS2 += " 要跳過" + AnsiString(tempLength)+ "個byte\n";
}
else if((memblock[i+1] >= 0xf0)&&(memblock[i+1] <= 0xfd))
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->reserved for JPEG extensions.\n";
else if(memblock[i+1] == 0xfe)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->COM:comment\n";
i = i + 2 + tempLength;
tempI1 = 0;
}
else
{
tempS2 += IntToHex((memblock[i]),2) + " ";
i++;
tempI1++;
if(tempI1 == 10)
{
tempS2 += "\n";
tempI1 = 0;
}
}
}
Label3->Caption = AnsiString(tempS2);
Button2->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
//int aaaaa = 127;
String sss;
StringGridDC_0->RowCount = LastK[0][0] + 1;
StringGridDC_1->RowCount = LastK[0][1] + 1;
StringGridAC_0->RowCount = LastK[1][0] + 1;
StringGridAC_1->RowCount = LastK[1][1] + 1;
int intCodeLength,intSymbol,intHuffcode;
int btnTemp= 0,btnTc,btnTh;
String tempSSS;
while( btnTemp< 4)
{
btnTc = btnTemp / 2;
btnTh = btnTemp % 2;
for(i = 0; i <= LastK[btnTc][btnTh];i++)
{
tempSSS = " ";
for(j = 0; j < Huffsize[btnTc][btnTh][i] ;j++)
{
tempSSS += AnsiString(Huffcodebin[btnTc][btnTh][i][j]);
}
sHuffcode[btnTc][btnTh][i] = tempSSS;
if(btnTemp == 0)//TcTh = 00--->DC0
{
StringGridDC_0->Cells[0][i+1] = AnsiString(i);
StringGridDC_0->Cells[1][i+1] = AnsiString(Huffsize[btnTc][btnTh][i]);
StringGridDC_0->Cells[2][i+1] = AnsiString(Huffcode[btnTc][btnTh][i]);
StringGridDC_0->Cells[3][i+1] = AnsiString(sHuffcode[btnTc][btnTh][i]);
StringGridDC_0->Cells[4][i+1] = AnsiString(HuffVal[btnTc][btnTh][i]);
DC0.insert(HuffVal[btnTc][btnTh][i],Huffcode[btnTc][btnTh][i],Huffsize[btnTc][btnTh][i]);
}
if(btnTemp == 1)//TcTh = 01--->DC1
{
StringGridDC_1->Cells[0][i+1] = AnsiString(i);
StringGridDC_1->Cells[1][i+1] = AnsiString(Huffsize[btnTc][btnTh][i]);
StringGridDC_1->Cells[2][i+1] = AnsiString(Huffcode[btnTc][btnTh][i]);
StringGridDC_1->Cells[3][i+1] = AnsiString(sHuffcode[btnTc][btnTh][i]);
StringGridDC_1->Cells[4][i+1] = AnsiString(HuffVal[btnTc][btnTh][i]);
DC1.insert(HuffVal[btnTc][btnTh][i],Huffcode[btnTc][btnTh][i],Huffsize[btnTc][btnTh][i]);
}
if(btnTemp == 2)//TcTh = 10---->AC0
{
StringGridAC_0->Cells[0][i+1] = AnsiString(i);
StringGridAC_0->Cells[1][i+1] = AnsiString(Huffsize[btnTc][btnTh][i]);
StringGridAC_0->Cells[2][i+1] = AnsiString(Huffcode[btnTc][btnTh][i]);
StringGridAC_0->Cells[3][i+1] = AnsiString(sHuffcode[btnTc][btnTh][i]);
StringGridAC_0->Cells[4][i+1] = AnsiString(HuffVal[btnTc][btnTh][i]);
AC0.insert(HuffVal[btnTc][btnTh][i],Huffcode[btnTc][btnTh][i],Huffsize[btnTc][btnTh][i]);
}
if(btnTemp == 3)//TcTh = 11--->AC1
{
StringGridAC_1->Cells[0][i+1] = AnsiString(i);
StringGridAC_1->Cells[1][i+1] = AnsiString(Huffsize[btnTc][btnTh][i]);
StringGridAC_1->Cells[2][i+1] = AnsiString(Huffcode[btnTc][btnTh][i]);
StringGridAC_1->Cells[3][i+1] = AnsiString(sHuffcode[btnTc][btnTh][i]);
StringGridAC_1->Cells[4][i+1] = AnsiString(HuffVal[btnTc][btnTh][i]);
AC1.insert(HuffVal[btnTc][btnTh][i],Huffcode[btnTc][btnTh][i],Huffsize[btnTc][btnTh][i]);
}
}
btnTemp++;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
StringGridDC_0->ColWidths[0] = 35;
StringGridDC_1->ColWidths[0] = 35;
StringGridAC_0->ColWidths[0] = 35;
StringGridAC_1->ColWidths[0] = 35;
//--------------------------------------
StringGridDC_0->ColWidths[1] = 45;
StringGridDC_1->ColWidths[1] = 45;
StringGridAC_0->ColWidths[1] = 45;
StringGridAC_1->ColWidths[1] = 45;
//----------------------------------------
StringGridDC_0->ColWidths[2] = 50;
StringGridDC_1->ColWidths[2] = 50;
StringGridAC_0->ColWidths[2] = 50;
StringGridAC_1->ColWidths[2] = 50;
//----------------------------------------
StringGridDC_0->ColWidths[3] = 110;
StringGridDC_1->ColWidths[3] = 110;
StringGridAC_0->ColWidths[3] = 110;
StringGridAC_1->ColWidths[3] = 110;
//------------------------------------------
StringGridDC_0->ColWidths[4] = 120;
StringGridDC_1->ColWidths[4] = 120;
StringGridAC_0->ColWidths[4] = 120;
StringGridAC_1->ColWidths[4] = 120;
//------------------------------------------
StringGridDC_0->Cells[0][0] = "DC_0";
StringGridDC_0->Cells[1][0] = "Huffsize";
StringGridDC_0->Cells[2][0] = "Huffcode";
StringGridDC_0->Cells[3][0] = "Huffcode(binary)";
StringGridDC_0->Cells[4][0] = "HuffVal";
//------------------------------------------
StringGridDC_1->Cells[0][0] = "DC_1";
StringGridDC_1->Cells[1][0] = "Huffsize";
StringGridDC_1->Cells[2][0] = "Huffcode";
StringGridDC_1->Cells[3][0] = "Huffcode(binary)";
StringGridDC_1->Cells[4][0] = "HuffVal";
//------------------------------------------
StringGridAC_0->Cells[0][0] = "AC_0";
StringGridAC_0->Cells[1][0] = "Huffsize";
StringGridAC_0->Cells[2][0] = "Huffcode";
StringGridAC_0->Cells[3][0] = "Huffcode(binary)";
StringGridAC_0->Cells[4][0] = "HuffVal";
//------------------------------------------
StringGridAC_1->Cells[0][0] = "AC_1";
StringGridAC_1->Cells[1][0] = "Huffsize";
StringGridAC_1->Cells[2][0] = "Huffcode";
StringGridAC_1->Cells[3][0] = "Huffcode(binary)";
StringGridAC_1->Cells[4][0] = "HuffVal";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
String resultDC0,resultDC1,resultAC0,resultAC1;
resultDC0 = DC0.Print();
resultDC1 = DC1.Print();
resultAC0 = AC0.Print();
resultAC1 = AC1.Print();
Label5->Caption = resultDC0;
Label6->Caption = resultDC1;
Label7->Caption = resultAC0;
Label8->Caption = resultAC1;
}
//---------------------------------------------------------------------------
終於決定把程式碼重寫一遍
為了以後程式的發展著想
還是寫一下比較好
不然debug都要超久的!!!
X的 今天我就要衝了
徹夜跟他奮戰
小黑幫我加油!!!
以下是噁心的舊的程式碼
(我貼來衝字數的....)
沒事千萬不要看
會頭暈的!!!!
敬請期待新的程式碼!!
//---------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include "IdGlobal.hpp"//IntToBin()函數要用到
using namespace std;
int size;
int* memblock;
int i,j;
int tempI1;
int tempLength;
int Bits[17];//L1~L16
int LastK[2][2],Tc,Th;
int *Huffsize[2][2],*Huffcode[2][2],**Huffcodebin[2][2],*eHufco[2][2],*eHufsize[2][2],huffmancode_number = 0;
int *HuffVal[2][2];
String tempS1,tempS2,sFileName,*sHuffcode[2][2];
ifstream input;
ofstream output;
int treesize;
int NodeNum = 0;
int num = 0;
class node
{
public:
int data;
int Number;
node *left;
node *right;
node();
/*
if data == -1 表示這只是個中間節點
else data == symbol value;
*/
};
node::node()
{
left=NULL;
right=NULL;
}
class Tree
{
private:
node *root;
int *KeyBin;
public:
Tree();
void insert(int Symbol,int huffmancode,int codelength);
String Print();
String visit(node *s);
};
Tree::Tree()
{
root=NULL;
}
void Tree::insert(int Symbol,int huffmancode,int codelength)
{
if(root == NULL)
{
//表示沒有任何節點->建立一個新的節點
root = new node;
root->Number = NodeNum;
NodeNum++;
root->right = NULL;
root->left = NULL;
}
node *p,*r;
if(codelength != 0)
{
p = root; //p 現在的Node
int bit;
int tempTCode,Ta,length,i = 0;
tempTCode = huffmancode;
int *huffBin;
huffBin = new int[codelength];
length = codelength;
while(length > 0)
{
Ta = tempTCode / 2;
bit = tempTCode - 2 * Ta; // b = 判斷bit
huffBin[codelength - i -1] = bit;
tempTCode = Ta; // 取下一個判斷的bit
length--;
i++;
}
for(i = 0;i < codelength;i++)
{
bit = huffBin[i];
if(bit == 0)//判斷要往左邊(bit == 0)
{
if(p->left != NULL)
{
p->data = -1;
p = p->left;
}
else
{
p->data = -1;
r = new node;
r->Number = NodeNum;
NodeNum++;
r->right = NULL;
r->left = NULL;
p->left = r;
p = r;
r = NULL;
}
}
else if(bit == 1)//判斷要往右邊(bit == 1)
{
if(p->right != NULL)
{
p->data = -1;
p = p->right;
}
else
{
p->data = -1;
r = new node;
r->Number = NodeNum;
NodeNum++;
r->right = NULL;
r->left = NULL;
p->right = r;
p = r;
r = NULL;
}
}
}
p->data = Symbol; //p->Number
p = NULL;
}
}
String Tree::visit(node* s)
{
String VisitS,LeftS,RightS;
VisitS += "節點編號 = " + AnsiString(s->Number);
VisitS += ",data = " + AnsiString(s->data);
if (s->left != NULL)
VisitS += ",左節點=" + AnsiString(s->left->Number);
if (s->right != NULL)
VisitS += ",右節點 =" + AnsiString(s->right->Number);
VisitS += " \n";
if (s->left != NULL)
LeftS = visit(s->left);
if (s->right != NULL)
RightS = visit(s->right);
return VisitS + LeftS + RightS ;
}
String Tree::Print()
{
node *p;
p = root;
String tempS ="";
int i = 0;
tempS += visit(p);
return tempS;
}
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
Tree DC0,DC1,AC0,AC1;
//---------------------------------------------------------------------------
void itob(int Tc,int Th,int GCT)
{
int tempindex = Huffsize[Tc][Th][GCT] - 1;
int tempLength = Huffsize[Tc][Th][GCT];
int tempCode = Huffcode[Tc][Th][GCT];
int tempbin = 0;
String tempSSS;
sHuffcode[Tc][Th][GCT] = " ";
while( tempindex >= 0)
{
if(tempCode >= 0)
tempbin = tempCode % 2;
else
tempbin = 0;
Huffcodebin[Tc][Th][GCT][tempindex] = tempbin;
tempCode = tempCode / 2;
tempindex = tempindex - 1;
}
}
void aaa(int begQ)
{
int aaai;
tempS2 += "PqTq=" + IntToHex(memblock[begQ],2) + "\n";
for(aaai = 1; aaai < 65; aaai++)
{
tempS2 += "Q(";
if(aaai < 11)
tempS2 += "0";
tempS2 += AnsiString(aaai-1) + ")=" + IntToHex(memblock[begQ+aaai],2) + " ";
if((aaai-1) % 8 == 7)
tempS2 +="\n";
}
}
int huffLi(int begH)
{
int temoLiCount,countreturn = 0;
tempS2 += "TcTh=" + IntToHex(memblock[begH],2) + "\n";
if(memblock[begH]/16 ==0) //Tc == 0
{
Tc = 0;
tempS2 += "Tc = 0 - - - - - - > DC Table or lossless table. ";
}
else if(memblock[begH]/16 ==1) //Tc == 1
{
Tc = 1;
tempS2 += "Tc = 1 - - - - - - > AC Table. ";
}
if(memblock[begH]%16 == 0) //Th == 0
{
Th = 0;
tempS2 += "Th = 0\n";
}
else if(memblock[begH]%16 == 1) //Th == 0
{
Th = 1;
tempS2 += "Th = 1\n";
}
for(temoLiCount = 1; temoLiCount < 17; temoLiCount++)
{
Bits[temoLiCount] = memblock[begH+temoLiCount];
tempS2 += "L(";
if(temoLiCount < 10)
tempS2 += "0";
tempS2 += AnsiString(temoLiCount) + ")= ";
tempS2 += "(Hex) " + IntToHex(memblock[begH+temoLiCount],2) +" = (DEC) "+ AnsiString(memblock[begH+temoLiCount])+" ";
countreturn += memblock[begH+temoLiCount];
if(temoLiCount % 2 == 0)
tempS2 += "\n";
}
return countreturn;
}
void Generate_size_table(int LiCount,int Tc,int Th)
{
int GSTK = 0, GSTL = 1,GSTJ = 1;
Huffsize[Tc][Th] = new int[LiCount+1];
for(GSTL = 1;GSTL < 17;GSTL++)
{
while(GSTJ <= Bits[GSTL])
{
Huffsize[Tc][Th][GSTK] = GSTL;
//tempS2 += "Huffsize(" + AnsiString(GSTK) + ")=" + AnsiString(GSTL) +"\n";
GSTJ++;
GSTK++;
}
GSTJ = 1;
}
Huffsize[Tc][Th][GSTK] = 0;
//tempS2 += "Huffsize(" + AnsiString(GSTK) + ")= 0, ";
LastK[Tc][Th]= GSTK;
tempS2 += "根據L1~L16產生的huffcode在隔壁頁囉,這裡的LASTK = "+ AnsiString(LastK[Tc][Th]) + "\n";
}
void Generate_code_table(int LiCount,int Tc,int Th)
{
int GCTK = 0, GCTSI = Huffsize[Tc][Th][0],GCTCODE = 0;
Huffcode[Tc][Th] = new int [LiCount+1];
sHuffcode[Tc][Th] = new String [LiCount+1];
Huffcodebin[Tc][Th] = new int* [LiCount+1];
HuffVal[Tc][Th] = new int[LiCount+1];
while(Huffsize[Tc][Th][GCTK] != 0)
{
while(Huffsize[Tc][Th][GCTK] == GCTSI)
{
Huffcode[Tc][Th][GCTK] = GCTCODE;
//tempS2 += "Huffcode(" + AnsiString(GCTK) + ")=" + AnsiString(GCTCODE) +"\n";
Huffcode[Tc][Th][GCTK] = GCTCODE;
Huffcodebin[Tc][Th][GCTK] = new int [Huffsize[Tc][Th][GCTK]];//為了每個Huffcode準備好相對應的陣列
itob(Tc,Th,GCTK);
GCTCODE = GCTCODE +1;
GCTK = GCTK +1;
}
if(Huffsize[Tc][Th][GCTK] != 0)
{
while(Huffsize[Tc][Th][GCTK] != GCTSI)
{
GCTCODE = GCTCODE *2;
GCTSI = GCTSI + 1;
}
}
}
Huffcode[Tc][Th][GCTK] = GCTCODE;
}
void Order_codes(int LiCount,int Tc,int Th)
{
}
void HuffmanTable(int begH,int LiCount,int Tc,int Th)
{
int tempLi,tempi,tempj,tempcount = LiCount;
int HMTK = 0;
for(tempi = 0;tempi < 16;tempi++)
{
tempLi = memblock[begH + tempi];
tempj =1;
while(tempj <= tempLi)
{
tempS2 += "V(" + AnsiString(tempi + 1) + "," + AnsiString(tempj)+") = " + IntToHex(memblock[begH + 16 + LiCount - tempcount],2) + " ";
HuffVal[Tc][Th][HMTK] = memblock[begH + 16 + LiCount - tempcount];
if(tempj == tempLi)
tempS2 += "\n";
HMTK++;
tempj++;
tempcount--;
}
}
}
void DQT(int begQ,int qLength)
{
int tempDQT = 0;
tempS2 += "Lq = 16進位的" + IntToHex(qLength,4) + " = 十進位的 " + AnsiString(qLength) + "\n";
qLength -= 2; //扣掉 qLength 的2個byte;
begQ +=2; //skip掉 qLength 的2個byte;
while(qLength > 1 )
{
tempS2 += " - - - - - -- - - - - - - - Qt- - - - - - - - - - - - - - - - - - \n";
aaa(begQ);
begQ = begQ + 65;//一組量化表 = 65個BYTE (PqTq + 64 個element)
qLength = qLength - 65;
}
}
void SOS(int begS,int sLength)
{
int Ns,tempSi = 1,TdTa,Td,Ta;
tempS2 += "Ls = " + IntToHex(sLength,4) + "(十六進位) = 十進位的 " + AnsiString(sLength) + "\n";
tempS2 += "Ns = " + IntToHex(memblock[begS+2],2) + "\n";
Ns = memblock[begS+2];
sLength -= 3; //扣掉 sLength 的2個byte;
begS += 3; //skip掉 sLength 的2個byte;
int wahaha = 0;
// while(sLength > 0)
// {
while(tempSi <= Ns)
{
tempS2 += "Cs" + AnsiString(tempSi)+ " = " + IntToHex(memblock[begS],2)+ " ";
tempS2 += "Td" + AnsiString(tempSi) + "Ta" + AnsiString(tempSi) +" = "+ IntToHex(memblock[begS+1],2)+"\n";
TdTa = memblock[begS+1];
Td = TdTa /16;
Ta = TdTa %16;
tempS2 += "Td" + AnsiString(tempSi) +" = " + AnsiString(Td)+ " --> 選擇了第"+ AnsiString(Td) + "個 DC Entropy table\n";
tempS2 += "Ta" + AnsiString(tempSi) +" = " + AnsiString(Ta)+ " --> 選擇了第"+ AnsiString(Ta) + "個 AC Entropy table\n";
sLength -=2;
begS +=2;
tempSi++;
}
tempS2 += "Ss = " +IntToHex(memblock[begS],2) +"\n";
tempS2 += "Se = " +IntToHex(memblock[begS+1],2) +"\n";
tempS2 += "AhAl = " +IntToHex(memblock[begS+2],2) +"\n";
begS = begS +3;
sLength = sLength +3;
//}
tempS2 += "- - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - \n";
}
void DHT(int begH,int hLength)
{
int tempDHT = 0,LiCount;
tempS2 += "Lh = 16進位的 " + IntToHex(hLength,4) + " = 十進位的 " + AnsiString(hLength) + "\n";
hLength -= 2;
begH += 2;
//tempS2 += "\nbegH = " + AnsiString(begH) + "\nhLength = " + AnsiString(hLength);
while(hLength > 1)
{
//算L1~L16的數量
tempS2 += "第" + AnsiString(huffmancode_number + 1) + "個huffmantable.\n";
LiCount = 0;
LiCount = huffLi(begH); //Licount = L1 ~ L16 的值相加
Generate_size_table( LiCount,Tc,Th);
Generate_code_table(LiCount,Tc,Th);
Order_codes(LiCount,Tc,Th);
huffmancode_number++;
HuffmanTable(begH+1,LiCount,Tc,Th);//根據Li的數量去產生Vij.加上1是因為TcTh佔了1byte;
begH += (LiCount+17); //用來skip上面那行指令--> HuffmanTable(begH)
hLength -=(17 + LiCount);
hLength = hLength;
//tempS2 += "\nbegH = " + AnsiString(begH) + "\nhLength = " + AnsiString(hLength) + "\nLiCount = " + AnsiString(LiCount);
}
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Open1Click(TObject *Sender)
{
if(OpenPictureDialog1->Execute())
{
String tempT;
char ch;
tempI1 = 0;
int tempI2 = 0,tempget;
sFileName = OpenPictureDialog1->FileName;
TJPEGImage* Jpg = new TJPEGImage;
Jpg->LoadFromFile(sFileName);
Image1->Picture->Bitmap->Assign(Jpg);
input.open(sFileName.c_str(),ios::binary|ios::in|ios::ate);
if(!input)
{
ShowMessage(" ");
}
size = input.tellg();
memblock = new int [size];
input.seekg (0, ios::beg);
tempget = input.get();
tempT = IntToHex(tempget,2);
while(!input.eof())
{
tempS1 += tempT + " ";
memblock[tempI2] = tempget;
tempI1++;
tempI2++;
tempget = input.get();
tempT = IntToHex(tempget,2);
/*if(tempget == 0xff)
tempget = tempget;
*/
if(tempI1 == 16)
{
tempS1 += "\n";
tempI1 = 0;
}
}
input.close();
Label1->Caption = AnsiString(tempS1);
Label2->Caption = AnsiString(tempI2);
}
Button1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
tempS2 = "-我是翻譯分隔線------------------------------------------------------------\n";
i = 0;
tempI1 = 0;
while(i < size)
{
if(memblock[i]== 0xff)
{
tempLength = 0;
if((memblock[i+1] >= 0xc0)&&(memblock[i+1] < 0xc4))
{
//(Start of Frame markers,non-differential,Huffman coding)
if(memblock[i+1] == 0xc0)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Baseline DCT(SOF0)";
if(memblock[i+1] == 0xc1)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Extended sequential DCT";
else if(memblock[i+1] == 0xc2)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Progressive DCT";
else if(memblock[i+1] == 0xc3)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Lossless(Sequential)\n";
tempS2 += "(Start of Frame markers,non-differential,Huffman coding)\n\n";
}
else if(memblock[i+1] == 0xcc)
{
//define arithmetic coding conditioning(s)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"--> Define arithmetic coding conditioning(s).";
tempS2 += "Arithmetic coding conditioning specification\n";
}
else if(memblock[i+1] == 0xc4)
{
//----FFC4:define Huffman table(s)
tempS2 += "\n"+ IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"--> Define Huffman table(s).\n";
tempLength = memblock[i+2]*256 + memblock[i+3];
tempS2 += "- - - - - - - - Huffman table 開始 - - - - - - - -\n";
DHT(i+2,tempLength);
tempS2 += "-- - - - - - - - Huffman table 結束 - - - - - - - -\n";
}
else if((memblock[i+1] >= 0xc5)&& (memblock[i+1] <= 0xC7))
{
if(memblock[i+1] == 0xc5)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential sequential DCT";
else if(memblock[i+1] == 0xc6)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential progressive DCT";
else if(memblock[i+1] == 0xc7)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential lossless(Sequential)";
tempS2 += "(Start of Frame markers,differential,Huffman coding)\n";
}
else if((memblock[i+1] >= 0xc8)&&(memblock[i+1] <= 0xcb))
{
if(memblock[i+1] == 0xc8)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->JPG:Reserved for JPEG extensions";
else if(memblock[i+1] == 0xc9)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Extended sequential DCT";
else if(memblock[i+1] == 0xca)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Extended sequential DCT";
else if(memblock[i+1] == 0xcb)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Lossless(Sequential)";
tempS2 += "(Start of Frame markers,non-differential,arithmetic coding)\n";
}
else if((memblock[i+1] >= 0xcd)&&(memblock[i+1] <= 0xcf))
{
if(memblock[i+1] == 0xcd)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential sequential DCT";
else if(memblock[i+1] == 0xce)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential progressive DCT";
else if(memblock[i+1] == 0xcf)
tempS2 += "\n" + IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Differential lossless(Sequential)";
tempS2 += "(Start of Frame markers,differential,arithmetic coding)\n";
}
else if((memblock[i+1] >= 0xd0)&&(memblock[i+1] <= 0xd7))
{
tempS2 += "RSTm*:Restart with modulo 8 count m\n";
}
else if(memblock[i+1] == 0xd8)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->Start of Image\n";
else if(memblock[i+1] == 0xd9)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->EOI:End of Image\n";
else if(memblock[i+1] == 0xda)
{
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->SOS:Start of Scan\n";
tempLength = memblock[i+2]*256 + memblock[i+3];
SOS(i+2,tempLength);
}
else if(memblock[i+1] == 0xdb)
{
//--FFDB:定義量化表-------------------------
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->DQT:Define quantization table\n";
tempLength = memblock[i+2]*256 + memblock[i+3];
tempS2 += "- - - - - - -- - - - - - - - Quqntization Table開始 - - - - - - - - - - - - - - - \n";
DQT(i+2,tempLength);
tempS2 += "- - - - - -- - - - - - - - Quqntization Table結束 - - - - - - - - - - - - - - \n";
}
else if(memblock[i+1] == 0xdc)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->DNL:Define number of line\n";
else if(memblock[i+1] == 0xdd)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->DRI:Define restart interval\n";
else if(memblock[i+1] == 0xde)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->DHP:Define hierarchical progression\n";
else if(memblock[i+1] == 0xdf)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->EXP:Expand reference component.\n";
else if((memblock[i+1] >= 0xe0)&&(memblock[i+1] <= 0xef))
{
//--我是給application的tag------------------------
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->我是給application的tag.\n";
tempLength = memblock[i+2]*256 + memblock[i+3];
tempS2 += " 要跳過" + AnsiString(tempLength)+ "個byte\n";
}
else if((memblock[i+1] >= 0xf0)&&(memblock[i+1] <= 0xfd))
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->reserved for JPEG extensions.\n";
else if(memblock[i+1] == 0xfe)
tempS2 += IntToHex((memblock[i]),2) + IntToHex((memblock[i+1]),2)+"-->COM:comment\n";
i = i + 2 + tempLength;
tempI1 = 0;
}
else
{
tempS2 += IntToHex((memblock[i]),2) + " ";
i++;
tempI1++;
if(tempI1 == 10)
{
tempS2 += "\n";
tempI1 = 0;
}
}
}
Label3->Caption = AnsiString(tempS2);
Button2->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
//int aaaaa = 127;
String sss;
StringGridDC_0->RowCount = LastK[0][0] + 1;
StringGridDC_1->RowCount = LastK[0][1] + 1;
StringGridAC_0->RowCount = LastK[1][0] + 1;
StringGridAC_1->RowCount = LastK[1][1] + 1;
int intCodeLength,intSymbol,intHuffcode;
int btnTemp= 0,btnTc,btnTh;
String tempSSS;
while( btnTemp< 4)
{
btnTc = btnTemp / 2;
btnTh = btnTemp % 2;
for(i = 0; i <= LastK[btnTc][btnTh];i++)
{
tempSSS = " ";
for(j = 0; j < Huffsize[btnTc][btnTh][i] ;j++)
{
tempSSS += AnsiString(Huffcodebin[btnTc][btnTh][i][j]);
}
sHuffcode[btnTc][btnTh][i] = tempSSS;
if(btnTemp == 0)//TcTh = 00--->DC0
{
StringGridDC_0->Cells[0][i+1] = AnsiString(i);
StringGridDC_0->Cells[1][i+1] = AnsiString(Huffsize[btnTc][btnTh][i]);
StringGridDC_0->Cells[2][i+1] = AnsiString(Huffcode[btnTc][btnTh][i]);
StringGridDC_0->Cells[3][i+1] = AnsiString(sHuffcode[btnTc][btnTh][i]);
StringGridDC_0->Cells[4][i+1] = AnsiString(HuffVal[btnTc][btnTh][i]);
DC0.insert(HuffVal[btnTc][btnTh][i],Huffcode[btnTc][btnTh][i],Huffsize[btnTc][btnTh][i]);
}
if(btnTemp == 1)//TcTh = 01--->DC1
{
StringGridDC_1->Cells[0][i+1] = AnsiString(i);
StringGridDC_1->Cells[1][i+1] = AnsiString(Huffsize[btnTc][btnTh][i]);
StringGridDC_1->Cells[2][i+1] = AnsiString(Huffcode[btnTc][btnTh][i]);
StringGridDC_1->Cells[3][i+1] = AnsiString(sHuffcode[btnTc][btnTh][i]);
StringGridDC_1->Cells[4][i+1] = AnsiString(HuffVal[btnTc][btnTh][i]);
DC1.insert(HuffVal[btnTc][btnTh][i],Huffcode[btnTc][btnTh][i],Huffsize[btnTc][btnTh][i]);
}
if(btnTemp == 2)//TcTh = 10---->AC0
{
StringGridAC_0->Cells[0][i+1] = AnsiString(i);
StringGridAC_0->Cells[1][i+1] = AnsiString(Huffsize[btnTc][btnTh][i]);
StringGridAC_0->Cells[2][i+1] = AnsiString(Huffcode[btnTc][btnTh][i]);
StringGridAC_0->Cells[3][i+1] = AnsiString(sHuffcode[btnTc][btnTh][i]);
StringGridAC_0->Cells[4][i+1] = AnsiString(HuffVal[btnTc][btnTh][i]);
AC0.insert(HuffVal[btnTc][btnTh][i],Huffcode[btnTc][btnTh][i],Huffsize[btnTc][btnTh][i]);
}
if(btnTemp == 3)//TcTh = 11--->AC1
{
StringGridAC_1->Cells[0][i+1] = AnsiString(i);
StringGridAC_1->Cells[1][i+1] = AnsiString(Huffsize[btnTc][btnTh][i]);
StringGridAC_1->Cells[2][i+1] = AnsiString(Huffcode[btnTc][btnTh][i]);
StringGridAC_1->Cells[3][i+1] = AnsiString(sHuffcode[btnTc][btnTh][i]);
StringGridAC_1->Cells[4][i+1] = AnsiString(HuffVal[btnTc][btnTh][i]);
AC1.insert(HuffVal[btnTc][btnTh][i],Huffcode[btnTc][btnTh][i],Huffsize[btnTc][btnTh][i]);
}
}
btnTemp++;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
StringGridDC_0->ColWidths[0] = 35;
StringGridDC_1->ColWidths[0] = 35;
StringGridAC_0->ColWidths[0] = 35;
StringGridAC_1->ColWidths[0] = 35;
//--------------------------------------
StringGridDC_0->ColWidths[1] = 45;
StringGridDC_1->ColWidths[1] = 45;
StringGridAC_0->ColWidths[1] = 45;
StringGridAC_1->ColWidths[1] = 45;
//----------------------------------------
StringGridDC_0->ColWidths[2] = 50;
StringGridDC_1->ColWidths[2] = 50;
StringGridAC_0->ColWidths[2] = 50;
StringGridAC_1->ColWidths[2] = 50;
//----------------------------------------
StringGridDC_0->ColWidths[3] = 110;
StringGridDC_1->ColWidths[3] = 110;
StringGridAC_0->ColWidths[3] = 110;
StringGridAC_1->ColWidths[3] = 110;
//------------------------------------------
StringGridDC_0->ColWidths[4] = 120;
StringGridDC_1->ColWidths[4] = 120;
StringGridAC_0->ColWidths[4] = 120;
StringGridAC_1->ColWidths[4] = 120;
//------------------------------------------
StringGridDC_0->Cells[0][0] = "DC_0";
StringGridDC_0->Cells[1][0] = "Huffsize";
StringGridDC_0->Cells[2][0] = "Huffcode";
StringGridDC_0->Cells[3][0] = "Huffcode(binary)";
StringGridDC_0->Cells[4][0] = "HuffVal";
//------------------------------------------
StringGridDC_1->Cells[0][0] = "DC_1";
StringGridDC_1->Cells[1][0] = "Huffsize";
StringGridDC_1->Cells[2][0] = "Huffcode";
StringGridDC_1->Cells[3][0] = "Huffcode(binary)";
StringGridDC_1->Cells[4][0] = "HuffVal";
//------------------------------------------
StringGridAC_0->Cells[0][0] = "AC_0";
StringGridAC_0->Cells[1][0] = "Huffsize";
StringGridAC_0->Cells[2][0] = "Huffcode";
StringGridAC_0->Cells[3][0] = "Huffcode(binary)";
StringGridAC_0->Cells[4][0] = "HuffVal";
//------------------------------------------
StringGridAC_1->Cells[0][0] = "AC_1";
StringGridAC_1->Cells[1][0] = "Huffsize";
StringGridAC_1->Cells[2][0] = "Huffcode";
StringGridAC_1->Cells[3][0] = "Huffcode(binary)";
StringGridAC_1->Cells[4][0] = "HuffVal";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
String resultDC0,resultDC1,resultAC0,resultAC1;
resultDC0 = DC0.Print();
resultDC1 = DC1.Print();
resultAC0 = AC0.Print();
resultAC1 = AC1.Print();
Label5->Caption = resultDC0;
Label6->Caption = resultDC1;
Label7->Caption = resultAC0;
Label8->Caption = resultAC1;
}
//---------------------------------------------------------------------------
星期四, 10月 04, 2007
[研究日誌]Frame header in JPEG
唔...
根據BOSS的說法
我似乎已經懂了JPEG規格書了
應該可以寫完JPEG Decoder了
真開心
覺得自己被認同了XDD
不過
因為人家現在的那個程式長的太大了
很礙眼啊
很難Debug
可是程式有問題又超痛苦的
現在想說先整理自己的想法
重新寫一次程式
首先
在Start of Image之後
我們會讀到DQT
也就是define Quantization table
接著會讀到Frame Header
在Frame Header中的資訊對於我們整張圖是很重要的
由規格書P35頁可以知道
除了一開始的tag之外
Frame Header還提供了Lf,P,Y,X,Nf,[C,H,V,Tq]等的資訊
Lf 就是Frame的Length是指這串tag佔了幾個byte
因為[C,H,V,Tq]可以有很多組啊
所以要跟人家說到多少個byte是我現在要解讀的東西
不然會讀到錯的資訊
然後由Y跟X就可以知道這張影像的大小
New相對應的陣列
可是要new幾個陣列咧
如果一張影像都是灰階
那就不需要那麼多個啦
一個就好!!
這時候Nf就派上用場了
Nf就是Number of Frame component
所以根據這個的值去產生Nf個 X * Y 的陣列
然後啊
JPEG不是有做Downsampling的動作
所以要根據接下來的[C,H,V,Tq]去做還原sampling的動作
那個C只是編號
H和V則是sampling的係數
而Tq則是這個Frame Component 要讀哪個Quantization Table
這就是Frame Header的功用
根據BOSS的說法
我似乎已經懂了JPEG規格書了
應該可以寫完JPEG Decoder了
真開心
覺得自己被認同了XDD
不過
因為人家現在的那個程式長的太大了
很礙眼啊
很難Debug
可是程式有問題又超痛苦的
現在想說先整理自己的想法
重新寫一次程式
首先
在Start of Image之後
我們會讀到DQT
也就是define Quantization table
接著會讀到Frame Header
在Frame Header中的資訊對於我們整張圖是很重要的
由規格書P35頁可以知道
除了一開始的tag之外
Frame Header還提供了Lf,P,Y,X,Nf,[C,H,V,Tq]等的資訊
Lf 就是Frame的Length是指這串tag佔了幾個byte
因為[C,H,V,Tq]可以有很多組啊
所以要跟人家說到多少個byte是我現在要解讀的東西
不然會讀到錯的資訊
然後由Y跟X就可以知道這張影像的大小
New相對應的陣列
可是要new幾個陣列咧
如果一張影像都是灰階
那就不需要那麼多個啦
一個就好!!
這時候Nf就派上用場了
Nf就是Number of Frame component
所以根據這個的值去產生Nf個 X * Y 的陣列
然後啊
JPEG不是有做Downsampling的動作
所以要根據接下來的[C,H,V,Tq]去做還原sampling的動作
那個C只是編號
H和V則是sampling的係數
而Tq則是這個Frame Component 要讀哪個Quantization Table
這就是Frame Header的功用
星期一, 10月 01, 2007
[研究日誌]Frame header
這陣子為了那個MCU編碼
真的是傷透腦筋
總感覺少了什麼
應該要再有個東西
像是標頭檔之類的
才能夠順利的解出MCU阿
boss一直叫我再多看幾遍
問我Ri是啥鬼
我...我...我...
我真的不知道錒
可是BOSS又說他已經看到了
只是不想跟我講
要我自己去找
煩耶
真的是很不想再看那本都是蝌蚪文的書
可是程式卡在這又不是辦法
想說硬解嘛
又不知道這個MCU要讀哪個table去做解碼
只好耐住性子
認真看規格書P.34的圖和P.37的Scan header syntax
結果在Csj那段發現了個Nf
Nf要去看frame header
oh my god!!!
我當初完全就只知道它是based line DCT 就跳過去姐huffmantable了
該不會這邊的參數是關鍵吧!!
今天晚上要拼了!!
念英文是吧!!
哼...
我跟你拼了!!
星期五, 9月 21, 2007
[JPEG]JPEG簡介
本來以為KO Huffmancoding就可以了
誰知道Boss上禮拜跟我說
後面的才難咧
現在我用完FFDA(Start of scan)了
今天跑去跟老闆確認是不是後面就是MCU
我只要一個bit一個bit讀進來就可以了
老闆跟我說應該是這樣子沒錯啦
可是他不確定
叫我再去看MCU的格式
以下是轉載來的JPEG簡介
原文在這
如果原作者不開心的話
要跟我講喔
我會拿掉的!!
JPEG 壓縮簡介
-------------
1. 色彩模型
JPEG 的圖片使用的是 YCrCb 顏色模型, 而不是電腦上最常用的 RGB. 關於色
彩模型, 這裏不多闡述. 只是說明, YCrCb 模型更適合圖形壓縮. 因為人眼對圖片上
的亮度 Y 的變化遠比色度 C 的變化敏感. 我們完全可以每個點保存一個 8bit 的亮
度值, 每 2x2 個點保存一個 Cr Cb 值, 而圖像在肉眼中的感覺不會起太大的變化.
所以, 原來用 RGB 模型, 4 個點需要 4x3=12 位元組. 而現在僅需要 4+2=6 位元組; 平
均每個點占 12bit. 當然 JPEG 格式裏允許每個點的 C 值都記錄下來; 不過 MPEG 裏
都是按 12bit 一個點來存放的, 我們簡寫為 YUV12.
[R G B] -> [Y Cb Cr] 轉換
-------------------------
(R,G,B 都是 8bit unsigned)
| Y | | 0.299 0.587 0.114 | | R | | 0 |
| Cb | = |- 0.1687 - 0.3313 0.5 | * | G | + |128|
| Cr | | 0.5 - 0.4187 - 0.0813| | B | |128|
Y = 0.299*R + 0.587*G + 0.114*B (亮度)
Cb = - 0.1687*R - 0.3313*G + 0.5 *B + 128
Cr = 0.5 *R - 0.4187*G - 0.0813*B + 128
[Y,Cb,Cr] -> [R,G,B] 轉換
-------------------------
R = Y + 1.402 *(Cr-128)
G = Y - 0.34414*(Cb-128) - 0.71414*(Cr-128)
B = Y + 1.772 *(Cb-128)
一般, C 值 (包括 Cb Cr) 應該是一個有符號的數位, 但這裏被處理過了, 方法
是加上了 128. JPEG 裏的資料都是無符號 8bit 的.
2. DCT (離散余弦變換)
JPEG 裏, 要對資料壓縮, 先要做一次 DCT 變換. DCT 變換的原理, 涉及到數學
知識, 這裏我們不必深究. 反正和傅立葉變換(學過高數的都知道) 是差不多了. 經過
這個變換, 就把圖片裏點和點間的規律呈現出來了, 更方便壓縮.JPEG 裏是對每 8x8
個點為一個單位處理的. 所以如果原始圖片的長寬不是 8 的倍數, 都需要先補成 8
的倍數, 好一塊塊的處理. 另外, 記得剛才我說的 Cr Cb 都是 2x2 記錄一次嗎? 所
以大多數情況, 是要補成 16x16 的整數塊.按從左到右, 從上到下的次序排列 (和我
們寫字的次序一樣). JPEG 裏是對 Y Cr Cb 分別做 DCT 變換的.
JPEG 編碼時使用的是 Forward DCT (FDCT) 解碼時使用的 Inverse DCT (IDCT)
下面給出公式:
FDCT:
c(u,v) 7 7 2*x+1 2*y+1
F(u,v) = --------- * sum sum f(x,y) * cos (------- *u*PI)* cos (------ *v*PI)
4 x=0 y=0 16 16
u,v = 0,1,...,7
{ 1/2 當 u=v=0 時
c(u,v) = {
{ 1 其他情況
IDCT:
1 7 7 2*x+1 2*y+1
f(x,y) = --- * sum sum c(u,v)*F(u,v)*cos (------- *u*PI)* cos (------ *v*PI)
4 u=0 v=0 16 16
x,y=0,1...7
這個步驟很花時間, 另外有種 AA&N 優化演算法, 大家可以去 inet 自己找一下.
在 Intel 主頁上可以找到 AA&N IDCT 的 MMX 優化代碼.
3. 重排列 DCT 結果
DCT 將一個 8x8 的陣列變換成另一個 8x8 的陣列. 但是記憶體裏所有資料都是線
形存放的, 如果我們一行行的存放這 64 個數字, 每行的結尾的點和下行開始的點就
沒有什麼關係, 所以 JPEG 規定按如下次序整理 64 個數字.
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
這樣數列裏的相鄰點在圖片上也是相鄰的了.
4. 量化
對於前面得到的 64 個空間頻率振幅值, 我們將對它們作幅度分層量化操作.方
法就是分別除以量化表裏對應值並四捨五入.
for (i = 0 ; i<=63; i++ )
vector[i] = (int) (vector[i] / quantization_table[i] + 0.5)
下面有張 JPEG 標準量化表. (按上面同樣的彎曲次序排列)
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
這張表依據心理視覺閥製作, 對 8bit 的亮度和色度的圖像的處理效果不錯.
當然我們可以使用任意的量化表. 量化表是定義在 jpeg 的 DQT 標記後. 一般
為 Y 值定義一個, 為 C 值定義一個.
量化表是控制 JPEG 壓縮比的關鍵. 這個步驟除掉了一些高頻量, 損失了很高
細節. 但事實上人眼對高空間頻率遠沒有低頻敏感.所以處理後的視覺損失很小.
另一個重要原因是所有的圖片的點與點之間會有一個色彩過渡的過程. 大量的圖像
資訊被包含在低空間頻率中. 經過量化處理後, 在高空間頻率段, 將出現大量連續
的零.
5. 0 RLC 編碼
現在我們向量中有許多連續的 0. 我們可以使用 RLC 來壓縮掉這些 0. 這裏我們
將跳過第一個向量 (後面將解釋為什麼) 因為它的編碼比較特別. 假設有一組向量
(64 個的後 63 個) 是
57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0, 0 , 0 ,0 , 0,..,0
經過 RLC 壓縮後就是
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB
EOB 是一個結束標記, 表示後面都是 0 了. 實際上, 我們用 (0,0) 表示 EOB
但是, 如果這組數字不以 0 結束, 那麼就不需要 EOB.
由於後面 huffman 編碼的要求, 每組數字前一個表示 0 的數量的必須是 4 bit,
就是說, 只能是 0~15, 所以我們實際這樣編碼:
(0,57) ; (15,0) (2,3) ; (4,2) ; (15,0) (15,0) (1,895) , (0,0)
注意 (15,0) 表示了 16 個連續的 0.
6. huffman 編碼
為了提高儲存效率, JPEG 裏並不直接保存數值, 而是將數值按位數分成 16 組:
數值 組 實際保存值
0 0 -
-1,1 1 0,1
-3,-2,2,3 2 00,01,10,11
-7,-6,-5,-4,4,5,6,7 3 000,001,010,011,100,101,110,111
-15,..,-8,8,..,15 4 0000,..,0111,1000,..,1111
-31,..,-16,16,..,31 5 00000,..,01111,10000,..,11111
-63,..,-32,32,..,63 6 .
-127,..,-64,64,..,127 7 .
-255,..,-128,128,..,255 8 .
-511,..,-256,256,..,511 9 .
-1023,..,-512,512,..,1023 10 .
-2047,..,-1024,1024,..,2047 11 .
-4095,..,-2048,2048,..,4095 12 .
-8191,..,-4096,4096,..,8191 13 .
-16383,..,-8192,8192,..,16383 14 .
-32767,..,-16384,16384,..,32767 15 .
還是來看前面的例子:
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)
只處理每對數右邊的那個:
57 是第 6 組的, 實際保存值為 111001 , 所以被編碼為 (6,111001)
45 , 同樣的操作, 編碼為 (6,101101)
23 -> (5,10111)
-30 -> (5,00001)
-8 -> (4,0111)
1 -> (1,1)
前面的那串數字就變成了:
(0,6), 111001 ; (0,6), 101101 ; (4,5), 10111; (1,5), 00001; (0,4) , 0111 ;
(2,1), 1 ; (0,0)
括弧裏的數值正好合成一個位元組. 後面被編碼的數位表示範圍是 -32767..32767.
合成的位元組裏, 高 4 位是前續 0 的個數, 低 4 位元描述了後面數字的位元數.
繼續剛才的例子, 如果 06 的 huffman 編碼為 111000
69 = (4,5) --- 1111111110011001
21 = (1,5) --- 11111110110
4 = (0,4) --- 1011
33 = (2,1) --- 11011
0 = EOB = (0,0) --- 1010
那麼最後對於前面的例子表示的 63 個係數 (記得我們將第一個跳過了嗎?) 按位流
寫入 JPG 檔中就是這樣的:
111000 111001 111000 101101 1111111110011001 10111 11111110110 00001
1011 0111 11011 1 1010
DC 的編碼
---------
記得剛才我們跳過了每組 64 個資料的第一個吧, DC 就是指的這個數字 (後面 63
個簡稱 AC) 代入前面的 FDCT 公式可以得到
c(0,0) 7 7
DC = F(0,0) = --------- * sum sum f(x,y) * cos 0 * cos 0 其中 c(0,0) = 1/2
4 x=0 y=0
1 7 7
= --- * sum sum f(x,y)
8 x=0 y=0
即一塊圖像樣本的平均值. 就是說, 它包含了原始 8x8 圖像塊裏的很多能量. (通常
會得到一個很大的數值)
JPEG 的作者指出連續塊的 DC 率之間有很緊密的聯繫, 因此他們決定對 8x8 塊的
DC 值的差別進行編碼. (Y, Cb, Cr 分別有自己的 DC)
Diff = DC(i) - DC(i-1)
所以這一塊的 DC(i) 就是: DC(i) = DC(i-1) + Diff
JPG 從 0 開始對 DC 編碼, 所以 DC(0)=0. 然後再將當前 Diff 值加在上一個值上得
到當前值.
下面再來看看上面那個例子: (記住我們保存的 DC 是和上一塊 DC 的差值 Diff)
例如上面例子中, Diff 是 -511, 就編碼成
(9, 000000000)
如果 9 的 Huffman 編碼是 1111110 (在 JPG 檔中, 一般有兩個 Huffman 表, 一
個是 DC 用, 一個是 AC 用) 那麼在 JPG 檔中, DC 的 2 進制表示為
1111110 000000000
它將放在 63 個 AC 的前面, 上面上個例子的最終 BIT 流如下:
1111110 000000000 111000 111001 111000 101101 1111111110011001 10111
11111110110 00001 1011 0111 11011 1 1010
下面簡單敍述一下針對一個資料單元的圖片 Y 的解碼
-----------------------------------------------
在整個圖片解碼的開始, 你需要先初始化 DC 值為 0.
1) 先解碼 DC:
a) 取得一個 Huffman 碼 (使用 Huffman DC 表)
b) Huffman解碼, 看看後面的資料位元數 N
c) 取得 N 位, 計算 Diff 值
d) DC + = Diff
e) 寫入 DC 值: " vector[0]=DC "
2) 解碼 63 個 AC:
------- 迴圈處理每個 AC 直到 EOB 或者處理到 64 個 AC
a) 取得一個 Huffman 碼 (使用 Huffman AC 表)
b) Huffman 解碼, 得到 (前面 0 數量, 組號)
[記住: 如果是(0,0) 就是 EOB 了]
c) 取得 N 位(組號) 計算 AC
d) 寫入相應數量的 0
e) 接下來寫入 AC
-----------------
下一步的解碼
------------
上一步我們得到了 64 個向量. 下面我們還需要做一些解碼工作:
1) 反量化 64 個向量 : "for (i=0;i<=63;i++) vector[i]*=quant[i]"
2) 重排列 64 個向量到 8x8 的塊中
3) 對 8x8 的塊作 IDCT
對 8x8 塊的 (Y,Cb,Cr) 重複上面的操作 [Huffman 解碼, 步驟 1), 2), 3)]
4) 將所有的有符號的 8bit 數加上 128
5) 轉換 YCbCr 到 RGB
JPG 檔(Byte 級)裏怎樣組織圖片資訊
-----------------------------------
注意 JPEG/JFIF 檔格式使用 Motorola 格式, 而不是 Intel 格式, 就是說, 如果
是一個字的話, 高位元組在前, 低位元組在後.
JPG 檔是由一個個段 (segments) 構成的. 每個段長度 <=65535. 每個段從一個標
記字開始. 標記字都是 0xff 打頭的, 以非 0 位元組和 0xFF 結束. 例如 'FFDA' ,
'FFC4', 'FFC0'. 每個標記有它特定意義, 這是由第2位元組指明的. 例如, SOS (Start
Of Scan = 'FFDA') 指明了你應該開始解碼. 另一個標記 DQT (Define Quantization
Table = 0xFFDB) 就是說它後面有 64 位元組的 quantization 表
在處理 JPG 檔時, 如果你碰到一個 0xFF, 而它後面的位元組不是 0, 並且這個位元組
沒有意義. 那麼你遇到的 0xFF 位元組必須被忽略. (一些 JPG 裏, 常用用 0xFF 做某
些填充用途) 如果你在做 huffman 編碼時碰巧產生了一個 0xFF, 那麼就用 0xFF
0x00 代替. 就是說在 jpeg 圖形解碼時碰到 FF00 就把它當作 FF 處理.
另外在 huffman 編碼區域結束時, 碰到幾個 bit 沒有用的時候, 應該用 1 去填充.
然後後面跟 FF.
下面是幾個重要的標記
--------------------
SOI = Start Of Image = 'FFD8'
這個標記只在檔開始出現一次
EOI = End Of Image = 'FFD9'
JPG 文件都以 FFD9 結束
RSTi = FFDi ( i = 0..7) [ RST0 = FFD0, RST7=FFD7]
= 重定標記
通常穿插在資料流程裏, 我想是擔心 JPG 解碼出問題吧(應該配合 DRI 使用). 不過很
多 JPG 都不使用它
(SOS --- RST0 --- RST1 -- RST2 --...
...-- RST6 --- RST7 -- RST0 --...)
----
標記
----
下面是必須處理的標記
SOF0 = Start Of Frame 0 = FFC0
SOS = Start Of Scan = FFDA
APP0 = it's the marker used to identify a JPG file which uses the JFIF
specification = FFE0
COM = Comment = FFFE
DNL = Define Number of Lines = FFDC
DRI = Define Restart Interval = FFDD
DQT = Define Quantization Table = FFDB
DHT = Define Huffman Table = FFC4
JPG 檔中 Haffman 表的儲存
---------------------------
JPEG 裏定義了一張表來描述 Haffman 樹. 定義在 DHT 標記後面. 注意: Haffman
代碼的長度限制在 16bit 內.
一般一個 JPG 檔裏會有 2 類 Haffman 表: 一個用於 DC 一個用於 AC (實際有 4
個表, 亮度的 DC,AC 兩個, 色度的 DC,AC 兩個)
這張表是這樣保存的:
1) 16 位元組:
第 i 位元組表示了 i 位元長的 Huffman 代碼的個數 (i= 1 到 16)
2) 這表的長度 (位元組數) = 這 16 個數字之和
現在你可以想像這張表怎麼存放的吧? 對應位元組就是對應 Haffman 代碼等價數字. 我
不多解釋, 這需要你先瞭解 Haffman 演算法. 這裏只舉一個例子:
Haffman 表的表頭是 0,2,3,1,1,1,0,1,0,0,0,0,0,0,0,0
就是說長度為 1 的代碼沒有
長度為 2 的代碼為 00
01
長度為 3 的代碼是 100
101
110
長度為 4 的代碼是 1110
長度為 5 的代碼是 11110
長度為 6 的代碼是 111110
長度為 7 的代碼沒有 (如果有一個的話應該是 1111110)
長度為 8 的代碼是 11111100
.....
後面都沒有了.
如果表下面的資料是
45 57 29 17 23 25 34 28
就是說
45 = 00
57 = 01
29 = 100
17 = 101
23 = 110
等等...
如果你懂 Haffman 編碼, 這些不難理解
採樣係數
--------
下面講解的都是真彩 JPG 的解碼, 灰度 JPG 的解碼很簡單, 因為圖形中只有亮度信
息. 而彩色圖形由 (Y, Cr, Cb) 構成, 前面提到過, Y 通常是每點採樣一次, 而 Cr,
Cb 一般是 2x2 點採樣一次, 當然也有的 JPG 是逐點採樣, 或者每兩點採樣 (橫向
兩點, 縱向一點) 採樣係數均被定義成對比最高採樣係數的相對值.
一般情況 (即: Y 逐點採樣, Cr Cb 每 2x2 點一次) 下: Y 有最高的採樣率, 橫向采
樣係數HY=2 縱向採樣係數 VY=2; Cb 的橫向採樣係數 HCb=1, 縱向採樣係數 VCb=1;
同樣 HCr=1, VCr=1
在 Jpeg 裏, 8x8 個原始資料, 經過 RLC, Huffman 編碼後的一串資料流程稱為一個
Data Unit (DU) JPG 裏按 DU 為單位的編碼次序如下:
1) for (counter_y=1;counter_y<=VY;counter_y++)
for (counter_x=1;counter_x<=HY;counter_x++)
{ 對 Y 的 Data Unit 編碼 }
2) for (counter_y=1;counter_y<=VCb ;counter_y++)
for (counter_x=1;counter_x<=HCb;counter_x++)
{ 對 Cb 的 Data Unit 編碼 }
3) for (counter_y=1;counter_y<=VCr;counter_y++)
for (counter_x=1;counter_x<=HCr;counter_x++)
{ 對 Cr 的 Data Unit 編碼 }
按我上面的例子: (HY=2, VY=2 ; HCb=VCb =1, HCr,VCr=1) 就是這樣一個次序
YDU,YDU,YDU,YDU,CbDU,CrDU
這些就描述了一塊 16x16 的圖形. 16x16 = (Hmax*8 x Vmax*8) 這裏 Hmax=HY=2
Vmax=VY=2
一個 (Hmax*8,Vmax*8) 的塊被稱作 MCU (Minimun Coded Unix) 前面例子中一個
MCU = YDU,YDU,YDU,YDU,CbDU,CrDU
如果 HY =1, VY=1
HCb=1, VCb=1
HCr=1, VCr=1
這樣 (Hmax=1,Vmax=1), MCU 只有 8x8 大, MCU = YDU,CbDU,CrDU
對於灰度 JPG, MCU 只有一個 DU (MCU = YDU)
JPG 檔裏, 圖像的每個組成部分的採樣係數定義在 SOF0 (FFC0) 標記後
簡單說一下 JPG 文件的解碼
-------------------------
解碼程式閑從 JPG 檔中讀出採樣係數, 這樣就知道了 MCU 的大小, 算出整個圖像
有幾個 MCU. 解碼程式再迴圈逐個對 MCU 解碼, 一直到檢查到 EOI 標記. 對於每個
MCU, 按正規的次序解出每個 DU, 然後組合, 轉換成 (R,G,B) 就 OK 了
附:JPEG 檔格式
~~~~~~~~~~~~~~~~
- 文件頭 (2 bytes): $ff, $d8 (SOI) (JPEG 檔標識)
- 任意數量的段 , 見後面
- 文件結束 (2 bytes): $ff, $d9 (EOI)
段的格式:
~~~~~~~~~
- header (4 bytes):
$ff 段標識
n 段的類型 (1 byte)
sh, sl 該段長度, 包括這兩個位元組, 但是不包括前面的 $ff 和 n.
注意: 長度不是 intel 次序, 而是 Motorola 的, 高位元組在前,
低位元組在後!
- 該段的內容, 最多 65533 位元組
注意:
- 有一些無參數的段 (下面那些前面注明星號的)
這些段沒有長度描述 (而且沒有內容), 只有 $ff 和類型位元組.
- 每一個段結束到下一個 $ff 間的資料都是合法的, 必須被忽略掉.
段的類型:
~~~~~~~~~
*TEM = $01 可以忽略掉
SOF0 = $c0 幀開始 (baseline JPEG), 細節附後
SOF1 = $c1 dito
SOF2 = $c2 通常不支持
SOF3 = $c3 通常不支持
SOF5 = $c5 通常不支持
SOF6 = $c6 通常不支持
SOF7 = $c7 通常不支持
SOF9 = $c9 arithmetic 編碼(Huffman 的一種擴展演算法), 通常不支援
SOF10 = $ca 通常不支持
SOF11 = $cb 通常不支持
SOF13 = $cd 通常不支持
SOF14 = $ce 通常不支持
SOF14 = $ce 通常不支持
SOF15 = $cf 通常不支持
DHT = $c4 定義 Huffman Table, 細節附後
JPG = $c8 未定義/保留 (引起解碼錯誤)
DAC = $cc 定義 Arithmetic Table, 通常不支援
*RST0 = $d0 RSTn 用於 resync, 通常被忽略
*RST1 = $d1
*RST2 = $d2
*RST3 = $d3
*RST4 = $d4
*RST5 = $d5
*RST6 = $d6
*RST7 = $d7
SOI = $d8 圖片開始
EOI = $d9 圖片結束
SOS = $da 掃描行開始, 細節附後
DQT = $db 定義 Quantization Table, 細節附後
DNL = $dc 通常不支持, 忽略
DRI = $dd 定義重新開始間隔, 細節附後
DHP = $de 忽略 (跳過)
EXP = $df 忽略 (跳過)
APP0 = $e0 JFIF APP0 segment marker (細節略)
APP15 = $ef 忽略
JPG0 = $f0 忽略 (跳過)
JPG13 = $fd 忽略 (跳過)
COM = $fe 注釋, 細節附後
其他的段類型都保留必須跳過
SOF0: Start Of Frame 0:
~~~~~~~~~~~~~~~~~~~~~~~
- $ff, $c0 (SOF0)
- 長度 (高位元組, 低位元組), 8+components*3
- 資料精度 (1 byte) 每個樣本位元數, 通常是 8 (大多數軟體不支援 12 和 16)
- 圖片高度 (高位元組, 低位元組), 如果不支援 DNL 就必須 >0
- 圖片寬度 (高位元組, 低位元組), 如果不支援 DNL 就必須 >0
- components 數量(1 byte), 灰度圖是 1, YCbCr/YIQ 彩色圖是 3, CMYK 彩色圖
是 4
- 每個 component: 3 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
- 採樣係數 (bit 0-3 vert., 4-7 hor.)
- quantization table 數
DRI: Define Restart Interval:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- $ff, $dd (DRI)
- 長度 (高位元組, 低位元組), 必須是 4
- MCU 塊的單元中的重新開始間隔 (高位元組, 低位元組),
意思是說, 每 n 個 MCU 塊就有一個 RSTn 標記.
第一個標記是 RST0, 然後是 RST1 等, RST7 後再從 RST0 重複
DQT: Define Quantization Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- $ff, $db (DQT)
- 長度 (高位元組, 低位元組)
- QT 信息 (1 byte):
bit 0..3: QT 號(0..3, 否則錯誤)
bit 4..7: QT 精度, 0 = 8 bit, 否則 16 bit
- n 位元組的 QT, n = 64*(精度+1)
評論:
- 一個單獨的 DQT 段可以包含多個 QT, 每個都有自己的資訊位元組
- 當精度=1 (16 bit), 每個字都是高位在前低位元在後
DAC: Define Arithmetic Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
法律原因, 現在的軟體不支援 arithmetic 編碼.
不能生產使用 arithmetic 編碼的 JPEG 檔
DHT: Define Huffman Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~
- $ff, $c4 (DHT)
- 長度 (高位元組, 低位元組)
- HT 信息 (1 byte):
bit 0..3: HT 號 (0..3, 否則錯誤)
bit 4 : HT 類型, 0 = DC table, 1 = AC table
bit 5..7: 必須是 0
- 16 bytes: 長度是 1..16 代碼的符號數. 這 16 個數的和應該 <=256
- n bytes: 一個包含了按遞增次序代碼長度排列的符號表
(n = 代碼總數)
評論:
- 一個單獨的 DHT 段可以包含多個 HT, 每個都有自己的資訊位元組
COM: 注釋:
~~~~~~~~~~
- $ff, $fe (COM)
- 注釋長度 (高位元組, 低位元組) = L+2
- 注釋為長度為 L 的字元流
SOS: Start Of Scan:
~~~~~~~~~~~~~~~~~~~
- $ff, $da (SOS)
- 長度 (高位元組, 低位元組), 必須是 6+2*(掃描行內元件的數量)
- 掃描行內元件的數量 (1 byte), 必須 >= 1 , <=4 (否則是錯的) 通常是 3
- 每個元件(部分): 2 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), 見 SOF0
- 使用的 Huffman 表00-1-14:
- bit 0..3: AC table (0..3)
- bit 4..7: DC table (0..3)
- 忽略 3 bytes (???)
評論:
- 圖片資料 (一個個掃描行) 緊接著 SOS 段.
誰知道Boss上禮拜跟我說
後面的才難咧
現在我用完FFDA(Start of scan)了
今天跑去跟老闆確認是不是後面就是MCU
我只要一個bit一個bit讀進來就可以了
老闆跟我說應該是這樣子沒錯啦
可是他不確定
叫我再去看MCU的格式
以下是轉載來的JPEG簡介
原文在這
如果原作者不開心的話
要跟我講喔
我會拿掉的!!
JPEG 壓縮簡介
-------------
1. 色彩模型
JPEG 的圖片使用的是 YCrCb 顏色模型, 而不是電腦上最常用的 RGB. 關於色
彩模型, 這裏不多闡述. 只是說明, YCrCb 模型更適合圖形壓縮. 因為人眼對圖片上
的亮度 Y 的變化遠比色度 C 的變化敏感. 我們完全可以每個點保存一個 8bit 的亮
度值, 每 2x2 個點保存一個 Cr Cb 值, 而圖像在肉眼中的感覺不會起太大的變化.
所以, 原來用 RGB 模型, 4 個點需要 4x3=12 位元組. 而現在僅需要 4+2=6 位元組; 平
均每個點占 12bit. 當然 JPEG 格式裏允許每個點的 C 值都記錄下來; 不過 MPEG 裏
都是按 12bit 一個點來存放的, 我們簡寫為 YUV12.
[R G B] -> [Y Cb Cr] 轉換
-------------------------
(R,G,B 都是 8bit unsigned)
| Y | | 0.299 0.587 0.114 | | R | | 0 |
| Cb | = |- 0.1687 - 0.3313 0.5 | * | G | + |128|
| Cr | | 0.5 - 0.4187 - 0.0813| | B | |128|
Y = 0.299*R + 0.587*G + 0.114*B (亮度)
Cb = - 0.1687*R - 0.3313*G + 0.5 *B + 128
Cr = 0.5 *R - 0.4187*G - 0.0813*B + 128
[Y,Cb,Cr] -> [R,G,B] 轉換
-------------------------
R = Y + 1.402 *(Cr-128)
G = Y - 0.34414*(Cb-128) - 0.71414*(Cr-128)
B = Y + 1.772 *(Cb-128)
一般, C 值 (包括 Cb Cr) 應該是一個有符號的數位, 但這裏被處理過了, 方法
是加上了 128. JPEG 裏的資料都是無符號 8bit 的.
2. DCT (離散余弦變換)
JPEG 裏, 要對資料壓縮, 先要做一次 DCT 變換. DCT 變換的原理, 涉及到數學
知識, 這裏我們不必深究. 反正和傅立葉變換(學過高數的都知道) 是差不多了. 經過
這個變換, 就把圖片裏點和點間的規律呈現出來了, 更方便壓縮.JPEG 裏是對每 8x8
個點為一個單位處理的. 所以如果原始圖片的長寬不是 8 的倍數, 都需要先補成 8
的倍數, 好一塊塊的處理. 另外, 記得剛才我說的 Cr Cb 都是 2x2 記錄一次嗎? 所
以大多數情況, 是要補成 16x16 的整數塊.按從左到右, 從上到下的次序排列 (和我
們寫字的次序一樣). JPEG 裏是對 Y Cr Cb 分別做 DCT 變換的.
JPEG 編碼時使用的是 Forward DCT (FDCT) 解碼時使用的 Inverse DCT (IDCT)
下面給出公式:
FDCT:
c(u,v) 7 7 2*x+1 2*y+1
F(u,v) = --------- * sum sum f(x,y) * cos (------- *u*PI)* cos (------ *v*PI)
4 x=0 y=0 16 16
u,v = 0,1,...,7
{ 1/2 當 u=v=0 時
c(u,v) = {
{ 1 其他情況
IDCT:
1 7 7 2*x+1 2*y+1
f(x,y) = --- * sum sum c(u,v)*F(u,v)*cos (------- *u*PI)* cos (------ *v*PI)
4 u=0 v=0 16 16
x,y=0,1...7
這個步驟很花時間, 另外有種 AA&N 優化演算法, 大家可以去 inet 自己找一下.
在 Intel 主頁上可以找到 AA&N IDCT 的 MMX 優化代碼.
3. 重排列 DCT 結果
DCT 將一個 8x8 的陣列變換成另一個 8x8 的陣列. 但是記憶體裏所有資料都是線
形存放的, 如果我們一行行的存放這 64 個數字, 每行的結尾的點和下行開始的點就
沒有什麼關係, 所以 JPEG 規定按如下次序整理 64 個數字.
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
這樣數列裏的相鄰點在圖片上也是相鄰的了.
4. 量化
對於前面得到的 64 個空間頻率振幅值, 我們將對它們作幅度分層量化操作.方
法就是分別除以量化表裏對應值並四捨五入.
for (i = 0 ; i<=63; i++ )
vector[i] = (int) (vector[i] / quantization_table[i] + 0.5)
下面有張 JPEG 標準量化表. (按上面同樣的彎曲次序排列)
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
這張表依據心理視覺閥製作, 對 8bit 的亮度和色度的圖像的處理效果不錯.
當然我們可以使用任意的量化表. 量化表是定義在 jpeg 的 DQT 標記後. 一般
為 Y 值定義一個, 為 C 值定義一個.
量化表是控制 JPEG 壓縮比的關鍵. 這個步驟除掉了一些高頻量, 損失了很高
細節. 但事實上人眼對高空間頻率遠沒有低頻敏感.所以處理後的視覺損失很小.
另一個重要原因是所有的圖片的點與點之間會有一個色彩過渡的過程. 大量的圖像
資訊被包含在低空間頻率中. 經過量化處理後, 在高空間頻率段, 將出現大量連續
的零.
5. 0 RLC 編碼
現在我們向量中有許多連續的 0. 我們可以使用 RLC 來壓縮掉這些 0. 這裏我們
將跳過第一個向量 (後面將解釋為什麼) 因為它的編碼比較特別. 假設有一組向量
(64 個的後 63 個) 是
57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0, 0 , 0 ,0 , 0,..,0
經過 RLC 壓縮後就是
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB
EOB 是一個結束標記, 表示後面都是 0 了. 實際上, 我們用 (0,0) 表示 EOB
但是, 如果這組數字不以 0 結束, 那麼就不需要 EOB.
由於後面 huffman 編碼的要求, 每組數字前一個表示 0 的數量的必須是 4 bit,
就是說, 只能是 0~15, 所以我們實際這樣編碼:
(0,57) ; (15,0) (2,3) ; (4,2) ; (15,0) (15,0) (1,895) , (0,0)
注意 (15,0) 表示了 16 個連續的 0.
6. huffman 編碼
為了提高儲存效率, JPEG 裏並不直接保存數值, 而是將數值按位數分成 16 組:
數值 組 實際保存值
0 0 -
-1,1 1 0,1
-3,-2,2,3 2 00,01,10,11
-7,-6,-5,-4,4,5,6,7 3 000,001,010,011,100,101,110,111
-15,..,-8,8,..,15 4 0000,..,0111,1000,..,1111
-31,..,-16,16,..,31 5 00000,..,01111,10000,..,11111
-63,..,-32,32,..,63 6 .
-127,..,-64,64,..,127 7 .
-255,..,-128,128,..,255 8 .
-511,..,-256,256,..,511 9 .
-1023,..,-512,512,..,1023 10 .
-2047,..,-1024,1024,..,2047 11 .
-4095,..,-2048,2048,..,4095 12 .
-8191,..,-4096,4096,..,8191 13 .
-16383,..,-8192,8192,..,16383 14 .
-32767,..,-16384,16384,..,32767 15 .
還是來看前面的例子:
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)
只處理每對數右邊的那個:
57 是第 6 組的, 實際保存值為 111001 , 所以被編碼為 (6,111001)
45 , 同樣的操作, 編碼為 (6,101101)
23 -> (5,10111)
-30 -> (5,00001)
-8 -> (4,0111)
1 -> (1,1)
前面的那串數字就變成了:
(0,6), 111001 ; (0,6), 101101 ; (4,5), 10111; (1,5), 00001; (0,4) , 0111 ;
(2,1), 1 ; (0,0)
括弧裏的數值正好合成一個位元組. 後面被編碼的數位表示範圍是 -32767..32767.
合成的位元組裏, 高 4 位是前續 0 的個數, 低 4 位元描述了後面數字的位元數.
繼續剛才的例子, 如果 06 的 huffman 編碼為 111000
69 = (4,5) --- 1111111110011001
21 = (1,5) --- 11111110110
4 = (0,4) --- 1011
33 = (2,1) --- 11011
0 = EOB = (0,0) --- 1010
那麼最後對於前面的例子表示的 63 個係數 (記得我們將第一個跳過了嗎?) 按位流
寫入 JPG 檔中就是這樣的:
111000 111001 111000 101101 1111111110011001 10111 11111110110 00001
1011 0111 11011 1 1010
DC 的編碼
---------
記得剛才我們跳過了每組 64 個資料的第一個吧, DC 就是指的這個數字 (後面 63
個簡稱 AC) 代入前面的 FDCT 公式可以得到
c(0,0) 7 7
DC = F(0,0) = --------- * sum sum f(x,y) * cos 0 * cos 0 其中 c(0,0) = 1/2
4 x=0 y=0
1 7 7
= --- * sum sum f(x,y)
8 x=0 y=0
即一塊圖像樣本的平均值. 就是說, 它包含了原始 8x8 圖像塊裏的很多能量. (通常
會得到一個很大的數值)
JPEG 的作者指出連續塊的 DC 率之間有很緊密的聯繫, 因此他們決定對 8x8 塊的
DC 值的差別進行編碼. (Y, Cb, Cr 分別有自己的 DC)
Diff = DC(i) - DC(i-1)
所以這一塊的 DC(i) 就是: DC(i) = DC(i-1) + Diff
JPG 從 0 開始對 DC 編碼, 所以 DC(0)=0. 然後再將當前 Diff 值加在上一個值上得
到當前值.
下面再來看看上面那個例子: (記住我們保存的 DC 是和上一塊 DC 的差值 Diff)
例如上面例子中, Diff 是 -511, 就編碼成
(9, 000000000)
如果 9 的 Huffman 編碼是 1111110 (在 JPG 檔中, 一般有兩個 Huffman 表, 一
個是 DC 用, 一個是 AC 用) 那麼在 JPG 檔中, DC 的 2 進制表示為
1111110 000000000
它將放在 63 個 AC 的前面, 上面上個例子的最終 BIT 流如下:
1111110 000000000 111000 111001 111000 101101 1111111110011001 10111
11111110110 00001 1011 0111 11011 1 1010
下面簡單敍述一下針對一個資料單元的圖片 Y 的解碼
-----------------------------------------------
在整個圖片解碼的開始, 你需要先初始化 DC 值為 0.
1) 先解碼 DC:
a) 取得一個 Huffman 碼 (使用 Huffman DC 表)
b) Huffman解碼, 看看後面的資料位元數 N
c) 取得 N 位, 計算 Diff 值
d) DC + = Diff
e) 寫入 DC 值: " vector[0]=DC "
2) 解碼 63 個 AC:
------- 迴圈處理每個 AC 直到 EOB 或者處理到 64 個 AC
a) 取得一個 Huffman 碼 (使用 Huffman AC 表)
b) Huffman 解碼, 得到 (前面 0 數量, 組號)
[記住: 如果是(0,0) 就是 EOB 了]
c) 取得 N 位(組號) 計算 AC
d) 寫入相應數量的 0
e) 接下來寫入 AC
-----------------
下一步的解碼
------------
上一步我們得到了 64 個向量. 下面我們還需要做一些解碼工作:
1) 反量化 64 個向量 : "for (i=0;i<=63;i++) vector[i]*=quant[i]"
2) 重排列 64 個向量到 8x8 的塊中
3) 對 8x8 的塊作 IDCT
對 8x8 塊的 (Y,Cb,Cr) 重複上面的操作 [Huffman 解碼, 步驟 1), 2), 3)]
4) 將所有的有符號的 8bit 數加上 128
5) 轉換 YCbCr 到 RGB
JPG 檔(Byte 級)裏怎樣組織圖片資訊
-----------------------------------
注意 JPEG/JFIF 檔格式使用 Motorola 格式, 而不是 Intel 格式, 就是說, 如果
是一個字的話, 高位元組在前, 低位元組在後.
JPG 檔是由一個個段 (segments) 構成的. 每個段長度 <=65535. 每個段從一個標
記字開始. 標記字都是 0xff 打頭的, 以非 0 位元組和 0xFF 結束. 例如 'FFDA' ,
'FFC4', 'FFC0'. 每個標記有它特定意義, 這是由第2位元組指明的. 例如, SOS (Start
Of Scan = 'FFDA') 指明了你應該開始解碼. 另一個標記 DQT (Define Quantization
Table = 0xFFDB) 就是說它後面有 64 位元組的 quantization 表
在處理 JPG 檔時, 如果你碰到一個 0xFF, 而它後面的位元組不是 0, 並且這個位元組
沒有意義. 那麼你遇到的 0xFF 位元組必須被忽略. (一些 JPG 裏, 常用用 0xFF 做某
些填充用途) 如果你在做 huffman 編碼時碰巧產生了一個 0xFF, 那麼就用 0xFF
0x00 代替. 就是說在 jpeg 圖形解碼時碰到 FF00 就把它當作 FF 處理.
另外在 huffman 編碼區域結束時, 碰到幾個 bit 沒有用的時候, 應該用 1 去填充.
然後後面跟 FF.
下面是幾個重要的標記
--------------------
SOI = Start Of Image = 'FFD8'
這個標記只在檔開始出現一次
EOI = End Of Image = 'FFD9'
JPG 文件都以 FFD9 結束
RSTi = FFDi ( i = 0..7) [ RST0 = FFD0, RST7=FFD7]
= 重定標記
通常穿插在資料流程裏, 我想是擔心 JPG 解碼出問題吧(應該配合 DRI 使用). 不過很
多 JPG 都不使用它
(SOS --- RST0 --- RST1 -- RST2 --...
...-- RST6 --- RST7 -- RST0 --...)
----
標記
----
下面是必須處理的標記
SOF0 = Start Of Frame 0 = FFC0
SOS = Start Of Scan = FFDA
APP0 = it's the marker used to identify a JPG file which uses the JFIF
specification = FFE0
COM = Comment = FFFE
DNL = Define Number of Lines = FFDC
DRI = Define Restart Interval = FFDD
DQT = Define Quantization Table = FFDB
DHT = Define Huffman Table = FFC4
JPG 檔中 Haffman 表的儲存
---------------------------
JPEG 裏定義了一張表來描述 Haffman 樹. 定義在 DHT 標記後面. 注意: Haffman
代碼的長度限制在 16bit 內.
一般一個 JPG 檔裏會有 2 類 Haffman 表: 一個用於 DC 一個用於 AC (實際有 4
個表, 亮度的 DC,AC 兩個, 色度的 DC,AC 兩個)
這張表是這樣保存的:
1) 16 位元組:
第 i 位元組表示了 i 位元長的 Huffman 代碼的個數 (i= 1 到 16)
2) 這表的長度 (位元組數) = 這 16 個數字之和
現在你可以想像這張表怎麼存放的吧? 對應位元組就是對應 Haffman 代碼等價數字. 我
不多解釋, 這需要你先瞭解 Haffman 演算法. 這裏只舉一個例子:
Haffman 表的表頭是 0,2,3,1,1,1,0,1,0,0,0,0,0,0,0,0
就是說長度為 1 的代碼沒有
長度為 2 的代碼為 00
01
長度為 3 的代碼是 100
101
110
長度為 4 的代碼是 1110
長度為 5 的代碼是 11110
長度為 6 的代碼是 111110
長度為 7 的代碼沒有 (如果有一個的話應該是 1111110)
長度為 8 的代碼是 11111100
.....
後面都沒有了.
如果表下面的資料是
45 57 29 17 23 25 34 28
就是說
45 = 00
57 = 01
29 = 100
17 = 101
23 = 110
等等...
如果你懂 Haffman 編碼, 這些不難理解
採樣係數
--------
下面講解的都是真彩 JPG 的解碼, 灰度 JPG 的解碼很簡單, 因為圖形中只有亮度信
息. 而彩色圖形由 (Y, Cr, Cb) 構成, 前面提到過, Y 通常是每點採樣一次, 而 Cr,
Cb 一般是 2x2 點採樣一次, 當然也有的 JPG 是逐點採樣, 或者每兩點採樣 (橫向
兩點, 縱向一點) 採樣係數均被定義成對比最高採樣係數的相對值.
一般情況 (即: Y 逐點採樣, Cr Cb 每 2x2 點一次) 下: Y 有最高的採樣率, 橫向采
樣係數HY=2 縱向採樣係數 VY=2; Cb 的橫向採樣係數 HCb=1, 縱向採樣係數 VCb=1;
同樣 HCr=1, VCr=1
在 Jpeg 裏, 8x8 個原始資料, 經過 RLC, Huffman 編碼後的一串資料流程稱為一個
Data Unit (DU) JPG 裏按 DU 為單位的編碼次序如下:
1) for (counter_y=1;counter_y<=VY;counter_y++)
for (counter_x=1;counter_x<=HY;counter_x++)
{ 對 Y 的 Data Unit 編碼 }
2) for (counter_y=1;counter_y<=VCb ;counter_y++)
for (counter_x=1;counter_x<=HCb;counter_x++)
{ 對 Cb 的 Data Unit 編碼 }
3) for (counter_y=1;counter_y<=VCr;counter_y++)
for (counter_x=1;counter_x<=HCr;counter_x++)
{ 對 Cr 的 Data Unit 編碼 }
按我上面的例子: (HY=2, VY=2 ; HCb=VCb =1, HCr,VCr=1) 就是這樣一個次序
YDU,YDU,YDU,YDU,CbDU,CrDU
這些就描述了一塊 16x16 的圖形. 16x16 = (Hmax*8 x Vmax*8) 這裏 Hmax=HY=2
Vmax=VY=2
一個 (Hmax*8,Vmax*8) 的塊被稱作 MCU (Minimun Coded Unix) 前面例子中一個
MCU = YDU,YDU,YDU,YDU,CbDU,CrDU
如果 HY =1, VY=1
HCb=1, VCb=1
HCr=1, VCr=1
這樣 (Hmax=1,Vmax=1), MCU 只有 8x8 大, MCU = YDU,CbDU,CrDU
對於灰度 JPG, MCU 只有一個 DU (MCU = YDU)
JPG 檔裏, 圖像的每個組成部分的採樣係數定義在 SOF0 (FFC0) 標記後
簡單說一下 JPG 文件的解碼
-------------------------
解碼程式閑從 JPG 檔中讀出採樣係數, 這樣就知道了 MCU 的大小, 算出整個圖像
有幾個 MCU. 解碼程式再迴圈逐個對 MCU 解碼, 一直到檢查到 EOI 標記. 對於每個
MCU, 按正規的次序解出每個 DU, 然後組合, 轉換成 (R,G,B) 就 OK 了
附:JPEG 檔格式
~~~~~~~~~~~~~~~~
- 文件頭 (2 bytes): $ff, $d8 (SOI) (JPEG 檔標識)
- 任意數量的段 , 見後面
- 文件結束 (2 bytes): $ff, $d9 (EOI)
段的格式:
~~~~~~~~~
- header (4 bytes):
$ff 段標識
n 段的類型 (1 byte)
sh, sl 該段長度, 包括這兩個位元組, 但是不包括前面的 $ff 和 n.
注意: 長度不是 intel 次序, 而是 Motorola 的, 高位元組在前,
低位元組在後!
- 該段的內容, 最多 65533 位元組
注意:
- 有一些無參數的段 (下面那些前面注明星號的)
這些段沒有長度描述 (而且沒有內容), 只有 $ff 和類型位元組.
- 每一個段結束到下一個 $ff 間的資料都是合法的, 必須被忽略掉.
段的類型:
~~~~~~~~~
*TEM = $01 可以忽略掉
SOF0 = $c0 幀開始 (baseline JPEG), 細節附後
SOF1 = $c1 dito
SOF2 = $c2 通常不支持
SOF3 = $c3 通常不支持
SOF5 = $c5 通常不支持
SOF6 = $c6 通常不支持
SOF7 = $c7 通常不支持
SOF9 = $c9 arithmetic 編碼(Huffman 的一種擴展演算法), 通常不支援
SOF10 = $ca 通常不支持
SOF11 = $cb 通常不支持
SOF13 = $cd 通常不支持
SOF14 = $ce 通常不支持
SOF14 = $ce 通常不支持
SOF15 = $cf 通常不支持
DHT = $c4 定義 Huffman Table, 細節附後
JPG = $c8 未定義/保留 (引起解碼錯誤)
DAC = $cc 定義 Arithmetic Table, 通常不支援
*RST0 = $d0 RSTn 用於 resync, 通常被忽略
*RST1 = $d1
*RST2 = $d2
*RST3 = $d3
*RST4 = $d4
*RST5 = $d5
*RST6 = $d6
*RST7 = $d7
SOI = $d8 圖片開始
EOI = $d9 圖片結束
SOS = $da 掃描行開始, 細節附後
DQT = $db 定義 Quantization Table, 細節附後
DNL = $dc 通常不支持, 忽略
DRI = $dd 定義重新開始間隔, 細節附後
DHP = $de 忽略 (跳過)
EXP = $df 忽略 (跳過)
APP0 = $e0 JFIF APP0 segment marker (細節略)
APP15 = $ef 忽略
JPG0 = $f0 忽略 (跳過)
JPG13 = $fd 忽略 (跳過)
COM = $fe 注釋, 細節附後
其他的段類型都保留必須跳過
SOF0: Start Of Frame 0:
~~~~~~~~~~~~~~~~~~~~~~~
- $ff, $c0 (SOF0)
- 長度 (高位元組, 低位元組), 8+components*3
- 資料精度 (1 byte) 每個樣本位元數, 通常是 8 (大多數軟體不支援 12 和 16)
- 圖片高度 (高位元組, 低位元組), 如果不支援 DNL 就必須 >0
- 圖片寬度 (高位元組, 低位元組), 如果不支援 DNL 就必須 >0
- components 數量(1 byte), 灰度圖是 1, YCbCr/YIQ 彩色圖是 3, CMYK 彩色圖
是 4
- 每個 component: 3 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
- 採樣係數 (bit 0-3 vert., 4-7 hor.)
- quantization table 數
DRI: Define Restart Interval:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- $ff, $dd (DRI)
- 長度 (高位元組, 低位元組), 必須是 4
- MCU 塊的單元中的重新開始間隔 (高位元組, 低位元組),
意思是說, 每 n 個 MCU 塊就有一個 RSTn 標記.
第一個標記是 RST0, 然後是 RST1 等, RST7 後再從 RST0 重複
DQT: Define Quantization Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- $ff, $db (DQT)
- 長度 (高位元組, 低位元組)
- QT 信息 (1 byte):
bit 0..3: QT 號(0..3, 否則錯誤)
bit 4..7: QT 精度, 0 = 8 bit, 否則 16 bit
- n 位元組的 QT, n = 64*(精度+1)
評論:
- 一個單獨的 DQT 段可以包含多個 QT, 每個都有自己的資訊位元組
- 當精度=1 (16 bit), 每個字都是高位在前低位元在後
DAC: Define Arithmetic Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
法律原因, 現在的軟體不支援 arithmetic 編碼.
不能生產使用 arithmetic 編碼的 JPEG 檔
DHT: Define Huffman Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~
- $ff, $c4 (DHT)
- 長度 (高位元組, 低位元組)
- HT 信息 (1 byte):
bit 0..3: HT 號 (0..3, 否則錯誤)
bit 4 : HT 類型, 0 = DC table, 1 = AC table
bit 5..7: 必須是 0
- 16 bytes: 長度是 1..16 代碼的符號數. 這 16 個數的和應該 <=256
- n bytes: 一個包含了按遞增次序代碼長度排列的符號表
(n = 代碼總數)
評論:
- 一個單獨的 DHT 段可以包含多個 HT, 每個都有自己的資訊位元組
COM: 注釋:
~~~~~~~~~~
- $ff, $fe (COM)
- 注釋長度 (高位元組, 低位元組) = L+2
- 注釋為長度為 L 的字元流
SOS: Start Of Scan:
~~~~~~~~~~~~~~~~~~~
- $ff, $da (SOS)
- 長度 (高位元組, 低位元組), 必須是 6+2*(掃描行內元件的數量)
- 掃描行內元件的數量 (1 byte), 必須 >= 1 , <=4 (否則是錯的) 通常是 3
- 每個元件(部分): 2 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), 見 SOF0
- 使用的 Huffman 表00-1-14:
- bit 0..3: AC table (0..3)
- bit 4..7: DC table (0..3)
- 忽略 3 bytes (???)
評論:
- 圖片資料 (一個個掃描行) 緊接著 SOS 段.
星期一, 8月 20, 2007
[jpeg]Huffmantree
上個禮拜二跟老師meeting之後
確認了自己目前的想法沒錯
HuffVal就是Symbol Value
接下來就要進入huffmantree的部份了
其實上學期期初我就有做過Huffmantree的部份
可是那時候不懂什麼是Symbol Value
只是單純的知道 Huffmancode 是怎麼產生的
一直用之前影像處理學到的方式去寫程式
原來我整個想錯了
利用規格書 Annex C 的作法
就會產生相對應的Huffmancode 和HuffVal
(其實HuffVal是他會給你的東西,就是那個在L1~L16之後的東西)
不過我目前的程式已經很大一個了
有點不好除錯
感覺直接在裡面寫Huffman Tree是不智之舉
乾脆另外寫一個程式
把JPEG Decoder裡面產生的Huffmancode(Binary)和HuffVal抄下來
手動輸入
測試看看
應該就不會錯了吧
好!!
今日目標
KO Huffmantree
確認了自己目前的想法沒錯
HuffVal就是Symbol Value
接下來就要進入huffmantree的部份了
其實上學期期初我就有做過Huffmantree的部份
可是那時候不懂什麼是Symbol Value
只是單純的知道 Huffmancode 是怎麼產生的
一直用之前影像處理學到的方式去寫程式
原來我整個想錯了
利用規格書 Annex C 的作法
就會產生相對應的Huffmancode 和HuffVal
(其實HuffVal是他會給你的東西,就是那個在L1~L16之後的東西)
不過我目前的程式已經很大一個了
有點不好除錯
感覺直接在裡面寫Huffman Tree是不智之舉
乾脆另外寫一個程式
把JPEG Decoder裡面產生的Huffmancode(Binary)和HuffVal抄下來
手動輸入
測試看看
應該就不會錯了吧
好!!
今日目標
KO Huffmantree
訂閱:
文章 (Atom)