ppm形式の画像

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

ppm形式の画像

#1

投稿記事 by rozeo » 10年前

お久しぶりです、rozeoです。

ppm形式の画像を扱うプログラムを書いてるんですが、1000ピクセル*1000ピクセルのppmのような大きなppmになると色要素が莫大になるため、1つ1つ読むとロードにかなりの時間を有します。

そこでですが、ppmの形式のような莫大な数の要素を扱う際処理が比較的に早いアルゴリズムってありますか?ヘッダ部の読み込みはできるため、データ部のみでいいです。
ppmを扱うフリーソフトがあるようですが、そういうようなソフトは読み込みが高速です。

なにかしっていることあればよろしくお願いします。

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: ppm形式の画像

#2

投稿記事 by h2so5 » 10年前

具体的にどのような方法でロードしているのでしょうか。
fscanfなどを利用していると遅いと思いますよ。

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#3

投稿記事 by rozeo » 10年前

バイナリ(P6)形式なのでrb指定で開いてfreadで読んでます

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: ppm形式の画像

#4

投稿記事 by h2so5 » 10年前

ソースコードを貼ってもらえますか。

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#5

投稿記事 by rozeo » 10年前

ソースに問題があるわけではなく、莫大な量の要素の能率のいいほうほうを聞いてるんですが…

あとソースは、オフラインPCで作業してるため、はることができません…悪しからず…
(これは携帯から投稿してます)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ppm形式の画像

#6

投稿記事 by softya(ソフト屋) » 10年前

> ソースに問題があるわけではなく、莫大な量の要素の能率のいいほうほうを聞いてるんですが…

freadは早いはずなので、rozeoさんが効率が悪いfreadの使い方をしているのでは?とh2so5さんは危惧しておられます。
プロがソースコードを要求するのは、それなりに理由がありますよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
へにっくす
記事: 634
登録日時: 12年前
住所: 東京都

Re: ppm形式の画像

#7

投稿記事 by へにっくす » 10年前

rozeo さんが書きました:ソースに問題があるわけではなく、莫大な量の要素の能率のいいほうほうを聞いてるんですが…
freadでファイルサイズぶん読み込めばいいだけでは?
ファイル読み込みを1画素ずつ何回も呼び出すより、
ファイル読み込みを1回で済ました方が格段に速いです。

まああまりにでかい画像だとメモリを圧迫して、システム全体が重くなりますけどね。
今あるソースを掲示してもらえると、能率のいいやり方を教えてもらえると思いますよ。
written by へにっくす

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#8

投稿記事 by rozeo » 10年前

ようするに一度ファイル全てを読みこみ、そのあとRGBの値を整理するって感じですかね?

ちなみに並べ替えを行うのでその後にまたRGBの値を走査しますが。

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#9

投稿記事 by rozeo » 10年前

あと、寮に帰ったらソースコードはれるかどうかやってみます

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#10

投稿記事 by rozeo » 10年前

なぜかプロジェクトを消してしまっていたのでデータ部の読み込みの概要のみかきます。

まず前提条件としてfopen関数でrb属性でファイルを開いています。

コード:

case WM_CREATE:
    FILE *f = fopen( "test.ppm","rb" );
    if( f == NULL ) return -1;
    break;
その後WM_PAINTメッセージが来たとこでロードを行います。
(WM_CREATEメッセージのときにヘッダ部はスキップしています。)

コード:

case WM_PAINT:
//hdcとpsは関数上部で定義済み
hdc = BeginPaint( hWnd,&ps );
for( int i = 0;i < 1000;i++ ){//ppmのサイズは1000*1000固定
    for( int j = 0;j < 1000;j++ ){
        unsigned char r,g,b;
        fread( &r,1,1,f );
        fread( &g,1,1,f );
        fread( &b,1,1,f );
        SetPixcel( hdc,i,j,RGB( r,g,b ));
    }
}
EndPaint( hWnd,&ps );
break;
ようするにサイズが1000*1000なので100万回ループさせてかつ、rgbの3つの値を読み取っています。

アバター
usao
記事: 1889
登録日時: 11年前

Re: ppm形式の画像

#11

投稿記事 by usao » 10年前

1バイトずつfreadしている「読み方」も確かに遅そうではありますが,
それ以前に
 fread()をWM_PAINTのとこに書いてる=表示が必要な際に毎回毎回読み込む
という方式を改めるべきかと思いますが,いかがでしょうか.

例えば,
WM_CREATE時に画像内容までを読み込み,その内容はどこかに保持しておく→WM_PAINT時にはその内容を表示する
という形にすれば ロードは一回で済みますよね.

[追記]
あと,SetPixel()も遅い部類のものだと聞いたことがありますよ.

アバター
usao
記事: 1889
登録日時: 11年前

Re: ppm形式の画像

#12

投稿記事 by usao » 10年前

>ロードにかなりの時間を有します。

とのことですが,
「ロード部分の処理時間だけを測った」とかいう話ではなくて
「何かプログラムの挙動が激しく重たい」という感じでの話なのであれば,
少なくとも,その原因として

