0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UWSCで作業を効率化しよう【画像の中心座標取得編】

Posted at

UWSCでは画像のサイズなど画像に関する情報を取得する関数がないため自分で作成しようと思います。

とりあえず今回は、画像の中心座標を計算してマウスを移動させて見ようと思います!

UWSCで扱える画像のフォーマットについて

UWSCでは「ビットマップ形式」で画像を扱うことができます。
拡張子は「bmp」

ビットマップファイルの構造

ビットマップファイルは先頭から

  1. ファイルヘッダ
  2. 情報ヘッダ
  3. カラーマスク
  4. カラーパレット
  5. ビットマップデータ
  6. カラープロファイル

の順で構成されています。
画像サイズとかは「情報ヘッダ」に格納されているのでそこから取得していきたいと思います!

情報ヘッダの構成

wikipediaより引用

オフセット サイズ 格納する情報 値・備考
0x000e 4バイト ヘッダサイズ 40
0x0012 4バイト ビットマップの横幅 単位はピクセル
0x0016 4バイト ビットマップの縦幅 単位はピクセル。値が負の場合はトップダウン画像となる
0x001a 2バイト プレーン数 常に1
0x001c 2バイト 1ピクセルあたりのビット数 0,1,4,8,16,24,32
0x001e 4バイト 圧縮形式 0,1,2,3,4,5 ※1
0x0022 4バイト 画像データサイズ 単位はバイト
0x0026 4バイト 水平方向の解像度 単位はピクセル/m
0x002a 4バイト 垂直方向の解像度 単位はピクセル/m
0x002e 4バイト 使用する色数 ビットマップで実際に使用するカラーパレット内のカラーインデックスの数。
0x0032 4バイト 重要な色数 ビットマップを表示するために必要なカラーインデックスの数。

ちなみにここで言うオフセットというのは16進数で表された先頭から数えたバイト数のことです。
例えば、ヘッダサイズの「0x000e」なら先頭から15バイト目ということになります!

実際に覗いてみる!

今回はこの画像について扱っていきたいと思います!
image.png

画像のサイズは「400×400」となっております。

まずは、バイナリエディタで画像を開いてほんとに情報があるか見てみます!
image.png

つまり、前半の26byteさえ取得できれば画像のサイズは取得できるのです!!!!

画像から「え?400なんてね~よ!!」と怒る人もいると思います?
ちょっと待ってください!なぜ400じゃないのか!?
なぜなら、これが16進数で表されているからです!

ちなみに、「90 01」と書かれていますが左から1桁であらわされているので実際は「01 90」を10進数に直して普段扱っている数字に直してあげます。
16進数から→10進数の計算方法は右から「16^(桁数-1)×数字」をそれぞれ計算して最後に全部足し合わせたものになります。
なので、この場合は「0190」で先頭の0は計算しても0なので「190」を計算します。右から
「16^(1-1) * 0」=「1×0」=0
「16^(2-1) * 9」=「16×9」=144
「16^(3-1) * 1」=「256×1」=256
となり、全部足すと「0+144+256 = 400」となりしっかりとサイズを確認できてると思います!

ちなみに、Windows10標準の電卓をプログラマーモードにして「Hex」の所に計算したい16進数の値を入れても計算することができます!
image.png

UWSCで実現するには?

まずは、どの画像を読み込むか教えるための画像のパスを用意します。
例えば、Cドライブ直下の「野獣先輩.bmp」という画像を読み込むなら

UWSCで実現するには?

まずは、どの画像を読み込むか教えるための画像のパスを用意します。
例えば、Cドライブ直下の「野獣先輩.bmp」という画像を読み込むなら

ImageFilePath = "C:/野獣先輩.bmp"

これで、「ImageFilePath」に画像までのパスが入りました!

画像のサイズを大きさを保存する配列を作成します。

Dim WHSize[1]

次に画像をバイナリ形式で扱えるCOMオブジェクトを用意します。

stream = CreateOleObj("ADODB.Stream")

これで、バイナリデータを扱ってくれる「stream」が準備できました!!

次に、実際に読み込んでもらうためにstreamを開いてあげましょう。

stream.Open()

これで、streamがいつでもデータを受け入れるようになりました!!

次に、デフォルトではテキストファイルとして読み込んでしまうのでしっかりとバイナリデータを扱うようにstreamに教えてあげましょう。

stream.Type = 1

ちなみに、1が「バイナリデータ」で2が「テキストデータ」として明示的に指定することができます。
これでstreamがファイルをバイナリデータとして扱えるようになりました!!

では、実際にstreamを使って画像をバイナリデータとして読み込んでみましょう!

stream.LoadFromFile(ImageFilePath)

これでエラーが出なければstreamに画像のバイナリデータが読み込まれているはずです!!

次に、読み込まれたバイナリデータを先頭から26byte取得しましょう!!

ImagePartBinary = stream.Read(26)

これでエラーが出なければstreamから先頭分のバイナリデータがImagePartBinaryに入ったはずです!!

もう、データを開き終わったのでstreamは閉じてあげましょう。

stream.Close()

ImagePartBinaryには嬉しいことにもともと16進数が10進数に変換されて1byteずつ配列に保存されています!!
今回ほしいのは、画像の中心の座標なので19バイト目から計算すればいいことになります。
なので19バイト目から26バイト目までをFor文を利用して横幅と縦幅を計算していこうと思います!!
計算を楽にするために計算を2バイトしか計算しない前提で処理を書いていきます。言い訳としては
超高精細映像の8Kでも8192×4320で
また、16Kの16384×8640でも
2バイトで表現できる65535×65535で十分足りるためですw
(64K以上だとちゃんと処理を書く必要がありますが)

