julia - bicubic ― 2015年06月18日 19:51
求める画素位置と、実際の画素の位置から、画素間の距離を求め、その距離に応じた係数をそれぞれの画素の輝度値に掛け、その総和を求める画素の輝度値とする。
ここで、距離と係数の関係は sinc 関数を3次近似したものが使われる。
上の画像のピンクの線が sinc 関数で、下の緑と青が近似した値である。見やすくするために sinc 関数は上に0.5だけ移動してある。
ちなみに、sinc 関数とは sin(πx)/(πx) のこと。
この部分を関数にするとこんな感じ。
function fsinc(d)
return (d < 1) ? d^3 - 2d^2 + 1 : (d < 2) ? -d^3 + 5d^2 - 8d + 4 : 0
end
実は julia には sinc 関数があるので、別の名前にした。x方向、y方向、それぞれ独立に係数を求め、掛け合わせることで16個の係数を求める。(試しに xy両方を含めた距離で計算してみたが、ノイズっぽい画像になってしまった)
x方向だけ考えると、求める画素の位置は、4つの画素の真ん中にくる。
x値を小さい順に x1, x2, x3, x4 と置くと、求める画素の位置(x)は x2≦x<x3 となり、x2= floor(x) である。
よって、x と x2 の距離は x - floor(x) であり、x と x1 の距離は x と x2 の距離に1を足したものである。
また、x と x3 の距離は、1から(x と x2 の距離)を引いたものとなり、x と x4 の距離はそれに1を足したものである。
よって、x と x2 の距離(すなわち、x - floor(x) )を xd とすれば、それぞれ xd+1, xd, 1-xd, 2-xd となる。
y に関しても同様。
これを関数で書くと以下のようになる。
function getCOEFFS (xin, yin)
# coefficient (a= -1)
function fsinc(d)
return (d < 1) ? d^3 - 2d^2 + 1 : (d < 2) ? -d^3 + 5d^2 - 8d + 4 : 0
end
# calc coefficients
xd= xin - floor(xin)
xc= map(x -> fsinc(x), [xd+1; xd; 1-xd; 2-xd])
#
yd= yin - floor(yin)
yc= map(x -> fsinc(x), [yd+1 yd 1-yd 2-yd])
#
return xc * yc
end
関数の中に関数が書けるのは便利。map を使って、行列の距離値を sinc 関数を使った係数に変換している。
xc は、4行1列の行列。yc は、1行4列の行列。
これらを掛け合わせると、4行4列の行列が得られる。これを戻り値にしている。
完成した関数は以下のとおり。
# ibuff の (xin,yin) から画素値を取得する
function imgpic (ibuff, xin, yin)
# get 4x4 pixels
function getPIX4x4 (ibuff, xin, yin)
xstart= ifloor(xin) - 1
ystart= ifloor(yin) - 1
try
return ibuff[xstart:(xstart+3), ystart:(ystart+3)]
catch # out of range
obuff= ibuff[1:4,1:4]
(xmax,ymax)= size(ibuff)
for x= 1:4, y= 1:4
xin= xstart + (x - 1)
yin= ystart + (y - 1)
xin= (xin < 1) ? 1 : (xin > xmax) ? xmax : xin
yin= (yin < 1) ? 1 : (yin > ymax) ? ymax : yin
obuff[x,y]= ibuff[xin,yin]
end
return obuff
end
end
# get 4x4 coefficients
function getCOEFFS (xin, yin)
# coefficient (a= -1)
function fsinc(d)
return (d < 1) ? d^3 - 2d^2 + 1 : (d < 2) ? -d^3 + 5d^2 - 8d + 4 : 0
end
# calc coefficients
xd= xin - floor(xin)
xc= map(x -> fsinc(x), [xd+1; xd; 1-xd; 2-xd])
#
yd= yin - floor(yin)
yc= map(x -> fsinc(x), [yd+1 yd 1-yd 2-yd])
#
return xc * yc
end
pixels= getPIX4x4(ibuff, xin, yin)
coeffs= getCOEFFS(xin, yin)
return sum(pixels .* coeffs) / sum(coeffs)
end
julia - 拡大・縮小 ― 2015年06月12日 18:14
今回は、画像の拡大・縮小の処理を行ってみる。
最終的には、imgzoom( img, xsize, ysize) という関数で、画像を拡大・縮小できるようにしたい。
任意サイズに画像を拡大・縮小する場合、画素の補間が必要となる。
ここでは、bicubic 法で補完を行う。
バイキュービックでは、周辺の16画素を用いて補完を行う。この際には、補完係数に3次関数を用いるので cubic と呼ばれるようだ。ちなみに、この補完係数は、sinc関数を3次近似したものらしい。
ということで、(x,y) の周辺16画素を取得する関数をまずは作ってみる。
簡単に書けばこんな感じか。
function getPIX4x4 (img, x, y)
xstart= ifloor(x) - 1
ystart= ifloor(y) - 1
return img[xstart:(xstart+3), ystart:(ystart+3)]
end
ただし、これだと、x=1 の時(左端)や右端の時に img の添え字をはみ出してしまうので、x, y の値のチェックが必要。しかし、これを毎回行うのは効率的ではないので、エラーが発生した時だけ真面目に処理をするようにした。(ちょっとだけ早い)
function getPIX4x4 (img, xin, yin)
xstart= ifloor(xin) - 1
ystart= ifloor(yin) - 1
try
return img[xstart:(xstart+3), ystart:(ystart+3)]
catch
buff= img[1:4,1:4]
(xmax,ymax)= size(img)
for x= 1:4, y= 1:4
xpos= xstart + (x - 1)
ypos= ystart + (y - 1)
xpos= (xpos < 1) ? 1 : (xpos > xmax) ? xmax : xpos
ypos= (ypos < 1) ? 1 : (ypos > ymax) ? ymax : ypos
buff[x,y]= img[xpos,ypos]
end
return buff
end
end
try ブロックを処理中にエラーが生じると catch ブロックに処理が移る。とりあえず今日はここまで。
julia - BMP の読み書き ― 2015年06月05日 17:36
imread(), imwrite() は、それぞれ load(), save() に変わりました。
機会があれば対応したものを執筆しますが、混乱を避けるため、とりあえず消しておきます。(2015/12/19)
Pkg.add("Images") でパッケージを追加。
入出力には ImageMagick を使用しているらしい。
以下、ちょっとしたコード。
# Images パッケージを使用する宣言
using Images
# sample.bmp を読み込む
img1= imread("sample.bmp")
# 白黒画像に変換
img1= convert(Image{Gray}, img1)
# sobel filter の係数を取得。2つの行列を返してくる
sobelX, sobelY= sobel()
# X方向の sobel filter を適用
img1= imfilter(img1, sobelX)
# 結果をファイルに書き込む
imwrite(colorim(img1), "edgeX.bmp")
RGB Image 構造体
img1= imread("sample.bmp")
評価値
RGB Image with:
data: 1280x720 Array{RGB{UfixedBase{Uint8,8}},2}
properties:
IMcs: sRGB
spatialorder: x y
pixelspacing: 1 1
ピクセルデータには、img1.data[100,100].r のようにしてアクセスできる。ちなみに、data は省略できて、img1[100,100].r でも同じ。
ただし、img1[:,:].r のように範囲指定はできない。
構造体の properties は、img1["IMcs"] のように指定する。
RGB それぞれを行列として扱いたい場合には、red(), green(), blue() という関数で分離できる
imgR= red (img1)
imgG= green(img1)
imgB= blue (img1)
これで imgR,imgG,imgB は、行列となるので、普通に計算などができる。imread で読み込んだ場合、この行列は、各画素 0 から 1 の値となる。
255 を掛けると元の BMP のピクセル値に一致する。
Image 構造体を作る
行列から Image 構造体を作るには、grayim(),colorim()関数を使う。
grayim() は、m x n の行列からグレースケールの Gray Image 構造体を作る。
colorim() は、3 x m x n の行列が必要。RGB から直接変換する方法は不明。
とりあえず、この大きさの行列を作って、RGB 値を代入すれば使える。
まとめ
using Images
# sample.bmp 読み出し
img1= imread("sample.bmp")
# RGB に分離
imgR= red (img1)
imgG= green(img1)
imgB= blue (img1)
# Gray を作ってみる
imgW= imgR * 0.29 + imgG * 0.60 + imgB * 0.11
imwrite(grayim(imgW), "gray.bmp")
# RGB Image 構造体に戻す
imgRGB= zeros(3, size(imgR,1), size(imgR,2))
imgRGB[1,:,:]= imgR
imgRGB[2,:,:]= imgG
imgRGB[3,:,:]= imgB
imwrite(colorim(imgRGB), "rgb.bmp")
julia - 代入 ― 2015年06月04日 18:46
変数への代入について
| 入力値 | 評価値 | 備考 |
| x= 3.0 + 2.0im | 3.0 + 2.0im |
虚数単位は、i ではなく im im の前に空白はダメ x= 3.0 + 2.0 * im なら OK |
| x= π | π = 3.1415926535897... |
x= pi でも同じ \pi と入れてタブを押すとπに変換される 内部的には定数型として扱われる |
| x= √3 | 1.7320508075688772 |
sqrt(3) でも同じ \sqrt と入れてタブを押すと√に変換される ちょっとやりすぎな感じ |
| y= √2sin(π/4) | 1.189207115002721 |
y= sqrt(2*sin(pi/4)) のことらしい 見た目に惑わされてしまうので注意 |
|
x= 0:0.1:20 y= sin(x) |
201-element Array{Float64,1}:
0.0
0.0998334
0.198669
0.29552
0.389418
0.479426
0.564642
0.644218
0.717356
0.783327
⋮
0.247834
0.343315
0.435365
0.523066
0.60554
0.681964
0.751573
0.813674
0.867644
0.912945
|
x に、0 から 20 まで 0.1 刻みの範囲を指定
y には、それに対応した sin(x) が入る 一番上にあるグラフがそれ |
| s= "Hello world!" | "Hello world!" | 文字列はダブルクオーテーションでくくる |
| f= sin | sin (generic function with 11 methods) |
関数も変数に代入できる y= f(3) として計算できる |
| sin= 5 |
Warning: imported binding for sin overwritten in module Main 5 |
関数名も変数として使えてしまう でも、関数としては機能しなくなるので注意 |
ツールを使ったので表の作成が簡単になった。
julia - 変数の型 ― 2015年06月02日 20:45
http://julialang.org
基本思想は MatLab に似ていて、データは行列のまま処理ができるので、画像処理やらデータ処理には便利そう。
変数の型の指定は不要で、適当に割り当ててくれる。
型についての簡単なまとめ
| 入力 | 評価値 | 型 | コメント |
|---|---|---|---|
| x= 3 |
|
Int64 | |
| x= 3.0 |
|
Float64 | |
| x= 1:3 |
|
UintRange{Int64} | 範囲をあらわす表記 行列からの切り出しや for ループなどで使う |
| x= [1 2 3] |
|
Array{Int64,2} |
下の3つとは結果が違う 1x3 の2次元行列になる |
| x= [1,2,3] | 2 3 |
Array{Int64,1} | (カンマで区切るのはよくないみたい) |
| x= [1;2;3] |
2 3 |
Array{Int64,1} | |
| x= [1:3] |
2 3 |
Array{Int64,1} | |
| x= (1,2,3) |
|
(Int64,Int64,Int64) | Tuple型: 関数の引数部分 |
| x= [1 2 3; 4 5 6; 7 8 9] |
4 5 6 7 8 9 |
Array{Int64,2} | 3x3 行列 |
表を作るのに疲れたのでここまで
[1,2,3] == [1;2;3] → true
[1 2 3] == [1,2,3] → false
最近のコメント