openGLで画像切出し表示した際に、切出し範囲に枠線ができてしまいます

1,059 views
Skip to first unread message

kono

unread,
Dec 16, 2013, 4:40:28 AM12/16/13
to android-g...@googlegroups.com
いつも拝見させて頂いております。
konoと申します。

OpenGLでhdpi端末(800*480)を基準に
Xhdpi端末(1280*720)でも同様の表示をさせたいと思っているのですが
下記のような状態で、画像を切り出して2D表示させた所、
hdpiでは正常で、Xhdpiで切り出し範囲をかたどるように線が出て困っております。
どうか助言等を頂けないでしょうか・・・
(添付のSSが問題の表示になります)

■画面
横画面固定

■画面の描画領域
gl.glViewport(0, 0, 端末画面サイズWidth, 端末画面サイズHeight);

※hdpi端末画面サイズ  Width:800px  height:480px
※Xhdpi端末画面サイズ Width:1280px height:720px

■平行投影変換
gl.glOrthof(-1.5f, 1.5f, -1.0f, 1.0f, 0.5f, -0.5f);
(画面に対して 3:2の比率)

■描画したいint値を平行投影用に値変換 (基準サイズに対する画像比率)
int w = 描画したいwidth値
int h = 描画したいheight値
int HDPI_WIDTH = 800
int HDPI_HEIGHT = 480

描画width値 = (w / (float) HDPI_WIDTH) * 3.0f; (比率横 3)
描画height値 = (h / (float) HDPI_HEIGHT) * 2.0f; (比率縦 2)


■画像切出し計算
int cutX = 画像切出し x位置
int cutY = 画像切出し y位置
int cutW = 画像切出し width範囲
int cutH = 画像切出し height範囲
int imageWidth  = 画像サイズ width
int imageHeight = 画像サイズ height

・切出し位置
cX = (float)cutX / (float) imageWidth
cY = (float)cutY / (float) imageHeight

・切出し範囲
cW = (float)cutW / (float) imageWidth
cH = (float)cutH / (float) imageHeight


以上が画像切出しと描画の計算です。

上記計算で描画すると添付画像のようになるのですが
Xhdpi端末で切出し範囲に線が出ており
切出し範囲に隣接する部分がにじみ出ている感じがします。

切出し範囲を隣接部分から離すと発生しないようですが
対策としてもっと良い方法はございますでしょうか。

長文となり申し訳ありませんでした。
自分なりに必要そうな情報を記載したつもりですが
内容がわからないという場合はご指摘頂けると嬉しいです。

ご助力頂けるかたがいらっしゃいましたら
何卒よろしくお願いいたします。
スクリーンショット.png

kacodama

unread,
Dec 16, 2013, 7:58:04 PM12/16/13
to android-g...@googlegroups.com
画像をロードしているところはどうなっていますか?
画像はどのように用意していますか?(リソースフォルダのどこにおいていますか?)
no-dpiとかに入れるとどうでしょう?

リソース読み込みの場合、hdpi下に用意した画像であるならば、xhdpi下に適切なサイズを用意していないと、
hdpi下のものを自動的に読みに行きますが、そのときに自動的に画像サイズが変更されて読み込まれます。
なのでその時点で「拡大」がかかっているのではないでしょうか?
そのため枠線のdotが増え、切り出す範囲にかかってしまっているのではと推測します。

2013年12月16日月曜日 18時40分28秒 UTC+9 kono:

kono

unread,
Dec 17, 2013, 9:52:18 AM12/17/13
to android-g...@googlegroups.com
kacodama様

ご返信ありがとうございます!

返事が遅くなり申し訳ありません。
画像はassetsフォルダに入れて、ファイル名を指定してIDを取得
BitmapFactory.decodeStreamで読み込んでおります。
現状はXhdpiも、hdpi用の同一画像を使用しております。

assets読み込みは早くて、ファイル名指定が容易なので
使っておりますが、こちらが問題になりえるでしょうか・・・

お時間ございましたらご返答のほどよろしくお願いいたします。

2013年12月17日火曜日 9時58分04秒 UTC+9 kacodama:

kacodama