// 配列の添え字は0から始まるため要素の19番目にアクセスするには
// ImagePartBinary[18]と書く
// Power(a, b)  aのb乗を返す
for i=18 to length(ImagePartBinary)-1
// 横幅の計算
if (i<22) then WHSize[0] = WHSize[0] + ImagePartBinary[i]*Power(256, i-18)
// 縦幅を計算
if (i>21) then WHSize[1] = WHSize[1] + ImagePartBinary[i]*Power(256, i-22)
next

1回目のループではPower(256, 0)となり配列の要素に影響はないのですが、
2回目のループではPower(256, 1)となり配列の要素に256をかけることで16進数の2桁目の処理を行います。

使いやすくするために関数にしましょう!

上の処理だと、毎度毎度この処理を書くのは面倒なのでパス名を引数にとって大きさを配列で返す関数を作成しましょう!
解説はソースコードのコメントに書きます。

// ImageFilePath:画像のパス
// 戻り値:WHSize[] (画像の横幅、縦幅の配列)
function bmpWH(ImageFilePath)

  // 画像のサイズを格納する配列
  Dim WHSize[1]

  // 画像をバイナリ形式で扱えるCOMオブジェクトを用意
  stream = CreateOleObj("ADODB.Stream")
  
  // 実際に読み込んでもらうためにstreamを開く
  stream.Open()
  
  // バイナリデータを扱うようにstreamのプロパティを設定
  stream.Type = 1  // 1:バイナリデータ  2:テキストデータ
  
  // streamを使って画像をバイナリデータとして読み込む
  stream.LoadFromFile(ImageFilePath)
  
  // 読み込まれたバイナリデータを先頭から26byte取得
  ImagePartBinary = stream.Read(26)
  
  // streamは閉じる
  stream.Close()

  // 配列から画像のサイズを計算
  // 配列の添え字は0から始まるため要素の19番目にアクセスするには
  // ImagePartBinary[18]と書く
  // Power(a, b)  aのb乗を返す
  for i=18 to length(ImagePartBinary)-1  
    // 横幅の計算
    if (i<22) then WHSize[0] = WHSize[0] + ImagePartBinary[i]*Power(256, i-18)
    // 縦幅を計算
    if (i>21) then WHSize[1] = WHSize[1] + ImagePartBinary[i]*Power(256, i-22)
  next
  
  // 計算が終わったのでサイズが格納された配列を返す
  result = slice(WHSize, 0, length(WHSize)-1)
fend

実際に作った関数を利用して画像の中心にマウスを移動させよう!!

// Cドライブ直下の「野獣先輩.bmp」という画像を読み込むなら
ImageFilePath = "C:/野獣先輩.bmp" 

// 画像サイズを取得する変数を用意
i_width = 0
i_height = 0
tmp = NULL

// 画像が見つかれば
ifb chkimg(ImageFilePath)
  print "いいカラダしてんねぇ!"
  // 画像のサイズを取得
  tmp = bmpWH(ImageFilePath)
  // 取得したサイズから画像の座標を計算
  i_width = tmp[0]/2
  i_height = tmp[1]/2
  // 中心にマウスを移動させる
  mmv(G_IMG_X+i_width, G_IMG_Y+i_height)
else
  print "田舎少年はスケベなことしか考えないのか……"
endif

これで画像の中心座標を無事計算することができました!!

お疲れ様でした!!

ソースコード全文

// Cドライブ直下の「野獣先輩.bmp」という画像を読み込むなら
ImageFilePath = "野獣先輩.bmp"

// 画像サイズを取得する変数を用意
i_width = 0
i_height = 0
tmp = NULL

// 画像が見つかれば
ifb chkimg(ImageFilePath)
	print "いいカラダしてんねぇ!"
	// 画像のサイズを取得
	tmp = bmpWH(ImageFilePath)
	// 取得したサイズから画像の座標を計算
	i_width = tmp[0]/2
	i_height = tmp[1]/2
	// 中心にマウスを移動させる
	mmv(G_IMG_X+i_width, G_IMG_Y+i_height)
else
	print "田舎少年はスケベなことしか考えないのか……"
endif


// ImageFilePath:画像のパス
// 戻り値:WHSize[] (画像の横幅、縦幅の配列)
function bmpWH(ImageFilePath)

	// 画像のサイズを格納する配列
	Dim WHSize[1]

	// 画像をバイナリ形式で扱えるCOMオブジェクトを用意
	stream = CreateOleObj("ADODB.Stream")

	// 実際に読み込んでもらうためにstreamを開く
	stream.Open()

	// バイナリデータを扱うようにstreamのプロパティを設定
	stream.Type = 1  // 1:バイナリデータ  2:テキストデータ

	// streamを使って画像をバイナリデータとして読み込む
	stream.LoadFromFile(ImageFilePath)

	// 読み込まれたバイナリデータを先頭から26byte取得
	ImagePartBinary = stream.Read(26)

	// streamは閉じる
	stream.Close()

	// 配列から画像のサイズを計算
	// 配列の添え字は0から始まるため要素の19番目にアクセスするには
	// ImagePartBinary[18]と書く
	// Power(a, b)  aのb乗を返す
	for i=18 to length(ImagePartBinary)-1
		// 横幅の計算
		if (i<22) then WHSize[0] = WHSize[0] + ImagePartBinary[i]*Power(256, i-18)
		// 縦幅を計算
		if (i>21) then WHSize[1] = WHSize[1] + ImagePartBinary[i]*Power(256, i-22)
	next

	// 計算が終わったのでサイズが格納された配列を返す
	result = slice(WHSize, 0, length(WHSize)-1)
fend
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?