• 検索結果がありません。

caim03

N/A
N/A
Protected

Academic year: 2021

シェア "caim03"

Copied!
23
0
0

読み込み中.... (全文を見る)

全文

(1)

CAIM:03

図形描画関数をつくる

演習講師:渡邉 賢悟 (渡辺電気株式会社)

東京工科大学メディア学部

(2)
(3)

使用するプログラム

caim03_draw.zip

(4)

基礎演習(1-1) : 四角を描く関数をつくる

ImageToolBox.swiftのfillRect関数をつくる

fillColor関数に似ているが、画面全体ではなく「x1,y1,x2,y2の範囲」を塗る関数である

static

func

fillRect(

_

img:

CAIMImage

,

x1:Int, y1:Int, x2:Int, y2:Int, color:CAIMColor

) {

// 画像のデータを取得

let

mat = img.

matrix

// 画像のピクセルデータ

let

wid = img.

width

// 画像の横幅

let

hgt = img.

height

// 画像の縦幅

// 2点の座標値の小さい方、大きい方を判別して別の変数に入れる

let min_x:Int = min(x1, x2)

let min_y:Int = min(y1, y2)

let max_x:Int = max(x1, x2)

let max_y:Int = max(y1, y2)

// min_x~max_x, min_y~max_yまでの範囲を塗る

for

y

in

min_y ... max_y

{

for

x

in

min_x ... max_x

{

// x,yが画像外にはみだしたら、エラー防止のためcontinueで処理をスキップする

if(x < 0 || y < 0 || x >= wid || y >= hgt) { continue }

mat[y][x].

R

= color.

R

mat[y][x].

G

= color.

G

mat[y][x].

B

= color.

B

mat[y][x].

A

= color.

A

}

}

}

(5)

基礎演習(1-2) : fillRectをつかう

DrawingViewController.swiftのsetup関数内でfillRect関数を位置を変えて複数回使ってみよう

今回から画面全体のビュー

(view_all)と画面と同じサイズの画像(img_all)を用意し、img_allに描画する

class DrawingViewController: CAIMViewController

{

// view_allを画面いっぱいのピクセル領域(screenPixelRect)の大きさで用意

var view_all:CAIMView = CAIMView(pixelFrame: CAIM.screenPixelRect) // 画像データimg_allを画面のピクセルサイズ(screenPixelSize)に合わせて用意

var img_all:CAIMImage = CAIMImage(size: CAIM.screenPixelSize)

override func setup() {

// img_allを白で塗りつぶす

img_all.fillColor( CAIMColor.white ) // view_allの画像として、img_allを設定する

view_all.image = img_all

// view_allを画面に追加

self.view.addSubview( view_all )

// 四角をずらしながら6つ描く

ImageToolBox.fillRect(img_all, x1: 30, y1: 20, x2: 110, y2: 100,

color: CAIMColor(R: 1.0, G: 0.0, B: 0.0, A: 1.0) )

ImageToolBox.fillRect(img_all, x1: 130, y1: 20, x2: 210, y2: 100,

color: CAIMColor(R: 0.8, G: 0.0, B: 0.2, A: 1.0) )

ImageToolBox.fillRect(img_all, x1: 230, y1: 20, x2: 310, y2: 100,

color: CAIMColor(R: 0.6, G: 0.0, B: 0.4, A: 1.0) )

ImageToolBox.fillRect(img_all, x1: 330, y1: 20, x2: 410, y2: 100,

color: CAIMColor(R: 0.4, G: 0.0, B: 0.6, A: 1.0) )

ImageToolBox.fillRect(img_all, x1: 430, y1: 20, x2: 510, y2: 100,

color: CAIMColor(R: 0.2, G: 0.0, B: 0.8, A: 1.0) )

ImageToolBox.fillRect(img_all, x1: 530, y1: 20, x2: 610, y2: 100,

color: CAIMColor(R: 0.0, G: 0.0, B: 1.0, A: 1.0) ) }

}

x1, x2とCAIMColorのRGB値を

(6)

基礎演習(1-3) : 範囲の指定について

ImageToolBox.swiftのfillRect関数は描画対象の範囲を限定している

以下の

