HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2018
0831
vram使用の画像処理高速化について14解決


リンク

2018/8/31(Fri) 22:16:31|NO.85255

個人的な興味からある種の画像処理ソフトを作っております。
いろいろ工夫してみましたが速度面の課題があります。
必要な部分だけ抽出したソースを作ってみました、適当な画像を選択すると点滅します。
うちの環境だと大きな画像(縦横1000ピクセル)で1秒程度変換時間がかかるのですが
これを劇的に早くする方法は無いでしょうか?
ルーチン内のpokeが3行あるのとか計算式は必要なものなので削れません。

screen 0,80,80 matrix=0,128,32,160,176,64,224,96,48,192,16,144,240,112,208,80 buffer 10 dialog "*",16,"画像" filename1=refstr gsel 10:picload filename1 picX=ginfo(26):picY=ginfo(27) screen 9,picX,picY buffer 1,picX,picY/2 xsize=ginfo_winx:ysize=ginfo_winy mref vram1,66 buffer 2,picX,picY/2 mref vram2,66 gsel 1 gzoom picX,picY,10,0,0,picX,picY*2 vwidth=((xsize*3)+3)&0xFFFFFFFC repeat b=cnt repeat ysize //変換描画コピールーチン index_h=cnt*vwidth yy=cnt repeat xsize index=cnt*3+index_h a=yy\4*4+cnt\4 poke vram2,index+2,(peek(vram1,index+2)>matrix(a))*255*(b\2) poke vram2,index+1,(peek(vram1,index+1)>matrix(a))*255*(b\2) poke vram2,index,(peek(vram1,index)>matrix(a))*255*(b\2) loop loop //描画ここまで gsel 9 gzoom picX,picY,2,0,0,xsize,ysize,0 redraw 1 await 0 loop



この記事に返信する


Velgail

リンク

2018/8/31(Fri) 22:39:53|NO.85258

ちらつかせることが目的ではないですよね? ベンチマークですよね?

次のコードでベンチマーク(結果はタイトルバーにms単位で表示)を取って、その速度をどれだけ上げられるか を競えばいいんですよね?

#include "d3m.hsp" screen 0,80,80 matrix=0,128,32,160,176,64,224,96,48,192,16,144,240,112,208,80 buffer 10 dialog "*",16,"画像" filename1=refstr gsel 10:picload filename1 picX=ginfo(26):picY=ginfo(27) screen 9,picX,picY buffer 1,picX,picY/2 xsize=ginfo_winx:ysize=ginfo_winy mref vram1,66 buffer 2,picX,picY/2 mref vram2,66 gsel 1 gzoom picX,picY,10,0,0,picX,picY*2 vwidth=((xsize*3)+3)&0xFFFFFFFC b=1 start=d3timer() repeat ysize //変換描画コピールーチン index_h=cnt*vwidth yy=cnt repeat xsize index=cnt*3+index_h a=yy\4*4+cnt\4 poke vram2,index+2,(peek(vram1,index+2)>matrix(a))*255*(b\2) poke vram2,index+1,(peek(vram1,index+1)>matrix(a))*255*(b\2) poke vram2,index,(peek(vram1,index)>matrix(a))*255*(b\2) loop loop //描画ここまで gsel 9 gzoom picX,picY,2,0,0,xsize,ysize,0 redraw 1 await 0 title strf("%dms",d3timer()-start)
ちなみに、当方Full HDの画像で760msかかっています。ここから結果を同じに詰めることにしましょう。



リンク

2018/8/31(Fri) 22:47:42|NO.85259

ベンチマークですね。点滅目的ではないので(b\2)は無くても良いです。
vram1のRGB値をmatrix値と比較して大きければ255小さければ0としてvram2にコピーします。
実際にはmatrixR,G,Bが存在しています。



ZAP

リンク

2018/8/31(Fri) 23:25:08|NO.85260

pokeをlpokeにして、3バイト分を4バイトデータとして一気に書き込むのでは駄目ですか?
4バイトデータを、インデックスを3バイトずつずらして書き込むため、
一番最後のデータを書き込む際にバッファオーバーランが出ます。
これを防止するためにバッファ2を1行余分に確保しています。


