講義科目「画像工学」では画像処理の演習課題として、プログラミング言語 Processing を用いてプログラムの作成を行います。ここでは、参考となる画像処理プログラムを記載します。
編集中・・・
プログラムの実行について
Processing version 3.5.4 で動作確認しています。JavaモードとPythonモードの両方のプログラムを記載しています。
プログラムの作成と実行の方法については講義資料のVODを見てください。
画像ファイルは自分で用意してください。このページでは pixabay からダウンロードした画像を使用しています。
プログラム一覧
- 変数の使用、コンソールへの出力
- 演算、型変換
- 画像ファイルの読み込みと画像の表示
- 画像の作成、画素値の読み書き、画像ファイルへの保存
- 画像を明るくする輝度変換
- 画像のガンマ補正
- カラー画像をRGBの各プレーンにわけて表示
- カラー画像をグレイスケール画像に変換
- カラー画像をセピア調画像に変換
- ヒストグラムの計算と描画
- カラー画像のホワイトバランス調整
- Processingの組み込みフィルタ
- 平均値フィルタ
- 1次微分フィルタ
- エンボス加工
- ラプラシアンフィルタ
- 画像の平行移動
- 画像の拡大縮小(最近隣内挿)
- 画像の拡大縮小(バイリニア内挿)
- 画像の回転
- アフィン変換
- 射影変換
- 任意の座標を中心して拡大する合成変換
- アフィン変換を使ったアニメーション
- 判別分析法によるグレイスケール画像の2値化
- モーメント特徴による図形の重心・面積・主軸方向の計測
- 図形の輪郭追跡と円形度の計測
- 2画像の相違度SSD(差分2乗和)の計測
- SSDによるテンプレートマッチング
変数の使用、コンソールへの出力
1 2 3 4 5 6 7 8 9 10 |
void setup() { int a; // 整数型変数aを宣言する float x; // 実数型変数xを宣言する a = 12; // aに12を代入する x = 3.5; // xに3.5を代入する println(a); // aの値をコンソールに出力する println(a, x); // aとxの値を並べてコンソールに出力する println("Hello"); // 文字列「Hello」をコンソールに出力する println("a=", a, ", x=", x); // 文字列と変数を並べてコンソールに出力する } |
1 2 3 4 5 6 7 |
def setup(): a = 12 # aに12を代入する。変数aは整数型になる x = 3.5 # xに3.5を代入する。変数xは実数型になる print a # aの値をコンソールに出力する。()は無くてもよい(Python2の仕様) print a, x # aとxの値を並べてコンソールに出力する print 'Hello' # 文字列「Hello」をコンソールに出力する。囲み記号は'でも"でもよい print "a=", a, ", x=", x # 文字列と変数を並べてコンソールに出力する |
演算、型変換
1 2 3 4 5 6 7 8 9 10 11 12 |
void setup() { int a; // 整数型変数aを宣言する float x; // 実数型変数xを宣言する a = 5; // aに5を代入する println("a=", a); // aの値を出力する println("a/2=", a/2); // a/2の演算結果を出力する。整数同士の演算結果は整数になる println("a/2.0=", a/2.0); // a/2.0の演算結果を出力する。小数点のある数値は実数型になる x = 3.14; // xに3.14を代入する // a = x; // 整数型変数には実数を代入できない【実行するとエラーになる】 a = int(x); // 実数をint()関数で整数に変換すれば整数型変数に代入できる println("a=", a); // aの値を出力する。3が出力される } |
1 2 3 4 5 6 7 8 |
def setup(): a = 5 # aに5を代入する。aは整数型変数になる print "a=", a # aの値を出力する print "a/2=", a/2 # a/2の演算結果を出力する。整数同士の演算結果は整数になる(Python2の仕様) print "a/2.0=", a/2.0 # a/2.0の演算結果を出力する。小数点のある数値は実数型になる x = 3.14 # xに3.14を代入する。xは実数型変数になる a = x # aにxの値を代入する。aは代入される数値の型に合わせて実数型変数に変わる print "a=", a # aの値を出力する。3.14が出力される |
画像ファイルの読み込みと画像の表示
1 2 3 4 5 6 7 8 9 10 |
PImage f; // 画像オブジェクトfを宣言する void setup() { f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む surface.setSize(f.width, f.height); // 実行画面のサイズを画像fと同じに設定する(size()関数の代替) } void draw() { image(f, 0, 0); // 実行画面に画像fを貼る } |
1 2 3 4 5 6 7 |
def setup(): global f # 変数fのグローバル宣言(draw()関数からも参照できるようにする) f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む this.surface.setSize(f.width, f.height) # 実行画面のサイズを画像fと同じに設定する(size()関数の代替) def draw(): image(f, 0, 0) # 実行画面に画像fを貼る |
画像の作成、画素値の読み書き、画像ファイルへの保存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
PImage f, g; // 画像オブジェクトf,gを宣言する void setup() { int x, y; // 整数型変数x,yを宣言する color c; // color型変数cを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む g = createImage(f.width, f.height, RGB); // 画像gを画像fと同じサイズで作る surface.setSize(f.width*2, f.height); // 実行画面の横幅を画像fの2倍に設定する // 2重forループでラスタ走査を行う for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 画像fの座標(x,y)の色の値(color型)をcに代入する g.set(x, y, c); // 画像gの座標(x,y)の色をcに設定する } } g.save("output.jpg"); // 画像gをファイルoutput.jpgに保存する } void draw() { image(f, 0, 0); // 実行画面の左側に画像f(原画像)を貼る image(g, f.width, 0); // 実行画面の右側に画像g(画像fから複製した画像)を貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def setup(): global f, g # 変数f,gのグローバル宣言(draw()関数からも参照できるようにする) f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む g = createImage(f.width, f.height, RGB) # 画像gを画像fと同じサイズで作る this.surface.setSize(f.width*2, f.height) # 実行画面の横幅を画像fの2倍に設定する # 2重forループでラスタ走査を行う for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y) # 画像fの座標(x,y)の色の値(color型)をcに代入する g.set(x, y, c) # 画像gの座標(x,y)の色をcに設定する g.save("output.jpg") # 画像gをファイルoutput.jpgに保存する def draw(): image(f, 0, 0) # 実行画面の左側に原画像fを貼る image(g, f.width, 0) # 実行画面の右側に画像g(画像fから複製した画像)を貼る |
画像を明るくする輝度変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
PImage f; // 画像オブジェクトfを宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float R, G, B; // 実数型変数R,G,Bを宣言する color c; // color型変数cを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む surface.setSize(f.width, f.height); // 実行画面のサイズを画像fと同じに設定する for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 画像fの座標(x,y)の色の値(color型)をcに代入する R = red(c); // cから赤の画素値を取り出してRに代入する G = green(c); // cから緑の画素値を取り出してGに代入する B = blue(c); // cから青の画素値を取り出してBに代入する R += 100; // Rに100を加算する G += 100; // Gに100を加算する B += 100; // Bに100を加算する c = color(R, G, B); // R,G,Bからcolor型の値を作ってcに代入する f.set(x, y, c); // 画像fの座標(x,y)の色をcに設定する } } f.save("output.jpg"); // 画像fをファイルoutput.jpgに保存する } void draw() { image(f, 0, 0); // 実行画面に画像fを貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
def setup(): global f # 変数fのグローバル宣言(draw()関数からも参照できるようにする) f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む this.surface.setSize(f.width, f.height) # 実行画面のサイズを画像fと同じに設定する for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x,y) # 画像fの座標(x,y)の色の値(color型)をcに代入する R = red(c) # cから赤の画素値を取り出してRに代入する G = green(c) # cから緑の画素値を取り出してGに代入する B = blue(c) # cから青の画素値を取り出してBに代入する R += 100 # Rに100を加算する G += 100 # Gに100を加算する B += 100 # Bに100を加算する c = color(R, G, B) # R,G,Bからcolor型の値を作ってcに代入する f.set(x, y, c) # 画像fの座標(x,y)の色をcに設定する f.save("output.jpg") # 画像fをファイルoutput.jpgに保存する def draw(): image(f, 0, 0) # 実行画面に画像fを貼る |
画像のガンマ補正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
PImage f; // 画像オブジェクトfを宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float R, G, B; // 実数型変数R,G,Bを宣言する float newR, newG, newB; // 実数型変数newR,newG,newBを宣言する color c; // color型変数cを宣言する float gamma = 2.0; // 実数型変数gammaを宣言して、ガンマ値を2.0に設定する float[] table = new float[256]; // 実数型配列tableを宣言する(ルックアップテーブル用) f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む surface.setSize(f.width, f.height); // 実行画面のサイズを画像fと同じに設定する for(x = 0; x < 256; x++) { // xを0から255まで1ずつ増やす table[x] = pow(x/255., 1./gamma)*255; // 画素値xに対するガンマ補正の変換値を算出してtable[x]に代入する } for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 画像fの座標(x,y)の色の値(color型)をcに代入する R = red(c); // cから赤の画素値を取り出してRに代入する G = green(c); // cから緑の画素値を取り出してGに代入する B = blue(c); // cから青の画素値を取り出してBに代入する newR = table[int(R)]; // 赤の画素値に対応する変換値をtableから取り出し、newRに代入する newG = table[int(G)]; // 緑の画素値に対応する変換値をtableから取り出し、newGに代入する newB = table[int(B)]; // 青の画素値に対応する変換値をtableから取り出し、newBに代入する c = color(newR, newG, newB); // newR,newG,newBからcolor型の値を作ってcに代入する f.set(x, y, c); // 画像fの座標(x,y)の色をcに設定する } } f.save("output.jpg"); // 画像fをファイルoutput.jpgに保存する } void draw() { image(f, 0, 0); // 実行画面に画像fを貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
def setup(): global f # 変数fのグローバル宣言(draw()関数からも参照できるようにする) f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む this.surface.setSize(f.width, f.height) # 実行画面のサイズを画像fと同じに設定する gamma = 2.0 # gammaにガンマ値2.0を設定する table = [pow(x/255., 1./gamma)*255 for x in range(0, 256)] # 画素値0~255のガンマ補正の変換値のリストをtableに代入する for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x,y) # 画像fの座標(x,y)の色の値(color型)をcに代入する R = red(c) # cから赤の画素値を取り出してRに代入する G = green(c) # cから緑の画素値を取り出してGに代入する B = blue(c) # cから青の画素値を取り出してBに代入する newR = table[int(R)] # 赤の画素値に対応する変換値をtableから取り出し、newRに代入する newG = table[int(G)] # 緑の画素値に対応する変換値をtableから取り出し、newGに代入する newB = table[int(B)] # 青の画素値に対応する変換値をtableから取り出し、newBに代入する c = color(newR, newG, newB) # newR,newG,newBからcolor型の値を作ってcに代入する f.set(x, y, c) # 画像fの座標(x,y)の色をcに設定する f.save("output.jpg") # 画像fをファイルoutput.jpgに保存する def draw(): image(f, 0, 0) # 実行画面に画像fを貼る |
カラー画像をRGBの各プレーンにわけて表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
PImage f, g1, g2, g3; // 画像オブジェクトf,g1,g2,g3を宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float R, G, B; // 実数型変数R,G,Bを宣言する color c; // color型変数cを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む g1 = createImage(f.width, f.height, RGB); // 画像g1を画像fと同じサイズで作る(赤プレーン用) g2 = createImage(f.width, f.height, RGB); // 画像g2を画像fと同じサイズで作る(緑プレーン用) g3 = createImage(f.width, f.height, RGB); // 画像g3を画像fと同じサイズで作る(青プレーン用) surface.setSize(f.width*2, f.height*2); // 実行画面の縦幅横幅を画像fの2倍に設定する for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 座標(x,y)の色の値(color型)をcに代入する R = red(c); // cから赤の画素値を取り出してRに代入する G = green(c); // cから緑の画素値を取り出してGに代入する B = blue(c); // cから青の画素値を取り出してBに代入する c = color(R, 0, 0); // 赤の画素値のみでcolor型の値を作ってcに代入する g1.set(x, y, c); // 画像g1の座標(x,y)の色をcに設定する c = color(0, G, 0); // 緑の画素値のみでcolor型の値を作ってcに代入する g2.set(x, y, c); // 画像g2の座標(x,y)の色をcに設定する c = color(0, 0, G); // 緑の画素値のみでcolor型の値を作ってcに代入する g3.set(x, y, c); // 画像g3の座標(x,y)の色をcに設定する } } } void draw() { image(f, 0, 0); // 実行画面の左上に原画像fを貼る image(g1, f.width, 0); // 実行画面の右上に画像g1(赤プレーン)を貼る image(g2, 0, f.height); // 実行画面の左下に画像g2(緑プレーン)を貼る image(g3, f.width, f.height); // 実行画面の右下に画像g3(青プレーン)を貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
def setup(): global f, g1, g2, g3 # 変数f,g1,g2,g3をグローバル宣言 f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む g1 = createImage(f.width, f.height, RGB) # 画像g1を画像fと同じサイズで作る(赤プレーン用) g2 = createImage(f.width, f.height, RGB) # 画像g2を画像fと同じサイズで作る(緑プレーン用) g3 = createImage(f.width, f.height, RGB) # 画像g3を画像fと同じサイズで作る(青プレーン用) this.surface.setSize(f.width*2, f.height*2) # 実行画面を画像fの縦横2倍のサイズに設定する for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x,y) # 画像fの座標(x,y)の色の値(color型)をcに代入する R = red(c) # cから赤の画素値を取り出してRに代入する G = green(c) # cから緑の画素値を取り出してGに代入する B = blue(c) # cから青の画素値を取り出してBに代入する c = color(R, 0, 0) # 赤の画素値のみでcolor型の値を作ってcに代入する g1.set(x, y, c) # 画像g1の座標(x,y)の色をcに設定する c = color(0, G, 0) # 緑の画素値のみでcolor型の値を作ってcに代入する g2.set(x, y, c) # 画像g2の座標(x,y)の色をcに設定する c = color(0, 0, G) # 緑の画素値のみでcolor型の値を作ってcに代入する g3.set(x, y, c) # 画像g3の座標(x,y)の色をcに設定する def draw(): image(f, 0, 0) # 実行画面の左上に原画像fを貼る image(g1, f.width, 0) # 実行画面の右上に画像g1(赤プレーン)を貼る image(g2, 0, f.height) # 実行画面の左下に画像g2(緑プレーン)を貼る image(g3, f.width, f.height) # 実行画面の右下に画像g3(青プレーン)を貼る |
カラー画像をグレイスケール画像に変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
PImage f, g; // 画像オブジェクトf,gを宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float R, G, B, V; // 実数型変数R,G,B,Vを宣言する color c; // color型変数cを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む g = createImage(f.width, f.height, RGB); // 画像gを画像fと同じサイズで作る surface.setSize(f.width*2, f.height); // 画像fの2倍の幅で実行画面のサイズを設定する for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 座標(x,y)の色の値(color型)をcに代入する R = red(c); // cから赤の画素値を取り出してRに代入する G = green(c); // cから緑の画素値を取り出してGに代入する B = blue(c); // cから青の画素値を取り出してBに代入する V = .299*R + .587*G + .114*B; // R,G,Bから明度を計算してVに代入する c = color(V); // Vからcolor型の値を作ってcに代入する。赤、緑、青の画素値がすべてVになる g.set(x, y, c); // 画像gの座標(x,y)の画素の色をcに設定する } } f.save("output.jpg"); // 画像fをファイルoutput.jpgに保存する } void draw() { image(f, 0, 0); // 実行画面の左に原画像fを貼る image(g, f.width, 0); // 実行画面の右に変換後画像gを貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
def setup(): global f, g # 変数f,gのグローバル宣言(draw()関数からも参照できるようにする) f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む g = createImage(f.width, f.height, RGB) # 画像gを画像fと同じサイズで作る this.surface.setSize(f.width*2, f.height) # 実行画面の横幅を画像fの2倍の幅に設定する for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x,y) # 座標(x,y)の色の値(color型)をcに代入する R = red(c) # cから赤の画素値を取り出してRに代入する G = green(c) # cから緑の画素値を取り出してGに代入する B = blue(c) # cから青の画素値を取り出してBに代入する V = .299*R + .587*G + .114*B # R,G,Bから明度を計算してVに代入する c = color(V) # Vからcolor型の値を作ってcに代入する。赤、緑、青の画素値がすべてVになる g.set(x, y, c) # 画像fの座標(x,y)の色をcに設定する g.save("output.jpg") # 画像fをファイルoutput.jpgに保存する def draw(): image(f, 0, 0) # 実行画面の左に原画像fを貼る image(g, f.width, 0) # 実行画面の右に変換後画像gを貼る |
カラー画像をセピア調画像に変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
PImage f, g; // 画像オブジェクトfを宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float R, G, B; // 実数型変数R,G,Bを宣言する float newR, newG, newB; // 実数型変数newR,newG,newBを宣言する color c; // color型変数cを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む g = createImage(f.width, f.height, RGB); // 画像gを画像fと同じサイズで作る surface.setSize(f.width*2, f.height); // 画像fの2倍の幅で実行画面のサイズを設定する for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 座標(x,y)の色の値(color型)をcに代入する R = red(c); // cから赤の画素値を取り出してRに代入する G = green(c); // cから緑の画素値を取り出してGに代入する B = blue(c); // cから青の画素値を取り出してBに代入する newR = .393*R + .769*G + .189*B; // セピア調の赤の画素値を計算してnewRに代入する newG = .349*R + .686*G + .168*B; // セピア調の緑の画素値を計算してnewGに代入する newB = .272*R + .534*G + .131*B; // セピア調の青の画素値を計算してnewBに代入する c = color(newR, newG, newB); // newR,newG,newBからcolor型の値を作ってcに代入する g.set(x, y, c); // 画像gの座標(x,y)の画素の色をcに設定する } } g.save("output.jpg"); // 画像gをファイルoutput.jpgに保存する } void draw() { image(f, 0, 0); // 実行画面の左に原画像fを貼る image(g, f.width, 0); // 実行画面の右に変換後画像gを貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
def setup(): global f, g # 変数fのグローバル宣言(draw()関数からも参照できるようにする) f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む g = createImage(f.width, f.height, RGB); this.surface.setSize(f.width*2, f.height) # 画像fの2倍の幅で実行画面のサイズを設定する for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x,y) # 座標(x,y)の色の値(color型)をcに代入する R = red(c) # cから赤の画素値を取り出してRに代入する G = green(c) # cから緑の画素値を取り出してGに代入する B = blue(c) # cから青の画素値を取り出してBに代入する newR = .393*R + .769*G + .189*B; # セピア調の赤の画素値を計算してnewRに代入する newG = .349*R + .686*G + .168*B; # セピア調の緑の画素値を計算してnewGに代入する newB = .272*R + .534*G + .131*B; # セピア調の青の画素値を計算してnewBに代入する c = color(newR, newG, newB); # newR,newG,newBからcolor型の値を作ってcに代入する g.set(x, y, c) # 画像fの座標(x,y)の画素の色をcに設定する g.save("output.jpg") # 画像fをファイルoutput.jpgに保存する def draw(): image(f, 0, 0) # 実行画面の左に原画像fを貼る image(g, f.width, 0) # 実行画面の右に変換後画像gを貼る |
ヒストグラムの計算と描画
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
PImage f; // 画像オブジェクトfを宣言する int m = 0; // 整数型変数mを宣言して初期値0を代入する int[] histR = new int[256]; // 整数型配列histRを宣言する(赤ヒストグラム用) int[] histG = new int[256]; // 整数型配列histGを宣言する(緑ヒストグラム用) int[] histB = new int[256]; // 整数型配列histBを宣言する(青ヒストグラム用) void setup() { int x, y; // 整数型変数x,yを宣言する float R, G, B; // 実数型変数R,G,Bを宣言する color c; // color型変数cを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む y = max(f.height, 304); // 画像fの縦幅とヒストグラムの縦幅の大きい方をyに代入する surface.setSize(f.width+258, y); // 実行画面を画像fとヒストグラムが並ぶサイズに設定する for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 座標(x,y)の色の値(カラー型)をcに代入する R = red(c); // cから赤の画素値を取り出してRに代入する G = green(c); // cから緑の画素値を取り出してGに代入する B = blue(c); // cから青の画素値を取り出してBに代入する histR[int(R)]++; // 赤の画素値Rの個数に1を加える histG[int(G)]++; // 緑の画素値Gの個数に1を加える histB[int(B)]++; // 青の画素値Bの個数に1を加える m = max(max(histR[int(R)], histG[int(G)], histB[int(B)]), m); // 最大頻度を求めてmに代入する } } } void draw() { int i; // 整数型変数iを宣言する background(240); // 実行画面の背景を灰色にする(R=G=B=240) for (i = 0; i < 256; i++) { // iを0から255まで1ずつ増やす stroke(255, 0, 0); // 線の色を赤色に設定する if (histR[i] > 0) line(i+1, 100, i+1, 100-histR[i]*100/m); // 赤画素値iのヒストグラムのビンを直線で描く stroke(0, 255, 0); // 線の色を緑色に設定する if (histG[i] > 0) line(i+1, 201, i+1, 201-histG[i]*100/m); // 緑画素値iのヒストグラムのビンを直線で描く stroke(0, 0, 255); // 線の色を青色に設定する if (histB[i] > 0) line(i+1, 302, i+1, 302-histB[i]*100/m); // 青画素値iのヒストグラムのビンを直線で描く } image(f, 258, 0); // 実行画面の座標(258,0)の位置(ヒストグラムの右側)に画像fを貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
def setup(): global f, histR, histG, histB, m f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む y = max(f.height, 304) # 画像fの縦幅とヒストグラムの縦幅の大きい方をyに代入する this.surface.setSize(f.width+258, y) # 実行画面を画像fとヒストグラムが並ぶサイズに設定する histR = [0]*256 # 要素数256のリストhistRを作る(赤ヒストグラム用) histG = [0]*256 # 要素数256のリストhistGを作る(緑ヒストグラム用) histB = [0]*256 # 要素数256のリストhistBを作る(青ヒストグラム用) for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x,y) # 画像fの座標(x,y)の色の値(カラー型)をcに代入する R = red(c) # cから赤の画素値を取り出してRに代入する G = green(c) # cから緑の画素値を取り出してGに代入する B = blue(c) # cから青の画素値を取り出してBに代入する histR[int(R)] += 1 # 赤の画素値Rの個数に1を加える histG[int(G)] += 1 # 緑の画素値Gの個数に1を加える histB[int(B)] += 1 # 青の画素値Bの個数に1を加える m = max(histR + histG + histB) # histR,histG,histBの要素の最大値を求めてmに代入する def draw(): background(240) # 実行画面の背景を灰色にする(R=G=B=240) for i in range(0, 256): # iを0から255まで1ずつ増やす stroke(255, 0, 0) # 線の色を赤色に設定する if histR[i] > 0: line(i+1, 100, i+1, 100-histR[i]*100/m) # 赤画素値iのヒストグラムのビンを直線で描く stroke(0, 255, 0) # 線の色を緑色に設定する if histG[i] > 0: line(i+1, 201, i+1, 201-histG[i]*100/m) # 緑画素値iのヒストグラムのビンを直線で描く stroke(0, 0, 255) # 線の色を青色に設定する if histB[i] > 0: line(i+1, 302, i+1, 302-histB[i]*100/m) # 青画素値iのヒストグラムのビンを直線で描く image(f, 258, 0) # 座標(258,0)の位置(ヒストグラムの右側)に画像fを貼る |
カラー画像のホワイトバランス調整
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
PImage f, g; // 画像オブジェクトf,gを宣言する int[] histR = new int[256]; // 整数型配列histRを宣言する(赤ヒストグラム) int[] histG = new int[256]; // 整数型配列histGを宣言する(緑ヒストグラム) int[] histB = new int[256]; // 整数型配列histBを宣言する(青ヒストグラム) void setup() { int x, y, i; // 整数型変数x,y,iを宣言する int minR, minG, minB, maxR, maxG, maxB; // 整数型変数minR,minG,minB,maxR,maxG,maxBを宣言する color c; // color型変数cを宣言する float a, s; // 実数型変数a,sを宣言する float R, G, B; // 実数型変数R,G,Bを宣言する float[] tableR = new float[256]; // 実数型配列tableRを宣言する(赤のルックアップテーブル用) float[] tableG = new float[256]; // 実数型配列tableGを宣言する(緑のルックアップテーブル用) float[] tableB = new float[256]; // 実数型配列tableBを宣言する(青のルックアップテーブル用) f = loadImage("image.jpg"); // 原画像を画像fに読み込む g = createImage(f.width, f.height, RGB); // 画像gを画像fと同じサイズで作る surface.setSize(f.width*2, f.height); // 実行画面のサイズを原画像の2倍の幅に設定する // ヒストグラムを計算する for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 画像fの座標(x,y)の色の値(color型)をcに代入する histR[int(red(c)) ]++; // cから赤画素値を取り出し、histRに個数をカウントする histG[int(green(c))]++; // cから緑画素値を取り出し、histGに個数をカウントする histB[int(blue(c)) ]++; // cから青画素値を取り出し、histBに個数をカウントする } } // 累積ヒストグラムを計算する for (i = 1; i < 256; i++) { // iを1から255まで1ずつ増やす histR[i] += histR[i-1]; // histR[i]にhistR[i-1]の値を加算する histG[i] += histG[i-1]; // histG[i]にhistG[i-1]の値を加算する histB[i] += histB[i-1]; // histB[i]にhistB[i-1]の値を加算する } // ヒストグラムから画素値の最小値と最大値を得る。ただし、ヒストグラムの右端と左端から割合aを除いた範囲とする a = .02; // aに計算から除くヒストグラムの範囲の割合を[0,.5)の範囲で指定する s = histR[255]; // sにhistR[255]の値(画像の全画素数)を代入する minR = minG = minB = 0; // 画素値の最小値minR,minG,minBを0で初期化する maxR = maxG = maxB = 255; // 画素値の最大値maxR,maxG,maxBを255で初期化する while (histR[minR]/s < a && minR < 255) minR++; // 赤の最小画素値を求めてminRに入れる while (histG[minG]/s < a && minG < 255) minG++; // 緑の最小画素値を求めてminGに入れる while (histB[minB]/s < a && minB < 255) minB++; // 青の最小画素値を求めてminBに入れる a = 1 - a; // aに1-aの値を代入する while (histR[maxR]/s > a && maxR > 0) maxR--; // 赤の最大画素値を求めてmaxRに入れる while (histG[maxG]/s > a && maxG > 0) maxG--; // 緑の最大画素値を求めてmaxGに入れる while (histB[maxB]/s > a && maxB > 0) maxB--; // 青の最大画素値を求めてmaxBに入れる // ヒストグラム伸長を行うルックアップテーブルをR,G,Bごとに作成する for (i = 0; i < 256; i++) { // iを0から255まで1ずつ増やす tableR[i] = 255./(maxR-minR)*(i-minR); // 赤画素値のヒストグラム伸長の変換値を求めてtableRに代入する tableG[i] = 255./(maxG-minG)*(i-minG); // 緑画素値のヒストグラム伸長の変換値を求めてtableGに代入する tableB[i] = 255./(maxB-minB)*(i-minB); // 青画素値のヒストグラム伸長の変換値を求めてtableBに代入する } // R,G,Bごとにヒストグラム伸長を行う for (y = 0; y < f.height; y++) { // yを0から画像縦幅-1まで1ずつ増やす for (x = 0; x < f.width; x++) { // xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y); // 画像fの座標(x,y)の色の値(color型)をcに代入する R = tableR[int(red(c))]; // 赤の画素値に対応する変換値をtableRから取り出してRに代入する G = tableG[int(green(c))]; // 緑の画素値に対応する変換値をtableGから取り出してRに代入する B = tableB[int(blue(c))]; // 青の画素値に対応する変換値をtableBから取り出してRに代入する g.set(x, y, color(R, G, B)); // R,G,Bから作ったcolor型の値を画像gの座標(x,y)の画素に設定する } } g.save("output.jpg"); // 画像gをファイルoutput.jpgに保存する } void draw() { image(f, 0, 0); // 実行画面の左側に原画像fを貼る image(g, f.width, 0); // 実行画面の右側に変換後画像gを貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
def setup(): global f, g # 変数f,gのグローバル宣言 f = loadImage("image.jpg") # 原画像を画像fに読み込む g = createImage(f.width, f.height, RGB) # 画像gを画像fと同じサイズで作る this.surface.setSize(f.width*2, f.height) # 実行画面のサイズを原画像の2倍の幅に設定する # ヒストグラムを計算する histR = [0]*256 # リストhistRを宣言する(赤ヒストグラム) histG = [0]*256 # リストhistGを宣言する(緑ヒストグラム) histB = [0]*256 # リストhistBを宣言する(青ヒストグラム) for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y) # 画像fの座標(x,y)の色の値(color型)をcに代入する histR[int(red(c)) ] += 1 # cから赤画素値を取り出し、histRに個数をカウントする histG[int(green(c))] += 1 # cから緑画素値を取り出し、histGに個数をカウントする histB[int(blue(c)) ] += 1 # cから青画素値を取り出し、histBに個数をカウントする # 累積ヒストグラムを計算する for i in range(1, 256): # iを1から255まで1ずつ増やす histR[i] += histR[i-1] # histR[i]にhistR[i-1]の値を加算する histG[i] += histG[i-1] # histG[i]にhistG[i-1]の値を加算する histB[i] += histB[i-1] # histB[i]にhistB[i-1]の値を加算する # ヒストグラムから画素値の最小値と最大値を得る。ただし、ヒストグラムの右端と左端から割合aを除いた範囲とする a = .02 # aに計算から除くヒストグラムの範囲の割合を[0,.5)の範囲で指定する s = float(histR[255]) # sにhistR[255]の値(画像の全画素数)を代入する minR = minG = minB = 0 # 画素値の最小値minR,minG,minBを0で初期化する maxR = maxG = maxB = 255 # 画素値の最大値maxR,maxG,maxBを255で初期化する while histR[minR]/s < a and minR < 255: minR += 1 # 赤の最小画素値を求めてminRに入れる while histG[minG]/s < a and minG < 255: minG += 1 # 緑の最小画素値を求めてminGに入れる while histB[minB]/s < a and minB < 255: minB += 1 # 青の最小画素値を求めてminBに入れる a = 1 - a # aに1-aの値を代入する while histR[maxR]/s > a and maxR > 0: maxR -= 1 # 赤の最大画素値を求めてmaxRに入れる while histG[maxG]/s > a and maxG > 0: maxG -= 1 # 緑の最大画素値を求めてmaxGに入れる while histB[maxB]/s > a and maxB > 0: maxB -= 1 # 青の最大画素値を求めてmaxBに入れる # ヒストグラム伸長を行うルックアップテーブルをR,G,Bごとに作成する tableR = [255./(maxR-minR)*(i-minR) for i in range(0, 256)] # 赤画素値のヒストグラム伸長の変換値を求めてtableRに代入する tableG = [255./(maxG-minG)*(i-minG) for i in range(0, 256)] # 緑画素値のヒストグラム伸長の変換値を求めてtableGに代入する tableB = [255./(maxB-minB)*(i-minB) for i in range(0, 256)] # 青画素値のヒストグラム伸長の変換値を求めてtableBに代入する # R,G,Bごとにヒストグラム伸長を行う for y in range(0, f.height): # yを0から画像縦幅-1まで1ずつ増やす for x in range(0, f.width): # xを0から画像横幅-1まで1ずつ増やす c = f.get(x, y) # 画像fの座標(x,y)の色の値(color型)をcに代入する R = tableR[int(red(c))] # 赤の画素値に対応する変換値をtableRから取り出してRに代入する G = tableG[int(green(c))] # 緑の画素値に対応する変換値をtableGから取り出してRに代入する B = tableB[int(blue(c))] # 青の画素値に対応する変換値をtableBから取り出してRに代入する g.set(x, y, color(R, G, B)) # R,G,Bから作ったcolor型の値を画像gの座標(x,y)の画素に設定する g.save("output.jpg") # 画像gをファイルoutput.jpgに保存する def draw(): image(f, 0, 0) # 実行画面の左側に原画像fを貼る image(g, f.width, 0) # 実行画面の右側に変換後画像gを貼る |
Processingの組み込みフィルタ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
PImage f, g1, g2, g3, g4, g5, g6; // 画像オブジェクトf,g1,g2,g3,g4,g5,g6を宣言する void setup() { f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む surface.setSize(f.width*3, f.height*2); // 実行画面のサイズを画像fの横3倍、縦2倍に設定する g1 = f.copy(); // 画像fをコピーして画像g1を作る g2 = f.copy(); // 画像fをコピーして画像g2を作る g3 = f.copy(); // 画像fをコピーして画像g3を作る g4 = f.copy(); // 画像fをコピーして画像g4を作る g5 = f.copy(); // 画像fをコピーして画像g5を作る g6 = f.copy(); // 画像fをコピーして画像g6を作る g1.filter(GRAY); // 画像g1をグレイスケール画像に変換する g2.filter(POSTERIZE, 4); // 画像g2をポスタリゼーション(階調数変更)する g3.filter(THRESHOLD, 0.5); // 画像g3を2値画像に閾値処理する g4.filter(INVERT); // 画像g4を輝度反転(ネガポジ反転)する g5.filter(BLUR, 1.5); // 画像g5にガウシアンフィルタ(平滑化フィルタ)をかける g6.filter(ERODE); // 画像g6に収縮フィルタ(最小値フィルタ)をかける。 // 膨張フィルタ(最大値フィルタ)の場合はDILATEを指定する } void draw() { image(g1, 0, 0); // 実行画面の左上に画像g1を貼る image(g2, f.width, 0); // 実行画面の中上に画像g2を貼る image(g3, f.width*2, 0); // 実行画面の右上に画像g3を貼る image(g4, 0, f.height); // 実行画面の左下に画像g4を貼る image(g5, f.width, f.height); // 実行画面の中下に画像g5を貼る image(g6, f.width*2, f.height); // 実行画面の右下に画像g6を貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
def setup(): global f, g1, g2, g3, g4, g5, g6 # 変数f,g1,g2,g3,g4,g5,g6のグローバル宣言 f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む this.surface.setSize(f.width*3, f.height*2) # 実行画面のサイズを画像fの横3倍、縦2倍に設定する g1 = f.copy() # 画像fをコピーして画像g1を作る g2 = f.copy() # 画像fをコピーして画像g2を作る g3 = f.copy() # 画像fをコピーして画像g3を作る g4 = f.copy() # 画像fをコピーして画像g4を作る g5 = f.copy() # 画像fをコピーして画像g5を作る g6 = f.copy() # 画像fをコピーして画像g6を作る g1.filter(GRAY) # 画像g1をグレイスケール画像に変換する g2.filter(POSTERIZE, 4) # 画像g2をポスタリゼーション(階調数変更)する g3.filter(THRESHOLD, 0.5) # 画像g3を2値画像に閾値処理する g4.filter(INVERT) # 画像g4を輝度反転(ネガポジ反転)する g5.filter(BLUR, 1.5) # 画像g5にガウシアンフィルタ(平滑化フィルタ)をかける g6.filter(ERODE) # 画像g6に収縮フィルタ(最小値フィルタ)をかける。 # 膨張フィルタ(最大値フィルタ)の場合はDILATEを指定する def draw(): image(g1, 0, 0) # 実行画面の左上に画像g1を貼る image(g2, f.width, 0) # 実行画面の中上に画像g2を貼る image(g3, f.width*2, 0) # 実行画面の右上に画像g3を貼る image(g4, 0, f.height) # 実行画面の左下に画像g4を貼る image(g5, f.width, f.height) # 実行画面の中下に画像g5を貼る image(g6, f.width*2, f.height) # 実行画面の右下に画像g6を貼る |
平均値フィルタ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
PImage f, g; // 画像オブジェクトf,gを宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float a, w; // 実数型変数x,yを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む f.filter(GRAY); // 画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 画像gを画像fと同じサイズで作る surface.setSize(f.width*2, f.height); // 実行画面のサイズを画像fの2倍の幅に設定する w = 1./9; // wに平均値フィルタの係数1/9を代入する for (y = 1; y < f.height-1; y++) { // yを1から画像縦幅-2まで1ずつ増やす for (x = 1; x < f.width-1; x++) { // xを1から画像縦幅-2まで1ずつ増やす // 画像fの座標(x,y)を中心した3×3の領域の各画素の画素値にwをかけて、その総和をaに代入する a = w*red(f.get(x-1,y-1)) + w*red(f.get(x,y-1)) + w*red(f.get(x+1,y-1)) + w*red(f.get(x-1,y )) + w*red(f.get(x,y )) + w*red(f.get(x+1,y )) + w*red(f.get(x-1,y+1)) + w*red(f.get(x,y+1)) + w*red(f.get(x+1,y+1)); g.set(x, y, color(a)); // aからcolor型の値を作り、画像gの座標(x,y)の画素値に設定する } } } void draw() { image(f, 0, 0); // 実行画面の左側に原画像fを貼る image(g, f.width, 0); // 実行画面の右側に変換後画像gを貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
def setup(): global f, g f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む f.filter(GRAY) # 画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB) # 画像gを画像fと同じサイズで作る this.surface.setSize(f.width*2, f.height) # 実行画面のサイズを画像fの2倍の幅に設定する w = 1./9 # wに平均値フィルタの係数1/9を代入する for y in range(1, f.height-1): # yを1から画像縦幅-2まで1ずつ増やす for x in range(1, f.width-1): # xを1から画像縦幅-2まで1ずつ増やす # 画像fの座標(x,y)を中心した3×3の領域の各画素の画素値にwをかけて、その総和をaに代入する a = w*red(f.get(x-1,y-1)) + w*red(f.get(x,y-1)) + w*red(f.get(x+1,y-1)) \ + w*red(f.get(x-1,y )) + w*red(f.get(x,y )) + w*red(f.get(x+1,y )) \ + w*red(f.get(x-1,y+1)) + w*red(f.get(x,y+1)) + w*red(f.get(x+1,y+1)) g.set(x, y, color(a)) # aからcolor型の値を作り、画像gの座標(x,y)の画素値に設定する def draw(): image(f, 0, 0) # 実行画面の左側に原画像fを貼る image(g, f.width, 0) # 実行画面の右側に変換後画像gを貼る |
1次微分フィルタ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
PImage f, g1, g2, g3; // 画像オブジェクトf,g1,g2,g3を宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float dx, dy, norm; // 実数型変数dx,dy,normを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む f.filter(GRAY); // 画像fをグレイスケールに変換する g1 = createImage(f.width, f.height, RGB); // 画像g1を画像fと同じサイズで作る g2 = createImage(f.width, f.height, RGB); // 画像g2を画像fと同じサイズで作る g3 = createImage(f.width, f.height, RGB); // 画像g3を画像fと同じサイズで作る surface.setSize(f.width*2, f.height*2); // 実行画面のサイズを画像fの2倍の幅に設定する for (y = 1; y < f.height-1; y++) { // yを1から画像縦幅-2まで1ずつ増やす for (x = 1; x < f.width-1; x++) { // xを1から画像縦幅-2まで1ずつ増やす dx = red(f.get(x+1,y )) - red(f.get(x,y)); // 座標(x,y)におけるx軸方向の微分を計算してdxに代入する dy = red(f.get(x ,y+1)) - red(f.get(x,y)); // 座標(x,y)におけるy軸方向の微分を計算してdyに代入する norm = sqrt(dx*dx + dy*dy); // エッジ強度を計算してnormに代入する dx = abs(dx); // dxを絶対値に変換する dy = abs(dy); // dyを絶対値に変換する g1.set(x, y, color(dx)); // dxからcolor型の値を作り、画像g1の座標(x,y)の画素値に設定する g2.set(x, y, color(dy)); // dyからcolor型の値を作り、画像g2の座標(x,y)の画素値に設定する g3.set(x, y, color(norm)); // normからcolor型の値を作り、画像g3の座標(x,y)の画素値に設定する } } } void draw() { image(f, 0, 0); // 実行画面の左上に原画像fを貼る image(g1, f.width, 0); // 実行画面の右上に画像g1を貼る image(g2, 0, f.height); // 実行画面の左下に画像g2を貼る image(g3, f.width, f.height); // 実行画面の右下に画像g3を貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
def setup(): global f, g1, g2, g3 f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む f.filter(GRAY) # 画像fをグレイスケールに変換する g1 = createImage(f.width, f.height, RGB) # 画像g1を画像fと同じサイズで作る g2 = createImage(f.width, f.height, RGB) # 画像g2を画像fと同じサイズで作る g3 = createImage(f.width, f.height, RGB) # 画像g3を画像fと同じサイズで作る this.surface.setSize(f.width*2, f.height*2) # 実行画面のサイズを画像fの2倍の幅に設定する for y in range(1, f.height-1): # yを1から画像縦幅-2まで1ずつ増やす for x in range(1, f.width-1): # xを1から画像縦幅-2まで1ずつ増やす dx = red(f.get(x+1,y )) - red(f.get(x,y)) # 座標(x,y)におけるx軸方向の微分を計算してdxに代入する dy = red(f.get(x ,y+1)) - red(f.get(x,y)) # 座標(x,y)におけるy軸方向の微分を計算してdyに代入する norm = sqrt(dx*dx + dy*dy) # エッジ強度を計算してnormに代入する dx = abs(dx) # dxを絶対値に変換する dy = abs(dy) # dyを絶対値に変換する g1.set(x, y, color(dx)) # dxからcolor型の値を作り、画像g1の座標(x,y)の画素値に設定する g2.set(x, y, color(dy)) # dyからcolor型の値を作り、画像g2の座標(x,y)の画素値に設定する g3.set(x, y, color(norm)) # normからcolor型の値を作り、画像g3の座標(x,y)の画素値に設定する def draw(): image(f, 0, 0) # 実行画面の左上に原画像fを貼る image(g1, f.width, 0) # 実行画面の右上に画像g1を貼る image(g2, 0, f.height) # 実行画面の左下に画像g2を貼る image(g3, f.width, f.height) # 実行画面の右下に画像g3を貼る |
エンボス加工
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
PImage f, g; // 画像オブジェクトf,gを宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float d; // 実数型変数dを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む f.filter(GRAY); // 画像fをグレイスケールに変換する g = createImage(f.width, f.height, RGB); // 画像gを画像fと同じサイズで作る surface.setSize(f.width*2, f.height); // 実行画面のサイズを画像fの2倍の幅に設定する for (y = 0; y < f.height-1; y++) { // yを0から画像縦幅-2まで1ずつ増やす for (x = 0; x < f.width-1; x++) { // xを0から画像縦幅-2まで1ずつ増やす d = red(f.get(x+1,y+1)) - red(f.get(x,y)); // 座標(x+1,y+1)から(x,y)の画素値の差分を計算してdに代入する d += 128; // dに128を加える g.set(x, y, color(d)); // dからcolor型の値を作り、画像gの座標(x,y)の画素値に設定する } } } void draw() { image(f, 0, 0); // 実行画面の左側に画像f(原画像)を貼る image(g, f.width, 0); // 実行画面の右側に画像g(変換後画像)を貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def setup(): global f, g f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む f.filter(GRAY) # 画像fをグレイスケールに変換する g = createImage(f.width, f.height, RGB) # 画像gを画像fと同じサイズで作る this.surface.setSize(f.width*2, f.height) # 実行画面のサイズを画像fの2倍の幅に設定する for y in range(0, f.height-1): # yを0から画像縦幅-2まで1ずつ増やす for x in range(0, f.width-1): # xを0から画像縦幅-2まで1ずつ増やす d = red(f.get(x+1,y+1)) - red(f.get(x,y)) # 座標(x,y)におけるx軸方向の微分を計算してdxに代入する d += 128 # dに128を加える g.set(x, y, color(d)) # dからcolor型の値を作り、画像gの座標(x,y)の画素値に設定する def draw(): image(f, 0, 0) # 実行画面の左側に原画像fを貼る image(g, f.width, 0) # 実行画面の右側に変換後画像gを貼る |
2次微分フィルタ(ラプラシアンフィルタ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
PImage f, g; // 画像オブジェクトf,gを宣言する void setup() { int x, y; // 整数型変数x,yを宣言する float a; // 実数型変数aを宣言する f = loadImage("image.jpg"); // 画像fへファイルimage.jpgのデータを読み込む f.filter(GRAY); // 画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 画像gを画像fと同じサイズで作成する surface.setSize(f.width*2, f.height); // 実行画面の横幅を画像fの2倍に設定する for (y = 1; y < f.height-1; y++) { // yを1から画像縦幅-2まで1ずつ増やす for (x = 1; x < f.width-1; x++) { // xを1から画像縦幅-2まで1ずつ増やす // 画像fの座標(x,y)を中心した3×3の領域の各画素の画素値にラプラシアンフィルタの係数をかけて、その総和をaに代入する a = + red(f.get(x,y-1)) + red(f.get(x-1,y )) - 4*red(f.get(x,y )) + red(f.get(x+1,y )) + red(f.get(x,y+1)); a = abs(a); // 画像化するために、aの絶対値を求めて0以上の数にする g.set(x, y, color(a)); // aからcolor型の値を作り、画像gの座標(x,y)の画素値に設定する } } } void draw() { image(f, 0, 0); // 実行画面の左側に原画像fを貼る image(g, f.width, 0); // 実行画面の右側に変換後画像gを貼る } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
def setup(): global f, g f = loadImage("image.jpg") # 画像fへファイルimage.jpgのデータを読み込む f.filter(GRAY) # 画像fをグレイスケールに変換する g = createImage(f.width, f.height, RGB) # 画像gを画像fと同じサイズで作る this.surface.setSize(f.width*2, f.height) # 実行画面のサイズを画像fの2倍の幅に設定する for y in range(1, f.height-1): # yを1から画像縦幅-2まで1ずつ増やす for x in range(1, f.width-1): # xを1から画像縦幅-2まで1ずつ増やす # 画像fの座標(x,y)を中心した3×3の領域の各画素の画素値にラプラシアンフィルタの係数をかけて、その総和をaに代入する a = + red(f.get(x,y-1)) \ + red(f.get(x-1,y )) -4*red(f.get(x,y )) + red(f.get(x+1,y )) \ + red(f.get(x,y+1)) a = abs(a) # 画像化するために、aの絶対値を求めて0以上の数にする g.set(x, y, color(a)) # aからcolor型の値を作り、画像gの座標(x,y)の画素値に設定する g.save("output.jpg") # 画像gをファイルoutput.jpgに保存する def draw(): image(f, 0, 0) # 実行画面の左側に原画像fを貼る image(g, f.width, 0) # 実行画面の右側に変換後画像gを貼る |
画像の平行移動
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
PImage f, g; void setup() { int X, Y, x, y; // 変換前座標を(X,Y)、変換後座標を(x,y)とする float a; f = loadImage("image.jpg"); // 原画像fをファイルから読み込む f.filter(GRAY); // 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 変換後画像gを作成する surface.setSize(f.width, f.height); for (y = 0; y < g.height; y++) { // 変換後座標x,yを用いてラスタ走査を行う for (x = 0; x < g.width; x++) { // x軸方向に+80、y軸方向に+30の平行移動の逆変換式(変換前座標←変換後座標) X = x - 80; Y = y - 30; a = red(f.get(X, Y)); // 画像fの座標(X,Y)から画素値aを取得する g.set(x, y, color(a)); // 画像gの座標(x,y)に画素値aを設定する } } } void draw() { image(g, 0, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def setup(): global g f = loadImage("image.jpg") # 原画像fをファイルから読み込む f.filter(GRAY) # 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB) # 変換後画像gを作成する this.surface.setSize(f.width, f.height) for y in range(0, g.height): # 変換後座標x,yを用いてラスタ走査を行う for x in range(0, g.width): # x軸方向に+80、y軸方向に+30の平行移動の逆変換式(変換前座標←変換後座標) X = x - 80 Y = y - 30 a = red(f.get(X, Y)) # 画像fの座標(X,Y)から画素値aを取得する g.set(x, y, color(a)) # 画像gの座標(x,y)に画素値aを設定する def draw(): image(g, 0, 0) |
画像の拡大縮小(最近隣内挿)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
PImage f, g; void setup() { int X, Y, x, y; // 変換前座標を(X,Y)、変換後座標を(x,y)とする float Xf, Yf; // 変換前の実数座標を(Xf, Yf)とする float a; f = loadImage("image.jpg"); f.filter(GRAY); // 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 変換後画像gを原画像fと同じサイズで作成する surface.setSize(f.width, f.height); for (y = 0; y < g.height; y++) { for (x = 0; x < g.width; x++) { // x軸方向に1.3倍、y軸方向に0.6倍の拡大の逆変換式(変換前座標←変換後座標) Xf = x / 1.3; Yf = y / 0.6; // 最近隣内挿により再標本化をする X = int(Xf + .5); // 小数点以下を四捨五入して整数座標を求める Y = int(Yf + .5); a = red(f.get(X, Y)); g.set(x, y, color(a)); } } } void draw() { image(g, 0, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
def setup(): global g f = loadImage("image.jpg") # 原画像fをファイルから読み込む f.filter(GRAY) # 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB) # 変換後画像gを原画像fと同じサイズで作成する this.surface.setSize(f.width, f.height) for y in range(0, g.height): # 変換後座標x,yを用いてラスタ走査を行う for x in range(0, g.width): # x軸方向に1.3倍、y軸方向に0.6倍の拡大の逆変換式(変換前座標←変換後座標) Xf = x / 1.3 Yf = y / 0.6 # 最近隣内挿により再標本化をする X = int(Xf + .5) # 小数点以下を四捨五入して整数座標を求める Y = int(Yf + .5) a = red(f.get(X, Y)) g.set(x, y, color(a)) def draw(): image(g, 0, 0) |
画像の拡大縮小(バイリニア内挿)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
PImage f, g; void setup() { int X, Y, x, y; // 変換前座標を(X,Y)、変換後座標を(x,y)とする float Xf, Yf; // 変換前の実数座標を(Xf, Yf)とする float a, s, t; f = loadImage("image.jpg"); f.filter(GRAY); // 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 変換後画像gを原画像fと同じサイズで作成する surface.setSize(f.width, f.height); for (y = 0; y < g.height; y++) { for (x = 0; x < g.width; x++) { // x軸方向に1.3倍、y軸方向に0.6倍の拡大の逆変換式(変換前座標←変換後座標) Xf = x / 1.3; Yf = y / 0.6; // バイリニア内挿により再標本化をする X = int(Xf); // Xfの整数部を取り出す Y = int(Yf); // Yfの整数部を取り出す s = Xf - X; // Xfの小数部を取り出す t = Yf - Y; // Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) + s *(1-t) * red(f.get(X+1, Y )) + (1-s)* t * red(f.get(X , Y+1)) + s * t * red(f.get(X+1, Y+1)); g.set(x, y, color(a)); } } } void draw() { image(g, 0, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
def setup(): global g f = loadImage("image.jpg") # 原画像fをファイルから読み込む f.filter(GRAY) # 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB) # 変換後画像gを原画像fと同じサイズで作成する this.surface.setSize(f.width, f.height) for y in range(0, g.height): # 変換後座標x,yを用いてラスタ走査を行う for x in range(0, g.width): # x軸方向に1.3倍、y軸方向に0.6倍の拡大の逆変換式(変換前座標←変換後座標) Xf = x / 1.3 Yf = y / 0.6 # バイリニア内挿により再標本化をする X = int(Xf) # Xfの整数部を取り出す Y = int(Yf) # Yfの整数部を取り出す s = Xf - X # Xfの小数部を取り出す t = Yf - Y # Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) \ + s *(1-t) * red(f.get(X+1, Y )) \ + (1-s)* t * red(f.get(X , Y+1)) \ + s * t * red(f.get(X+1, Y+1)) g.set(x, y, color(a)) def draw(): image(g, 0, 0) |
画像の回転
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
PImage f, g; void setup() { int X, Y, x, y; // 変換前座標を(X,Y)、変換後座標を(x,y)とする float Xf, Yf; // 変換前の実数座標を(Xf, Yf)とする float a, s, t, rad; f = loadImage("image.jpg"); f.filter(GRAY); // 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 変換後画像gを原画像fと同じサイズで作成する surface.setSize(f.width, f.height); rad = radians(15); // 角度15度をラジアン単位に変換してradに代入する for (y = 0; y < g.height; y++) { for (x = 0; x < g.width; x++) { // 角度radの回転の逆変換式(変換前座標←変換後座標) Xf = x*cos(rad) + y*sin(rad); Yf = -x*sin(rad) + y*cos(rad); // バイリニア内挿により再標本化をする X = int(Xf); // Xfの整数部を取り出す Y = int(Yf); // Yfの整数部を取り出す s = Xf - X; // Xfの小数部を取り出す t = Yf - Y; // Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) + s *(1-t) * red(f.get(X+1, Y )) + (1-s)* t * red(f.get(X , Y+1)) + s * t * red(f.get(X+1, Y+1)); g.set(x, y, color(a)); } } } void draw() { image(g, 0, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
def setup(): global g f = loadImage("image.jpg") # 原画像fをファイルから読み込む f.filter(GRAY) # 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB) # 変換後画像gを原画像fと同じサイズで作成する this.surface.setSize(f.width, f.height) rad = radians(15) # 角度15度をラジアン単位に変換してradに代入する for y in range(0, g.height): # 変換後座標x,yを用いてラスタ走査を行う for x in range(0, g.width): # 角度radの回転の逆変換式(変換前座標←変換後座標) Xf = x*cos(rad) + y*sin(rad) Yf = -x*sin(rad) + y*cos(rad) # バイリニア内挿により再標本化をする X = int(Xf) # Xfの整数部を取り出す Y = int(Yf) # Yfの整数部を取り出す s = Xf - X # Xfの小数部を取り出す t = Yf - Y # Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) \ + s *(1-t) * red(f.get(X+1, Y )) \ + (1-s)* t * red(f.get(X , Y+1)) \ + s * t * red(f.get(X+1, Y+1)) g.set(x, y, color(a)) def draw(): image(g, 0, 0) |
アフィン変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
PImage f, g; void setup() { int X, Y, x, y; // 変換前座標を(X,Y)、変換後座標を(x,y)とする float Xf, Yf; // 変換前の実数座標を(Xf, Yf)とする float a, s, t; float a1, a2, a3, a4, a5, a6; // アフィン変換パラメータの変数a1~a6の宣言 f = loadImage("image.jpg"); f.filter(GRAY); // 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 変換後画像gを原画像fと同じサイズで作成する surface.setSize(f.width, f.height); for (y = 0; y < g.height; y++) { for (x = 0; x < g.width; x++) { // アフィン変換パラメータを設定する a1 = 2.2; a2 = 0.4; a3 = -300; a4 = -0.2; a5 = 1.5; a6 = -50; // アフィン変換を計算する Xf = a1*x + a2*y + a3; Yf = a4*x + a5*y + a6; // バイリニア内挿により再標本化をする X = int(Xf); // Xfの整数部を取り出す Y = int(Yf); // Yfの整数部を取り出す s = Xf - X; // Xfの小数部を取り出す t = Yf - Y; // Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) + s *(1-t) * red(f.get(X+1, Y )) + (1-s)* t * red(f.get(X , Y+1)) + s * t * red(f.get(X+1, Y+1)); g.set(x, y, color(a)); } } } void draw() { image(g, 0, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
def setup(): global g f = loadImage("image.jpg") # 原画像fをファイルから読み込む f.filter(GRAY) # 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB) # 変換後画像gを原画像fと同じサイズで作成する this.surface.setSize(f.width, f.height) for y in range(0, g.height): # 変換後座標x,yを用いてラスタ走査を行う for x in range(0, g.width): # アフィン変換パラメータを設定する a1 = 2.2 a2 = 0.4 a3 = -300.0 a4 = -0.2 a5 = 1.5 a6 = -50.0 # アフィン変換を計算する Xf = a1*x + a2*y + a3 Yf = a4*x + a5*y + a6 # バイリニア内挿により再標本化をする X = int(Xf) # Xfの整数部を取り出す Y = int(Yf) # Yfの整数部を取り出す s = Xf - X # Xfの小数部を取り出す t = Yf - Y # Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) \ + s *(1-t) * red(f.get(X+1, Y )) \ + (1-s)* t * red(f.get(X , Y+1)) \ + s * t * red(f.get(X+1, Y+1)) g.set(x, y, color(a)) def draw(): image(g, 0, 0) |
射影変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
PImage f, g; void setup() { int X, Y, x, y; // 変換前座標を(X,Y)、変換後座標を(x,y)とする float Xf, Yf; // 変換前の実数座標を(Xf, Yf)とする float a, s, t; float h1, h2, h3, h4, h5, h6, h7, h8; // 射影変換パラメータ f = loadImage("image.jpg"); f.filter(GRAY); // 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 変換後画像gを原画像fと同じサイズで作成する surface.setSize(f.width, f.height); for (y = 0; y < g.height; y++) { for (x = 0; x < g.width; x++) { // 射影変換パラメータを設定する h1 = 0.936719; h2 = 0.054535; h3 = -92.94375; h4 = -0.730045; h5 = 1.358224; h6 = 43.02176; h7 = -0.003078805; h8 = 0.001698254; // 射影変換を計算する Xf = (h1*x + h2*y + h3) / (h7*x + h8*y + 1); Yf = (h4*x + h5*y + h6) / (h7*x + h8*y + 1); // バイリニア内挿により再標本化をする X = int(Xf); // Xfの整数部を取り出す Y = int(Yf); // Yfの整数部を取り出す s = Xf - X; // Xfの小数部を取り出す t = Yf - Y; // Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) + s *(1-t) * red(f.get(X+1, Y )) + (1-s)* t * red(f.get(X , Y+1)) + s * t * red(f.get(X+1, Y+1)); g.set(x, y, color(a)); } } } void draw() { image(g, 0, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
def setup(): global g f = loadImage("image.jpg") # 原画像fをファイルから読み込む f.filter(GRAY) # 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB) # 変換後画像gを原画像fと同じサイズで作成する this.surface.setSize(f.width, f.height) for y in range(0, g.height): # 変換後座標x,yを用いてラスタ走査を行う for x in range(0, g.width): # 射影変換パラメータを設定する h1 = 0.936719 h2 = 0.054535 h3 = -92.94375 h4 = -0.730045 h5 = 1.358224 h6 = 43.02176 h7 = -0.003078805 h8 = 0.001698254 # 射影変換を計算する Xf = (h1*x + h2*y + h3) / (h7*x + h8*y + 1) Yf = (h4*x + h5*y + h6) / (h7*x + h8*y + 1) # バイリニア内挿により再標本化をする X = int(Xf) # Xfの整数部を取り出す Y = int(Yf) # Yfの整数部を取り出す s = Xf - X # Xfの小数部を取り出す t = Yf - Y # Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) \ + s *(1-t) * red(f.get(X+1, Y )) \ + (1-s)* t * red(f.get(X , Y+1)) \ + s * t * red(f.get(X+1, Y+1)) g.set(x, y, color(a)) def draw(): image(g, 0, 0) |
任意の座標を中心にして拡大する合成変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
PImage f, g; void setup() { int X, Y, x, y; // 変換前座標を(X,Y)、変換後座標を(x,y)とする float Xf, Yf; // 変換前座標を(Xf, Yf)とする float a, s, t; float a1, a2, a3, a4, a5, a6; // アフィン変換パラメータの変数a1~a6の宣言 float x0, y0, scale; // 拡大中心座標を(x0,y0)、拡大率をscaleとする f = loadImage("image.jpg"); f.filter(GRAY); // 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 変換後画像gを原画像fと同じサイズで作成する surface.setSize(f.width, f.height); x0 = 160; // 拡大中心座標を設定する y0 = 200; scale = 1.8; // 拡大率を設定する for (y = 0; y < g.height; y++) { for (x = 0; x < g.width; x++) { // アフィン変換パラメータを設定する a1 = 1./scale; a2 = 0; a3 = x0*(1 - 1./scale); a4 = 0; a5 = 1./scale; a6 = y0*(1 - 1./scale); // アフィン変換を計算する Xf = a1*x + a2*y + a3; Yf = a4*x + a5*y + a6; // バイリニア内挿により再標本化をする X = int(Xf); // Xfの整数部を取り出す Y = int(Yf); // Yfの整数部を取り出す s = Xf - X; // Xfの小数部を取り出す t = Yf - Y; // Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) + s *(1-t) * red(f.get(X+1, Y )) + (1-s)* t * red(f.get(X , Y+1)) + s * t * red(f.get(X+1, Y+1)); g.set(x, y, color(a)); } } } void draw() { image(g, 0, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
def setup(): global g f = loadImage("image.jpg") # 原画像fをファイルから読み込む f.filter(GRAY) # 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB) # 変換後画像gを原画像fと同じサイズで作成する this.surface.setSize(f.width, f.height) x0 = 160; # 拡大中心座標を設定する y0 = 200; scale = 1.8; # 拡大率を設定する for y in range(0, g.height): # 変換後座標x,yを用いてラスタ走査を行う for x in range(0, g.width): # アフィン変換パラメータを設定する a1 = 1./scale; a2 = 0; a3 = x0*(1 - 1./scale); a4 = 0; a5 = 1./scale; a6 = y0*(1 - 1./scale); # アフィン変換を計算する Xf = a1*x + a2*y + a3 Yf = a4*x + a5*y + a6 # バイリニア内挿により再標本化をする X = int(Xf) # Xfの整数部を取り出す Y = int(Yf) # Yfの整数部を取り出す s = Xf - X # Xfの小数部を取り出す t = Yf - Y # Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) \ + s *(1-t) * red(f.get(X+1, Y )) \ + (1-s)* t * red(f.get(X , Y+1)) \ + s * t * red(f.get(X+1, Y+1)) g.set(x, y, color(a)) def draw(): image(g, 0, 0) |
アフィン変換を使ったアニメーション
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
PImage f, g; float p = 0; void setup() { f = loadImage("image.jpg"); f.filter(GRAY); // 原画像fをグレイスケール画像に変換する g = createImage(f.width, f.height, RGB); // 変換後画像gを原画像fと同じサイズで作成する surface.setSize(f.width, f.height); } void draw() { int X, Y, x, y; // 変換前座標を(X,Y)、変換後座標を(x,y)とする float Xf, Yf; // 変換前の実数座標を(Xf, Yf)とする float a, s, t; float a1, a2, a3, a4, a5, a6; // アフィン変換パラメータの変数の宣言 float as, ac, sr, br; as = f.height / sqrt(sq(f.width)+sq(f.height)); ac = f.width / sqrt(sq(f.width)+sq(f.height)); p += 0.02; sr = sin(p); br = sr > 0 ? 1. : .5; for (y = 0; y < g.height; y++) { for (x = 0; x < g.width; x++) { // アフィン変換パラメータを設定する a1 = ac*ac + as*as/sr; a2 = as*ac - as*ac/sr; a3 = 0; a4 = as*ac - as*ac/sr; a5 = as*as + ac*ac/sr; a6 = 0; // アフィン変換を計算する Xf = a1*x + a2*y + a3; Yf = a4*x + a5*y + a6; // バイリニア内挿により再標本化をする X = int(Xf); // Xfの整数部を取り出す Y = int(Yf); // Yfの整数部を取り出す s = Xf - X; // Xfの小数部を取り出す t = Yf - Y; // Yfの小数部を取り出す a = (1-s)*(1-t) * red(f.get(X , Y )) + s *(1-t) * red(f.get(X+1, Y )) + (1-s)* t * red(f.get(X , Y+1)) + s * t * red(f.get(X+1, Y+1)); a = a*br; // 画像の明るさ変更 g.set(x, y, color(a)); } } image(g, 0, 0); } |
判別分析法によるグレイスケール画像の2値化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
PImage f, g; void setup() { int x, y, i; float n_all, n0, n1, s_all = 0, s0, s1, u0, u1; int[] histogram = new int[256]; float sep, maxsep = 0; int th = 0; f = loadImage("image.jpg"); g = f.copy(); g.filter(GRAY); surface.setSize(f.width*2, f.height); // ヒストグラムを求める for (y = 0; y < f.height; y++) { for (x = 0; x < f.width; x++) { histogram[int(red(f.get(x, y)))]++; } } n_all = f.width * f.height; // 全画素数 n_all n0 = 0; s0 = 0; for (i = 1; i < 256; i++) { // 画素値と画素数の積和 s_all s_all += histogram[i] * i; } // 分離度を計算する for (i = 1; i < 256; i++) { n0 += histogram[i-1]; // クラス0の画素数 n0 n1 = n_all - n0; // クラス1の画素数 n1 s0 += histogram[i-1] * (i-1); s1 = s_all - s0; if (n0 == 0 || n1 == 0) continue; u0 = s0 / n0; // クラス0の平均画素値 u0 u1 = s1 / n1; // クラス1の平均画素値 u1 sep = n0 * n1 * sq(u0 - u1); // 分離度 sep if (sep > maxsep) { // 分離度が最大になるときの画素値をthに代入する maxsep = sep; th = i; } } println("しきい値", th); g.filter(THRESHOLD, th / 255.); // 画像gをしきい値thで2値化する } void draw() { image(f, 0, 0); image(g, f.width, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
histogram = [0]*256 def setup(): global f, g f = loadImage("image.jpg") g = f.copy() g.filter(GRAY) this.surface.setSize(f.width*2, f.height) # ヒストグラムを求める for y in range(0, f.height): for x in range(0, f.width): histogram[int(red(f.get(x, y)))] += 1 # 画像全体の平均画素値を計算する n_all = f.width * f.height # 全画素数 n_all s_all = sum(histogram[i]*i for i in range(0, 256)) # 画素値と画素数の積和 s_all n0 = 0. s0 = 0. maxsep = 0. # 分離度を計算する for i in range(1, 256): n0 += histogram[i-1] # クラス0の画素数 n0 n1 = n_all - n0 # クラス1の画素数 n1 s0 += histogram[i-1] * (i-1) s1 = s_all - s0 if n0 == 0 or n1 == 0: continue u0 = s0 / n0 # クラス0の平均画素値 u0 u1 = s1 / n1 # クラス0の平均画素値 u1 sep = n0 * n1 * (u0-u1) * (u0-u1); # 分離度 sep if sep > maxsep: # 分離度が最大になるときの画素値をthに代入する maxsep = sep th = i print "threshold:", th g.filter(THRESHOLD, th / 255.) # 画像gをしきい値thで2値化する def draw(): image(f, 0, 0) image(g, f.width, 0) |
モーメント特徴による図形の重心・面積・主軸方向の計測
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
PImage f, g; float gx, gy, t; void setup() { int x, y; float M00 = 0, M10 = 0, M01 = 0; float m11 = 0, m20 = 0, m02 = 0; f = loadImage("image.png"); f.filter(THRESHOLD, 0.5); surface.setSize(f.width, f.height); for (y = 0; y < f.height; y++) { for (x = 0; x < f.width; x++) { if (red(f.get(x, y)) > 0) { M10 += x; // モーメント特徴 M10(x座標の総和) M01 += y; // モーメント特徴 M01(y座標の総和) M00 += 1; // モーメント特徴 M00(面積) } } } gx = M10 / M00; // 重心のx座標 gx gy = M01 / M00; // 重心のy座標 gy println("面積", M00); println("重心 (", gx, ",", gy, ")"); // 主軸の計算 for (y = 0; y < f.height; y++) { for (x = 0; x < f.width; x++) { if (red(f.get(x, y)) > 0) { m20 += sq(x - gx); // 重心周りのモーメント特徴 m20 m02 += sq(y - gy); // 重心周りのモーメント特徴 m02 m11 += (x-gx) * (y-gy); // 重心周りのモーメント特徴 m11 } } } t = atan2(2*m11, m20-m02) / 2; // 主軸の角度 t println("主軸の角度", degrees(t)); } void draw() { float w = 1000*cos(t), h = 1000*sin(t); image(f, 0, 0); stroke(0, 255, 0); // 線を緑色にする fill(0, 255, 0); // 塗りつぶしを緑色にする circle(gx, gy, 10); // 重心位置に円を描画する line(gx-w, gy-h, gx+w, gy+h); // 主軸の直線を描画する } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
def setup(): global f, gx, gy, t f = loadImage("image.png") f.filter(THRESHOLD, 0.5) this.surface.setSize(f.width, f.height) M00 = M10 = M01 = 0. for y in range(0, f.height): for x in range(0, f.width): if red(f.get(x, y)) > 0: M10 += x # モーメント特徴 M10(x座標の総和) M01 += y # モーメント特徴 M01(y座標の総和) M00 += 1 # モーメント特徴 M00(面積) gx = M10 / M00 # 重心のx座標 gx gy = M01 / M00 # 重心のy座標 gy print "area:", M00 print "center of gravity: (", gx, ",", gy, ")" # 主軸の計算 m11 = m20 = m02 = 0. for y in range(0, f.height): for x in range(0, f.width): if red(f.get(x, y)) > 0: m20 += sq(x - gx) # 重心周りのモーメント特徴 m20 m02 += sq(y - gy) # 重心周りのモーメント特徴 02 m11 += (x-gx) * (y-gy) # 重心周りのモーメント特徴 m11 t = atan2(2*m11, m20-m02) / 2 # 主軸の角度 t print "angle of principal axis:", degrees(t) def draw(): w = 1000*cos(t) h = 1000*sin(t) image(f, 0, 0) stroke(0, 255, 0) # 線を緑色にする fill(0, 255, 0) # 塗りつぶしを緑色にする circle(gx, gy, 10) # 重心位置に円を描画する line(gx-w, gy-h, gx+w, gy+h) # 主軸の直線を描画する |
図形の輪郭追跡と円形度の計測
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
PImage f, g; float gx, gy, t; void setup() { int x, y, x0 = 0, y0 = 0, flag = 0, k = 0; int nx, ny, area = 0; int[] vx = {-1, -1, 0, 1, 1, 1, 0, -1}; // 8近傍の方向ベクトル int[] vy = { 0, 1, 1, 1, 0, -1, -1, -1}; float L = 0; f = loadImage("image.png"); f.filter(THRESHOLD, 0.5); surface.setSize(f.width, f.height); for (y = 0; y < f.height; y++) { for (x = 0; x < f.width; x++) { if (red(f.get(x, y)) > 0){ area++; // 面積areaを求める f.set(x, y, color(64)); // 2値画像の色を灰色にする } } } // 輪郭の開始点(x0,y0)を探す for (y0 = 0; y0 < f.height; y0++) { for (x0 = 0; x0 < f.width; x0++) { if (red(f.get(x0, y0)) > 0) { flag = 1; break; } } if (flag == 1) break; } // 孤立点であれば処理を中止する if (f.get(x0+1, y0) == color(0) && f.get(x0-1, y0+1) == color(0) && f.get(x0, y0+1) == color(0) && f.get(x0+1, y0+1) == color(0)) { println("孤立点"); f.set(x0, y0, color(0, 255, 0)); return; } // 輪郭追跡 x = x0; y = y0; do { while(true) { // 連結している輪郭の画素を探す nx = x + vx[k]; ny = y + vy[k]; if (red(f.get(nx, ny)) > 0) break; k = (k+1) % 8; } x = nx; y = ny; f.set(x, y, color(0, 255, 0)); // 検出した輪郭の画素を緑色にする L += (k % 2 == 0) ? 1 : sqrt(2); // 周囲長Lを計算する k = (k+6) % 8; // 次の探索開始位置を設定する } while(!(nx == x0 && ny == y0)); // 開始点に戻ってきたら終了する println("面積 ", area); println("周囲長", L); println("円形度", 4*PI*area/L/L); } void draw() { image(f, 0, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
def setup(): global f; vx = [-1, -1, 0, 1, 1, 1, 0, -1] # 8近傍の方向ベクトル vy = [ 0, 1, 1, 1, 0, -1, -1, -1] f = loadImage("image.png") f.filter(THRESHOLD, 0.5) this.surface.setSize(f.width, f.height) area = 0 for y in range(0, f.height): for x in range(0, f.width): if red(f.get(x, y)) > 0: area += 1 # 面積areaを求める f.set(x, y, color(64)) # 2値画像の色を灰色にする # 輪郭の開始点(x0,y0)を探す flag = 0 for y0 in range(0, f.height): for x0 in range(0, f.width): if red(f.get(x0, y0)) > 0: flag = 1 break if flag == 1: break # 孤立点であれば処理を中止する if f.get(x0+1, y0) == color(0) and f.get(x0-1, y0+1) == color(0) and \ f.get(x0, y0+1) == color(0) and f.get(x0+1, y0+1) == color(0): print "isolated point" f.set(x0, y0, color(0, 255, 0)) return # 輪郭追跡 x = x0 y = y0 k = 0 L = 0. while True: while True: # 連結している輪郭の画素を探す nx = x + vx[k] ny = y + vy[k] if red(f.get(nx, ny)) > 0: break k = (k+1) % 8 x = nx y = ny f.set(x, y, color(0, 255, 0)) # 輪郭の画素を緑色にする L += 1 if k % 2 == 0 else sqrt(2) # 周囲長Lを計算する k = (k+6) % 8 # 次の探索開始位置を設定する if nx == x0 and ny == y0: break # 開始点に戻ってきたら終了する print "area ", area print "perimeter ", L print "circularity", 4*PI*area/L/L def draw(): image(f, 0, 0) |
2画像の相違度SSD(差分2乗和)の計測
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
PImage f, g; void setup() { int x, y; float a, ssd = 0; f = loadImage("image1.jpg"); g = loadImage("image2.jpg"); f.filter(GRAY); g.filter(GRAY); surface.setSize(f.width*2, f.height); for (y = 0; y < f.height; y++) { for (x = 0; x < f.width; x++) { a = red(f.get(x, y)) - red(g.get(x, y)); // 画像fと画像gの座標(x,y)の画素値の差をaに代入する ssd += a*a; // aの2乗の総和をssdに代入する } } println("SSD =", ssd); } void draw() { image(f, 0, 0); image(g, f.width, 0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def setup(): global f, g f = loadImage("image1.jpg") g = loadImage("image2.jpg") f.filter(GRAY) g.filter(GRAY) this.surface.setSize(f.width*2, f.height) ssd = 0. for y in range(0, f.height): for x in range(0, f.width): a = red(f.get(x, y)) - red(g.get(x, y)) # 画像fと画像gの座標(x,y)の画素値の差をaに代入する ssd += a*a # aの2乗の総和をssdに代入する print "SSD =", ssd def draw(): image(f, 0, 0) image(g, f.width, 0) |
SSDによるテンプレートマッチング
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
PImage f, t; int mx = 0, my = 0; void setup() { int x, y, X, Y; float a, ssd, ssdmin = 1e+38; f = loadImage("image.jpg"); // 画像fへ対象画像のデータを読み込む t = loadImage("template.jpg"); // 画像tへテンプレート画像のデータを読み込む f.filter(GRAY); t.filter(GRAY); surface.setSize(f.width+t.width+20, f.height); for (Y = 0; Y < f.height-t.height; Y++) { // 画像f上の座標(X,Y)のラスタ走査 for (X = 0; X < f.width-t.width; X++) { // 画像fの座標(x,y)の位置にテンプレート画像tを合わせたときのSSDを求める ssd = 0; for (y = 0; y < t.height; y++) { // 画像t上の座標(x,y)のラスタ走査 for (x = 0; x < t.width; x++) { a = red(f.get(x+X, y+Y)) - red(t.get(x, y)); ssd += a*a; } } if (ssd < ssdmin) { mx = X; my = Y; // SSDが最小になるときの座標(X,Y)を(mx,my)に代入する ssdmin = ssd; } } } println("x =", mx, ", y =", my, ", SSD =", ssdmin); } void draw() { background(0); image(f, 0, 0); // 実行画面の左に画像fを貼る image(t, f.width+10, (f.height-t.height)/2); // 実行画面の左に画像tを貼る stroke(255, 0, 0); // 線の色を赤色にする noFill(); // 塗りつぶしを無しにする rect(mx, my, t.width-1, t.height-1); // 画像f上でSSDが最小になった位置に四角形を描く } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
def setup(): global f, t, mx, my ssdmin = 1e+38; f = loadImage("image.jpg") # 画像fへ対象画像のデータを読み込む t = loadImage("template.jpg") # 画像tへテンプレート画像のデータを読み込む f.filter(GRAY) t.filter(GRAY) this.surface.setSize(f.width+t.width+20, f.height) for Y in range(0, f.height-t.height): # 画像f上の座標(X,Y)のラスタ走査 for X in range(0, f.width-t.width): # 画像fの座標(x,y)の位置にテンプレート画像tを合わせたときのSSDを求める ssd = 0. for y in range(0, t.height): # 画像t上の座標(x,y)のラスタ走査 for x in range(0, t.width): a = red(f.get(x+X, y+Y)) - red(t.get(x, y)) ssd += a*a if ssd < ssdmin: mx = X # SSDが最小になるときの座標(X,Y)を(mx,my)に代入する my = Y ssdmin = ssd print "x =", mx, ", y =", my, ", SSD =", ssdmin def draw(): image(f, 0, 0) # 実行画面の左に画像fを貼る image(t, f.width+10, (f.height-t.height)/2) # 実行画面の左に画像tを貼る stroke(255, 0, 0) # 線の色を赤色にする noFill() # 塗りつぶしを無しにする rect(mx, my, t.width-1, t.height-1) # 画像f上でSSDが最小になった位置に四角形を描く |
ここから下は未修正です。
3DCGにおけるシェーディング
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
void settings() { size(400, 400, P3D); } void setup() { background(0); noStroke(); translate(200, 200, 0); ambientLight(120, 120, 120); lightSpecular(255, 255, 255); directionalLight(255, 255, 255, -1, 1, -1); specular(250, 250, 250); shininess(10.0); fill(0, 180, 0); sphere(120); } |
3DCGにおけるテクスチャマッピング
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
float rx = -0.5; float ry = 0.5; float rz = 0.0; PImage tex1, tex2, tex3; void setup() { size(400, 400, P3D); noStroke(); tex1 = loadImage("texture1.jpg"); tex2 = loadImage("texture2.jpg"); tex3 = loadImage("texture3.jpg"); textureMode(NORMAL); } void draw() { background(255); translate(200, 200, 0); rotateX(rx); rotateY(ry); rotateZ(rz); scale(100); beginShape(QUADS); texture(tex3); vertex(-1,-1, 1, 0, 0); vertex(-1, 1, 1, 0, 1); vertex( 1, 1, 1, 1, 1); vertex( 1,-1, 1, 1, 0); endShape(); beginShape(QUADS); texture(tex3); vertex(-1,-1,-1, 0, 0); vertex(-1, 1,-1, 0, 1); vertex( 1, 1,-1, 1, 1); vertex( 1,-1,-1, 1, 0); endShape(); beginShape(QUADS); texture(tex1); vertex(-1,-1, 1, 0, 1); vertex( 1,-1, 1, 1, 1); vertex( 1,-1,-1, 1, 0); vertex(-1,-1,-1, 0, 0); endShape(); beginShape(QUADS); texture(tex1); vertex(-1, 1, 1, 0, 0); vertex( 1, 1, 1, 1, 0); vertex( 1, 1,-1, 1, 1); vertex(-1, 1,-1, 0, 1); endShape(); beginShape(QUADS); texture(tex2); vertex(-1,-1, 1, 0, 0); vertex(-1, 1, 1, 0, 1); vertex(-1, 1,-1, 1, 1); vertex(-1,-1,-1, 1, 0); endShape(); beginShape(QUADS); texture(tex2); vertex(1,-1, 1, 0, 0); vertex(1, 1, 1, 0, 1); vertex(1, 1,-1, 1, 1); vertex(1,-1,-1, 1, 0); endShape(); } void keyPressed() { if (key == 'a') { ry = ry - 0.04; } else if (key == 'd') { ry = ry + 0.04; } else if (key == 'w') { rx = rx + 0.04; } else if (key == 's') { rx = rx - 0.04; } else if (keyCode == LEFT) { rz = rz - 0.04; } else if (keyCode == RIGHT){ rz = rz + 0.04; } } |