全体の流れ 画像ファイルを開き,画像データをメモリ上にロード メモリ上にロードした画像データに処理を加える

Slides:



Advertisements
Similar presentations
プログラミング演習Ⅱ 課題 4 第 2 週 画像ファイル (ppm) の読み書き 画像データ用のメモリ確保・解放 1.
Advertisements

プログラミング 関数編 情報科学科. プログラミングにあたって C 言語では、 main 内に処理を記述 1000 行になるような大きなプログラムでは、 プログラム全体が何をしているのかを把握 することが困難になる 他人が見ると非常に理解しにくい 作成者であっても時が経てば内容を忘れて、他 人が見た時と同じ状況になる.
1 全体の流れ 画像ファイルを開き,画像データをメモリ上にロード メモリ上にロードした画像データに処理を加える 処理後のデータを出力ファイルに書き出す 画像データ用に確保したメモリを解放.
構造体変数 1234 x xyz A 普通の変数 ( ここでは座標値 ) 構造体変数 ( ここでは点を表す ) xyz B 14 y 5 z 点 A の x 座標 プログラム中では A.x 点 B の y 座標 プログラム中では B.y 例えば 「 3 次元空間で2点 A と B の 間に線分を引き・・・」
A B x y z 復習 構造体変数 普通の変数 x y z 構造体変数 x y z 箱のイメージ 引き出しのイメージ
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
プログラミング入門2 第10回 動的な領域確保 情報工学科 篠埜 功.
第12回新しい型と構造体.
第13回構造体.
データ構造とアルゴリズム 第10回 mallocとfree
第12回構造体.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
画像ファイル(ppm)の読み書き 画像データ用のメモリ確保・解放
OSとコマンド OS:コンピュータを使うための基本プログラム コマンド:OS上で使用できる命令 OS本体であるカーネルの内部コマンド
記憶クラス 変数をどのような記憶領域に割り当てるかを指定するのが記憶クラス 記憶クラスには、自動変数、静的変数、外部変数などがある。
第8回 プログラミングⅡ 第8回
担当:青木義満 情報工学科 3年生対象 専門科目 システムプログラミング システムプログラミング プロセス間通信(パイプ) 担当:青木義満
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
画像ファイル(ppm)の読み書き 画像データ用のメモリ確保・解放
10: ファイル入出力 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
補足説明.
プログラミング2 関数
関数の定義.
iioLoadFile()とiioMallocImageBuffer()の補足
Cプログラミング演習 第7回 メモリ内でのデータの配置.
iioLoadFile()とiioMallocImageBuffer()の補足
iioLoadFile()とiioMallocImageBuffer()の補足
プログラミング 4 記憶の割り付け.
プログラミング演習I 2003年6月25日(第10回) 木村巌.
画像処理プログラムの説明.
プログラミング演習I 2003年5月7日(第4回) 木村巌.
プログラミング入門2 第11回 情報工学科 篠埜 功.
同じ構造をした「引き出し」変数を構造体変数と呼ぶ
プログラミング演習Ⅱ 課題4第3週 画像処理 (1) ビット演算子.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
第11回 プログラミングⅡ 第11回
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
フロントエンドとバックエンドのインターフェース
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
画像処理プログラミング 知的画像処理研究室 M2 小林 佳奈美.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
文字列へのポインタの配列 static char *lines[MAXLINES]; lines[0] NULL
情報基礎演習B 後半第2回 担当 岩村 TA 谷本君.
ファイルの読み込み, ファイルからのデータの取り出し, ファイルの書き出し
第5回 プログラミングⅡ 第5回
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
C プログラミング入門 基幹7 (水5) 14: 発展事項
プログラミング演習Ⅱ 課題4第4週 画像処理 (2) 応用.
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
プログラミング演習I 2003年6月11日(第9回) 木村巌.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
14: 発展事項 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング演習II 2003年11月19日(第6回) 木村巌.
プログラミング演習II 2003年12月10日(第7回) 木村巌.
マスク合成(のような処理) 出力画像 Out 入力画像1 In1 In1 In2 Out 入力画像2 In
左右反転と180度回転 [0][xsize – 1] [0][0] → i ↓ j [ysize – 1][xsize – 1]
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
C プログラミング入門 総機1 (月1) 14: 発展事項
Presentation transcript:

全体の流れ 画像ファイルを開き,画像データをメモリ上にロード メモリ上にロードした画像データに処理を加える 処理後のデータを出力ファイルに書き出す 画像データ用に確保したメモリを解放