unread,
Dec 17, 2013, 11:27:38 PM12/17/13
to android-g...@googlegroups.com
asstes下に置いているのでしたら、私の書いた内容はあまり関係ないですね・・・
あとは、
・画像のサイズは2のべき乗になっていますか?
・切り出し位置、範囲を0.5単位で四捨五入するとどうなりますか?(floatをintに代入しているので切り捨てられているところが影響しているかも?hdpiとxhdpiで差異が出るのは分かりませんが)

といったあたりでしょうか・・・


2013年12月17日火曜日 23時52分18秒 UTC+9 kono:

おのk

unread,
Dec 18, 2013, 11:00:38 AM12/18/13
to android-g...@googlegroups.com
ご返答ありがとうございます!

画像サイズは2のべき乗ですので、
切出し範囲位置等の少数以下を確認して見たいと思います。


2013年12月18日 13:27 kacodama <le.s....@gmail.com>:

--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループから退会し、メールの受信を停止するには、android-group-j...@googlegroups.com にメールを送信します。
このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。

ふはじん

unread,
Dec 28, 2013, 12:31:42 PM12/28/13
to android-g...@googlegroups.com
だいぶ時間が空いてしまいました・・・
一応当記事の完了として

kacodama様より頂いたアドバイスに加えて
画像切り出しを確認して見ましたが
問題点がわかりませんでした・・・

>> ?(floatをintに代入しているので切り捨てられているところが影響しているかも?hdpiとxhdpiで差異が出るのは分かりませんが)

こちらのアドバイスも以前に自分が記載した
下記の切出し範囲の計算からきたものかと思いますが
cW cH のところは実はfloatとなっておりました、申し訳ありません!

cW = (float)cutW / (float) imageWidth
cH = (float)cutH / (float) imageHeight


ひとまず回避策として、切り出し範囲を1px狭めることで
当記事の症状がほとんどなくなるので
HDPI端末はこれで行こうと思います・・・

kacodama様、ありがとうございました!


2013年12月19日 1:00 おのk <oyadi...@gmail.com>:

Naoya Morikawa

unread,
Dec 28, 2013, 10:07:38 PM12/28/13
to android-g...@googlegroups.com
ざっと目を通しただけなので見当違いだったら申し訳ないのですが……

切り出しロジックやUV座標の指定に問題がないと仮定して、
GLUtils.texImage2D を使用してテクスチャを作成しているのであれば
乗算済みアルファによる現象かもしれません。

乗算済みアルファのテクスチャの場合、以下の設定にしないとアルファ部分が暗くなってしまいます。

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

エフェクト等の都合でブレンドを変更したくない場合は
texImage2D を使わずに自力で補間アルファのテクスチャを生成する必要があります。

Hiroaki GOTO as GORRY

unread,
Dec 29, 2013, 12:53:58 AM12/29/13
to android-g...@googlegroups.com

後藤 浩昭(GORRY)です。

全画面キャプチャを同時に取得して、「指定された座標値で実際にどこが
切り出されているか」を調査すれば、すぐ答えが出ると思いますが…。


In message <CAD1tVF9s+o9Y+2L1GZ03mCDYHZZjpkPbV7=KbvRKRp...@mail.gmail.com>
"Re: [android-group-japan: 25763] Re: openGLで画像切出し表示した際に、切出し範囲に枠線ができてしまいます"
>>>> *ご返信ありがとうございます!*
>>>>
>>>> *返事が遅くなり申し訳ありません。*
>>>> *画像はassetsフォルダに入れて、ファイル名を指定してIDを取得*
>>>> *BitmapFactory.decodeStreamで**読み込んでおります。*
>>>> *現状はXhdpiも、hdpi用の同一画像を使用しております。*
>>>>
>>>> *assets読み込みは早くて、ファイル名指定が容易なので*
>>>> *使っておりますが、こちらが問題になりえるでしょうか・・・*
>>>>
>>>>
>>>> *お時間ございましたらご返答のほどよろしくお願いいたします。 *
--
Hiroaki GOTO as "GORRY" : 後藤 浩昭
EMAIL: gorr...@gmail.com

kono

unread,
Dec 30, 2013, 2:45:11 PM12/30/13
to android-g...@googlegroups.com
Morikawa様
後藤様
 
返信が遅れ大変申し訳ございません。

助言のほどありがとうございます!
実は前回投稿時に回避策を提示してましたが
これでは完全ではなくまたも困っていたところでした・・・

頂いた助言の内容に関して確認させて頂いたところを
ご連絡させて頂きます。