#include "d3m.hsp" screen 0,80,80 matrix=0,128,32,160,176,64,224,96,48,192,16,144,240,112,208,80 buffer 10 dialog "*",16,"画像" filename1=refstr gsel 10:picload filename1 picX=ginfo(26):picY=ginfo(27) screen 9,picX,picY buffer 1,picX,picY/2 xsize=ginfo_winx:ysize=ginfo_winy mref vram1,66 buffer 2,picX,picY/2+1 ;変換描画ルーチンで4バイト単位で書き込むため、冗長部分を確保 mref vram2,66 gsel 1 gzoom picX,picY,10,0,0,picX,picY*2 vwidth=((xsize*3)+3)&0xFFFFFFFC b=1 start=d3timer() repeat ysize //変換描画コピールーチン index_h=cnt*vwidth yy=cnt repeat xsize index=cnt*3+index_h a=yy\4*4+cnt\4 ;RGBの3バイトの情報をまとめて4バイトデータとして書き込む lpoke vram2,index,(peek(vram1,index)>matrix(a))*255+(peek(vram1,index+1)>matrix(a))*$ff00+(peek(vram1,index+2)>matrix(a))*$ff0000 loop loop //描画ここまで gsel 9 gzoom picX,picY,2,0,1,xsize,ysize,0 ;冗長部分として確保した1行目を除外してコピー redraw 1 await 0 title strf("%dms",d3timer()-start)



リンク

2018/8/31(Fri) 23:42:18|NO.85261

早速の改良ありがとうございます、11%ぐらい高速になりましたね。
メモリを多く使っても、とにかく速さが正義の認識でお願いします。
画像サイズは一応可変を許可しない予定です。



Velgail

リンク

2018/8/31(Fri) 23:50:22|NO.85262

スーパー黒魔術を駆使して「多分」正しく動いてるコード。

#include "d3m.hsp" screen 0,80,80 matrix=0,128,32,160,176,64,224,96,48,192,16,144,240,112,208,80 buffer 10 dialog "*",16,"画像" filename1=refstr gsel 10:picload filename1 picX=ginfo(26):picY=ginfo(27) screen 9,picX,picY screen 1,picX,picY/2 xsize=ginfo_winx:ysize=ginfo_winy mref vram1,66 buffer 2,picX,picY/2 mref vram2,66 gsel 1 gzoom picX,picY/2,10,0,0,picX,picY b=1 start=d3timer() buffer 3,4,4 mref vram3,66 for y,0,4 for x,0,4 repeat 3 poke vram3,cnt+x*3+y*12,limit(matrix(x+y*4)+1,0,255)//なぜ1を足さねばならないか理解してない。あかん。 loop next next redraw 1 buffer 4,picX,picY/2 pos 0,ysize-4 gcopy 3,0,0,4,4 box=4 repeat pos box,ysize-4 gcopy 4,0,ysize-4,box,4 box*=2 if box>picX:break loop box=4 repeat pos 0,ysize-box*2 gcopy 4,0,ysize-box,picX,box box*=2 if box>ysize:break loop //ここまでで全体フィルターを生成 redraw 1 gmode 6,,,256 pos 0,0 gcopy 1,0,0,xsize,ysize//減算することで値が1以上残るピクセルをはじき出す gmode 5,,,256 repeat 8 gcopy 4,0,0,xsize,ysize//同値加算8回で0か255の2値化が可能 loop gsel 2 gmode 6,,,256 gcopy 4,0,0,xsize,ysize//実は反転絵を作ってたのでここで反転し規定のグラフィックを生成する gsel 9 gzoom picX,picY,2,0,0,xsize,ysize,0 redraw 1 await 0 title strf("%dms",d3timer()-start)

黒魔術過ぎて作者もちょっと手におえてない"+1"とかあるけど、速度は 750ms→40msとかいう異次元の速度になった。



MillkeyStars

リンク

2018/8/31(Fri) 23:51:21|NO.85263

repeat ysize 側で計算が完結するものは、ysize 側でやった方が計算量を抑えられると思うよ。
a = yy\4*4+cnt\4
など。



ZAP

リンク

2018/9/1(Sat) 02:25:11|NO.85265

黒魔術の前には無意味かもしれませんが、
一応、先ほどの自分の投稿のスクリプトのループ内を極力高速化してみました。


#include "d3m.hsp" screen 0,80,80 matrix=0,128,32,160,176,64,224,96,48,192,16,144,240,112,208,80 buffer 10 dialog "*",16,"画像" filename1=refstr gsel 10:picload filename1 picX=ginfo(26):picY=ginfo(27) screen 9,picX,picY buffer 1,picX,picY/2 xsize=ginfo_winx:ysize=ginfo_winy mref vram1,66 buffer 2,picX,picY/2+1 ;変換描画ルーチンで4バイト単位で書き込むため、冗長部分を確保 mref vram2,66 gsel 1 gzoom picX,picY,10,0,0,picX,picY*2 vwidth=((xsize*3)+3)&0xFFFFFFFC start=d3timer() repeat ysize //変換描画コピールーチン index=cnt*vwidth yy=cnt\4*4 repeat xsize a=matrix(yy+cnt\4) ;RGBの3バイトの情報をまとめて4バイトデータとして書き込む lpoke vram2,index,(peek(vram1,index)>a)*$ff+(peek(vram1,index+1)>a)*$ff00+(peek(vram1,index+2)>a)*$ff0000 index+=3 loop loop //描画ここまで gsel 9 gzoom picX,picY,2,0,1,xsize,ysize,0 ;冗長部分として確保した1行目を除外してコピー redraw 1 await 0 title strf("%dms",d3timer()-start)

