32
1 全全全 全全全全全全全全全 全全全全全全全全全全全全全全 全全全全全全全全全全全全全全全全全全全全全全 全全全全全全全全全全全全全全全全全全全 全全全全全全全全全全全全全全全全全

全体の流れ

Embed Size (px)

DESCRIPTION

全体の流れ. 画像ファイルを開き,画像データをメモリ上にロード. メモリ上にロードした画像データに処理を加える. 処理後のデータを出力ファイルに書き出す. 画像データ用に確保したメモリを解放. 88 (136). B1 (177). E7 (231). 8A (138). B2 (178). E7 (231). …. データ構造 ~ 1 画素をどう表現するか~. 画像ファイル内での画素データのフォーマット. typedef struct { unsigned char r; unsigned char g; - PowerPoint PPT Presentation

Citation preview

Page 1: 全体の流れ

1

全体の流れ

画像ファイルを開き,画像データをメモリ上にロード

メモリ上にロードした画像データに処理を加える

処理後のデータを出力ファイルに書き出す

画像データ用に確保したメモリを解放

Page 2: 全体の流れ

2

画像ファイル内での画素データのフォーマット

データ構造~ 1 画素をどう表現するか~

typedef struct {unsigned char r;unsigned char g;unsigned char b;

} PIXEL, *PPIXEL;

88(136)

B1(177)

E7(231)

8A(138)

B2(178)

E7(231)

1画素あたり RGB各 8ビット 合計 3バイト

88B1E7

PIXEL 構造体rgb

Page 3: 全体の流れ

3

画像ファイル内での画素データのフォーマット

データ構造~ 1 画素をどう表現するか~

typedef struct {unsigned char r;unsigned char g;unsigned char b;

} PIXEL, *PPIXEL;

88(136)

B1(177)

E7(231)

8A(138)

B2(178)

E7(231)

1画素あたり RGB各 8ビット 合計 3バイト

88B1E7

PIXEL 構造体rgb

PIXEL 構造体へのポインタ型.名前は PPIXEL にするよ

この構造体の型名はPIXEL にするよ

Page 4: 全体の流れ

4

データ構造~画像データをどう表現するか~

typedef struct {int xsize;int ysize;int level;PPIXEL *pBuffer;

} IMAGE;

画像ファイルのフォーマット

ヘッダー ( 画像サイズ,最大輝度 ) 画像データ

256192255

IMAGE 構造体xsizeysizelevel

pBuffer

画像データのサイズは,ヘッダ読み込み後でないと分からない→ 画像用のメモリは [                ]  

88(136)

B1(177)

E7(231)

Page 5: 全体の流れ

5

データ構造~画像データをどう表現するか~

typedef struct {int xsize;int ysize;int level;PPIXEL *pBuffer;

} IMAGE;

画像ファイルのフォーマット

ヘッダー ( 画像サイズ,最大輝度 ) 画像データ

画像データのサイズは,ヘッダ読み込み後でないと分からない→ 画像用のメモリは 動的 に確保

256192255

IMAGE 構造体xsizeysizelevel

pBuffer

PPIXEL へのポインタ= ( PIXEL へのポインタ)へのポインタ

88(136)

B1(177)

E7(231)

Page 6: 全体の流れ

6

ポインタの配列~課題 2 の文字列のソートの復習~

strawberry\0lines[0]

lines[1]

lines[2]

watermelon\0

banana\0

lines[MAXLINES-1]

char *lines[MAXLINES]; 文字列にあわせた長さ

定数MAXLINES個 ( 20000 )

Page 7: 全体の流れ

7

ポインタの配列~画像バッファの確保~

void iioMallocImageBuffer(IMAGE *pImage)

256192255

xsizeysizelevel

pBuffer

ysize 個の [        ]の配列を確保malloc(ysize * sizeof(PPIXEL));

xsize 個の [        ]の配列を確保malloc(xsize * sizeof(PIXEL));

pImage

Page 8: 全体の流れ

8

ポインタの配列~画像バッファの確保~

void iioMallocImageBuffer(IMAGE *pImage)

256192255

xsizeysizelevel

pBuffer

xsize 個の PIXELの配列を確保malloc(xsize * sizeof(PIXEL));

pImage

ysize 個の PPIXELの配列を確保malloc(ysize * sizeof(PPIXEL));

Page 9: 全体の流れ

9

モジュール設計

どういう機能を用意するか モジュールごとの独立性をどう高めるか

メイン

main.c

画像処理

img_proc.cimg_proc.h

画像のファイル入出力画像データ用メモリ確保と解放

img_io.cimg_io.h

Page 10: 全体の流れ

10

復習:コンパイラの動作 (1)

コンパイラはソースファイルを [                ]

// 呼び出される関数 double func(double d) { return 0.0; } // 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

func という関数は、 doubleを受け取って double を返すんだな・・

double を渡して double を返してもらうようなコードを生成しよう・・ 4 は 4.0 に変換してから渡そう・・・ 関数呼出部分をコンパイルするときに、コンパイラは呼び出される関数の引数の数・型、戻り値の型を知っておく必要がある

Page 11: 全体の流れ

11

復習:コンパイラの動作 (1)

コンパイラはソースファイルを上から下へ解釈していく

// 呼び出される関数 double func(double d) { return 0.0; } // 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

func という関数は、 doubleを受け取って double を返すんだな・・

double を渡して double を返してもらうようなコードを生成しよう・・ 4 は 4.0 に変換してから渡そう・・・ 関数呼出部分をコンパイルするときに、コンパイラは呼び出される関数の引数の数・型、戻り値の型を知っておく必要がある

Page 12: 全体の流れ

12

コンパイラの動作 (2)

関数記述位置の上下を逆にすると・・・

// 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

// 呼び出される関数 double func(double d) { return 0.0; }

正常にコンパイルできない

( C 処理系では warningが、 C++ 処理系ではエラーが発生する)

Page 13: 全体の流れ

13

コンパイラの動作 (2)

関数記述位置の上下を逆にすると・・・

// 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

// 呼び出される関数 double func(double d) { return 0.0; }

func 関数の引数の型も引数の個数も知らないぞ・・・

正常にコンパイルできない

( C 処理系では warningが、 C++ 処理系ではエラーが発生する)

Page 14: 全体の流れ

14

関数プロトタイプ宣言

double func(double d);

// 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

// 呼び出される関数 double func(double d) { return 0.0; }

関数呼出部分より前に[ ]を行うことにより、正常にコンパイルが可能となる

func という関数は、 doubleを受け取って double を返すんだな・・

double を渡して double を返してもらうようなコードを生成しよう・・ 4 は 4.0 に変換してから渡そう・・・

Page 15: 全体の流れ

15

関数プロトタイプ宣言

double func(double d);

// 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

// 呼び出される関数 double func(double d) { return 0.0; }

関数呼出部分より前に

  プロトタイプ宣言を行うことにより、正常にコンパイルが可能となる

func という関数は、 doubleを受け取って double を返すんだな・・

double を渡して double を返してもらうようなコードを生成しよう・・ 4 は 4.0 に変換してから渡そう・・・

最後はセミコロン

Page 16: 全体の流れ

16

分割コンパイル

ソースファイルを複数に分割し、それぞれをコンパイルしてできたオブジェクトファイルをリンカで結合

更新されたソースファイルのみコンパイルすればよいため、プログラムの規模が大きくなった場合でも、微細な変更時のビルド時間を大幅に短縮可能

gin.c lime.c

gin.obj lime.obj libc.lib

ginlime.exe

ソースファイル

オブジェクトファイル

実行ファイル

ライブラリファイル( コンパイル済 )[ ] [ ]

[ ]

Page 17: 全体の流れ

17

分割コンパイル

ソースファイルを複数に分割し、それぞれをコンパイルしてできたオブジェクトファイルをリンカで結合

更新されたソースファイルのみコンパイルすればよいため、プログラムの規模が大きくなった場合でも、微細な変更時のビルド時間を大幅に短縮可能

gin.c lime.c

gin.obj lime.obj libc.lib

ginlime.exe

ソースファイル

オブジェクトファイル

実行ファイル

リンク

コンパイル コンパイルライブラリファイル

( コンパイル済 )

Page 18: 全体の流れ

18

単純にファイルを分割すると…

// 呼び出される関数 double func(double d) { return 0.0; }

module.c

// 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

caller.c

コンパイルは

[                         ]

ため、 caller.c は正常にコンパイルできない。

func って何 ? 

Page 19: 全体の流れ

19

単純にファイルを分割すると…

// 呼び出される関数 double func(double d) { return 0.0; }

module.c

// 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

caller.c

コンパイルは

 ファイル単位で別々に実行されるため、 caller.c は正常にコンパイルできない。

func って何 ? 

Page 20: 全体の流れ

20

ヘッダファイルの利用

#include “module.h”

// 呼び出される関数 double func(double d) { return 0.0; }

module.c#include “module.h”

// 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

caller.c

// プロトタイプ宣言double func(double d);

module.hコンパイラは #include 擬似命令の部分で、 module.h ファイルを読み込む

呼び出される関数のプロトタイプ宣言は                に記述 呼び出し側のソースファイルで #include 擬似命令により、ヘッダファイル内の

宣言を読み込む

ヘッダファイル

” ” で囲んでいることに注意!

Page 21: 全体の流れ

21

ヘッダファイルの利用

#include “module.h”

// 呼び出される関数 double func(double d) { return 0.0; }

module.c#include “module.h”

// 呼び出し側関数 int caller(void) {    f = func(4); // 関数呼び出し }

caller.c

// プロトタイプ宣言double func(double d);

module.h

呼び出される関数のプロトタイプ宣言はヘッダファイルに記述 呼び出し側のソースファイルで #include 擬似命令により、ヘッ

ダファイル内の宣言を読み込むヘッダファイル

コンパイラは #include 擬似命令の部分で、 module.h ファイルを読み込む

” ” で囲んでいることに注意!

Page 22: 全体の流れ

22

< > と  " "

#include <stdio.h> のように < > で囲まれていると,プリプロセッサはシステムで定められた場所にあるファイルを取り込む

#include “module.h” のように” ”で囲まれていると,まずプログラムファイルと同じ場所を探し,存在しない場合はシステムで定められた場所を探す

Page 23: 全体の流れ

23

モジュール化の基本

#include <string.h> #include “module.h”

int internal_func(int a); #define INT_MACRO(a) (…)

static int internal_func(int a) { // モジュール内で // 使用する関数 }

#define MAX 1024typedef unsigned char BYTE;void exported_func(int i);

module.c

module.h

void exported_func(int i) { //外部に公開する関数 }

ヘッダファイルには[                      ]

• 関数のプロトタイプ宣言 • typedef  型宣言 • #define マクロ定義

など

プロトタイプ宣言が関数本体と一致するように注意

モジュール内のみで使用する関数のプロトタイプ宣言やマクロ定義などは [            ]で行う

Page 24: 全体の流れ

24

モジュール化の基本

#include <string.h> #include “module.h”

int internal_func(int a); #define INT_MACRO(a) (…)

static int internal_func(int a) { // モジュール内で // 使用する関数 }

module.c

module.h

void exported_func(int i) { //外部に公開する関数 }

ヘッダファイルには外部に公開する情報のみを記述

• 関数のプロトタイプ宣言 • typedef  型宣言 • #define マクロ定義

など

プロトタイプ宣言が関数本体と一致するように注意

モジュール内のみで使用する関数のプロトタイプ宣言やマクロ定義などはモジュール内で行う

モジュールで,何を公開し,何を隠すかがポイント

#define MAX 1024typedef unsigned char BYTE;void exported_func(int i);

Page 25: 全体の流れ

25

ファイルを分割したときの関数のスコープ

×

#include <string.h> #include “module.h”

int internal_func(int a); #define INT_MACRO(a) (…)

static int internal_func(int a) { // モジュール内で // 使用する関数 }

module.c

module.h

void exported_func(int i) { //外部に公開する関数 }

#define MAX 1024typedef unsigned char BYTE;void exported_func(int i);

別のモジュール

#include “module.h”

exported_func(15);

internal_func(30);

foo.c

• ヘッダファイルにプロトタイプ宣言がない  関数は外部から参照できない

• static な関数は外部から参照できない

見える ?

Page 26: 全体の流れ

26

img_io.c画像ファイルのロード

ファイルオープン画像バッファ確保データコピーファイルクローズ

画像ファイルのセーブ

画像バッファ確保

画像バッファ解放

サンプルプログラム 2 の関数呼び出し関係

main.c

 画像ファイルをロードする関数を呼び出す 画像処理関数を呼び出す 画像ファイルをセーブする関数を呼び出す 画像バッファを解放

img_proc.c

画像を 90 度回転 作業用バッファを確保 データを移し変え 不要なバッファを解放

( あとで処理を追加したい )

etc

Page 27: 全体の流れ

27

img_io.c画像ファイルのロード

ファイルオープン画像バッファ確保データコピーファイルクローズ

画像ファイルのセーブ

画像バッファ確保

画像バッファ解放

サンプルプログラム 2 の関数呼び出し関係

main.c

 画像ファイルをロードする関数を呼び出す 画像処理関数を呼び出す 画像ファイルをセーブする関数を呼び出す 画像バッファを解放

img_proc.c

画像を 90 度回転 作業用バッファを確保 データを移し変え 不要なバッファを解放

( あとで処理を追加したい )

etc

Page 28: 全体の流れ

28

関数の設計

ファイル入出力&メモリ確保 / 解放 関連int iioLoadFile(IMAGE *pImage, const char *fname);

int iioSaveFile(IMAGE *pImage, const char *fname);

void iioMallocImageBuffer(IMAGE *pImage);

void iioFreeImageBuffer(IMAGE *pImage);

画像処理関連void ipRotateImage(IMAGE *pImage);

Page 29: 全体の流れ

29

関数の設計

ファイル入出力&メモリ確保 / 解放 関連int iioLoadFile(IMAGE *pImage, const char *fname);

int iioSaveFile(IMAGE *pImage, const char *fname);

void iioMallocImageBuffer(IMAGE *pImage);

void iioFreeImageBuffer(IMAGE *pImage);

画像処理関連void ipRotateImage(IMAGE *pImage);

IMAGE 構造体へのポイン

ファイル名を表す文字列へのポイン

Page 30: 全体の流れ

30

サンプルプログラム2の説明

実装済みの関数( main 関数, iioLoadFile , iioMallocImageBuffer )の説明をするので配布資料のサンプルプログラムを見ること

Page 31: 全体の流れ

31

画像ファイルのセーブ

出力用ファイルをバイナリモードでオープン

ヘッダ情報を出力

画像データを出力

ファイルクローズ

開始

終了

int iioSaveFile(IMAGE *pImage, const char *fname)

256

192

255

xsize

ysize

level

pBuffer

pImage

pBuffer[0]

pBuffer[1]

pBuffer[2]

一行ずつ出力ヒント:  fwrite

ヒント 1: fprintfヒント 2: xsize の後ろに空白 1 つ       ysize の後ろに改行       level の後ろに改行      を忘れない

Page 32: 全体の流れ

32

画像バッファの解放void iioFreeImageBuffer(IMAGE *pImage)

pBuffer を解放 ②

開始

終了

  j < ysize?

256

192

255

xsize

ysize

level

pBuffer

pImage

pBuffer[0]

pBuffer[1]

pBuffer[2]

①一行ずつ解放

②最後に各行へのポインタの配列を解放

pBuffer[ j  ] を解放 ①j++;

j   =0;

Y

N