ppm形式の画像
ppm形式の画像
お久しぶりです、rozeoです。
ppm形式の画像を扱うプログラムを書いてるんですが、1000ピクセル*1000ピクセルのppmのような大きなppmになると色要素が莫大になるため、1つ1つ読むとロードにかなりの時間を有します。
そこでですが、ppmの形式のような莫大な数の要素を扱う際処理が比較的に早いアルゴリズムってありますか?ヘッダ部の読み込みはできるため、データ部のみでいいです。
ppmを扱うフリーソフトがあるようですが、そういうようなソフトは読み込みが高速です。
なにかしっていることあればよろしくお願いします。
ppm形式の画像を扱うプログラムを書いてるんですが、1000ピクセル*1000ピクセルのppmのような大きなppmになると色要素が莫大になるため、1つ1つ読むとロードにかなりの時間を有します。
そこでですが、ppmの形式のような莫大な数の要素を扱う際処理が比較的に早いアルゴリズムってありますか?ヘッダ部の読み込みはできるため、データ部のみでいいです。
ppmを扱うフリーソフトがあるようですが、そういうようなソフトは読み込みが高速です。
なにかしっていることあればよろしくお願いします。
Re: ppm形式の画像
具体的にどのような方法でロードしているのでしょうか。
fscanfなどを利用していると遅いと思いますよ。
fscanfなどを利用していると遅いと思いますよ。
Re: ppm形式の画像
バイナリ(P6)形式なのでrb指定で開いてfreadで読んでます
Re: ppm形式の画像
ソースに問題があるわけではなく、莫大な量の要素の能率のいいほうほうを聞いてるんですが…
あとソースは、オフラインPCで作業してるため、はることができません…悪しからず…
(これは携帯から投稿してます)
あとソースは、オフラインPCで作業してるため、はることができません…悪しからず…
(これは携帯から投稿してます)
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ppm形式の画像
> ソースに問題があるわけではなく、莫大な量の要素の能率のいいほうほうを聞いてるんですが…
freadは早いはずなので、rozeoさんが効率が悪いfreadの使い方をしているのでは?とh2so5さんは危惧しておられます。
プロがソースコードを要求するのは、それなりに理由がありますよ。
freadは早いはずなので、rozeoさんが効率が悪いfreadの使い方をしているのでは?とh2so5さんは危惧しておられます。
プロがソースコードを要求するのは、それなりに理由がありますよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ppm形式の画像
freadでファイルサイズぶん読み込めばいいだけでは?rozeo さんが書きました:ソースに問題があるわけではなく、莫大な量の要素の能率のいいほうほうを聞いてるんですが…
ファイル読み込みを1画素ずつ何回も呼び出すより、
ファイル読み込みを1回で済ました方が格段に速いです。
まああまりにでかい画像だとメモリを圧迫して、システム全体が重くなりますけどね。
今あるソースを掲示してもらえると、能率のいいやり方を教えてもらえると思いますよ。
written by へにっくす
Re: ppm形式の画像
ようするに一度ファイル全てを読みこみ、そのあとRGBの値を整理するって感じですかね?
ちなみに並べ替えを行うのでその後にまたRGBの値を走査しますが。
ちなみに並べ替えを行うのでその後にまたRGBの値を走査しますが。
Re: ppm形式の画像
あと、寮に帰ったらソースコードはれるかどうかやってみます
Re: ppm形式の画像
なぜかプロジェクトを消してしまっていたのでデータ部の読み込みの概要のみかきます。
まず前提条件としてfopen関数でrb属性でファイルを開いています。 その後WM_PAINTメッセージが来たとこでロードを行います。
(WM_CREATEメッセージのときにヘッダ部はスキップしています。) ようするにサイズが1000*1000なので100万回ループさせてかつ、rgbの3つの値を読み取っています。
まず前提条件としてfopen関数でrb属性でファイルを開いています。 その後WM_PAINTメッセージが来たとこでロードを行います。
(WM_CREATEメッセージのときにヘッダ部はスキップしています。) ようするにサイズが1000*1000なので100万回ループさせてかつ、rgbの3つの値を読み取っています。
Re: ppm形式の画像
1バイトずつfreadしている「読み方」も確かに遅そうではありますが,
それ以前に
fread()をWM_PAINTのとこに書いてる=表示が必要な際に毎回毎回読み込む
という方式を改めるべきかと思いますが,いかがでしょうか.
例えば,
WM_CREATE時に画像内容までを読み込み,その内容はどこかに保持しておく→WM_PAINT時にはその内容を表示する
という形にすれば ロードは一回で済みますよね.
[追記]
あと,SetPixel()も遅い部類のものだと聞いたことがありますよ.
それ以前に
fread()をWM_PAINTのとこに書いてる=表示が必要な際に毎回毎回読み込む
という方式を改めるべきかと思いますが,いかがでしょうか.
例えば,
WM_CREATE時に画像内容までを読み込み,その内容はどこかに保持しておく→WM_PAINT時にはその内容を表示する
という形にすれば ロードは一回で済みますよね.
[追記]
あと,SetPixel()も遅い部類のものだと聞いたことがありますよ.
Re: ppm形式の画像
>ロードにかなりの時間を有します。
とのことですが,
「ロード部分の処理時間だけを測った」とかいう話ではなくて
「何かプログラムの挙動が激しく重たい」という感じでの話なのであれば,
少なくとも,その原因として
・読み方(1バイトずつ読んでる)
・読込処理を書いている場所(WM_PAINTのところに書いてる)
・描画方法(SetPixel)
の3つがあるのではないかと思います ……ということです.
とのことですが,
「ロード部分の処理時間だけを測った」とかいう話ではなくて
「何かプログラムの挙動が激しく重たい」という感じでの話なのであれば,
少なくとも,その原因として
・読み方(1バイトずつ読んでる)
・読込処理を書いている場所(WM_PAINTのところに書いてる)
・描画方法(SetPixel)
の3つがあるのではないかと思います ……ということです.
Re: ppm形式の画像
ならば、WM_CREATEでピクセル数100万*三色、300万の配列をmallocで用意してWM_CREATEのときにusao さんが書きました:1バイトずつfreadしている「読み方」も確かに遅そうではありますが,
それ以前に
fread()をWM_PAINTのとこに書いてる=表示が必要な際に毎回毎回読み込む
という方式を改めるべきかと思いますが,いかがでしょうか.
例えば,
WM_CREATE時に画像内容までを読み込み,その内容はどこかに保持しておく→WM_PAINT時にはその内容を表示する
という形にすれば ロードは一回で済みますよね.
[追記]
あと,SetPixel()も遅い部類のものだと聞いたことがありますよ.
unsigned char color[100000];//malloc文書くのめんどいので省略
fread( color,sizeof( char ),1000000,f );
で読み込むのはいいのですが、描画の際にSetPixcel以外で描画する方法ってあるのでしょうか?
SetPixcelをつかうと100万回ループさせないといけないので...
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ppm形式の画像
usaoさんが書いているDIBセクションを使ってください。WIn32APIの一部であるGDIの機能です。
「標準 Windows API」
http://wisdom.sakura.ne.jp/system/winap ... index.html
「標準 Windows API」
http://wisdom.sakura.ne.jp/system/winap ... index.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ppm形式の画像
GDIちょっとやってみることにします。
またこの方法でのちのち読んだファイル内容(RGB配列やピクセル位置)を変更することは可能でしょうか?(この部分だけきりとって新しくファイルつくるとか)
またこの方法でのちのち読んだファイル内容(RGB配列やピクセル位置)を変更することは可能でしょうか?(この部分だけきりとって新しくファイルつくるとか)
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ppm形式の画像
ペイント系ソフトが使っているものなので、もちろん出来ますよ。rozeo さんが書きました:GDIちょっとやってみることにします。
またこの方法でのちのち読んだファイル内容(RGB配列やピクセル位置)を変更することは可能でしょうか?(この部分だけきりとって新しくファイルつくるとか)
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ppm形式の画像
先ほどのページでやってみたんですが、CreateDIBSectionの第4引数でエラーがでます。
BYTE *bCBits;
HBITMAP hBitmap = CreateDIBSction( NULL,bmpinfo,DIB_RGB_COLORS,&bCBits,NULL,0 );
エラー文
BYTE **からvoid **に変換できません。
さっきのページは通っていたのですがやはり仕様の変更でしょうか?もしそうなら解決方法を教えてください
っていうかこのサイトビットマップを例にあげてやってますが、PPMの場合はどのように工夫すればよいでしょうか?
BYTE *bCBits;
HBITMAP hBitmap = CreateDIBSction( NULL,bmpinfo,DIB_RGB_COLORS,&bCBits,NULL,0 );
エラー文
BYTE **からvoid **に変換できません。
さっきのページは通っていたのですがやはり仕様の変更でしょうか?もしそうなら解決方法を教えてください
っていうかこのサイトビットマップを例にあげてやってますが、PPMの場合はどのように工夫すればよいでしょうか?
最後に編集したユーザー rozeo on 2014年5月09日(金) 01:10 [ 編集 1 回目 ]
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ppm形式の画像
> C++ としてコンパイルした場合、エラーが発生する場合があります
と書かれている通りC++でコンパイルされてませんか?
一応C++でもキャストすれば通るはずです。
と書かれている通りC++でコンパイルされてませんか?
一応C++でもキャストすれば通るはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ppm形式の画像
C++でコンパイルしています。void **でキャストすると通りました
Re: ppm形式の画像
コード丸写ししましたがbmpが表示できません。なにが考えられるでしょうか?
変更したところはCreateDIBSctionのキャストだけです
変更したところはCreateDIBSctionのキャストだけです
Re: ppm形式の画像
rozeo さんが書きました:先ほどのページでやってみたんですが、CreateDIBSectionの第4引数でエラーがでます。
BYTE *bCBits;
HBITMAP hBitmap = CreateDIBSction( NULL,bmpinfo,DIB_RGB_COLORS,&bCBits,NULL,0 );
・・・rozeo さんが書きました:コード丸写ししましたがbmpが表示できません。なにが考えられるでしょうか?
変更したところはCreateDIBSctionのキャストだけです
コード丸写しってことは元のソースがあるはずですよね。そのリンクかもしくは、今のソースをはってください。
少なくともこのスレではそれが示されていません。
今のあなたは、なんでも教えてクンか察してクンと同じ印象を受けます。
オフトピック
written by へにっくす
Re: ppm形式の画像
softyaさんのURLのDIBセクションって項目です
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ppm形式の画像
プログラムコードは、ちゃんと理解されていますか?
コマンドライン引数で画像を指定するようになっているコードですが、そこは自分の都合に合わせて変更なり、引数の指定なりをされていますよね?
コマンドライン引数で画像を指定するようになっているコードですが、そこは自分の都合に合わせて変更なり、引数の指定なりをされていますよね?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ppm形式の画像
手順としては こんな感じですかね.
(1)~(3)はWM_CREATE時なり,あるいはWinMain()の最初らへんでやるなりすればいいでしょう.
(1) BITMAPINFO 型の変数を用意して,そこに(bit数とか縦横サイズ等々の)情報を入れる
(2) CreateDIBSection() でDIBセクションを作る.
(2-1)戻り値として,作られたDIB用のHBITMAPが返される
(2-2)引数によって,作られたDIBの画素データメモリ位置を得られる
(3)ファイルから画像をロードした結果の画素値を (2-2)の場所に入れれば描画準備完了.
(4)あとはWM_PAINTのとこで好きな方法でDIBを描画する(↓が一応ヒントになるかな)
(5)後始末は,DeleteObject()で.
(1)~(3)はWM_CREATE時なり,あるいはWinMain()の最初らへんでやるなりすればいいでしょう.
(1) BITMAPINFO 型の変数を用意して,そこに(bit数とか縦横サイズ等々の)情報を入れる
(2) CreateDIBSection() でDIBセクションを作る.
(2-1)戻り値として,作られたDIB用のHBITMAPが返される
(2-2)引数によって,作られたDIBの画素データメモリ位置を得られる
(3)ファイルから画像をロードした結果の画素値を (2-2)の場所に入れれば描画準備完了.
(4)あとはWM_PAINTのとこで好きな方法でDIBを描画する(↓が一応ヒントになるかな)
(5)後始末は,DeleteObject()で.
オフトピック
StretchDIBits()みたいなAPIで単に等倍描画するやつって無いのかな?…といろいろ見てたら
SetDIBitsToDevice() なんていうAPIがあるんですね.
SetDIBitsToDevice() とか StretchDIBits() は
画像描画コードがとりあえずそのAPIだけで済むので書くのが楽.
↑↓
メモリデバイスコンテキストを用意してそこにSelectObject()して…という手順は
やや面倒だけど描画(転送?)方法の自由度が高い.
(大昔にやったときは AlphaBlend()やTransparentBlt() が自環境でサポートされてなくて無念だったなぁ)
SetDIBitsToDevice() なんていうAPIがあるんですね.
SetDIBitsToDevice() とか StretchDIBits() は
画像描画コードがとりあえずそのAPIだけで済むので書くのが楽.
↑↓
メモリデバイスコンテキストを用意してそこにSelectObject()して…という手順は
やや面倒だけど描画(転送?)方法の自由度が高い.
(大昔にやったときは AlphaBlend()やTransparentBlt() が自環境でサポートされてなくて無念だったなぁ)
Re: ppm形式の画像
もちろんそこはCreateFileで開くときに一つのファイル名に決めてますsoftya(ソフト屋) さんが書きました:プログラムコードは、ちゃんと理解されていますか?
コマンドライン引数で画像を指定するようになっているコードですが、そこは自分の都合に合わせて変更なり、引数の指定なりをされていますよね?
usao氏のやり方で再度コードを組み直してみます。
また質問があれば質問させていただくので一旦解決とさせていただきます
最後に編集したユーザー rozeo on 2014年5月09日(金) 17:39 [ 編集 1 回目 ]
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ppm形式の画像
私の所ではキャスト(void**)で問題なく動きましたのでなにか間違いがあると思います。rozeo さんが書きました:もちろんそこはCreateFileで開くときに一つのファイル名に決めてますsoftya(ソフト屋) さんが書きました:プログラムコードは、ちゃんと理解されていますか?
コマンドライン引数で画像を指定するようになっているコードですが、そこは自分の都合に合わせて変更なり、引数の指定なりをされていますよね?
usao氏のやり方で再度コードを組み直してみます。
また質問があれば質問させていただくので一旦解決とさせていただきます
VisualC++2008を使用。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ppm形式の画像
帰ったらプログラムを見直してみます。
あとusao氏の手順3、ファイルから画像をロードした画素値を2-2に入れるというのはどのような処理をおこなったらいいのでしょう?
ほかのサイトを漁ってみるとvoid **でキャストしてました。しかしその変数の型がそのサイトはLPDWORD型、softyaさんに紹介してもらったサイトはBYTE型でしたがそこに問題はないのでしょうか?
あとusao氏の手順3、ファイルから画像をロードした画素値を2-2に入れるというのはどのような処理をおこなったらいいのでしょう?
ほかのサイトを漁ってみるとvoid **でキャストしてました。しかしその変数の型がそのサイトはLPDWORD型、softyaさんに紹介してもらったサイトはBYTE型でしたがそこに問題はないのでしょうか?
Re: ppm形式の画像
>あとusao氏の手順3、ファイルから画像をロードした画素値を2-2に入れるというのはどのような処理をおこなったらいいのでしょう?
うーん,イメージ湧きませんかね?
CreateDIBSection() は,
例えば,あなたが「画像サイズが1000*1000で,1画素あたり24bitなんですが」という指定で使えば,
そのサイズの画素データ群を保持するために必要なメモリ領域を確保してくれて,そのメモリの場所を
((void**)がどうのといっている引数で)教えてもらえるわけです.
なので,後は,そのメモリに,あなたが表示したいイメージの画素値を書き込んであげればいいわけです.
(1000*1000画素分の画素値を,DIBのフォーマットに従って.←フォーマットについては少し調べましょう)
>ほかのサイトを漁ってみるとvoid **でキャストしてました。しかしその変数の型がそのサイトはLPDWORD型、softyaさんに紹介してもらったサイトはBYTE型でしたがそこに問題はないのでしょうか?
上記のように,この引数で返される情報は,指定した画像サイズ分の画素値群を格納するのに必要なサイズ(バイト数)のメモリ領域の「場所」
であって,その場所をどのようにアクセスしようが,それはあなたの自由です.
バイト単位でアクセスしやすいように BYTE* 型を使ってもいいし,
4バイト単位でアクセスした方がやりやすいのであれば DWORD* 型を使ったりすればいいわけです.
うーん,イメージ湧きませんかね?
CreateDIBSection() は,
例えば,あなたが「画像サイズが1000*1000で,1画素あたり24bitなんですが」という指定で使えば,
そのサイズの画素データ群を保持するために必要なメモリ領域を確保してくれて,そのメモリの場所を
((void**)がどうのといっている引数で)教えてもらえるわけです.
なので,後は,そのメモリに,あなたが表示したいイメージの画素値を書き込んであげればいいわけです.
(1000*1000画素分の画素値を,DIBのフォーマットに従って.←フォーマットについては少し調べましょう)
>ほかのサイトを漁ってみるとvoid **でキャストしてました。しかしその変数の型がそのサイトはLPDWORD型、softyaさんに紹介してもらったサイトはBYTE型でしたがそこに問題はないのでしょうか?
上記のように,この引数で返される情報は,指定した画像サイズ分の画素値群を格納するのに必要なサイズ(バイト数)のメモリ領域の「場所」
であって,その場所をどのようにアクセスしようが,それはあなたの自由です.
バイト単位でアクセスしやすいように BYTE* 型を使ってもいいし,
4バイト単位でアクセスした方がやりやすいのであれば DWORD* 型を使ったりすればいいわけです.
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ppm形式の画像
こういうRGBなど素のデータを扱うのならメモリイメージの理解は必須です。
デバッガでメモリダンプなどを眺めてみてはどうでしょう?
デバッガでメモリダンプなどを眺めてみてはどうでしょう?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ppm形式の画像
わかりました。ありがとうございます。
とりあえず、丸ごとコピペプログラムがなぜ動かないのか検討してみます
とりあえず、丸ごとコピペプログラムがなぜ動かないのか検討してみます
Re: ppm形式の画像
CreateDIBSection関数はうまく成功していますが、いまいちどのように画素を格納すればいいのかわかりません。
画素を格納するメモリをさす変数をDWORD *型に変えて
とやってみましたが、無理でした。
DIBの画素構成は
BYTE型4つ、RGB値と輝度で4bytesであっているでしょうか?
画素を格納するメモリをさす変数をDWORD *型に変えて
//hFile : ファイルハンドル
//bmpinfo : BITMAPINFO ,ピクチャデータは格納済み
DWORD *Bits;
hBitmap = CreateDIBSction( hdc,&bmpinfo,DIB_RGB_COLORS,( void ** )Bits,NULL,0 );
for( int i = 0;i < 1000*1000;i++ ) ReadFile( hFile,&Bits[i],3,&dwBytes,NULL );
DIBの画素構成は
BYTE型4つ、RGB値と輝度で4bytesであっているでしょうか?
Re: ppm形式の画像
"SetDIBitsToDevice"で過去ログ検索したらいい感じのサンプルコードが。
http://dixq.net/forum/viewtopic.php?f=3&t=14569#p115692
メモリにピクセルデータ展開してるとこをNo.10のppm読み込むのにそのまま当てはめてしまえるのでは?
1バイトずつ読み込んでもキャッシュがあればいうほど遅くないと思いますが。
http://dixq.net/forum/viewtopic.php?f=3&t=14569#p115692
メモリにピクセルデータ展開してるとこをNo.10のppm読み込むのにそのまま当てはめてしまえるのでは?
1バイトずつ読み込んでもキャッシュがあればいうほど遅くないと思いますが。
Re: ppm形式の画像
ありがとうございます。読んでみたのですが、あまりうまくわからないので、、もう少し自分で考えてみたいと思います。Mana さんが書きました:"SetDIBitsToDevice"で過去ログ検索したらいい感じのサンプルコードが。
http://dixq.net/forum/viewtopic.php?f=3&t=14569#p115692
メモリにピクセルデータ展開してるとこをNo.10のppm読み込むのにそのまま当てはめてしまえるのでは?
1バイトずつ読み込んでもキャッシュがあればいうほど遅くないと思いますが。
とりあえず、解決にしておきます