■後藤様へ
>>全画面キャプチャを同時に取得して、「指定された座標値で実際にどこが
>>切り出されているか」を調査

こちらは切出し元の画像を切出さず表示して
スクリーンショットで比較といった所でしょうか。
確認したところでは切出し位置などは問題なさそうです。
実際の表示を添付いたしますのでお時間宜しければご確認頂けますと幸いです。
[Goto.png]

■Morikawa様へ
>>GLUtils.texImage2D を使用してテクスチャを作成しているのであれば
>>乗算済みアルファによる現象かもしれません。
>>乗算済みアルファのテクスチャの場合、以下の設定にしないとアルファ部分が暗くなってしまいます。
>>glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
>>エフェクト等の都合でブレンドを変更したくない場合は
>>texImage2D を使わずに自力で補間アルファのテクスチャを生成する必要があります。

こちら、仰る通り現状下記設定で描画しており
当症状のようなアルファ部分(アンチエイリアス?)が暗くなってました。
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

ご提示頂いた下記設定では
確かに暗かった箇所がなくなり、普通に透過されておりました。
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

しかしながらこちらの設定は
アルファ変更して画像を重ねると明るくなってしまうのですね・・・

その回避方法として、上記設定はせず
texImage2D を使わずに自力で補間アルファのテクスチャを生成する
ということをするとアルファを暗くせず、アルファ変更で透過できるでしょうか。
添付画像にてこちらが行いたいことを示して見ましたので
お時間宜しければ確認いただき、ご教授頂けませんでしょうか。
   [Morikawa.png]

 
Goto.png
Morikawa.png

Naoya Morikawa

unread,
Dec 30, 2013, 10:02:57 PM12/30/13
to android-g...@googlegroups.com
ブレンド設定を変更して現象が回避されたのであれば
乗算済みアルファによる現象だと見て良いかと思います。

補間アルファでテクスチャを生成すれば、
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA でも綺麗に表示され
他の画像と重ねても加算合成されることはありません。

補間アルファでテクスチャを生成するには
ビットマップ画像を RGBA 形式でバッファに溜め込み
GL10 クラスの glTexImage2D を使用して生成します。

ざっとで申し訳ありませんが、例えば下記のような感じです。

int[] src = new int[textureWidth * textureHeight];
bitmap.getPixels(src, 0, textureWidth, 0, 0, textureWidth, textureHeight);
byte[] dest = new byte[src.length * 4];
for (int i = 0; i < bitmapHeight; i++)
  for (int j = 0; j < bitmapWidth; j++) {
    dest[(i * textureWidth + j) * 4]     = (byte)((src[i * textureWidth + j] >> 16) & 0xff); //赤要素
    dest[(i * textureWidth + j) * 4 + 1] = (byte)((src[i * textureWidth + j] >> 8) & 0xff);  //緑要素
    dest[(i * textureWidth + j) * 4 + 2] = (byte)(src[i * textureWidth + j] & 0xff);         //青要素
    dest[(i * textureWidth + j) * 4 + 3] = (byte)(src[i * textureWidth + j] >> 24);          //アルファ要素
  }
ByteBuffer buffer = ByteBuffer.wrap(dest);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, textureWidth, textureHeight, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, buffer);

GLUtils.texImage2D は乗算済みアルファのテクスチャを作成するメソッドなので
用途に応じて glTexImage2D と使い分けてください。

また、Java 実装だとテクスチャ変換する画像が多い場合に時間が掛かりますので
必要に応じてネイティブ化した方が良いかと思います。

それでは皆様、良いお年を。

Hiroaki GOTO as GORRY

unread,
Dec 31, 2013, 12:54:45 AM12/31/13
to android-g...@googlegroups.com

後藤 浩昭(GORRY)です。

>>> ■後藤様へ
>>
>> >>全画面キャプチャを同時に取得して、「指定された座標値で実際にどこが
>>
>> >>切り出されているか」を調査
>>
>>
>>> こちらは切出し元の画像を切出さず表示して
>>
>> スクリーンショットで比較といった所でしょうか。
>>
>> 確認したところでは切出し位置などは問題なさそうです。
>>
>> 実際の表示を添付いたしますのでお時間宜しければご確認頂けますと幸いです。

当方が確認するまでもなく、この画像を作る過程で「実機にどのように
表示され、キャプチャされ、切り出されたか」をご自身で理解されて
いるでしょうから、それで十分ではないかと。