・読み方(1バイトずつ読んでる)
・読込処理を書いている場所(WM_PAINTのところに書いてる)
・描画方法(SetPixel)

の3つがあるのではないかと思います ……ということです.

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#13

投稿記事 by rozeo » 10年前

usao さんが書きました:1バイトずつfreadしている「読み方」も確かに遅そうではありますが,
それ以前に
 fread()をWM_PAINTのとこに書いてる=表示が必要な際に毎回毎回読み込む
という方式を改めるべきかと思いますが,いかがでしょうか.

例えば,
WM_CREATE時に画像内容までを読み込み,その内容はどこかに保持しておく→WM_PAINT時にはその内容を表示する
という形にすれば ロードは一回で済みますよね.

[追記]
あと,SetPixel()も遅い部類のものだと聞いたことがありますよ.
ならば、WM_CREATEでピクセル数100万*三色、300万の配列をmallocで用意してWM_CREATEのときに
unsigned char color[100000];//malloc文書くのめんどいので省略
fread( color,sizeof( char ),1000000,f );

で読み込むのはいいのですが、描画の際にSetPixcel以外で描画する方法ってあるのでしょうか?
SetPixcelをつかうと100万回ループさせないといけないので...

アバター
usao
記事: 1889
登録日時: 11年前

Re: ppm形式の画像

#14

投稿記事 by usao » 10年前

DIBセクションとか使うとよいのではないでしょうか.

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ppm形式の画像

#15

投稿記事 by softya(ソフト屋) » 10年前

usaoさんが書いているDIBセクションを使ってください。WIn32APIの一部であるGDIの機能です。
「標準 Windows API」
http://wisdom.sakura.ne.jp/system/winap ... index.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#16

投稿記事 by rozeo » 10年前

GDIちょっとやってみることにします。

またこの方法でのちのち読んだファイル内容(RGB配列やピクセル位置)を変更することは可能でしょうか?(この部分だけきりとって新しくファイルつくるとか)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ppm形式の画像

#17

投稿記事 by softya(ソフト屋) » 10年前

rozeo さんが書きました:GDIちょっとやってみることにします。

またこの方法でのちのち読んだファイル内容(RGB配列やピクセル位置)を変更することは可能でしょうか?(この部分だけきりとって新しくファイルつくるとか)
ペイント系ソフトが使っているものなので、もちろん出来ますよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#18

投稿記事 by rozeo » 10年前

先ほどのページでやってみたんですが、CreateDIBSectionの第4引数でエラーがでます。
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形式の画像

#19

投稿記事 by softya(ソフト屋) » 10年前

> C++ としてコンパイルした場合、エラーが発生する場合があります
と書かれている通りC++でコンパイルされてませんか?
一応C++でもキャストすれば通るはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#20

投稿記事 by rozeo » 10年前

C++でコンパイルしています。void **でキャストすると通りました

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#21

投稿記事 by rozeo » 10年前

コード丸写ししましたがbmpが表示できません。なにが考えられるでしょうか?
変更したところはCreateDIBSctionのキャストだけです

アバター
へにっくす
記事: 634
登録日時: 12年前
住所: 東京都

Re: ppm形式の画像

#22

投稿記事 by へにっくす » 10年前

rozeo さんが書きました:先ほどのページでやってみたんですが、CreateDIBSectionの第4引数でエラーがでます。
BYTE *bCBits;
HBITMAP hBitmap = CreateDIBSction( NULL,bmpinfo,DIB_RGB_COLORS,&bCBits,NULL,0 );
rozeo さんが書きました:コード丸写ししましたがbmpが表示できません。なにが考えられるでしょうか?
変更したところはCreateDIBSctionのキャストだけです
・・・
コード丸写しってことは元のソースがあるはずですよね。そのリンクかもしくは、今のソースをはってください。
少なくともこのスレではそれが示されていません。
今のあなたは、なんでも教えてクンか察してクンと同じ印象を受けます。
オフトピック
先ほどのページってどこのことよ。
softyaさんの示した「標準 Windows API」のことでも、DIBに関するページがいくつかあるんですけど。
質問するなら、ちゃんとその情報を伝えてください。
written by へにっくす

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#23

投稿記事 by rozeo » 10年前

softyaさんのURLのDIBセクションって項目です

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ppm形式の画像

#24

投稿記事 by softya(ソフト屋) » 10年前

プログラムコードは、ちゃんと理解されていますか?
コマンドライン引数で画像を指定するようになっているコードですが、そこは自分の都合に合わせて変更なり、引数の指定なりをされていますよね?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
usao
記事: 1889
登録日時: 11年前

Re: ppm形式の画像

#25

投稿記事 by usao » 10年前

手順としては こんな感じですかね.
(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() が自環境でサポートされてなくて無念だったなぁ)

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#26

投稿記事 by rozeo » 10年前

softya(ソフト屋) さんが書きました:プログラムコードは、ちゃんと理解されていますか?
コマンドライン引数で画像を指定するようになっているコードですが、そこは自分の都合に合わせて変更なり、引数の指定なりをされていますよね?
もちろんそこはCreateFileで開くときに一つのファイル名に決めてます


