『Visual Basic 6.0』を使って動画処理をしています。カメラで撮った画像を画像処理ボードを通して配列に入れ、その配列を処理(物体の重心を求める)してPictureに映し出しているのですが、プログラム実行中に物体を移動させるとフリーズしてしまいます。クリックしても反応が全くありません。どうしたらフリーズさせずにプログラムを実行させることができるのでしょうか?いいアドバイスがあれば、ぜひ教えてください。お願いします。
画像処理ボードから取得した配列の値は更新したはいけないとか?
処理用の配列を準備してコピーして処理しては?
処理ボードから所得した配列の値を変えても問題ありません。例えば、所得した配列の値を使って画面の一部を赤くしてもフリーズせずにプログラムが実行されます。
フリーズしないのならいいのでは?
解決?
物体の重心を求めるために色の抽出処理をしているのですが、1つの物体なら簡単に求められます。しかし、2つ以上の物体の重心を求めようとすると各画素のモーメントによって求めているため、求めることができません。そこで、ラベリングして物体の重心を求めようとしているのですが、そのプログラムを入れて実行するとフリーズしてしまいます。どうすればいいのでしょうか?
全く物理用語がわかりませんが、
感じからして、
2つ以上にすると計算量が増加すると思うので
do loop や for next 構文などループ処理に
doevents処理が適切に行われていますか?
ただ単に計算量が増えたため反応が帰ってきてないので
フリーズしたように見えているだけでは?
ヤマ@文系様の言われる通りdoevent処理を入れる事で
反応が返ってくるようになる気がします。
もちろん計算が終わるまでPictureは更新されないでしょうが。
一回ごとにdoeventsをしていると処理速度が劇的に低下するので、
何回か一回にdoeventsを実行するようにしておけばいいです。
gettickcountなどで mod 500 =0 のときdoevents
や
計算に使ってる変数がmod いくつのときとかがよろしいかと思います。
プログラムとしてはdo loop構文になっていています。その内容としては、まずキャプチャーを取得する命令が出され、そのキャプチャーが一端配列に入ります。その配列を使って画像処理(配列に入っている画素の色情報を使って物体を認識させる)を行います。その後、その所得した配列がPictureに映し出されます。その繰返しです。処理が終わらないと次のキャプチャーを取得する命令が出ないように戻り値を使っています。ラベリングのプログラムを入れて実行する場合、物体を移動させなければフリーズしないのですが、物体を移動させるとフリーズしてしまいます。
問題の切り分けが出来ていないものと思われます。
コードを1行も出さないで、
憶測と空論でスレッドを伸ばしても無駄が多いでしょう。
・PCのスペックの問題(メモリが足りない等)
・キャプチャ部分のハードウェア仕様
・画像処理ボードのハードウェア仕様
・コードのバグ(キャプチャとラベリングの2本ですか?他にもありますか?)
・(複数プログラムなら)プログラム間でのリソースのデッドロック
・その他
などいろいろ考えられるので、ひとつづつ見ていく必要があるのでは?
この板で扱うべきVBに関連する部分に絞りましょう...
(質問1)
物体を 移動させる/移動させない で、
どこにどのような変化点(違い)が生じますか?(データ、ロジック...)
(質問2)
フリーズする と仰いますが、
実際には、コードのどこの部分まで実行されて、
どこでで止まっているか確認しましたか?
お詫び
質問内容がわかりにくく大変ご迷惑をかけて本当にすみません。プログラム初心者で、こういった掲示板の利用が初めてなので過去ログを参考にして質問してみたのですが、なかなかどうやって質問していいのかわかりませんでした。今後、気をつけたいと思います。
もげさんへ
(質問1)
物体を 移動させる/移動させない で、
どこにどのような変化点(違い)が生じますか?(データ、ロジック...)
(回答1)
取得した画像の配列の値が変わるだけです。
(質問2)
フリーズする と仰いますが、
実際には、コードのどこの部分まで実行されて、
どこでで止まっているか確認しましたか?
(回答2)
確認しようとデバックを行い1文ずつ試みましたが、条件文(if)の内容に当てはまらなかったため、あまり意味がありませんでした。
何か他にいい方法があるのでしょうか?
下記の内容はdo loop構文内のラベリングのプログラムです。この場合だとフリーズせずに実行できるのですが、処理数が多いために1秒間あたりのキャプチャー数が少なくなってしまいます。また、タイムラグが発生してしまいます。そのため、目標は実時間に近いかたちなのですが‥‥。
何かいい方法があれば教えてください。お願いします!
<プログラム>
For i = 1 To FrameSize - 1 Step 3
X_coord = Int((i Mod 1920) / 3)
Y_coord = Int(i / 1920)
If X_coord = 0 Or X_coord = 640 Or Y_coord = 0 Or Y_coord = 480 Then
lab(X_coord, Y_coord) = 0
Else
If dot(X_coord, Y_coord) = 1 Then
If lab(X_coord, Y_coord) = 0 Then
If dot(X_coord - 1, Y_coord) = 0 Then
code = 7
label = label + 1
Call LabelingBorder(X_coord, Y_coord, code, label, dot, lab)
ElseIf dot(X_coord + 1, Y_coord) = 0 Then
code = 3
For k = X_coord + 1 To 640 - 2
If lab(k, Y_coord) >= 1 Then
label0 = lab(k, Y_coord)
Exit For
End If
Next k
Call LabelingBorder(X_coord, Y_coord, code, label0, dot, lab)
End If
End If
End If
k = lab(X_coord, Y_coord)
If k >= 1 Then
area(k) = area(k) + 1
xc(k) = xc(k) + X_coord
yc(k) = yc(k) + Y_coord
End If
Next i
時限性など求めていないので、
無駄にスレッドを消費せず、よく考え、整理してから投稿してください。
スレッドの消費 = ここの管理者殿の負担増です。
また、貴殿の研究内容を知らない、赤の他人にもVBレベルで理解できるような
適切な情報整理と開示(情報共有)を心掛けてください。
>取得した画像の配列の値が変わるだけです。
これが貴殿のプログラムに与える影響を考察する必要がありそうです。
例えば、値が変わることで終了条件値に到達できなくなり無限ループする等ですが、
なにか心当たりはありますか?
>確認しようとデバックを行い1文ずつ試みましたが、
>条件文(if)の内容に当てはまらなかったため、あまり意味がありませんでした。
可能であれば、フリーズする条件でデバッグし、
フリーズする個所と原因を追求してください。
うまくいくコード例だけ見ても意味が無いです。
うまくいかないコードとの差異を考察してください。
1秒間あたりのキャプチャー数が、
少ない→OK 多い→フリーズ
タイムラグが、
ある→OK ない→フリーズ
ということなら、マシンスペック等ハードウェア的な限界も考えられます。
こうなるとVBの話ではなくなりますが、
フリーズしない程度に負荷を調整してみてください。
'ここから先は、貴殿の指導担当教官殿の仕事のような気がしてきました。
理系の研究の内部事情はわかりませんし、
このコードの意味も不明なんですが、
私なりに思い浮かんだのは
1.framesizeをいくつかに分割して処理を複数回にして
タイムラグを発生しないようにして、フリーズも回避させる。
'2.マルチスレッド化してタイムラグが発生しないように設計する。
なんてどうですか?
役に立たなかったらごめんなさい。
始めのIf文が終わってませんが
ヤマ@文系さんへ
マルチスレッド化について自分なりに調べてみたのですが、イマイチよくわかりませんでした。もしよければ簡単に説明していただくとありがたいのですが‥‥。
VB6なのだから、マルチスレッド化はかなり難しいものと思われます。
PCの能力などにもよりますが、こういう処理はVB6には不向きです。
で、それを踏まえた上で、それでも挑むというのならば、とりあえず
できる範囲から高速化を検討してみては。
たとえば、
Forループでは、Step 3などではなく、常にStep 1になるようにする。
少数除算(/)ではなく、整数除算(\)を使う。
変換関数(Intなど)の呼び出しを極力減らす。
内部での他関数の呼び出しを極力減らす。
ユーザインターフェースにかかわることは最低限度にする。
などなど、今でもできることはたくさんあります。
# まぁ、これだけやっても1桁上がればいいほうですが。
このコードの実行速度は、ひとえに
Call LabelingBorder(X_coord, Y_coord, code, label, dot, lab)
この画像の境界線を切り出すモジュールにかかっています。
このモジュールがいったい何者であるか解からないかぎり、適切なコメントは
誰にも出来ないのです。
K.J.K.さんへ
マルチスレッド化については、難しそうのなのであきらめることにします。そのかわり、K.J.K.さんが言われるように自分なりにこれからも高速化を検討したいと思います。まだまだプログラム初心者なので自分なりに考えたものは無駄が多いと思いますが、なかなか自分では気づきにくいと思うので、またアドバイスがあればよろしくお願いします。
我龍院さんへ
画像の境界線を切り出すプログラムについては本に書いてあったものをそのまま参考にして使いました。下記の内容がそのプログラムです。今の状態では画素を1つずつ走査しているのでかなり処理時間がかかってしまいます。そのため、自分なりに工夫してみたのですが、その結果フリーズしてしまいました。何かいいアドバイスがあればよろしくお願いします。
<プログラム>
'境界線追跡を行いながら境界のラベリング(8-連結)
Private Sub LabelingBorder(ByVal X_coord%, ByVal Y_coord%, ByVal code%, label%, ByRef dot() As Integer, ByRef lab() As Integer)
Dim X_coordStart%, Y_coordStart% '始点
Dim X_coord1%, Y_coord1% '現在位置
Dim X_coord2%, Y_coord2% '探索位置
X_coordStart = X_coord: X_coord1 = X_coord
Y_coordStart = Y_coord: Y_coord1 = Y_coord
While (X_coord2 <> X_coordStart Or Y_coord2 <> Y_coordStart)
Select Case code
Case 0: '下を調査
X_coord2 = X_coord1: Y_coord2 = Y_coord1 + 1
If dot(X_coord2, Y_coord2) = 1 Then
code = 6
Else
code = 1
End If
Case 1: '右下
X_coord2 = X_coord1 + 1: Y_coord2 = Y_coord1 + 1
If dot(X_coord2, Y_coord2) = 1 Then
code = 7
Else
code = 2
End If
Case 2: '右を調査
X_coord2 = X_coord1 + 1: Y_coord2 = Y_coord1
If dot(X_coord2, Y_coord2) = 1 Then
code = 0
Else
code = 3
End If
Case 3: '右上
X_coord2 = X_coord1 + 1: Y_coord2 = Y_coord1 - 1
If dot(X_coord2, Y_coord2) = 1 Then
code = 1
Else
code = 4
End If
Case 4: '上を調査
X_coord2 = X_coord1: Y_coord2 = Y_coord1 - 1
If dot(X_coord2, Y_coord2) = 1 Then
code = 2
Else
code = 5
End If
Case 5: '左上を調査
X_coord2 = X_coord1 - 1: Y_coord2 = Y_coord1 - 1
If dot(X_coord2, Y_coord2) = 1 Then
code = 3
Else
code = 6
End If
Case 6: '左を調査
X_coord2 = X_coord1 - 1: Y_coord2 = Y_coord1
If dot(X_coord2, Y_coord2) = 1 Then
code = 4
Else
code = 7
End If
Case 7: '左下を調査
X_coord2 = X_coord1 - 1: Y_coord2 = Y_coord1 + 1
If dot(X_coord2, Y_coord2) = 1 Then
code = 5
Else
code = 0
End If
End Select
If dot(X_coord2, Y_coord2) = 1 Then
lab(X_coord2, Y_coord2) = label
X_coord1 = X_coord2: Y_coord1 = Y_coord2 '現在位置の更新
End If
Wend
End Sub
ウーン...
画像ボードから吐き出される、2値化された480x640の画像データー
をラベリングしているような。
Select Case はIf〜Thenに比べて遅いんですよね、と言うか、
VBの板で言うのも何ですがこういう処理はVBでは無理ですね、
速くしたいんならそっくりCのDllでしょう。
我龍院さんへ
やはり実行速度を考えるとVBではなく、Cなのかも知れません。一度VC++でDLLを行ってみたいと思います。また、今のVBでのプログラム内容にまだ無駄なところがあると思うので、検討してみたいと思います。
また何かアドバイスがあればよろしくお願いします。
>X_coord = Int((i Mod 1920) / 3)
>Y_coord = Int(i / 1920)
この部分は1画像毎に640x480/3=102400回計算されますが、
結構時間がかかります。
これは実は定数なんですね、そこでこれをその都度計算するのでは無く、
始めに配列を確保して、最初の一度だけ計算しましょう。
配列の大きさは、480x640x2/3=204800個 となりますが、
現在の様にマシンにメモリーを沢山積む時代には、メモリを活用し
その恩恵に浴しましょう。
C++でDllを作る場合は、インスタンス毎にこの変数がアロケート
されることが無いように、Dll側で変数を保持する場合は
#pragma data_segを使うか、VBの方に配列を持たせて、
Dllに参照渡しで渡します。
我龍院さんへ
キャプチャー画像はもともとバイト型で1次元配列(640×480×3)で構成されています。しかし、ラベリングをする際にわかりにくくなるために2次元配列をつくり、XY座標系に変換してから計算していました。やはり計算に時間がかかりすぎるようなので頑張って1次元配列でもできるようにしたいと思います。
VC++のDLLは一度もやったことがないので自分なりに調べてやってみるつもりですが、簡単にできる方法ややり方など教えてもらえるとありがたいです。
またアドバイスがあればよろしくお願いします。
ツイート | ![]() |