データ構造~1画素をどう表現するか~ 88 B1 E7 8A B2 … PIXEL構造体 typedef struct { 画像ファイル内での画素データのフォーマット 88 (136) B1 (177) E7 (231) 8A (138) B2 (178) … 1画素あたり RGB各8ビット 合計3バイト PIXEL構造体 typedef struct { unsigned char r; unsigned char g; unsigned char b; } PIXEL, *PPIXEL; r 88 g B1 b E7

データ構造~1画素をどう表現するか~ 88 B1 E7 8A B2 … PIXEL構造体 typedef struct { 画像ファイル内での画素データのフォーマット 88 (136) B1 (177) E7 (231) 8A (138) B2 (178) … 1画素あたり RGB各8ビット 合計3バイト PIXEL構造体 typedef struct { unsigned char r; unsigned char g; unsigned char b; } PIXEL, *PPIXEL; r 88 g B1 b E7 この構造体の型名は PIXELにするよ PIXEL構造体へのポインタ型. 名前はPPIXELにするよ

データ構造~画像データをどう表現するか~ 画像ファイルのフォーマット 88 (136) B1 (177) E7 (231) ヘッダー(画像サイズ,最大輝度) 画像データ 画像データのサイズは,ヘッダ読み込み後でないと分からない →画像用のメモリは[              ]  typedef struct { int xsize; int ysize; int level; PPIXEL *pBuffer; } IMAGE; IMAGE構造体 xsize 256 ysize 192 level 255 pBuffer

データ構造~画像データをどう表現するか~ 画像ファイルのフォーマット 88 (136) B1 (177) E7 (231) ヘッダー(画像サイズ,最大輝度) 画像データ 画像データのサイズは,ヘッダ読み込み後でないと分からない →画像用のメモリは 動的 に確保 typedef struct { int xsize; int ysize; int level; PPIXEL *pBuffer; } IMAGE; IMAGE構造体 xsize 256 ysize 192 level 255 pBuffer PPIXELへのポインタ =(PIXELへのポインタ)へのポインタ

ポインタの配列~課題2の文字列のソートの復習~ char *lines[MAXLINES]; 文字列にあわせた長さ lines[0] strawberry\0 lines[1] watermelon\0 lines[2] banana\0 定数 MAXLINES個 (20000) lines[MAXLINES-1]

ポインタの配列~画像バッファの確保~ pImage xsize 256 xsize個の[ ] ysize 192 の配列を確保 level void iioMallocImageBuffer(IMAGE *pImage) pImage xsize 256 xsize個の[      ] の配列を確保 malloc(xsize * sizeof(PIXEL)); ysize 192 level 255 pBuffer ysize個の[      ] の配列を確保 malloc(ysize * sizeof(PPIXEL));

ポインタの配列~画像バッファの確保~ pImage xsize 256 xsize個のPIXEL ysize 192 の配列を確保 void iioMallocImageBuffer(IMAGE *pImage) pImage xsize 256 xsize個のPIXEL の配列を確保 malloc(xsize * sizeof(PIXEL)); ysize 192 level 255 pBuffer ysize個のPPIXEL の配列を確保 malloc(ysize * sizeof(PPIXEL));

モジュール設計 どういう機能を用意するか モジュールごとの独立性をどう高めるか メイン main.c 画像のファイル入出力 画像処理 画像データ用メモリ確保と解放 img_io.c img_io.h 画像処理 img_proc.c img_proc.h

復習:コンパイラの動作(1) コンパイラはソースファイルを[ ] コンパイラはソースファイルを[              ] func という関数は、doubleを受け取ってdoubleを返すんだな・・ //呼び出される関数 double func(double d) { return 0.0; } //呼び出し側関数 int caller(void)   f = func(4); // 関数呼び出し double を渡してdoubleを返してもらうようなコードを生成しよう・・ 4は4.0に変換してから渡そう・・・ 関数呼出部分をコンパイルするときに、コンパイラは呼び出される関数の引数の数・型、戻り値の型を知っておく必要がある

復習:コンパイラの動作(1) コンパイラはソースファイルを上から下へ解釈していく func という関数は、doubleを受け取ってdoubleを返すんだな・・ //呼び出される関数 double func(double d) { return 0.0; } //呼び出し側関数 int caller(void)   f = func(4); // 関数呼び出し double を渡してdoubleを返してもらうようなコードを生成しよう・・ 4は4.0に変換してから渡そう・・・ 関数呼出部分をコンパイルするときに、コンパイラは呼び出される関数の引数の数・型、戻り値の型を知っておく必要がある

コンパイラの動作(2) 関数記述位置の上下を逆にすると・・・ //呼び出し側関数 int caller(void) {   f = func(4); // 関数呼び出し } //呼び出される関数 double func(double d) return 0.0; 正常にコンパイルできない (C処理系ではwarningが、C++処理系ではエラーが発生する)

コンパイラの動作(2) 関数記述位置の上下を逆にすると・・・ func 関数の引数の型も //呼び出し側関数 引数の個数も知らないぞ・・・ int caller(void) {   f = func(4); // 関数呼び出し } //呼び出される関数 double func(double d) return 0.0; 正常にコンパイルできない (C処理系ではwarningが、C++処理系ではエラーが発生する)

関数プロトタイプ宣言 [ ] 関数呼出部分より前に を行うことにより、正常にコンパイルが可能となる [ ] を行うことにより、正常にコンパイルが可能となる 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に変換してから渡そう・・・

関数プロトタイプ宣言 プロトタイプ宣言 関数呼出部分より前に を行うことにより、正常にコンパイルが可能となる   プロトタイプ宣言 を行うことにより、正常にコンパイルが可能となる 最後はセミコロン 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に変換してから渡そう・・・

分割コンパイル gin.c lime.c gin.obj lime.obj libc.lib ginlime.exe ソースファイル ライブラリファイル (コンパイル済) [ ] [ ] オブジェクトファイル [ ] 実行ファイル ソースファイルを複数に分割し、それぞれをコンパイルしてできたオブジェクトファイルをリンカで結合 更新されたソースファイルのみコンパイルすればよいため、プログラムの規模が大きくなった場合でも、微細な変更時のビルド時間を大幅に短縮可能

分割コンパイル gin.c lime.c gin.obj lime.obj libc.lib ginlime.exe ソースファイル ライブラリファイル (コンパイル済) コンパイル コンパイル オブジェクトファイル リンク 実行ファイル ソースファイルを複数に分割し、それぞれをコンパイルしてできたオブジェクトファイルをリンカで結合 更新されたソースファイルのみコンパイルすればよいため、プログラムの規模が大きくなった場合でも、微細な変更時のビルド時間を大幅に短縮可能

単純にファイルを分割すると… [ ] //呼び出される関数 double func(double d) { return 0.0; } module.c //呼び出し側関数 int caller(void)   f = func(4); // 関数呼び出し caller.c func って何?  コンパイルは  [                       ] ため、caller.c は正常にコンパイルできない。

単純にファイルを分割すると… ファイル単位で別々に実行される //呼び出される関数 double func(double d) { return 0.0; } module.c //呼び出し側関数 int caller(void)   f = func(4); // 関数呼び出し caller.c func って何?  コンパイルは  ファイル単位で別々に実行される ため、caller.c は正常にコンパイルできない。

ヘッダファイルの利用 呼び出される関数のプロトタイプ宣言は に記述 呼び出される関数のプロトタイプ宣言は                に記述 呼び出し側のソースファイルで #include 擬似命令により、ヘッダファイル内の宣言を読み込む module.h ヘッダファイル コンパイラは #include 擬似命令の部分で、module.h ファイルを読み込む //プロトタイプ宣言 double func(double d); module.c caller.c ” ” で囲んでいることに注意! #include “module.h” //呼び出される関数 double func(double d) { return 0.0; } #include “module.h” //呼び出し側関数 int caller(void) {   f = func(4); // 関数呼び出し }

ヘッダファイルの利用 呼び出される関数のプロトタイプ宣言はヘッダファイルに記述 呼び出し側のソースファイルで #include 擬似命令により、ヘッダファイル内の宣言を読み込む module.h ヘッダファイル コンパイラは #include 擬似命令の部分で、module.h ファイルを読み込む //プロトタイプ宣言 double func(double d); module.c caller.c ” ” で囲んでいることに注意! #include “module.h” //呼び出される関数 double func(double d) { return 0.0; } #include “module.h” //呼び出し側関数 int caller(void) {   f = func(4); // 関数呼び出し }

< > と " " #include <stdio.h>のように< >で囲まれていると,プリプロセッサはシステムで定められた場所にあるファイルを取り込む #include “module.h”のように” ”で囲まれていると,まずプログラムファイルと同じ場所を探し,存在しない場合はシステムで定められた場所を探す

モジュール化の基本 ヘッダファイルには [ ] 関数のプロトタイプ宣言 typedef 型宣言 #define マクロ定義 など [                    ]  関数のプロトタイプ宣言  typedef 型宣言  #define マクロ定義 など module.h #define MAX 1024 typedef unsigned char BYTE; void exported_func(int i); module.c #include <string.h> #include “module.h” int internal_func(int a); #define INT_MACRO(a) (…) static int internal_func(int a) { //モジュール内で //使用する関数 } プロトタイプ宣言が関数本体と一致するように注意 void exported_func(int i) { //外部に公開する関数 } モジュール内のみで使用する関数のプロトタイプ宣言やマクロ定義などは[          ]で行う

モジュール化の基本 ヘッダファイルには 外部に公開する情報のみを記述 関数のプロトタイプ宣言 typedef 型宣言  関数のプロトタイプ宣言  typedef 型宣言  #define マクロ定義 など module.h #define MAX 1024 typedef unsigned char BYTE; void exported_func(int i); module.c #include <string.h> #include “module.h” int internal_func(int a); #define INT_MACRO(a) (…) static int internal_func(int a) { //モジュール内で //使用する関数 } プロトタイプ宣言が関数本体と一致するように注意 void exported_func(int i) { //外部に公開する関数 } モジュール内のみで使用する関数のプロトタイプ宣言やマクロ定義などはモジュール内で行う モジュールで,何を公開し, 何を隠すかがポイント

○ × ファイルを分割したときの関数のスコープ 見える? 別のモジュール ヘッダファイルにプロトタイプ宣言がない 関数は外部から参照できない #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 1024 typedef unsigned char BYTE; void exported_func(int i); 見える? 別のモジュール foo.c ○ #include “module.h” exported_func(15); internal_func(30); ×  ヘッダファイルにプロトタイプ宣言がない   関数は外部から参照できない  staticな関数は外部から参照できない

サンプルプログラム2の関数呼び出し関係 main.c 画像ファイルをロードする関数を呼び出す 画像処理関数を呼び出す  画像ファイルをロードする関数を呼び出す  画像処理関数を呼び出す  画像ファイルをセーブする関数を呼び出す  画像バッファを解放 img_io.c 画像ファイルのロード ファイルオープン 画像バッファ確保 データコピー ファイルクローズ 画像ファイルのセーブ 画像バッファ解放 img_proc.c 画像を90度回転 作業用バッファを確保 データを移し変え 不要なバッファを解放 (あとで処理を追加したい) etc

サンプルプログラム2の関数呼び出し関係 main.c 画像ファイルをロードする関数を呼び出す 画像処理関数を呼び出す  画像ファイルをロードする関数を呼び出す  画像処理関数を呼び出す  画像ファイルをセーブする関数を呼び出す  画像バッファを解放 img_io.c 画像ファイルのロード ファイルオープン 画像バッファ確保 データコピー ファイルクローズ 画像ファイルのセーブ 画像バッファ解放 img_proc.c 画像を90度回転 作業用バッファを確保 データを移し変え 不要なバッファを解放 (あとで処理を追加したい) etc

関数の設計 ファイル入出力&メモリ確保/解放 関連 画像処理関連 ファイル入出力&メモリ確保/解放 関連 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);

関数の設計 ファイル入出力&メモリ確保/解放 関連 画像処理関連 ファイル入出力&メモリ確保/解放 関連 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構造体へのポインタ

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

画像ファイルのセーブ int iioSaveFile(IMAGE *pImage, const char *fname) 開始 ヒント1: fprintf ヒント2: xsizeの後ろに空白1つ       ysizeの後ろに改行       levelの後ろに改行       を忘れない 開始 pImage 出力用ファイルを バイナリモードでオープン xsize 256 ysize 192 level 255 一行ずつ出力 ヒント: fwrite ヘッダ情報を出力 pBuffer pBuffer[0] 画像データを出力 pBuffer[1] pBuffer[2] ファイルクローズ 終了

画像バッファの解放 void iioFreeImageBuffer(IMAGE *pImage) 開始 j =0; xsize 256 ysize 192  j < ysize? N level 255 pBuffer Y pBuffer[ j ]を解放 ① j++; ① 一行ずつ解放 pBuffer[0] pBuffer[1] pBuffer[2] pBufferを解放 ② ②最後に各行へのポインタの配列を解放 終了