usao氏のやり方で再度コードを組み直してみます。
また質問があれば質問させていただくので一旦解決とさせていただきます
最後に編集したユーザー rozeo on 2014年5月09日(金) 17:39 [ 編集 1 回目 ]

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ppm形式の画像

#27

投稿記事 by softya(ソフト屋) » 10年前

rozeo さんが書きました:
softya(ソフト屋) さんが書きました:プログラムコードは、ちゃんと理解されていますか?
コマンドライン引数で画像を指定するようになっているコードですが、そこは自分の都合に合わせて変更なり、引数の指定なりをされていますよね?
もちろんそこはCreateFileで開くときに一つのファイル名に決めてます


usao氏のやり方で再度コードを組み直してみます。
また質問があれば質問させていただくので一旦解決とさせていただきます
私の所ではキャスト(void**)で問題なく動きましたのでなにか間違いがあると思います。
VisualC++2008を使用。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#28

投稿記事 by rozeo » 10年前

帰ったらプログラムを見直してみます。

あとusao氏の手順3、ファイルから画像をロードした画素値を2-2に入れるというのはどのような処理をおこなったらいいのでしょう?

ほかのサイトを漁ってみるとvoid **でキャストしてました。しかしその変数の型がそのサイトはLPDWORD型、softyaさんに紹介してもらったサイトはBYTE型でしたがそこに問題はないのでしょうか?

アバター
usao
記事: 1889
登録日時: 11年前

Re: ppm形式の画像

#29

投稿記事 by usao » 10年前

>あとusao氏の手順3、ファイルから画像をロードした画素値を2-2に入れるというのはどのような処理をおこなったらいいのでしょう?

うーん,イメージ湧きませんかね?
CreateDIBSection() は,
例えば,あなたが「画像サイズが1000*1000で,1画素あたり24bitなんですが」という指定で使えば,
そのサイズの画素データ群を保持するために必要なメモリ領域を確保してくれて,そのメモリの場所を
((void**)がどうのといっている引数で)教えてもらえるわけです.
なので,後は,そのメモリに,あなたが表示したいイメージの画素値を書き込んであげればいいわけです.
(1000*1000画素分の画素値を,DIBのフォーマットに従って.←フォーマットについては少し調べましょう)


>ほかのサイトを漁ってみるとvoid **でキャストしてました。しかしその変数の型がそのサイトはLPDWORD型、softyaさんに紹介してもらったサイトはBYTE型でしたがそこに問題はないのでしょうか?

上記のように,この引数で返される情報は,指定した画像サイズ分の画素値群を格納するのに必要なサイズ(バイト数)のメモリ領域の「場所」
であって,その場所をどのようにアクセスしようが,それはあなたの自由です.
バイト単位でアクセスしやすいように BYTE* 型を使ってもいいし,
4バイト単位でアクセスした方がやりやすいのであれば DWORD* 型を使ったりすればいいわけです.

コード:

BYTE A[ 40 ]; //こんなバイト列があるときに…
//A[]にデータを入れるために こんなことをしても別にいいですよね
DWORD *pDW = (DWORD*)A;
pDW[2] = 0xFF801001;  //A[]のどこに何が書き込まれるのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ppm形式の画像

#30

投稿記事 by softya(ソフト屋) » 10年前

こういうRGBなど素のデータを扱うのならメモリイメージの理解は必須です。
デバッガでメモリダンプなどを眺めてみてはどうでしょう?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#31

投稿記事 by rozeo » 10年前

わかりました。ありがとうございます。
とりあえず、丸ごとコピペプログラムがなぜ動かないのか検討してみます

rozeo
記事: 86
登録日時: 10年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: ppm形式の画像

#32

投稿記事 by rozeo » 10年前

CreateDIBSection関数はうまく成功していますが、いまいちどのように画素を格納すればいいのかわかりません。

画素を格納するメモリをさす変数を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であっているでしょうか?

Mana

Re: ppm形式の画像

#33

投稿記事 by Mana » 10年前

"SetDIBitsToDevice"で過去ログ検索したらいい感じのサンプルコードが。
http://dixq.net/forum/viewtopic.php?f=3&t=14569#p115692

メモリにピクセルデータ展開してるとこをNo.10のppm読み込むのにそのまま当てはめてしまえるのでは?
1バイトずつ読み込んでもキャッシュがあればいうほど遅くないと思いますが。

rozeo_h

Re: ppm形式の画像

#34

投稿記事 by rozeo_h » 10年前

Mana さんが書きました:"SetDIBitsToDevice"で過去ログ検索したらいい感じのサンプルコードが。
http://dixq.net/forum/viewtopic.php?f=3&t=14569#p115692

メモリにピクセルデータ展開してるとこをNo.10のppm読み込むのにそのまま当てはめてしまえるのでは?
1バイトずつ読み込んでもキャッシュがあればいうほど遅くないと思いますが。
ありがとうございます。読んでみたのですが、あまりうまくわからないので、、もう少し自分で考えてみたいと思います。

とりあえず、解決にしておきます

閉鎖

“C言語何でも質問掲示板” へ戻る