おのk

unread,
Dec 31, 2013, 2:52:02 PM12/31/13
to android-g...@googlegroups.com
Morikawa様
後藤様

ご返信ありがとうございます。

>後藤様
自分自身切出しに不安がありましたので念の為に
確認までさせて頂きました。
現状アルファブレンドに問題ありのようなので切出しに問題なさそうです。
ご確認ありがとうございました。

>Morikawa様
ご丁寧に計算式をご教授頂き誠にありがとうございます。
知識不足な自分ではこの計算を頂けていなかったらどれだけ苦労していたか・・・
本当に助かります!
しかしながら、この計算式でテクスチャ作成をしても
表示できませんでした・・・(白四角形で表示される)
下記のような流れで画像を読み込んでいるのですが
足りない処理や誤りがありますでしょうか。

お時間ございましたら
何卒ご確認頂けませんでしょうか。
宜しくお願いいたします。

//------------画像を読み込む------------
Bitmap bmp = null;
try {
 InputStream is = context.getResources().getAssets().open(imageName);
 bmp = BitmapFactory.decodeStream(is);
} catch (IOException e) {
  /* 例外処理 */
}

//------------テクスチャID割り当て用変数用意------------
int[] textures = new int[3];
textures[1] = bmp.getWidth();
textures[2] = bmp.getHeight();

//------------テクスチャID割り当て等------------
//テクスチャIDを割り当てる
gl.glGenTextures(1, textures, 0);
//テクスチャIDのバインド
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//OpenGL ES用のメモリ領域に画像データを渡す。上でバインドされたテクスチャIDと結び付けられる。
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);

//------------画像サイズ決め (画像全体サイズ 2べき乗)------------
int textureWidth = bmp.getWidth();
int textureHeight = bmp.getHeight();
int bitmapWidth = bmp.getWidth();
int bitmapHeight = bmp.getHeight();

//------------補間アルファ計算------------
int[] src = new int[textureWidth * textureHeight];
bmp.getPixels(src, 0, textureWidth, 0, 0, textureWidth, textureHeight);
byte[] dest = new byte[src.length * 4];
for (int i = 0; i < bitmapHeight; i++)
 for (int j = 0; j < bitmapWidth; j++) {
  dest[(i * textureWidth + j) * 4]     = (byte)((src[i * textureWidth + j] >> 16) & 0xff); //赤要素
  dest[(i * textureWidth + j) * 4 + 1] = (byte)((src[i * textureWidth + j] >> 8) & 0xff);  //緑要素
  dest[(i * textureWidth + j) * 4 + 2] = (byte)(src[i * textureWidth + j] & 0xff);         //青要素
  dest[(i * textureWidth + j) * 4 + 3] = (byte)(src[i * textureWidth + j] >> 24);          //アルファ要素
 }
ByteBuffer buffer = ByteBuffer.wrap(dest);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, textureWidth, textureHeight, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, buffer);

bmp.recycle();


2013年12月31日 14:54 Hiroaki GOTO as GORRY <gorr...@gmail.com>:

Naoya Morikawa

unread,
Dec 31, 2013, 11:28:34 PM12/31/13
to android-g...@googlegroups.com
皆様、明けましておめでとうございます。
本年もよろしくお願い致します。

コードの方を拝見させて頂きましたが
テクスチャの初期化について、誤って理解されているように感じます。

それぞれのメソッドやパラメータの意味を調べ
glTexParameterf や glTexEnvf なども合わせて確認してみてください。

また、当方が挙げたコードは GLUtils.texImage2D に代わるものですので
別途 GLUtils.texImage2D を呼ぶ必要はありません。

挙げさせて頂いたコードも一応動作するとは思いますが
丸コピーではなくご自分で理解した上でカスタマイズして頂けたらと思います。

kono

unread,
Jan 1, 2014, 1:17:26 AM1/1/14
to android-g...@googlegroups.com
Morikawa様

ご確認のほど誠に、ありがとうございます。

自身の勉強不足でお手数をお掛けし申し訳ございませんでした・・・
ご指摘頂いた内容に関しましては、これから確認させて頂きたいと思います!
また、結果報告をさせて頂くかも知れませんが
改めて、この度はありがとうございました。

今回の問題をしっかり解決できるようがんばってみたいと思います!


Reply all
Reply to author
Forward
0 new messages