キー | 画像 | 意味 | 特徴 |
---|---|---|---|
0 | 元.png | 3つの元画像を横に並べたもの | |
1 | 1無圧縮.png | 無圧縮でデータ化したものから復元したものを横に並べたもの | 元.pngと完全に同じ |
2 | 2非等長.png | 非等長符号でデータ化したものから復元したものを横に並べたもの | 元.pngと完全に同じ |
3 | 3ランレングス.png | ランレングス符号でデータ化したものから復元したものを横に並べたもの | 元.pngと完全に同じ |
4 | 結果.png | 画像・データ化の方法ごとの圧縮率が書き込まれたもの | 黒背景の白文字画像 |
|
→ |
|
→ |
|
// 画像の変数 PImage[][] img = new PImage[4][3]; // 元画像と復元画像[元,無圧縮,非等長,ランレングス][A, B, C] PImage[] imgr = new PImage[5]; // 保存用に結合した画像と圧縮結果画像[元,無圧縮,非等長,ランレングス,圧縮結果] PGraphics[] pg = new PGraphics[5]; // imgrに対応するグラフィックス // 画像名 String[] fName = {"元", "1無圧縮", "2非等長", "3ランレングス", "結果"}; int w, h; // 元画像の横と縦のサイズ // 非等長符号の0000~1111の置き換え先 String[] code = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}; String[] bt = new String[16]; // codeの逆の置き換え先 void setup() { size(750, 250); for (int i=0; i<16; i++) { bt[i]=binary(i, 4); } noSmooth(); // 元画像のロードと変換結果保存用画像の準備 for (int i=0; i<3; i++) { img[0][i]=loadImage(char('A'+i)+"元.bmp"); w=img[0][i].width; h=img[0][i].height; for (int j=1; j<=3; j++) { img[j][i]=createImage(w, h, ARGB); } } // 結果表示用画像とそのグラフィックスの準備 for (int i=0; i<=4; i++) { imgr[i] = createImage(w*3, h, RGB); pg[i] = createGraphics(imgr[i].width, imgr[i].height); pg[i].beginDraw(); } pg[4].textFont(createFont("MS Pゴシック", 16)); // 元画像の結合画像作成 for (int i=0; i<3; i++) { pg[0].image(img[0][i], w*i, 0, w, h); } textFont(createFont("MS Pゴシック", 48)); for (int k=0; k<3; k++) { // k番目の画像を無圧縮でデータ化する // 無圧縮のデータファイルを読み込んでk番目の画像を復元する } for (int k=0; k<3; k++) { // k番目の画像を非等長符号でデータ化する // 非等長符号のデータファイルを読み込んでk番目の画像を復元する } for (int k=0; k<3; k++) { // k番目の画像をランレングス符号でデータ化する // ランレングス符号のデータファイルを読み込んでk番目の画像を復元する } // 結果をファイルに保存 for (int i=0; i<=4; i++) { pg[i].endDraw(); imgr[i].pixels = pg[i].pixels; imgr[i].updatePixels(); imgr[i].save("data/" + fName[i] + ".png"); } image(imgr[0], 0, 0, width, height); println("完了"); } void draw() { } // 押したキーに応じて対応する画像を表示 void keyPressed() { int k = key-'0'; if (k>=0 && k<=4) { background(0); image(imgr[k], 0, 0, width, height); fill(255, 0, 0); text(fName[k], 30, height-30); fill(0, 0, 100); } }
// 元画像kを無圧縮でバイナリ化したデータをファイルに保存 void encode1(int k) { ArrayList<Byte> b = new ArrayList(); int pos=0; // 1バイト中の位置 byte b0=0; // 8bit (1バイト)分の情報を入れる変数 for (int j=0; j<h; j++) { for (int i=0; i<w; i++) { // (i, j)のピクセルの明度に応じたビットをb0に追加 pos++; if (pos<8) { b0*=2; // 2進数的な桁上げ } else { b.add(b0); pos=0; b0=0; } } } // 最後に8bitに達しなかった分の後ろに0を詰めてリストに追加 for (; pos<7; pos++) { b0*=2; } b.add(b0); // リストから配列にデータをコピーする byte[] bytes = new byte[b.size()]; for (int i=0; i<bytes.length; i++) { bytes[i]=b.get(i); } // 圧縮結果を画像に書き込む String result = char('A'+k) + fName[1] + ":" + bytes.length + "バイト"; result += "(" + int(100*bytes.length/(w*h/8)) + "%)"; pg[4].text(result, 10, 16*(1+k)); // バイナリデータをファイルに保存 saveBytes("data/" + char('A'+k) + fName[1] + ".dat", bytes); }
// 無圧縮データから画像kを復元 void decode1(int k) { // ファイル読み込み byte[] bytes = loadBytes("data/" + char('A'+k) + fName[1] + ".dat"); String data=""; // バイナリデータを文字列化して入れるもの for (int i=0; i<bytes.length; i++) { data += binary(bytes[i]); } for (int i=0; i<w*h; i++) { // i番目のデータが'0'なら黒、'1'なら白を画像[1][k]のi番目のピクセルに設定する } img[1][k].updatePixels(); pg[1].image(img[1][k], w*k, 0); }
|
→ |
|
→ |
|
→ |
|
// 元画像kを非等長符号でバイナリ化したデータをファイルに保存 void encode2(int k) { ArrayList<Byte> b = new ArrayList(); int pos=0; // 1バイト中の位置 byte b0=0; // 8bit (1バイト)分の情報を入れる変数 for (int j=0; j<h; j++) { for (int i=0; i<w; i+=4) { // 横に並んだ元画像のピクセルの色に対応する値(0, 1) int bb_[]={0, 0, 0, 0}; for (int l=0; l<4; l++) { if (i+l<w) { bb_[l]+=(int)brightness(img[0][k].pixels[i+l+j*w])/255; } } // bb_のビットの並びを2進数として扱った値 int bb = bb_[0]*8+bb_[1]*4+bb_[2]*2+bb_[3]; // 置き換えた並びをb0に追加 for (int cpos=0; cpos<code[bb].length(); cpos++) { // code[bb]の文字に応じたビットをb0に追加 b0 += code[bb].charAt(cpos)-'0'; pos++; if (pos<8) { // 2進数的な桁上げ b0 *= 2; } // 8ビット目の処理後ならリストにb0を追加してリセット else { b.add(b0); pos=0; b0=0; } } } } // 最後に8bitに達しなかった分の後ろに0を詰めてリストに追加 for (; pos<7; pos++) { b0*=2; } b.add(b0); // リストから配列にデータをコピーする byte[] bytes = new byte[b.size()]; for (int i=0; i<bytes.length; i++) { bytes[i]=b.get(i); } // 圧縮結果を画像に書き込む String result = char('A'+k) + fName[2] + ":" + bytes.length + "バイト"; result += "(" + int(100*bytes.length/(w*h/8)) + "%)"; pg[4].text(result, 10, 16*(5+k)); // バイナリデータをファイルに保存 saveBytes("data/" + char('A'+k) + fName[2] + ".dat", bytes); }
// 非等長符号で圧縮したデータから画像kを復元 void decode2(int k) { // ファイル読み込み byte[] bytes = loadBytes("data/" + char('A'+k) + fName[2] + ".dat"); String data=""; // バイナリデータを文字列化して入れるもの for (int i=0; i<bytes.length; i++) { data += binary(bytes[i]); } int x=0; int y=0; while (true) { int bitnum = -1; // 置き換えるビットの並びの番号(0~3) for (int j=0; j<code.length; j++) { // dataの先頭の文字列とcodeの並びを比較する if (code[j].length()<=data.length()) { if (code[j].equals(data.substring(0, code[j].length()))) { bitnum = j; } } } // 置き換え先の値に応じてピクセルの色を設定する for (int i=0; i<4; i++) { if (x+i<w) { img[2][k].pixels[x+i+y*w] = color((bt[bitnum].charAt(i)-'0')*255); } } // 読み込んだ分だけデータを削除 data = data.substring(code[bitnum].length()); // 次の位置に移動 x+=4; if (x>=w) { // 最後のピクセルに達したらループを抜ける if (y==h-1) { break; } x=0; y++; } } img[2][k].updatePixels(); pg[2].image(img[2][k], w*k, 0); }
// 元画像kをランレングス符号でバイナリ化したデータをファイルに保存 void encode3(int k) { ArrayList<Byte> b = new ArrayList(); for (int j=0; j<h; j++) { int count=0; // 連続個数カウント int previousColor=1; // 「直前の色」(最初は白とする) for (int i=0; i<w; i++) { // 元画像kの(i, j)のピクセルが黒なら0, 白なら1を int currentColorに入れる int currentColor = 0; // 色が変わったら if (currentColor != previousColor) { previousColor = currentColor; // 「直前の色」を更新 b.add(byte(count)); // リストに連続個数を追加 count = 1; // このピクセルの分をカウント } // 前と同じ色なら連続個数を追加 else { count++; } // 行の最後に達したら if (i == w-1) { b.add(byte(count)); // リストに連続個数を追加 } } } // リストから配列にデータをコピーする byte[] bytes = new byte[b.size()]; for (int i=0; i<bytes.length; i++) { bytes[i]=b.get(i); } // 圧縮結果を画像に書き込む String result = char('A'+k) + fName[3] + ":" + bytes.length + "バイト"; result += "(" + int(100*bytes.length/(w*h/8)) + "%)"; pg[4].text(result, 10, 16*(9+k)); // バイナリデータをファイルに出力 saveBytes("data/" + char('A'+k) + fName[3] + ".dat", bytes); }
// ランレングス符号で圧縮したデータから画像kを復元 void decode3(int k) { // ファイル読み込み byte[] bytes = loadBytes("data/" + char('A'+k) + fName[3] + ".dat"); int x=0; int y=0; // 8ビットずつ画像のピクセルに置き換える int currentColor=1; for (int l=0; l<bytes.length; l++) { int n = 0; // l番目のデータを整数化してnに入れる for (int i=0; i<n; i++) { img[3][k].pixels[x+i+y*w] = color(currentColor*255); } x+=n; // 設定した分だけ現在位置を進める // 行末に達したら次の行に移って色を白に戻す if (x>=w) { x=0; y++; currentColor=1; } // 行の途中の場合は白黒反転 else { currentColor=1-currentColor; } } img[3][k].updatePixels(); pg[3].image(img[3][k], w*k, 0); }