多少は速くなりましたが、やはりアルゴリズムそのものを見直すのには敵いませんね。



ソラ

リンク

2018/9/1(Sat) 16:23:15|NO.85267

ただの感想でごめんなさい。
でも言いたいんです。

みんな凄い。



リンク

2018/9/1(Sat) 22:01:51|NO.85268

ご意見改善案等ありがとうございました。
Velgariさんの黒魔術があまりに魔術過ぎて狂ったような速度が出ています。
多分今回の目的に特化した専用コードのようなので応用に悩みまして
組み込みに手間取ってしまいましたが、なんとか
RGB値とフィルター値のリアルタイム変更に追従できるようになりました。

http://fast-uploader.com/file/7091362450097/

ところで後出しで仕様を追加するようで申し訳ないのですが、実は
jpg等のブロックノイズを抑えるためbuffer1(vram1)の画像から
変換コピーする際に簡易減色をしていたのです。自分のソースでいうと
poke vram2,index+2,(peek(vram1,index+2)/BUNAKI*BUNKAI>matrix(a))*255
のように。
この部分を魔術コードで書き加える事は可能でしょうか?
buffer1をgmodeとgcopyの組み合わせで減色する方法がお手上げです。
可能であればご教示いただければ幸いです。



Velgail

リンク

2018/9/1(Sat) 22:42:29|NO.85269

peek(vram1,index+2)/BUNAKI*BUNKAI
→このまま最適化するとpeek(vram1,index+2)になる(実は変数名が違うとかそういうことがなければ)

で、除算はないんだよなぁ。透過率という形なら書ける(gmode3)

ということで、
gmode 3,0,0,256/(BUNKAI*BUNKAI)を仕込んで元絵を「黒cls画面(cls 4)」上にgcopyすると、擬似的に(あくまで近似値)できるはず。



法貴優雅

リンク

2018/9/2(Sun) 19:04:17|NO.85282

空気を読まずにコメントしますが
体験談として、画像処理させるDLLをCやC++で作って
HSPで使用するのが、一番処理が早いです。



リンク

2018/9/2(Sun) 19:24:52|NO.85283

>このまま最適化すると
HSPでは幸か不幸か最適化されないので自分はよく使っています。

a=15 b=a/16*16 mes b stop

減色はまあこんな感じで使用目的に足りました。

#define BUN 5 //簡易減色 BUNは1〜7 buffer 10 dialog "*",16,"画像" filename1=refstr gsel 10:picload filename1 picX=ginfo(26):picY=ginfo(27) screen 0,picX,picY title"元" gcopy 10,0,0,picX,picY screen 1,picX,picY:color:boxf title"減色" tmp_i=powf(2,BUN) gmode 5,0,0,128/tmp_i+1 repeat 2*tmp_i gcopy 10,0,0,picX,picY loop redraw 1 stop

>画像処理させるDLLをCやC++で作って
まあそうでしょうね。C使いやプロの方はそうすべきと思います。
今回はHSPのみで期待以上の速度が出たので満足です。



リンク

2018/9/2(Sun) 19:30:45|NO.85284

ひとまず解決とさせていただきます。いろいろありがとうございました。
ところで、思いのほか楽しい変換ソフトになったので、
高速減色についてはほぼVelgail様(スペル間違っていて失礼しました)
作成ソースなのですが、コンテストに出してみても良いでしょうか?



Velgail

リンク

2018/9/2(Sun) 22:04:39|NO.85286

私のソースは「Boost Software License - Version 1.0 - August 17th, 2003」として提供しますよ。

あ、面倒だな……って思ったかもしれないけど、利用要件は簡単。
ソースで利用した区間について、以下のライセンスが適用されていますと「ソースのコメントで」記載すれば良いのです。
他ドキュメントには一切書かなくてOK。コメントだからコンパイルすると消えるけど、「ソースコードにさえ著作権表示が残っていればよい」ということです。

ということで、以下のコード(というかコメント)をコピーしたコードの適当な場所に貼っておいてください。
そしたら、あとはどんなライセンスで(商用だろうと)提供しても構いませんよ。


/* Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */



ONION software Copyright 1997-2021(c) All rights reserved.