ScanLineを用いて、ライントレースをしたいです。(Delphi6 Personal)

解決


太郎  2013-02-08 00:39:35  No: 43775

こんにちは、太郎と申します。
プログラミング初心者ですが、Delphi6を用いてライントレースみたいなことをしようと考えています。

BitmapやJpeg画像にある物体に対し、ScanLineを用いてその物体の外形の境目付近のRGB値を取得して、その物体の形を判断しようというものです。

普通に2値化したり最小二乗法を用いてやる方法もあるようですが、今回はこの方法を敢えてやってみたいと思った所存です。

コピー機のように縦に何ピクセルかずつ、横にRGB値を取得していく感じです。
その物体の上部が出来たら次は右分、その次は下部、そして左部とやっていくイメージです。
(つまり、上・下部は縦何ピクセルかを横に、左右部は横何ピクセルかを縦にスキャンしていく感じです。)

今のところ、スタート位置の座標だけ自分で打ち、そこから横に読み込んでいくところまではできました。
次は縦に読み込んでいくのですが、ボタン一つで縦も横もすべてやりたいというのが本音で、できれば楕円やピーナッツのようなものを出来るようにしたいです。

今のところのやり方は、以下の通りです。

unit Unit1;
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,Jpeg;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
    procedure OutputRGB(Col: TColor);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.OutputRGB(Col: TColor);
type
  TRGB = packed record
    case Integer of
      0: (Col: TColor;);
      1: (R:   Byte;
          G:   Byte;
          B:   Byte;
          I:   Byte;);
  end;
var
  R, G, B : Byte;

begin
  // 関数(マクロ扱い)を使った、TColor値 → R,G,Bの取り出し
    R:=GetRValue(Col);
    G:=GetGValue(Col);
    B:=GetBValue(Col);

    Memo1.Lines.Add(' (R): '+InttoStr(R)+
                    ' (G): '+InttoStr(G)+
                    ' (B): '+InttoStr(B));

  end;

procedure TForm1.Button1Click(Sender: TObject);
const
  // Bmpファイルを指定する
  BMPFile='C:\Users\User\Pictures\My  PictureⅠ\ファイル名.bmp';

var
  BMP: TBitmap;
  i,j:integer;
begin
  BMP:=TBitmap.Create;
  try
    BMP.LoadFromFile(BMPFile);
    Memo1.Lines.Add('--------------------'+ExtractFileName(BMPFile));

    for i:=0 to 10 do begin     //(x,y)=(0,0)〜(10,10)の場合
    for j:=0 to 10 do begin

    Memo1.Lines.Add(inttoStr(i)+'---------------------');
    Memo1.Lines.Add(inttoStr(j)+'---------------------');
    OutputRGB(BMP.Canvas.Pixels[i, j]);

    end;
    end;

  finally
    BMP.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
const
  // Jpegファイルを指定する
  JPGFile='C:\Users\User\Pictures\My  PictureⅠ\ファイル名.jpg';
var
  JPG: TJPEGImage;
  BMP: TBitmap;
  i,j:integer;
begin
  JPG:=TJPEGImage.Create;
  BMP:=TBitmap.Create;

  try
    JPG.LoadFromFile(JPGFile);
    BMP.Assign(JPG);
    Memo1.Lines.Add('----------'+ExtractFileName(JPGFile));

    for i:=0 to 10 do begin       //(x,y)=(0,0)〜(10,10)の場合
    for j:=0 to 10 do begin

    Memo1.Lines.Add(inttoStr(i)+'-----------------');
    Memo1.Lines.Add(inttoStr(j)+'-----------------');

    OutputRGB(BMP.Canvas.Pixels[i, j]);
    end;

   end;
  finally
    BMP.Free;
    JPG.Free;
  end;
end;

end.

初心者故、スマートに出来ていないところ、拙いところはかなりあるかと思いますが、ご助言頂けると幸いです。
また、ここをこうすると良いといった改善策等もございましたら、ご教授頂けると嬉しいです。
質問に関してわからない事等ございましたら、知識はあまりないかもしれませんが、できる限り答えさせて頂きたいと思います!

どうぞよろしくお願いしますm(__)m


太郎  2013-02-08 00:42:31  No: 43776

申し訳ありません。
注釈のところにある、画像の座標は(i,j)でしたm(_ _)m


助監督  2013-02-09 02:21:24  No: 43777

質問が不明確すぎて、何を知りたいのかまったく分からないのですが…。

>ScanLineを用いて、ライントレースをしたいです。
現在はCanvas.Pixelsを使ってますよね。これをScanLineに変更したいということでしょうか?
もしそうならScanLineは若干難しいので、今はCanvas.Pixelsを使っていたほうが良いと思います。
アルゴリズムが固まり、望む動作をするコードが出来てからチャレンジしても遅くありません。

気になった点ですが、レコード型の宣言はTRGB型を使用していないなら不要です。
type 〜 end; までを削除してしまった方が良いかと。

あと、for〜end文はインデントさせて見やすくすると良いと思います。


太郎  2013-02-12 02:29:52  No: 43778

>>Canvas.Pixelsを使っていたほうが良いと思います。

了解しました。このまま、まず自分のやりたい動作が出来る様にしたいと思います。

>>レコード型の宣言はTRGB型を使用していないなら不要です。
type 〜 end; までを削除してしまった方が良いかと。
for〜end文はインデントさせて見やすくすると良いと思います。