min_x, min_y, max_x, max_yがその範囲

引数で渡された

x1,x2、およびy1,y2について小さい値、大きい値を判別する

小さい方

(min_x,min_y)∼大きい方(max_x,max_y)をループの範囲として指定する


(これまでは

{0~wid-1, 0~hgt-1} = 画面全体であった)

// 2点の座標値の小さい方、大きい方を判別して別の変数に入れる

let min_x:Int = min(x1, x2)

let min_y:Int = min(y1, y2)

let max_x:Int = max(x1, x2)

let max_y:Int = max(y1, y2)

     

// 小さい方

大きい方の範囲のループにすることで処理範囲を限定する

for

y

in

min_y ... max_y

{

for

x

in

min_x ... max_x

{

…(以下ループ割愛)…

(7)

基礎演習(1-4) : はみ出し防止処理

fillRect関数では引数x1,y1,x2,y2で描画範囲を自由に指定できる

その代わり、指定した座標値が画像データをはみ出す可能性がある

(mat[y][x]は範囲をはみ出すとエラーで止まる)

そこで画像からはみ出さないようにはみ出し防止の処理を入れる

赤字部分は

「はみ出したときの条件式」

はみだしたら

continue

を呼び出してスキップする(次のループ処理へ進む)

// min_x~max_x, min_y~max_yまでの範囲を塗る

for

y

in

min_y ... max_y

{

for

x

in

min_x ... max_x

{

// x,yが画像外にはみだしたら、エラー防止のためcontinueで処理をスキップする

if(x < 0 || y < 0 || x >= wid || y >= hgt) { continue }

mat[y][x].

R

= color.

R

mat[y][x].

G

= color.

G

mat[y][x].

B

= color.

B

mat[y][x].

A

= color.

A

}

}

(8)

基礎演習(2-1) : fillRectに透明度をつける

ImageToolBox.swiftのfillRect関数に

引数

opacity

を追加する

opacityにはデフォルト値として

=1.0

を入れておく 

※opacity = 0.0(透明)∼1.0(完全不透明)

opacityを使って、元の色mat[y][x]と塗る色colorで混色計算を行う

mat[y][x].R = color.R * opacity + mat[y][x].R * (1.0-opacity)

static func fillRect(_ img:CAIMImage, x1:Int, y1:Int, x2:Int, y2:Int, color:CAIMColor, opacity:Float=1.0) { // 画像のデータを取得

let mat = img.matrix // 画像のピクセルデータ let wid = img.width // 画像の横幅

let hgt = img.height // 画像の縦幅

// 2点の座標値の小さい方、大きい方を判別して別の変数に入れる let min_x:Int = min(x1, x2)

let min_y:Int = min(y1, y2) let max_x:Int = max(x1, x2) let max_y:Int = max(y1, y2)

// min_x~max_x, min_y~max_yまでの範囲を塗る for y in min_y ... max_y {

for x in min_x ... max_x {

// x,yが画像外にはみだしたら、エラー防止のためcontinueで処理をスキップする if(x < 0 || y < 0 || x >= wid || y >= hgt) { continue }

mat[y][x].R = color.R * opacity + mat[y][x].R * (1.0-opacity) mat[y][x].G = color.G * opacity + mat[y][x].G * (1.0-opacity) mat[y][x].B = color.B * opacity + mat[y][x].B * (1.0-opacity) mat[y][x].A = color.A * opacity + mat[y][x].A * (1.0-opacity) }

} }

(9)

基礎演習(2-2) : fillRect(opacity付)を使う

DrawingViewController.swiftのsetup関数内でfillRect関数のopacity付きを使う

下記のように

for文と計算を用いて、複数の四角をimg_all上に描いてみる

class

DrawingViewController:

CAIMViewController

{

// view_allを画面いっぱいのピクセル領域(screenPixelRect)の大きさで用意

var

view_all:

CAIMView

=

CAIMView

(pixelFrame:

CAIM

.

screenPixelRect

)

// 画像データimg_allを画面のピクセルサイズ(screenPixelSize)に合わせて用意

var

img_all:

CAIMImage

=

CAIMImage

(size:

CAIM

.

screenPixelSize

)

override

func

setup() {

…(基礎演習1で記述済 : 割愛)…

// 透明度付きの四角を描く

for i in 0 ..< 6 {

ImageToolBox.fillRect(img_all, x1: 30+100*i, y1: 120, x2: 110+100*i, y2: 200,

color: CAIMColor(R: 1.0 - Float(i) * 0.2, G: 0.0, B: Float(i) * 0.2, A: 1.0),

opacity:0.8 - Float(i) * 0.1 )

}

}

}

(10)

基礎演習(3-1) : 円を描く

ImageToolBox.swiftにfillCircle関数を作ろう

引数は円の中心座標

(cx,cy)と半径(radius), 色(color), 不透明度(opacity)とする

static func fillCircle(_ img:CAIMImage, cx:Int, cy:Int, radius:Int, color:CAIMColor, opacity:Float=1.0) {

// 画像のデータを取得

let mat = img.matrix // 画像のピクセルデータ

let wid = img.width // 画像の横幅

let hgt = img.height // 画像の縦幅

// 処理の範囲を決める

let min_x:Int = cx - radius let min_y:Int = cy - radius let max_x:Int = cx + radius let max_y:Int = cy + radius

// min_x~max_x, min_y~max_yまでの範囲を塗る

for y in min_y ... max_y {

for x in min_x ... max_x {

// x,yが画像外にはみだしたら、エラー防止のためcontinueで処理をスキップする

if(x < 0 || y < 0 || x >= wid || y >= hgt) { continue }

// 中心点からの距離

let dist:Float = sqrt(Float((x-cx)*(x-cx)) + Float((y-cy)*(y-cy)))

// 中心点(cx, cy)からの距離が半径radius以内なら塗る

if( dist <= Float(radius) ) {

mat[y][x].R = color.R * opacity + mat[y][x].R * (1.0-opacity) mat[y][x].G = color.G * opacity + mat[y][x].G * (1.0-opacity) mat[y][x].B = color.B * opacity + mat[y][x].B * (1.0-opacity) mat[y][x].A = color.A * opacity + mat[y][x].A * (1.0-opacity) }

} }

(11)

基礎演習(3-2) : fillCircleを使う

DrawingViewController.swiftのsetup関数内でfillCircle関数を使ってみる

opacityを設定しない使い方、設定した使い方をしてみよう

class

DrawingViewController:

CAIMViewController

{

// view_allを画面いっぱいのピクセル領域(screenPixelRect)の大きさで用意

var

view_all:

CAIMView

=

CAIMView

(pixelFrame:

CAIM

.

screenPixelRect

)

// 画像データimg_allを画面のピクセルサイズ(screenPixelSize)に合わせて用意

var

img_all:

CAIMImage

=

CAIMImage

(size:

CAIM

.

screenPixelSize

)

override

func

setup() {

…(基礎演習1,2で記述済 : 割愛)…

// 丸を描く

for i in 0 ..< 6 {

ImageToolBox.fillCircle(img_all, cx: 70+100*i, cy: 260, radius: 40,

color: CAIMColor(R: 1.0, G: 0.5 + Float(i) * 0.1, B:Float(i) * 0.1, A: 1.0))

}

// 丸を描く(透明度付き)

for i in 0 ..< 6 {

ImageToolBox.fillCircle(img_all, cx: 70+100*i, cy: 360, radius: 40,

color: CAIMColor(R: 1.0, G: 0.5, B: 0.0, A: 1.0),

opacity:1.0 - Float(i) * 0.15 )

}

}

}

(12)

基礎演習(3-3) : 円の内部判定

fillCircle関数でもループ自体は「四角」で行っている

ループ内で

if文「円の内部のみ塗る」よう処理すれば円が描ける

処理対象の座標

(x,y)の、円の中心(cx,cy)からの距離distを計算する

distが半径radius内 = 円の内部 → 塗る

// 中心点からの距離

let dist:Float = sqrt(Float((x-cx)*(x-cx)) + Float((y-cy)*(y-cy)))

// 中心点(cx, cy)からの距離が半径radius以内なら塗る

if

(

dist <= Float(radius)

) {

mat[y][x].

R

= color.

R

* opacity + mat[y][x].

R

* (

1.0

-opacity)

…(上記のようにG,B,Aの色指定: 以下割愛)…

(13)

基礎演習(3-4) : fillCircleで円を重ねる

DrawingViewController.swiftのsetup関数内でfillCircle関数で


透けた円が重なるように

img_allに描画してみよう(opacityを小さくしておく)

class DrawingViewController:

CAIMViewController

{

// view_allを画面いっぱいのピクセル領域(screenPixelRect)の大きさで用意

var

view_all:

CAIMView

=

CAIMView

(pixelFrame:

CAIM

.

screenPixelRect

)

// 画像データimg_allを画面のピクセルサイズ(screenPixelSize)に合わせて用意

var

img_all:

CAIMImage

=

CAIMImage

(size:

CAIM

.

screenPixelSize

)

override func setup() {

…(基礎演習1,2で記述済 : 割愛)…

…(基礎演習3-2で記述済 : 割愛)…

// 丸を重ねて描く

for i in 0 ..< 12 {

ImageToolBox.fillCircle(img_all, cx: 70+45*i, cy: 460, radius: 40,

color: CAIMColor(R: 1.0, G: 0.2, B: 0.2, A: 1.0),

opacity:0.3 - Float(i) * 0.02 )

}

}

}

(14)
(15)

発展演習(1-1) : グラデーション円を描く

ImageToolBox.swiftにfillDome関数を作ろう

fillCircle関数をCopy&Pasteして書き直すとよい

static func fillDome(_ img:CAIMImage, cx:Int, cy:Int, radius:Int, color:CAIMColor, opacity:Float=1.0) { // 画像のデータを取得

let mat = img.matrix // 画像のピクセルデータ let wid = img.width // 画像の横幅

let hgt = img.height // 画像の縦幅 // 処理の範囲を決める

let min_x:Int = cx - radius let min_y:Int = cy - radius let max_x:Int = cx + radius let max_y:Int = cy + radius for y in min_y ... max_y {

for x in min_x ... max_x {

if(x < 0 || y < 0 || x >= wid || y >= hgt) { continue }

let dist:Float = sqrt(Float((x-cx)*(x-cx)) + Float((y-cy)*(y-cy)))

if( dist <= Float(radius) ) {

// 中心からの距離でcosを計算してαとして用いる

var alpha = Float(cos(Double(dist) / Double(radius) * Double.pi / 2.0)) // αに不透明度opacityを掛ける

alpha *= opacity

mat[y][x].R = color.R * alpha + mat[y][x].R * (1.0-alpha) mat[y][x].G = color.G * alpha + mat[y][x].G * (1.0-alpha) mat[y][x].B = color.B * alpha + mat[y][x].B * (1.0-alpha) mat[y][x].A = color.A * alpha + mat[y][x].A * (1.0-alpha) }

} }

(16)

発展演習(1-2) : fillDomeを使う

DrawingViewController.swiftのsetup関数内でfillDome関数を使ってみる

img_all上にフワッとした円が描かれることを確認する

class

DrawingViewController:

CAIMViewController

{

// view_allを画面いっぱいのピクセル領域(screenPixelRect)の大きさで用意

var

view_all:

CAIMView

=

CAIMView

(pixelFrame:

CAIM

.

screenPixelRect

)

// 画像データimg_allを画面のピクセルサイズ(screenPixelSize)に合わせて用意

var

img_all:

CAIMImage

=

CAIMImage

(size:

CAIM

.

screenPixelSize

)

override

func

setup() {

…(基礎演習1,2で記述済 : 割愛)…

…(基礎演習3-2で記述済 : 割愛)… …(基礎演習3-4で記述済 : 割愛)…

// ドームを描く(透明度付き)

for i in 0 ..< 6 {

ImageToolBox.fillDome(img_all, cx: 70+100*i, cy: 560, radius: 40,

color: CAIMColor(R: 0.0, G: 0.5, B: 0.0, A: 1.0),

opacity:1.00 - Float(i)*0.15 )

}

// ドームを重ねて描く(透明度付き)

for i in 0 ..< 12 {

ImageToolBox.fillDome(img_all, cx: 70+45*i, cy: 660, radius: 40,

color: CAIMColor(R: 0.0, G: 0.5, B: 0.0, A: 1.0),

opacity:0.5 - Float(i)*0.025 )

}

}

}

(17)

発展演習(1-3) : cosと半径を用いたα計算

角度が

0∼π/2ラジアンを取る間のcosの値を活用

cos(0) = 1.0, cos(π/2) = 0.0

中心からの距離

dが半径rになったとき、


cosの角度がπ/2になるような計算を行う

d = √(x-cx)(x-cx) + (y-cy)(y-cy)

α = cos(d / r * π/2)

よって

Swiftで記述すると以下のようになる

var

alpha =

Float

(cos(

Double

(dist) /

Double

(radius) *

Double.pi

/

2.0

))

0

0.5

1

0

45

90

半径r

(18)

発展演習(2-1) : 直線を描く

ImageToolBox.swiftにdrawLine関数を作ろう

ここまでできた人は挑戦してみてほしい

drawLineについてはWikiのサンプルを参照のこと

Bresenhamアルゴリズム

を使用している

検索で調べてみよう。いろいろな情報がある

(19)
(20)

break

breakは、forやwhileのループ内で呼ばれた時、処理を中断してループの外に

出る

for

x

in

min_x ... max_x {

if

(x <

0

|| x >= wid) {

break

}

mat[0][x].

R

= color.

R

mat[0][x].

G

= color.

G

mat[0][x].

B

= color.

B

mat[0][x].

A

= color.

A

}

breakが呼ばれたら問答無用で

現在回しているループから抜ける

ここは処理されない

(21)

continue

continueは、forやwhileのループ内で呼ばれた時、今の処理をスキップして

次のループステップに進む

for

x

in

min_x ... max_x {

if

(x <

0

|| x >= wid) {

continue

}

mat[0][x].

R

= color.

R

mat[0][x].

G

= color.

G

mat[0][x].

B

= color.

B

mat[0][x].

A

= color.

A

}

continueが呼ばれたら、

今のステップは飛ばして

次のステップに進む

ここは1回処理がスキップされる

(22)

引数のデフォルト値

関数の引数には「デフォルト値」を設定できる

static

func

fillCircle(

_

img:

CAIMImage

, cx:

Int

, cy:

Int

, radius:

Int

,

color:

CAIMColor

, opacity:

Float

=1.0

) {

…(中身割愛)…

デフォルト値のある関数は、使用時に引数を省略できる

省略した引数はデフォルト値が適用される

引数で値を設定した場合は、設定値が優先され処理される

ImageToolBox.fillCircle(img_all, cx:

70

, cy:

460

, radius:

40

,

color: CAIMColor(R:

1.0

, G:

0.2

, B:

0.2

, A:

1.0

))

// opacityを省略。opacity=1.0

ImageToolBox.fillCircle(img_all, cx: 7

0

, cy:

460

, radius:

40

,

(23)

型推論とビルド

Swiftには「型推論」の機能がある。変数の型を指定しなくても

初期化で代入される型から自動的に型を推測してくれる

var

x =

Int

(3)

// xは自動的にIntになる

しかし型推論はビルドに時間がかかる。

ビルドが遅くなり始めたら型を明示すると、高速化する

参照

関連したドキュメント

Instagram 等 Flickr 以外にも多くの画像共有サイトがあるにも 関わらず, Flickr を利用する研究が多いことには, 大きく分けて 2

管理画面へのログイン ID について 管理画面のログイン ID について、 希望の ID がある場合は備考欄にご記載下さい。アルファベット小文字、 数字お よび記号 「_ (アンダーライン)

200 インチのハイビジョンシステムを備えたハ イビジョン映像シアターやイベントホール,会 議室など用途に合わせて様々に活用できる施設

※1

Fig.5 The number of pulses of time series for 77 hours in each season in summer, spring and winter finally obtained by using the present image analysis... Fig.6 The number of pulses

SST を活用し、ひとり ひとりの個 性に合 わせた   

○関計画課長

自動車環境管理計画書及び地球温暖化対策計 画書の対象事業者に対し、自動車の使用又は