ご指摘、ありがとうございます。そのようにして改善したいと思います。

>>質問が不明確すぎて、何を知りたいのかまったく分からないのですが…。

例えば背景を黒、物体を白としたときに、その物体の外形の座標だけを出力するようなプログラムを作りたいと思っています。
最終的にその座標を線で繋ぐことが出来れば万々歳、と思っていますが^^;
説明が不十分で申し訳ありませんでしたm(_ _)m


Mr.XRAY  2013-02-12 09:35:33  No: 43779

こんにちは,

>例えば背景を黒、物体を白としたときに、その物体の外形の座標

これはそんなに難しくはないでしょう.
左上からスキャンして,黒でなければ,そのピクセルの座標を保存または,
そのピクセルには何もせず,次のピクセルを黒にするだけです.
この操作を縦方向にもやるだけです.
これなら,輪郭抽出処理のアルゴリズムにしたがって処理するよりはるかに高速です.

>最終的にその座標を線で繋ぐことが出来れば

全く必要ありません.何故なら,

>例えば背景を黒、物体を白としたときに

と仮定していますから,その白い図形は閉じています(たとえ複数あっても,各々は).
つまり,結果のピクセルは連続しています.部分的にはすでに直線です.
ただし,結果の図形,これは輪郭となっています.
これを拡大や縮小あるいは,何かしらの処理をすると問題が発生することがあります.
どんな問題なのかは,経験....  かな ?

そういう場合は,
本来の画像処理のアルゴリズムにしたがって処理するしかありません.
だからこそ,画像処理のアルゴリズムが,いろいろ開発されているわけですね.


太郎  2013-02-12 14:35:35  No: 43780

Mr.XRAYさん
コメントありがとうございます。
なるほど・・・とてもわかりやすいです!

>>左上からスキャンして,黒でなければ,そのピクセルの座標を保存または,そのピクセルには何もせず,次のピクセルを黒にするだけです

とありますが、そのようなプログラムはどのように作ればいいでしょうか?
誠に恐縮ですが、ソースプログラムを載せて頂けたら幸いです。
拡大・縮小等の処理については、今のところはまだ良いです。


Mr.XRAY  2013-02-12 16:57:07  No: 43781

>そのようなプログラムはどのように作ればいいでしょうか?

多分,世の中には,同じようなことを考えている,やっているかも知れない.
と考えて,ネット上を探してみるといいでしょう.
ただ,検索語句を何にするかによって,検索結果が変わってきます.
このあたりも一種のノウハウかも知れません.
Delphi なので,これは入れるといいですね.

自分で調べることには,副次効果もあります.
他の情報を見て,画像のことだけではなく,「あっ,こんなの方法もあるのか.こんなのも」
というように.

Personal 版を使用しているということですが,許されるのであれば,
有料のエデション (Pro 版) 等を購入するいいです.
すると,ソースコードが付いています.
このソースコードが大変参考になります.

では,がんばってください !!


太郎  2013-02-12 17:25:33  No: 43782

Mr.XRAYさん
ありがとうございます。
もっと調べてやってみたいと思います。

このプログラムが出来た時、この質問は解決としたいと思います。


Mr.XRAY  2013-02-12 19:03:58  No: 43783

>そのピクセルには何もせず,次のピクセルを黒にするだけです.
>この操作を縦方向にもやるだけです.

と書いたのですが,これだけでは輪郭抽出はできませんね.
あるピクセルに対して,上下左右方向の検査も必要です.
単なるスキャンだけでは難しいかも知れませんね.

先人達が苦労して開発したアルゴリズムというのは伊達ではないということでしょうか.


Mr.XRAY  2013-02-12 19:08:27  No: 43784

>単なるスキャンだけでは難しいかも知れませんね.

単なるスキャンだけではできませんね.


太郎  2013-02-12 21:50:02  No: 43785

Mr.XRAYさん

それか、for k:=i to i+5  のようにして、i+3に白が来るときの座標を出して、辿っていくというのはどうでしょうか??


太郎  2013-02-12 21:56:34  No: 43786

もしその方法で出来るのであれば、プログラムをどう組んでいいのかわからないので、ソースプログラムを知りたいです。
エッジ検出もままならない現状なので・・・><。


Nov  2013-02-12 22:42:18  No: 43787

この辺が参考になるかも。

第3章 画像処理入門1  〜 アルゴリズム入門 〜
http://msdn.microsoft.com/ja-jp/cc998604.aspx

目的がラスターベクター変換なら、テーマが重すぎる気がしますが、
実現の暁には、相当なレベルアップが期待できます。


太郎  2013-02-12 23:03:19  No: 43788

Novさん

ありがとうございます。
手も足も出なくて困っています・・・(泣


Mr.XRAY  2013-02-13 05:40:39  No: 43789

>実現の暁には、相当なレベルアップが期待できます。

御意.
簡単にできるようなら,画像処理の研究は苦労しませんって.
今回は,輪郭抽出が目的ではなく,自分で,その機能をコーディングしたいようですので.
がんばってください,というしかないですね.


太郎  2013-02-13 07:28:58  No: 43790

Mr.XRAYさん
ありがとうございます。今日も徹夜で頑張って考えてみます。


太郎  2013-02-27 06:48:15  No: 43791

https://www.petitmonte.com/bbs/answers?question_id=7886

こちらに合流しました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加